doStrongBranching.cpp
Go to the documentation of this file.
1 /* $Id: doStrongBranching.cpp 860 2012-06-12 20:36:11Z pbelotti $
2  *
3  * Name: doStrongBranching.cpp
4  * Authors: Andreas Waechter, IBM Corp.
5  * Pietro Belotti, CMU
6  * Purpose: actual strong branching method
7  *
8  * (C) Carnegie-Mellon University, 2008-10.
9  * This file is licensed under the Eclipse Public License (EPL)
10  */
11 
12 #include "CoinTime.hpp"
13 #include "BonChooseVariable.hpp"
14 #include "CouenneChooseStrong.hpp"
15 #include "CouenneProblem.hpp"
16 #include "CouenneObject.hpp"
18 
19 //#define TRACE_STRONG
20 //#define TRACE_STRONG2
21 
22 using namespace Ipopt;
23 using namespace Couenne;
24 
27 bool BranchingFBBT (CouenneProblem *problem,
28  OsiObject *Object,
29  OsiSolverInterface *solver);
30 
33 double distance (const double *p1, const double *p2, int size, double k=2.) {
34 
35  double
36  result = 0.,
37  element;
38 
39  if (k == 2.) // a bit faster, probably
40 
41  while (size--) {
42  element = *p1++ - *p2++;
43  result += element * element;
44  }
45 
46  else
47 
48  while (size--) {
49  element = *p1++ - *p2++;
50  result += pow (element, k);
51  }
52 
53  return pow (result, 1. / k);
54 }
55 
56 
69  int CouenneChooseStrong::doStrongBranching (OsiSolverInterface *solver,
70  OsiBranchingInformation *info,
71  int numberToDo, int returnCriterion) {
72 
73 #ifdef TRACE_STRONG2
74  int pv = -1;
75  if(problem_->doPrint_) {
76  if(pv > -1) {
77  printf("doSB: beg: x[%d]: %10.4f lb: %10.4f ub: %10.4f\n",
78  pv, solver->getColSolution()[pv], solver->getColLower()[pv], solver->getColUpper()[pv]);
79  printf("doSB: info: x[%d]: %10.4f lb: %10.4f ub: %10.4f\n",
80  pv, info->solution_[pv], info->lower_[pv], info->upper_[pv]);
81  printf("doSB: problem: lb: %10.4f ub: %10.4f\n",
82  problem_->Lb(pv), problem_->Ub(pv));
83  }
84  }
85 #endif
86 
87  jnlst_ -> Printf (J_ITERSUMMARY, J_BRANCHING,
88  "\n-\n------- CCS: trying %d objects:\n", numberToDo);
89 
90  //solver -> doingResolve () = false; // turns off setCutoff and restoreUnused
91 
92  int numberColumns = solver -> getNumCols ();
93 
94  solver -> markHotStart (); // save current LP point
95 
96  // save initial bounds
97  const double
98  *initLower = info -> lower_,
99  *initUpper = info -> upper_;
100 
101  // save intersection of bounds obtained by branching on all objects
102  double
103  *saveLower = CoinCopyOfArray (info -> lower_, numberColumns),
104  *saveUpper = CoinCopyOfArray (info -> upper_, numberColumns),
105 
106  *Lower0 = NULL,
107  *Upper0 = NULL,
108 
109  // save union of bounds on both branches of one object;
110  // reset to (current) saveLower when branching on a new object
111  *unionLower = new double [numberColumns],
112  *unionUpper = new double [numberColumns],
113 
114  *lpSol = NULL,
115  timeStart = CoinCpuTime ();
116 
117  if (jnlst_ -> ProduceOutput (J_DETAILED, J_BRANCHING)) {
118  Lower0 = CoinCopyOfArray (info -> lower_, numberColumns); // delete afterwards
119  Upper0 = CoinCopyOfArray (info -> upper_, numberColumns);
120  }
121 
122  // LP solution for distance
123  if (pseudoUpdateLP_)
124  lpSol = CoinCopyOfArray (info -> solution_, numberColumns);
125 
126  // provide Couenne problem with point/bounds contained in info
127  // problem_ -> domain () -> push
128  // (problem_ -> nVars (),
129  // info -> solution_,
130  // info -> lower_,
131  // info -> upper_);
132 
133  //Bonmin::HotInfo * results = results_ ();
134 
135  int returnCode = 0, iDo = 0;
136 
137  for (iDo = 0; iDo < numberToDo; iDo++) {
138 
139  Bonmin::HotInfo * result = results_ () + iDo; // retrieve i-th object to test
140 
141  OsiObject *Object = solver_ -> objects () [result -> whichObject ()];
142 
143  // printf ("doStrongBranching: object %d -> x%d\n",
144  // result -> whichObject (),
145  // solver_ -> objects () [result -> whichObject ()] -> columnNumber ());
146 
147  // TODO: apply isCuttable()
148 
149  // TODO: set a cutoff for dual bound in dual simplex
150  // do the same for primal based on SB's alpha
151 
152  // For now just 2 way
153  OsiBranchingObject * branch = result -> branchingObject ();
154  assert (branch->numberBranches()==2);
155 
156  CouenneBranchingObject *cb = dynamic_cast <CouenneBranchingObject *> (branch);
157 
158  if (cb) cb -> setSimulate (true);
159 
160  int
161  status0 = -1,
162  status1 = -1;
163 
165 
166  /* Try the first direction. Each subsequent call to branch()
167  performs the specified branch and advances the branch object
168  state to the next branch alternative. */
169 
170  bool isInf0 = false;
171  bool isInf1 = false;
172 
173  double indUb = 0, indLb = 0;
174  CouenneObject *CouObj = dynamic_cast <CouenneObject *> (Object);
175  OsiSimpleInteger *simpl = dynamic_cast <OsiSimpleInteger *>(solver_->objects()[result->whichObject ()]);
176  // if OsiSimpleInteger Object with branching point outside
177  // current solver bound interval, one branch must
178  // be set as infeasible, otherwise bounds are enlarged
179  // in one branch
180  int objVarIndex = -1;
181  if(CouObj) {
182  objVarIndex = CouObj->Reference()->Index();
183  }
184  else {
185  objVarIndex = Object->columnNumber();
186  }
187  if(simpl) {
188  if(objVarIndex >= 0) {
189  indUb = solver->getColUpper()[objVarIndex];
190  indLb = solver->getColLower()[objVarIndex];
191  if(info->solution_[objVarIndex] < indLb) {
192  isInf0 = true;
193  }
194  if(info->solution_[objVarIndex] > indUb) {
195  isInf1 = true;
196  }
197  }
198  }
199 
200  // Left branch
201  status0 = simulateBranch (Object, info, branch, solver, result, -1);
202 
203  if(isInf0) {
204  status0 = 1; // branch was known to be infeasible
205  result->setDownStatus(1);
206  }
207 
208  // save current bounds as tightened by the down branch; will be
209  // used below to update global bounding box in solver
210  // if status0 == 1 unionLower will be ignored below
211  CoinCopyN (solver->getColLower(), numberColumns, unionLower);
212  CoinCopyN (solver->getColUpper(), numberColumns, unionUpper);
213 
214  // Restore pre-left-branch bounds in solver and problem
215  for (int j=0; j<numberColumns; j++) {
216  if(problem_->Lb(j) > unionLower[j]) {
217  unionLower[j] = problem_->Lb(j);
218  }
219  if(problem_->Ub(j) < unionLower[j]) {
220  unionLower[j] = problem_->Ub(j);
221  }
222 
223  solver->setColLower(j, saveLower [j]);
224  solver->setColUpper (j, saveUpper [j]);
225  problem_ -> Lb (j) = saveLower [j];
226  problem_ -> Ub (j) = saveUpper [j];
227  }
228 
229  /* second direction */
230 
231  status1 = simulateBranch (Object, info, branch, solver, result, +1);
232 
233  if(isInf1) {
234  status1 = 1; // branch was known to be infeasible
235  result->setUpStatus(1);
236  }
237 
238 #ifdef TRACE_STRONG
239  if(problem_->doPrint_) {
240  printf("Strong on object %d: status0: %d status1: %d\n",
241  result->whichObject(), status0, status1);
242  }
243 #endif
244 
246 
247  jnlst_ -> Printf (J_ITERSUMMARY, J_BRANCHING, "-------\n");
248 
249  if (cb)
250  cb -> setSimulate (false);
251 
253 
254  bool tightened = false;
255 
256  t_chg_bounds *chg_bds = new t_chg_bounds [numberColumns];
257 
258  const double *sLb = solver->getColLower();
259  const double *sUb = solver->getColUpper();
260 
261  if(status1 != 1) { // feasible
262  if(status0 != 1) { // feasible; take union of both branches
263  for (int j=0; j<numberColumns; j++) {
264  double maxLb = (problem_->Lb(j) < sLb[j] ? sLb[j] : problem_->Lb(j));
265  double minUb = (problem_->Ub(j) < sUb[j] ? problem_->Ub(j) : sUb[j]);
266  problem_->Lb(j) = (unionLower[j] > maxLb ? maxLb : unionLower [j]);
267  problem_->Ub(j) = (unionUpper[j] < minUb ? minUb : unionUpper [j]);
268  }
269  }
270  else { // keep current bounds; best of problem_ and solver
271  for (int j=0; j<numberColumns; j++) {
272  problem_->Lb(j) = (problem_->Lb(j) < sLb[j] ? sLb[j] : problem_->Lb(j));
273  problem_->Ub(j) = (problem_->Ub(j) < sUb[j] ? problem_->Ub(j) : sUb[j]);
274  }
275  }
276  }
277  else { // branch 1 infeasible
278  if(status0 != 1) { // feasible; otherwise both branches are infeasible
279  // keep current inconsistant bounds in solver
280  for (int j=0; j<numberColumns; j++) {
281  problem_->Lb (j) = unionLower [j];
282  problem_->Ub (j) = unionUpper [j];
283  }
284  }
285  }
286 
287  if((status0 == 1) && (status1 == 1)) {
288  tightened = false;
289 
290  // make sure that bounds in solver proves problem is
291  // infeasible
292  double lbVar0 = solver->getColLower()[0];
293  if(lbVar0 < 1) {
294  solver->setColLower(0, 1);
295  solver->setColUpper(0, 0);
296  }
297  else {
298  solver->setColUpper(0, lbVar0-1);
299  }
300  }
301  else {
302  for (int j=0; j<numberColumns; j++) {
303  if (problem_ -> Lb (j) > initLower [j] + COUENNE_EPS) {
304  chg_bds [j].setLower (t_chg_bounds::CHANGED);
305  tightened = true;
306  }
307 
308  if (problem_ -> Ub (j) < initUpper [j] - COUENNE_EPS) {
309  chg_bds [j].setUpper (t_chg_bounds::CHANGED);
310  tightened = true;
311  }
312  }
313  }
314  if (tightened && // have tighter bounds
315  (problem_ -> doFBBT ()) && // selected FBBT
316  !(problem_ -> btCore (chg_bds))) // tighten again on root
317 
318  status0 = status1 = 1; // if returns false, problem is infeasible
319 
320  delete [] chg_bds;
321 
322  if ((status0 != 1) || (status1 != 1)) {
323 
324  // set new bounding box as the possibly tightened one (a subset
325  // of the initial)
326  for (int j=0; j<numberColumns; j++) {
327  solver -> setColLower (j, saveLower [j] = problem_ -> Lb (j));
328  solver -> setColUpper (j, saveUpper [j] = problem_ -> Ub (j));
329  }
330  }
331 
332  /*
333  End of evaluation for this candidate object. Possibilities are:
334 
335  * Both sides below cutoff; this variable is a candidate for
336  branching.
337 
338  * Both sides infeasible or above the objective cutoff: no
339  further action here. Break from the evaluation loop and
340  assume the node will be purged by the caller.
341 
342  * One side feasible and below cutoff: Install the branch
343  (i.e., fix the variable). Possibly break from the evaluation
344  loop and assume the node will be reoptimised by the caller.
345  */
346 
347  if (status0 == 1 &&
348  status1 == 1) { // infeasible
349  returnCode=-1;
350  break; // exit loop
351  } else if (status0==1 || status1==1) {
352 
353 #ifdef COIN_HAS_NTY
354  if (problem_ -> orbitalBranching () &&
355  (Object -> columnNumber () >= 0) &&
356  (problem_ -> Find_Orbit (Object -> columnNumber ()) -> size () > 1)) {
357 
358  problem_ -> ChangeBounds (solver -> getColLower (),
359  solver -> getColUpper (),
360  problem_ -> nVars ());
361 
362  problem_ -> Compute_Symmetry ();
363  }
364 #endif
365 
366  numberStrongFixed_++;
367  if (!returnCriterion) {
368  returnCode=1;
369  } else {
370  returnCode=2;
371  break;
372  }
373  }
374 
375  bool hitMaxTime = ( CoinCpuTime()-timeStart > info->timeRemaining_);
376  if (hitMaxTime) {
377  returnCode=3;
378  break;
379  }
380  } // end loop /***********************************/
381 
382  if (jnlst_ -> ProduceOutput (J_DETAILED, J_BRANCHING)) {
383  printf ("strong branching: tightened bounds. ");
384  // create union of bounding box from both branching directions
385  for (int j=0; j<numberColumns; j++) {
386 
387  if (problem_ -> Lb (j) > Lower0 [j]) printf ("l%d (%g-->%g) ", j,Lower0[j], problem_->Lb (j));
388  if (problem_ -> Ub (j) < Upper0 [j]) printf ("u%d (%g-->%g) ", j,Upper0[j], problem_->Ub (j));
389  }
390 
391  delete [] Lower0;
392  delete [] Upper0;
393  }
394 
395  //problem_ -> domain () -> pop (); // discard current point/bounds from problem
396 
397  delete [] lpSol;
398 
399  jnlst_ -> Printf (J_ITERSUMMARY, J_BRANCHING, "----------------------done\n\n\n");
400 
401 #ifdef TRACE_STRONG2
402  if(problem_->doPrint_) {
403  if(pv > -1) {
404  printf("doSB: beg: x[%d]: %10.4f lb: %10.4f ub: %10.4f\n",
405  pv, solver->getColSolution()[pv], solver->getColLower()[pv], solver->getColUpper()[pv]);
406  printf("doSB: info: x[%d]: %10.4f lb: %10.4f ub: %10.4f\n",
407  pv, info->solution_[pv], info->lower_[pv], info->upper_[pv]);
408  printf("doSB: problem: lb: %10.4f ub: %10.4f\n",
409  problem_->Lb(pv), problem_->Ub(pv));
410  }
411  }
412 #endif
413 
414  if (iDo < numberToDo) iDo++; // exited due to infeasibility
415  assert (iDo <= (int) results_.size());
416  results_.resize (iDo);
417 
418  delete [] unionLower;
419  delete [] unionUpper;
420 
421  delete [] saveLower;
422  delete [] saveUpper;
423 
424  solver -> unmarkHotStart (); // Delete the snapshot
425 
426  //solver -> doingResolve () = true;
427  branchtime_ += CoinCpuTime () - timeStart;
428 
429  jnlst_ -> Printf (J_DETAILED, J_BRANCHING, "Done doStrongBranching\n");
430 
431  return returnCode;
432  }
433 
434 
435 // Do one side of strong branching
436 int CouenneChooseStrong::simulateBranch (OsiObject *Object,
437  OsiBranchingInformation *info,
438  OsiBranchingObject *branch,
439  OsiSolverInterface *solver,
440  Bonmin::HotInfo * result,
441  int direction) {
442 
443  bool boundBranch = branch -> boundBranch ();
444 
445  int status = -1;
446 
447  // TODO: avoid cloning solver all the time
448 
449  OsiSolverInterface *thisSolver =
450  boundBranch ? solver : solver -> clone ();
451 
452  CouenneObject *CouObj = dynamic_cast <CouenneObject *> (Object);
453 
454  if ((branch -> branch (thisSolver) > COUENNE_INFINITY) || // branch is infeasible
455  // Bound tightening if not a CouenneObject -- explicit since
456  // FBBT is done at ::branch() for CouenneObjects
457  (!CouObj && !BranchingFBBT (problem_, Object, thisSolver))) {
458 
459  status = 1;
460 
461  if (direction < 0) result -> setDownStatus (1);
462  else result -> setUpStatus (1);
463 
464  } else {
465 
466  if (boundBranch) // branching rule is a variable bound, can use hotstart
467 
468  thisSolver -> solveFromHotStart ();
469 
470  else { // branching rule is more complicated, need a resolve
471 
472  int limit;
473  thisSolver -> getIntParam (OsiMaxNumIterationHotStart, limit);
474  thisSolver -> setIntParam (OsiMaxNumIteration, limit);
475 
476  thisSolver -> resolve ();
477 
478  CouObj -> setEstimate (COUENNE_EPS, direction < 0 ? 0 : 1);
479  }
480 
481  if (pseudoUpdateLP_ && CouObj && thisSolver -> isProvenOptimal ()) {
482  CouNumber dist = distance (info -> solution_, thisSolver -> getColSolution (),
483  problem_ -> nVars ());
484 
485  if (dist > COUENNE_EPS)
486  CouObj -> setEstimate (dist, direction < 0 ? 0 : 1);
487  }
488  }
489 
490  // Can check if we got solution
491  // status is 0 finished, 1 infeasible and 2 unfinished and 3 is solution
492 
493  // only update information if this branch is feasible
494  if (status < 0)
495  status = result -> updateInformation (thisSolver, info, this);
496 
497  numberStrongIterations_ += thisSolver -> getIterationCount ();
498 
499  if ((status == 3) && (trustStrongForSolution_)) {
500  // new solution already saved
501  info -> cutoff_ = goodObjectiveValue_;
502  //problem_ -> setCutOff (goodObjectiveValue_);
503  status = 0;
504  }
505 
506  if (solver != thisSolver)
507  delete thisSolver;
508 
509  return status;
510 }
511 
515  OsiObject *Object,
516  OsiSolverInterface *solver) {
517 
518  bool feasible = true;
519 
520  if (problem -> doFBBT ()) {
521 
522  problem -> domain () -> push (solver);
523 
524  int
525  indVar = Object -> columnNumber (),
526  nvars = problem -> nVars ();
527 
528  // do not perform this if object is not a variable object
529 
530  if (indVar >= 0) {
531 
532  // Tell Couenne one bound has changed
533 
534  t_chg_bounds *chg_bds = new t_chg_bounds [nvars];
535  chg_bds [indVar].setUpper (t_chg_bounds::CHANGED);
536  chg_bds [indVar].setLower (t_chg_bounds::CHANGED);
537 
538  problem -> installCutOff ();
539 
540  if ((feasible = problem -> btCore (chg_bds))) {
541 
542  const double
543  *lb = solver -> getColLower (),
544  *ub = solver -> getColUpper (),
545  *nLB = problem -> Lb (),
546  *nUB = problem -> Ub ();
547 
548  for (int i=0; i<nvars; i++) {
549  if (nLB [i] > lb [i]) solver -> setColLower (i, nLB [i]);
550  if (nUB [i] < ub [i]) solver -> setColUpper (i, nUB [i]);
551  }
552  }
553 
554  delete [] chg_bds;
555  }
556 
557  problem -> domain () -> pop ();
558  }
559 
560  return feasible;
561 }
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)$.
status of lower/upper bound of a variable, to be checked/modified in bound tightening ...
void setLower(ChangeStatus lower)
&quot;Spatial&quot; branching object.
const Ipopt::EJournalCategory J_BRANCHING(Ipopt::J_USER1)
static char * j
Definition: OSdtoa.cpp:3622
void setUpper(ChangeStatus upper)
Class for MINLP problems with symbolic information.
void fint fint * k
#define COUENNE_EPS
double CouNumber
main number type in Couenne
int Index() const
Get variable index in problem.
#define COUENNE_INFINITY
exprVar * Reference() const
return reference auxiliary variable
double distance(const double *p1, const double *p2, int size, double k=2.)
compute Euclidean distance between two points (most likely LP solutions) l_2 norm by default...