FixPointGenCuts.cpp
Go to the documentation of this file.
1 /* $Id: FixPointGenCuts.cpp 1079 2014-10-30 17:25:09Z pbelotti $
2  *
3  * Name: FixPointGenCuts.cpp
4  * Author: Pietro Belotti
5  * Purpose: Fix point bound tightener -- separator
6  *
7  * (C) Pietro Belotti, 2010.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CoinHelperFunctions.hpp"
12 #include "OsiClpSolverInterface.hpp"
13 #include "OsiCuts.hpp"
14 #include "CoinTime.hpp"
15 
16 #include "CouenneFixPoint.hpp"
17 
18 #include "CouenneProblem.hpp"
19 #include "CouennePrecisions.hpp"
20 #include "CouenneExprVar.hpp"
21 #include "CouenneInfeasCut.hpp"
22 
23 using namespace Ipopt;
24 using namespace Couenne;
25 
27 
28 void CouenneFixPoint::generateCuts (const OsiSolverInterface &si,
29  OsiCuts &cs,
30  const CglTreeInfo treeInfo)
31 #if CGL_VERSION_MAJOR == 0 && CGL_VERSION_MINOR <= 57
32  const
33 #endif
34  {
35 
44 
45  if (firstCall_)
46  firstCall_ = false;
47  else
48  if (!(problem_ -> fbbtReachedIterLimit ()))
49  return;
50 
51  if (isWiped (cs))
52  return;
53 
54  // do it at most once per node
55 
56  if (treeInfo.inTree &&
57  treeInfo.level > 0 &&
58  treeInfo.pass > 1)
59  return;
60 
61  double startTime = CoinCpuTime ();
62 
63  int nInitTightened = nTightened_;
64 
65  if (treeInfo.inTree &&
66  treeInfo.level <= 0) {
67 
68  problem_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, "Fixed Point FBBT: ");
69  fflush (stdout);
70  }
71 
72  //++nRuns_;
73 
74  double now = CoinCpuTime ();
75 
76  problem_ -> domain () -> push (&si, &cs);
77 
78  double
79  *oldLB = CoinCopyOfArray (problem_ -> Lb (), problem_ -> nVars ()),
80  *oldUB = CoinCopyOfArray (problem_ -> Ub (), problem_ -> nVars ());
81 
82  perfIndicator_. setOldBounds (problem_ -> Lb (), problem_ -> Ub ());
83 
102 
103  OsiSolverInterface *fplp = NULL;
104 
105  if (true) { // placeholder for later selection of LP solver among
106  // those available
107 
108  fplp = new OsiClpSolverInterface;
109  }
110 
127 
129 
130  const CoinPackedMatrix *A = si. getMatrixByRow ();
131 
132  const int
133  n = si. getNumCols (),
134  m = si. getNumRows (),
135  nCuts = cs.sizeRowCuts (),
136  *ind = A -> getIndices ();
137 
138  const double
139  *lb = problem_ -> Lb (), //si. getColLower (),
140  *ub = problem_ -> Ub (), //si. getColUpper (),
141  *rlb = si. getRowLower (),
142  *rub = si. getRowUpper (),
143  *coe = A -> getElements ();
144 
145  if (problem_ -> Jnlst () -> ProduceOutput (J_ERROR, J_BOUNDTIGHTENING))
146  for (int i=0; i<n; i++)
147  printf ("----------- x_%d in [%g,%g]\n", i, lb [i], ub [i]);
148 
149  // turn off logging
150  fplp -> messageHandler () -> setLogLevel (0);
151 
152  // add lvars and uvars to the new problem
153  for (int i=0; i<n; i++) {
154  bool isActive = problem_ -> Var (i) -> Multiplicity () > 0;
155  fplp -> addCol (0, NULL, NULL, lb [i], ub [i], isActive ? -1. : 0.); // xL_i
156  }
157 
158  for (int i=0; i<n; i++) {
159  bool isActive = problem_ -> Var (i) -> Multiplicity () > 0;
160  fplp -> addCol (0, NULL, NULL, lb [i], ub [i], isActive ? +1. : 0.); // xU_i
161  }
162 
163  if (extendedModel_) {
164 
165  for (int j=0; j<m; j++) fplp -> addCol (0, NULL, NULL, rlb [j], COIN_DBL_MAX, 0.); // bL_j
166  for (int j=0; j<m; j++) fplp -> addCol (0, NULL, NULL, -COIN_DBL_MAX, rub [j], 0.); // bU_j
167  }
168 
169  // Scan each row of the matrix
170 
171  for (int j=0; j<m; j++) { // for each row
172 
173  int nEl = A -> getVectorSize (j); // # elements in each row
174 
175  if (!nEl)
176  continue;
177 
178  if (problem_ -> Jnlst () -> ProduceOutput (J_ERROR, J_BOUNDTIGHTENING)) {
179 
180  printf ("row %4d, %4d elements: ", j, nEl);
181 
182  for (int i=0; i<nEl; i++) {
183  printf ("%+g x%d ", coe [i], ind [i]);
184  fflush (stdout);
185  }
186 
187  printf ("\n");
188  }
189 
190  // create cuts for the xL and xU elements //////////////////////
191 
192  if (extendedModel_ || rlb [j] > -COUENNE_INFINITY)
193  for (int i=0; i<nEl; i++)
194  createRow (-1, ind [i], n, fplp, ind, coe, rlb [j], nEl, extendedModel_, j, m + nCuts); // downward constraints -- on x_i
195 
196  if (extendedModel_ || rub [j] < COUENNE_INFINITY)
197  for (int i=0; i<nEl; i++)
198  createRow (+1, ind [i], n, fplp, ind, coe, rub [j], nEl, extendedModel_, j, m + nCuts); // downward constraints -- on x_i
199 
200  // create (at most 2) cuts for the bL and bU elements //////////////////////
201 
202  if (extendedModel_) {
203  createRow (-1, 2*n + j, n, fplp, ind, coe, rlb [j], nEl, extendedModel_, j, m + nCuts); // upward constraints -- on bL_i
204  createRow (+1, 2*n + m + j, n, fplp, ind, coe, rub [j], nEl, extendedModel_, j, m + nCuts); // upward constraints -- on bU_i
205  }
206 
207  ind += nEl;
208  coe += nEl;
209  }
210 
211  // similarly, scan previous cuts in cs //////////////////////////////////////
212 
213  for (int j = 0, jj = nCuts; jj--; j++) {
214 
215  // create cuts for the xL and xU elements //////////////////////
216 
217  OsiRowCut *cut = cs.rowCutPtr (j);
218 
219  const CoinPackedVector &row = cut -> row ();
220 
221  const int
222  nEl = row.getNumElements (),
223  *ind = row.getIndices ();
224 
225  const double *coe = row.getElements ();
226 
227  if (extendedModel_) {
228  fplp -> addCol (0, NULL, NULL, cut -> lb (), COIN_DBL_MAX, 0.); // bL_j
229  fplp -> addCol (0, NULL, NULL, -COIN_DBL_MAX, cut -> ub (), 0.); // bU_j
230  }
231 
232  if (extendedModel_ || cut -> lb () > -COUENNE_INFINITY)
233  for (int i=0; i<nEl; i++)
234  createRow (-1, ind [i], n, fplp, ind, coe, cut -> lb (), nEl, extendedModel_, m + j, m + nCuts); // downward constraints -- on x_i
235 
236  if (extendedModel_ || cut -> ub () < COUENNE_INFINITY)
237  for (int i=0; i<nEl; i++)
238  createRow (+1, ind [i], n, fplp, ind, coe, cut -> ub (), nEl, extendedModel_, m + j, m + nCuts); // downward constraints -- on x_i
239 
240  // create (at most 2) cuts for the bL and bU elements
241 
242  if (extendedModel_) {
243  createRow (-1, 2*n + j, n, fplp, ind, coe, cut -> lb (), nEl, extendedModel_, m + j, m + nCuts); // upward constraints -- on bL_i
244  createRow (+1, 2*n + m + nCuts + j, n, fplp, ind, coe, cut -> ub (), nEl, extendedModel_, m + j, m + nCuts); // upward constraints -- on bU_i
245  }
246 
247  ind += nEl;
248  coe += nEl;
249  }
250 
251  // finally, add consistency cuts, bL <= bU
252 
253  if (extendedModel_)
254 
255  for (int j=0; j<m; j++) { // for each row
256 
257  int ind [2] = {2*n + j, 2*n + m + j};
258  double coe [2] = {1., -1.};
259 
260  CoinPackedVector row (2, ind, coe);
261  fplp -> addRow (row, -COIN_DBL_MAX, 0.);
262  }
263 
266 
267  fplp -> setObjSense (-1.); // we want to maximize
268 
269  //printf ("(writing lp) "); fflush (stdout);
270  //fplp -> writeLp ("fplp");
271 
272  // sometimes Clp gets stuck on these fplps...
273  fplp -> setIntParam (OsiMaxNumIteration, CoinMax (100, fplp -> getNumRows ()));
274 
275  // we are maximizing the size of the box. If the initial box [l0,u0]
276  // is bounded, since the final one is contained in [l0,u0] we can
277  // set as a primal limit (Clp will stop after reaching it) a value
278  // close to it, since we won't need tightening if the one norm is
279  // very close to the old one.
280 
281  double one_norm = 0;
282  bool one_inf_bd = false;
283 
284  for (int i=0; i<n; ++i) {
285 
286  if ((oldLB [i] < -COUENNE_INFINITY) ||
287  (oldUB [i] > COUENNE_INFINITY)) {
288  one_inf_bd = true;
289  break;
290  }
291 
292  one_norm += (oldUB [i] - oldLB [i]);
293  }
294 
295 #define APPROX_USELESS .99
296 
297  //csi -> setDblParam (OsiDualObjectiveLimit, COIN_DBL_MAX);
298  if (!one_inf_bd)
299  fplp -> setDblParam (OsiPrimalObjectiveLimit, APPROX_USELESS * one_norm);
300 
301  fplp -> initialSolve ();
302 
303  //fplp -> writeLp ("beforefplp"); // TODO: remove
304 
305  // Extra pre-solve: if the initial LP is unbounded (that is,
306  // dual-infeasible but not primal-infeasible), then repeat after a
307  // call to BT. This is a cheap way not to throw
308 
309  if (fplp -> isProvenDualInfeasible () &&
310  !(fplp -> isProvenPrimalInfeasible ())) {
311 
312  problem_ -> Jnlst () -> Printf (J_WARNING, J_BOUNDTIGHTENING, "FPLP unbounded: extra BT\n");
313 
314  if (!(problem_ -> doFBBT ()) && // if FBBT was not applied before (because it was excluded,
315  !(problem_ -> btCore (NULL))) // do a round of FBBT. If infeasible,
316  WipeMakeInfeas (cs); // well, this is infeasible though FPLP will take the merit
317 
318  // Otherwise, reset bounds on auxiliaries based on new bounds in problem_ -> domain ();
319 
320  for (int i=0; i<n; i++) {
321  fplp -> setColLower ( i, problem_ -> Lb (i)); // set lower bound for xL [i]
322  fplp -> setColLower (n+i, problem_ -> Lb (i)); // xU
323  fplp -> setColUpper ( i, problem_ -> Ub (i)); // upper xL
324  fplp -> setColUpper (n+i, problem_ -> Ub (i)); // xU
325  }
326 
327  //fplp -> writeLp ("fplp+bt"); // TODO: remove
328 
329  fplp -> resolve ();
330  }
331 
332  const double
333  *newLB = fplp -> getColSolution (),
334  *newUB = newLB + n;
335 
336  double infeasBounds [] = {1,-1};
337 
338  //problem_ -> Jnlst () -> Printf (J_WARNING, J_BOUNDTIGHTENING, "FBBTFP point:\n");
339 
340  if (fplp -> isProvenOptimal ()) {
341 
342  // if problem not solved to optimality, bounds are useless
343 
344  // check old and new bounds
345 
346  int
347  *indLB = new int [n],
348  *indUB = new int [n],
349  ntightenedL = 0,
350  ntightenedU = 0;
351 
352  double
353  *valLB = new double [n],
354  *valUB = new double [n];
355 
356  for (int i=0; i<n; i++) {
357 
358  if (problem_ -> Jnlst () -> ProduceOutput (J_ERROR, J_BOUNDTIGHTENING))
359  printf ("x%d: [%g,%g] --> [%g,%g]\n", i,
360  oldLB [i], oldUB [i],
361  newLB [i], newUB [i]);
362 
363  if (newLB [i] > oldLB [i] + COUENNE_EPS) {
364 
365  indLB [ntightenedL] = i;
366  valLB [ntightenedL++] = newLB [i];
367 
368  ++nTightened_;
369  }
370 
371  if (newUB [i] < oldUB [i] - COUENNE_EPS) {
372 
373  indUB [ntightenedU] = i;
374  valUB [ntightenedU++] = newUB [i];
375 
376  ++nTightened_;
377  }
378  }
379 
380  if (ntightenedL || ntightenedU) {
381 
382  OsiColCut newBound;
383 
384  newBound.setLbs (ntightenedL, indLB, valLB);
385  newBound.setUbs (ntightenedU, indUB, valUB);
386 
387  cs.insert (newBound);
388  }
389 
390  delete [] indLB;
391  delete [] indUB;
392  delete [] valLB;
393  delete [] valUB;
394 
395  CPUtime_ += CoinCpuTime () - now;
396 
397  if (treeInfo.inTree &&
398  treeInfo.level <= 0)
399  problem_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, "%d bounds tightened (%g seconds)\n",
400  nTightened_ - nInitTightened, CoinCpuTime () - now);
401 
402  } else if (fplp -> isProvenPrimalInfeasible ()) {
403 
404  if (treeInfo.inTree &&
405  treeInfo.level <= 0)
406  problem_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, " FPLP infeasible.\n");
407 
408  WipeMakeInfeas (cs);
409 
410  newLB = infeasBounds;
411  newUB = infeasBounds + 1;
412 
413  } else {
414 
415  // we won't use the solution from FPLP, and should tell the BT
416  // performance indicator that nothing should change.
417 
418  if (treeInfo.inTree &&
419  treeInfo.level <= 0)
420  problem_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, " FPLP inconclusive, won't be used.\n");
421 
422  newLB = oldLB;
423  newUB = oldUB;
424  }
425 
426  // problem_ -> Jnlst () -> Printf (J_ERROR, J_BOUNDTIGHTENING, "END\n");
427 
428  delete fplp;
429 
430  perfIndicator_. update (newLB, newUB, treeInfo.level);
431  perfIndicator_. addToTimer (CoinCpuTime () - startTime);
432 
433  problem_ -> domain () -> pop ();
434 
435  delete [] oldLB;
436  delete [] oldUB;
437 }
438 
439 
440 // single cut creation. Parameters:
441 //
442 // 1) sign: tells us whether this is a <= or a >= (part of a) constraint.
443 // 2) indexVar: index of variable we want to do upward or downward bt
444 // 3) nVars: number of variables in the original problems (original +
445 // auxiliaries). Used to understand if we are adding an
446 // up or a down constraint
447 // 4) p: solver interface to which we are adding constraints
448 // 5) indices: vector containing indices of the linearization constraint (the i's)
449 // 6) coe: coeffs a_ji's
450 // 7) rhs: right-hand side of constraint
451 // 8) nEl: number of elements of this linearization cut
452 // 9) extMod: extendedModel_
453 // 10) indCon: index of constraint being treated (and corresponding bL, bU)
454 // 11) nCon: number of constraints
455 
456 void CouenneFixPoint::createRow (int sign,
457  int indexVar,
458  int nVars,
459  OsiSolverInterface *p,
460  const int *indices,
461  const double *coe,
462  const double rhs,
463  const int nEl,
464  bool extMod,
465  int indCon,
466  int nCon) const {
467 
569 
570 
571  if (problem_ -> Jnlst () -> ProduceOutput (J_ERROR, J_BOUNDTIGHTENING)) {
572 
573  printf ("creating constraint from: ");
574 
575  for (int i=0; i<nEl; i++)
576  printf ("%+g x%d ", coe [i], indices [i]);
577 
578  printf ("%c= %g for variable index %d: ", sign > 0 ? '<' : '>', rhs, indexVar);
579  }
580 
581  int nTerms = nEl;
582 
583  if (extMod)
584  nTerms++; // always add one element when using extended model
585 
586  int *iInd = new int [nTerms];
587  double *elem = new double [nTerms];
588 
589  // coefficients are really easy
590 
591  CoinCopyN (coe, nEl, elem);
592 
593  if (extMod) {
594  elem [nEl] = -1.; // extended model, coefficient for bL or bU
595  iInd [nEl] = 2*nVars + indCon + ((sign > 0) ? nCon : 0);
596  }
597 
598  // indices are not so easy...
599 
600  for (int k=0; k<nEl; k++) {
601 
602  int curInd = indices [k];
603 
604  iInd [k] = curInd; // Begin with xL_i, same index as x_i in the
605  // original model. Should add n depending on a
606  // few things...
607 
608  if (curInd == indexVar) { // x_k is x_i itself
609  if (((sign > 0) && (coe [k] > 0.)) ||
610  ((sign < 0) && (coe [k] < 0.)))
611 
612  iInd [k] += nVars;
613 
614  } else if (((coe [k] > 0.) && (sign < 0)) ||
615  ((coe [k] < 0.) && (sign > 0)))
616 
617  iInd [k] += nVars;
618  }
619 
620  CoinPackedVector vec (nTerms, iInd, elem);
621 
622  double
623  lb = sign > 0 ? -COIN_DBL_MAX : extMod ? 0. : rhs,
624  ub = sign < 0 ? +COIN_DBL_MAX : extMod ? 0. : rhs;
625 
626  p -> addRow (vec, lb, ub);
627 
628  // Update time spent doing this
629 
630  if (problem_ -> Jnlst () -> ProduceOutput (J_ERROR, J_BOUNDTIGHTENING)) {
631 
632  for (int i=0; i<nEl; i++)
633  printf ("%+g x%d ", elem [i], iInd [i]);
634 
635  printf ("in [%g,%g]\n", lb, ub);
636  }
637 
638  // OsiRowCut *cut = new OsiRowCut (lb, ub, nTerms, nTerms, iInd, elem);
639  // cut -> print ();
640  // delete cut;
641 
642  delete [] iInd;
643  delete [] elem;
644 }
bool isWiped(OsiCuts &cs)
Check whether the previous cut generators have added an infeasible cut.
static char * j
Definition: OSdtoa.cpp:3622
const Ipopt::EJournalCategory J_BOUNDTIGHTENING(Ipopt::J_USER2)
void fint fint * k
#define COUENNE_EPS
#define COUENNE_INFINITY
void fint * m
const Ipopt::EJournalCategory J_COUENNE(Ipopt::J_USER8)
void WipeMakeInfeas(OsiCuts &cs)
Add a fictitious cut 1&lt;= x_0 &lt;= -1 as a signal to the node solver that this node is deemed infeasible...
void fint * n
#define APPROX_USELESS