getDisjunctions.cpp
Go to the documentation of this file.
1 /* $Id: getDisjunctions.cpp 694 2011-06-18 20:13:17Z stefan $
2  *
3  * Name: getDisjunctions.cpp
4  * Author: Pietro Belotti
5  * Purpose: get nonlinear (and integer?) disjunctions for the problem
6  *
7  * (C) Carnegie-Mellon University, 2008-10.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CouenneCutGenerator.hpp"
12 #include "CouenneProblem.hpp"
13 #include "CouenneObject.hpp"
15 #include "CouenneDisjCuts.hpp"
16 
17 using namespace Ipopt;
18 using namespace Couenne;
19 
22 bool BranchingFBBT (CouenneProblem *problem,
23  OsiObject *Object,
24  OsiSolverInterface *solver);
25 
27 int CouenneDisjCuts::getDisjunctions (std::vector <std::pair <OsiCuts *, OsiCuts *> > &disjs,
28  OsiSolverInterface &si,
29  OsiCuts &cs,
30  const CglTreeInfo &info) const {
31 
32  OsiBranchingInformation brInfo (&si,
33  true, // bool normalSolver,
34  false); // bool copySolution=false);
35 
36  if (jnlst_ -> ProduceOutput (J_MATRIX, J_DISJCUTS))
37  for (int i=0; i<si.getNumCols (); i++)
38  printf ("%3d. %8g [%8g %8g]\n", i,
39  brInfo. solution_ [i],
40  brInfo. lower_ [i],
41  brInfo. upper_ [i]);
42 
43  // get list of best disjunction as though we were branching
44  branchingMethod_ -> setupList (&brInfo, true); // initialize
45 
46  int
47  ncols = si.getNumCols (),
48  retval = COUENNE_FEASIBLE;
49 
50  int nobjs = branchingMethod_ -> numberUnsatisfied ();
51 
52  if (nobjs) {
53 
54  if (jnlst_ -> ProduceOutput (J_DETAILED, J_DISJCUTS))
55  printf ("--- %d disjunctive objects\n", nobjs);
56 
57  const int *candidates = branchingMethod_ -> candidates ();
58  OsiObject **objs = si. objects ();
59 
60  // enumerate first (most infeasible, or most promising) objects of
61  // the list
62 
63  for (int candInd = 0, num = 0;
64  (candInd < nobjs) && (num < numDisjunctions_);
65  candInd++) {
66 
67  OsiObject *Object = objs [candidates [candInd]];
68  CouenneObject *cObj = dynamic_cast <CouenneObject *> (Object);
69 
70  // TODO: add SOS support in disjunctive cuts
71 
72  int indVar = Object -> columnNumber ();
73  if (indVar < 0)
74  continue;
75 
76  if (cObj && // IF a nonlinear object BUT:
77  ((cObj -> checkInfeasibility (&brInfo) == 0.) || // not violated
78  (cObj -> isCuttable ()))) // or we are on the "good" (convex) side
79  continue; // THEN skip
80 
81  bool feasLeft = true, feasRight = true;
82  OsiCuts *leftCuts = NULL, *rightCuts = NULL;
83 
84  const double
85  *saveLower = CoinCopyOfArray (si.getColLower (), ncols),
86  *saveUpper = CoinCopyOfArray (si.getColUpper (), ncols);
87 
88  OsiBranchingObject *brObj = Object -> createBranch (&si, &brInfo, 0); // down!
89 
90  if (brObj &&
91  jnlst_ -> ProduceOutput (J_VECTOR, J_DISJCUTS) &&
92  dynamic_cast <CouenneBranchingObject *> (brObj) &&
93  dynamic_cast <CouenneBranchingObject *> (brObj) -> variable ())
94  printf ("--- cand [%d] is %d: x_%d <>= %g [%g,%g]\n",
95  candInd,
96  candidates [candInd],
97  dynamic_cast <CouenneBranchingObject *> (brObj) -> variable () -> Index (),
98  brObj -> value (),
99  couenneCG_->Problem()->Lb(dynamic_cast<CouenneBranchingObject*>(brObj)
100  ->variable()->Index ()),
101  couenneCG_->Problem()->Ub(dynamic_cast<CouenneBranchingObject*>(brObj)
102  ->variable()->Index ()));
103 
104  // left branch ////////////////////////////////////////////////////////////
105 
106  if ((brObj -> branch (&si) >= COUENNE_INFINITY) ||
107  // Bound tightening if not a CouenneObject -- explicit
108  (!cObj && !BranchingFBBT (couenneCG_ -> Problem (), Object, &si)))
109  feasLeft = false; // left subtree infeasible
110  else leftCuts = getSingleDisjunction (si); // feasible, store new bounds in OsiCuts
111 
112  // restore initial bounds
113  si.setColLower (saveLower);
114  si.setColUpper (saveUpper);
115 
116  delete brObj;
117 
118  // right branch ////////////////////////////////////////////////////////////
119 
120  brObj = Object -> createBranch (&si, &brInfo, 1); // up!
121 
122  if ((brObj -> branch (&si) >= COUENNE_INFINITY) ||
123  // Bound tightening if not a CouenneObject -- explicit
124  (!cObj && !BranchingFBBT (couenneCG_ -> Problem (), Object, &si)))
125  feasRight = false; // right subtree infeasible
126  else rightCuts = getSingleDisjunction (si); // feasible, store new bounds in OsiCuts
127 
128  delete brObj;
129 
130  // restore initial bounds
131  si.setColLower (saveLower);
132  si.setColUpper (saveUpper);
133 
134  // done with generating a disjunction. Is any (or both) side infeasible?
135 
136  if (feasLeft && feasRight) {
137 
138  // feasible, which variables tightened?
139 
140  std::pair <OsiCuts *, OsiCuts *> newpair;
141  newpair.first = leftCuts;
142  newpair.second = rightCuts;
143 
144  disjs.push_back (newpair);
145 
146  num++;
147 
148  } else if (feasLeft) {
149 
150  jnlst_ -> Printf (J_VECTOR, J_DISJCUTS, "--- disj: infeasible right\n");
151  applyColCuts (si, leftCuts); // !!! culprit
152  retval = COUENNE_TIGHTENED;
153 
154  } else if (feasRight) {
155 
156  jnlst_ -> Printf (J_VECTOR, J_DISJCUTS, "--- infeasible left\n");
157  applyColCuts (si, rightCuts); // !!! culprit
158  retval = COUENNE_TIGHTENED;
159 
160  } else {
161  jnlst_ -> Printf (J_VECTOR, J_DISJCUTS, "--- infeasible!!!\n");
162  retval = COUENNE_INFEASIBLE;
163  break;
164  }
165 
166  delete [] saveLower;
167  delete [] saveUpper;
168  }
169  }
170 
171  // disjunctions (of bounding boxes) generated. Do some extra
172  // tightening that may result from tightened sides of the
173  // disjunctions
174 
175  if (retval != COUENNE_INFEASIBLE) {
176 
177  if (jnlst_ -> ProduceOutput (J_DETAILED, J_DISJCUTS))
178  printf ("have %d disjunctions\n", (int) (disjs.size ()));
179 
180  // sanity check: for each disjunction, check if left and right
181  // part are feasible with (possibly improved) bounds of si --
182  // these may have tightened and now exclude either (or both!)
183  // sides of a disjunction
184 
185  for (std::vector <std::pair <OsiCuts *, OsiCuts *> >::iterator disjI = disjs.begin ();
186  disjI != disjs.end (); ++disjI) {
187 
188  if (checkDisjSide (si, disjI -> first) == COUENNE_INFEASIBLE) { // left side infeasible?
189  if (checkDisjSide (si, disjI -> second) == COUENNE_INFEASIBLE) { // right side infeasible?
190 
191  retval = COUENNE_INFEASIBLE;
192  break;
193 
194  } else {
195 
196  if (jnlst_ -> ProduceOutput (J_VECTOR, J_DISJCUTS))
197  printf ("--- infeasible left [2]!\n");
198  applyColCuts (si, disjI -> second);
199  retval = COUENNE_TIGHTENED;
200  }
201  } else if (checkDisjSide (si, disjI -> second) == COUENNE_INFEASIBLE) { // right side
202 
203  if (jnlst_ -> ProduceOutput (J_VECTOR, J_DISJCUTS))
204  printf ("--- infeasible right [2]!\n");
205  applyColCuts (si, disjI -> first);
206  retval = COUENNE_TIGHTENED;
207  }
208  }
209 
210  if (retval == COUENNE_INFEASIBLE)
211  return retval;
212 
213  // merge tightened disjunction by intersecting si's bounding box
214  // with intersections of smallest boxes, one per disjunction,
215  // containing each both sides of the disjunction
216 
217  for (std::vector <std::pair <OsiCuts *, OsiCuts *> >::iterator disjI = disjs.begin ();
218  disjI != disjs.end (); ++disjI) {
219 
220  CoinPackedVector lowerChg, upperChg;
221 
222  // find smallest box containing two disjunctions
223  getBoxUnion (si, disjI -> first, disjI -> second, lowerChg, upperChg);
224 
225  if ((lowerChg.getNumElements () > 0) ||
226  (upperChg.getNumElements () > 0)) {
227 
228  OsiColCut cut;
229  cut.setLbs (lowerChg);
230  cut.setUbs (upperChg);
231  applyColCuts (si, &cut);
232 
233  cs.insert (cut);
234  }
235  }
236  }
237 
238  return retval;
239 }
240 
241 
243 void CouenneDisjCuts::applyColCuts (OsiSolverInterface &si, OsiCuts *cuts) const {
244 
245  if (jnlst_ -> ProduceOutput (J_MATRIX, J_DISJCUTS)) {
246  printf ("applying cuts to SI:\n");
247  // apply column cuts to si
248  for (int i = cuts -> sizeColCuts (); i--;)
249  cuts -> colCutPtr (i) -> print ();
250  printf ("--------------------\n");
251  }
252 
253  // apply column cuts to si
254  for (int i = cuts -> sizeColCuts (); i--;)
255  applyColCuts (si, cuts -> colCutPtr (i));
256 }
257 
258 
260 void CouenneDisjCuts::applyColCuts (OsiSolverInterface &si, OsiColCut *cut) const {
261 
262  // apply single column cut to si
263  if (jnlst_ -> ProduceOutput (J_VECTOR, J_DISJCUTS)) {
264  printf ("tightening bounds: ");
265  cut -> print ();
266  }
267 
268  const CoinPackedVector
269  &lbs = cut -> lbs (),
270  &ubs = cut -> ubs ();
271 
272  const int *lind = lbs.getIndices (), *uind = ubs.getIndices ();
273  const double *lval = lbs.getElements (), *uval = ubs.getElements (),
274  *oldLower = si.getColLower (),
275  *oldUpper = si.getColUpper ();
276 
277  for (int j=lbs.getNumElements (); j--; lval++, lind++)
278  if (*lval > oldLower [*lind] + COUENNE_EPS)
279  si.setColLower (*lind, *lval);
280 
281  for (int j=ubs.getNumElements (); j--; uval++, uind++)
282  if (*uval < oldUpper [*uind] - COUENNE_EPS)
283  si.setColUpper (*uind, *uval);
284 }
bool BranchingFBBT(CouenneProblem *problem, OsiObject *Object, OsiSolverInterface *solver)
Called from simulateBranch and from disjunctive cut generators when object is not CouenneObject and t...
void fint fint fint real fint real real real real real real real real real fint real fint fint fint real fint fint fint fint * info
OsiObject for auxiliary variables $w=f(x)$.
const Ipopt::EJournalCategory J_DISJCUTS(Ipopt::J_USER6)
static char * j
Definition: OSdtoa.cpp:3622
Class for MINLP problems with symbolic information.
#define COUENNE_EPS
#define COUENNE_INFINITY