CouenneChooseVariable.cpp
Go to the documentation of this file.
1 /* $Id: CouenneChooseVariable.cpp 868 2012-07-03 16:58:51Z stefan $
2  *
3  * Name: CouenneChooseVariable.cpp
4  * Authors: Pierre Bonami, IBM Corp.
5  * Pietro Belotti, Carnegie Mellon University
6  * Purpose: Branching object for choosing branching auxiliary variable
7  *
8  * (C) Carnegie-Mellon University, 2006-10.
9  * This file is licensed under the Eclipse Public License (EPL)
10  */
11 
12 #include "OsiSolverInterface.hpp"
13 
14 #include "CbcBranchActual.hpp"
15 #include "CbcModel.hpp"
16 
18 #include "CouenneProblem.hpp"
19 #include "CouenneProblemElem.hpp"
20 #include "CouenneExprVar.hpp"
21 #include "CouenneObject.hpp"
22 
23 #ifdef COIN_HAS_NTY
24 #include "Nauty.h"
25 #endif
26 
27 struct objPri {
28  int objIndex_;
29  int priority_;
30 };
31 
32 bool compPri (struct objPri *one, struct objPri *two) {
33  return (one -> priority_ <
34  two -> priority_);
35 }
36 
37 using namespace Couenne;
38 
39 void eliminateIntegerObjects (OsiSolverInterface *model);
40 void eliminateIntegerObjects (CbcModel *model);
41 
44  OsiChooseVariable (),
45  problem_ (NULL) {}
46 
47 
49 CouenneChooseVariable::CouenneChooseVariable (const OsiSolverInterface *si,
50  CouenneProblem *p,
51  JnlstPtr jnlst):
52  OsiChooseVariable (si),
53  problem_ (p),
54  jnlst_ (jnlst) {}
55 
56 
59  OsiChooseVariable (source),
60  problem_ (source.problem_),
61  jnlst_ (source.jnlst_) {}
62 
63 
66  problem_ = rhs.problem_;
67  jnlst_ = rhs.jnlst_;
68  return *this;
69 }
70 
71 
75 int CouenneChooseVariable::setupList (OsiBranchingInformation *info, bool initialize) {
76 
77  static bool firstCall = true;
78 
79  int n = problem_ -> nVars ();
80 
81  problem_ -> domain () -> push
82  (n,
83  info -> solution_,
84  info -> lower_,
85  info -> upper_);
86 
87  jnlst_ -> Printf (Ipopt::J_ITERSUMMARY, J_BRANCHING, "----------------- setup list\n");
88  if (jnlst_ -> ProduceOutput (Ipopt::J_DETAILED, J_BRANCHING)) {
89  printf ("----------------- setup list\n");
90  for (int i=0; i<problem_ -> domain () -> current () -> Dimension (); i++)
91  if (problem_ -> Var (i) -> Multiplicity () > 0) {
92  printf ("%4d %20.4g [%20.4g %20.4g]", i, info -> solution_ [i], info -> lower_ [i], info -> upper_ [i]);
93  if (problem_ -> Var (i) -> Type () == AUX) {
94  printf (" expr. %20.4g [%+e] ", (*(problem_ -> Var (i) -> Image ())) (), (*(problem_ -> Var (i) -> Image ())) () - info -> solution_ [i]);
95  problem_ -> Var (i) -> Image () -> print ();
96  }
97  printf ("\n");
98  }
99  }
100 
101  int retval;
102 
103  // Make it stable, in OsiChooseVariable::setupList() numberObjects must be 0.
104  // retval = (solver_ -> numberObjects ()) ?
105  // OsiChooseVariable::setupList (info, initialize) : 0;
106 
107  // Copied OsiChooseVariable::setupList to adjust it to Orbital Branching
108 
109  {
110  if (initialize) {
111  status_=-2;
112  delete [] goodSolution_;
113  bestObjectIndex_=-1;
114  numberStrongDone_=0;
115  numberStrongIterations_ = 0;
116  numberStrongFixed_ = 0;
117  goodSolution_ = NULL;
118  goodObjectiveValue_ = COIN_DBL_MAX;
119  }
120 
121  numberOnList_=0;
122  numberUnsatisfied_=0;
123 
124  if (firstCall) {
125 
126  eliminateIntegerObjects (const_cast <OsiSolverInterface *> (solver_));
127  eliminateIntegerObjects (const_cast <OsiSolverInterface *> (info -> solver_));
128 
129  firstCall = false;
130  }
131 
132  int numberObjects = solver_ -> numberObjects();
133 
134  assert (numberObjects);
135 
136  OsiObject ** object = info -> solver_ -> objects ();
137 
138  // false when problem found infeasible
139  bool feasible = true;
140 
141  // CouenneChooseVariable has numberStrong_ set once, to one, so
142  // CouenneChooseVariable::chooseVariable() simply picks the first
143  // in the list. There is no point in scanning the whole list of
144  // objects, given that infeasibility() and checkInfeasibility()
145  // are expensive.
146  //
147  // Subdivide them by priority, then find the one with minimum
148  // priority (primary key) and maximum infeasibility, and store it
149  // at list_ [0]. No need for code on orbital branching here, the
150  // only change will be during the branching proper.
151 
152 #define NEW_SETUPLIST
153 
154 #ifdef NEW_SETUPLIST
155 
156  int way;
157 
158  std::vector <struct objPri *> listPri;
159 
160  for (int i=0; i<numberObjects; i++) {
161 
162  struct objPri *singleton = new struct objPri;
163  singleton -> objIndex_ = i;
164  singleton -> priority_ = object [i] -> priority ();
165 
166  listPri.push_back (singleton);
167  }
168 
169  // for (std::vector <struct objPri *>::iterator i=listPri.begin (); i != listPri.end (); ++i)
170  // printf ("[%d:%d,%e] ", (*i) -> objIndex_, (*i) -> priority_, object [(*i) -> objIndex_] -> infeasibility (info,way));
171 
172  // printf (" ---- ");
173 
174  std::sort (listPri.begin (), listPri.end (), compPri);
175 
176  // for (std::vector <struct objPri *>::iterator i=listPri.begin (); i != listPri.end (); ++i)
177  // printf ("[%d:%d,%e] ", (*i) -> objIndex_, (*i) -> priority_, object [(*i) -> objIndex_] -> infeasibility (info,way));
178  // printf ("\n");
179 
180  int minPriority = -1;
181 
182  double maxInfeas = 0.;
183 
184  for (int i=0; i<numberObjects; ++i) {
185 
186  int
187  currIndex = listPri [i] -> objIndex_,
188  priority = listPri [i] -> priority_;
189 
190  if ((minPriority >= 0) &&
191  (priority > minPriority))
192  break;
193 
194  //double infeas = object [currIndex] -> infeasibility (info,way); // MOST EXPENSIVE PART
195  double infeas = object [currIndex] -> checkInfeasibility (info); // Less expensive
196 
197  //printf ("<%d:%d,%e> ", currIndex, priority, infeas);
198 
199  if (((minPriority < 0) || (priority == minPriority)) &&
200  (infeas > maxInfeas)) {
201 
202  // printf (" bingo! ");
203 
204  if (minPriority < 0)
205  minPriority = priority;
206 
207  maxInfeas = infeas;
208 
209  ++numberUnsatisfied_;
210 
211  if (infeas == COIN_DBL_MAX) {
212 
213  feasible = false;
214  break;
215 
216  } else {
217 
218  list_ [0] = currIndex;
219  useful_ [0] = infeas;
220  }
221  }
222  }
223 
224  // if (feasible)
225  // if (!numberUnsatisfied_)
226  // printf ("no violations ");
227  // else
228  // printf ("Selected %d (%e)", list_ [0], useful_ [0]);
229  // else printf ("infeasible ");
230 
231  for (std::vector <struct objPri *>::iterator i=listPri.begin (); i != listPri.end (); ++i)
232  delete (*i);
233 
234 #else
235 
236  int maximumStrong = numberStrong_ ? CoinMin (numberStrong_, numberObjects) : 1;
237 
238  double check = 0.0;
239 
240  int
241  checkIndex = 0,
242  bestPriority = COIN_INT_MAX,
243  // pretend one strong even if none
244  putOther = numberObjects; // counts downward from end of list
245 
246  // init member list_
247 
248  for (int i=0; i < maximumStrong; i++) {
249  list_ [i] = -1;
250  useful_ [i] = 0.;
251  }
252 
253  // printf ("numObj: %d, maxStrong: %d\n", numberObjects, maximumStrong);
254  // for (int i=0; i<numberObjects;) {
255  // printf ("(%d,%d,%d,%g)", i, object [i] -> columnNumber (), object [i] -> priority (), object [i] -> checkInfeasibility (info));
256  // if (!(++i % 10) || i>=numberObjects) printf ("\n");
257  // }
258 
259  for (int i=0; i<numberObjects; i++) {
260 
261  int way;
262  //double value = object [i] -> infeasibility (info,way); // TODO: use checkInfeasibility instead
263  double value = object [i] -> checkInfeasibility (info); //
264 
265  if (value > 0.) {
266 
267  numberUnsatisfied_++;
268 
269  if (value == COIN_DBL_MAX) { // infeasible
270  feasible = false;
271  break;
272  }
273 
274  int priorityLevel = object [i] -> priority ();
275 
276  // Better priority? Flush choices
277  if (priorityLevel < bestPriority) {
278 
279  for (int j=0; j<maximumStrong; j++) {
280 
281  if (list_ [j] >= 0) {
282 
283  int iObject = list_[j];
284 
285  list_ [j] = -1;
286  useful_ [j] = 0.;
287  list_ [--putOther] = iObject;
288  }
289  }
290 
291  bestPriority = priorityLevel;
292  check = 0.;
293  }
294 
295  if ((priorityLevel == bestPriority) // only consider those with equal priority
296  && (value > check)
297 
298  ) {
299 
300  int iObject = list_ [checkIndex];
301  if (iObject >= 0)
302  list_ [--putOther] = iObject; // put former best to end
303 
304  // add to list
305  list_ [checkIndex] = i;
306  useful_ [checkIndex] = value;
307 
308  // Now find next element to (possibly) replace, i.e., find worst
309  check=COIN_DBL_MAX;
310  for (int j=0;j<maximumStrong;j++) {
311  if (list_[j]>=0) {
312  if (useful_[j]<check) {
313  check=useful_[j];
314  checkIndex=j;
315  }
316  } else {
317  check=0.0;
318  checkIndex = j;
319  break;
320  }
321  }
322  } else list_ [--putOther] = i; // greater (weaker) priority or
323  // not most fractional
324  }
325  }
326 #endif
327 
328  // Get list
329  numberOnList_=0;
330 
331  if (feasible) {
332 #ifndef NEW_SETUPLIST
333  for (int i=0;i<maximumStrong;i++) {
334  if (list_[i]>=0) {
335  list_[numberOnList_]=list_[i];
336  useful_[numberOnList_++]=-useful_[i];
337  }
338  }
339  if (numberOnList_) {
340  // Sort
341  CoinSort_2(useful_,useful_+numberOnList_,list_);
342  // move others
343  int i = numberOnList_;
344  for (;putOther<numberObjects;putOther++)
345  list_[i++]=list_[putOther];
346  assert (i==numberUnsatisfied_);
347  if (!numberStrong_)
348  numberOnList_=0;
349  }
350 #endif
351  } else {
352  // infeasible
353  numberUnsatisfied_ = -1;
354  }
355 
356  retval = numberUnsatisfied_;
357  }
358 
360  //
361  // End copy
362  //
364 
365  problem_ -> domain () -> pop ();
366 
367  jnlst_ -> Printf (Ipopt::J_ITERSUMMARY, J_BRANCHING, "----------------- setup list done, %d objects\n", retval);
368 
369  // for (int i=0, k = (numberStrong_ ? CoinMin (numberStrong_, solver_ -> numberObjects ()) : 1); i<k; i++) {
370  // printf ("list %3d: %3d ", i, list_ [i]);
371  // if (!((i+1) % 12) || i == k-1) printf ("\n");
372  // }
373 
374  // printf ("returning %d\n", retval);
375 
376  return retval;
377 }
378 
379 
381 // int CouenneChooseVariable::chooseVariable (OsiSolverInterface * solver,
382 // OsiBranchingInformation *info,
383 // bool fixVariables) {
384 
385 // // !!!should go -- just choose the first element
386 // problem_ -> domain () -> push
387 // (problem_ -> nVars (),
388 // info -> solution_,
389 // info -> lower_,
390 // info -> upper_);
391 
392 // int retval = OsiChooseVariable::chooseVariable (solver, info, fixVariables);
393 // problem_ -> domain () -> pop ();
394 // return retval;
395 // }
396 
397 
398 // Returns true if solution looks feasible against given objects
399 bool CouenneChooseVariable::feasibleSolution (const OsiBranchingInformation * info,
400  const double * solution,
401  int numberObjects,
402  const OsiObject ** objects) {
403 
404 #ifdef FM_CHECKNLP2
405  bool isFeas = problem_->checkNLP2(solution,
406  0,
407  false, // do not care about obj
408  true, // stopAtFirstViol
409  true, // checkAll
410  problem_ -> getFeasTol());
411 
412  return isFeas;
413 #else
414  int indobj = problem_ -> Obj (0) -> Body () -> Index ();
415  double obj = indobj >= 0 ? solution [indobj] : problem_ -> Obj (0) -> Body () -> Value ();
416  return problem_ -> checkNLP (solution, obj);
417 #endif
418 }
419 
420 
423 
424  roptions -> AddStringOption2
425  ("enable_sos",
426  "Use Special Ordered Sets (SOS) as indicated in the MINLP model",
427  "no",
428  "no","",
429  "yes","");
430 
431  roptions -> AddStringOption2
432  ("branch_fbbt",
433  "Apply bound tightening before branching",
434  "yes",
435  "no","",
436  "yes","",
437  "After applying a branching rule and before re-solving the subproblem, apply Bound Tightening.");
438 
439  roptions -> AddStringOption2
440  ("branch_conv_cuts",
441  "Apply convexification cuts before branching (for now only within strong branching)",
442  "yes",
443  "no","",
444  "yes","",
445  "After applying a branching rule and before resolving the subproblem, generate a round of linearization cuts with the new bounds enforced by the rule."
446  );
447 
448  roptions -> AddStringOption6
449  ("branch_pt_select",
450  "Chooses branching point selection strategy",
451  "mid-point",
452  "lp-clamped", "LP point clamped in [k,1-k] of the bound intervals (k defined by lp_clamp)",
453  "lp-central", "LP point if within [k,1-k] of the bound intervals, middle point otherwise"
454  "(k defined by branch_lp_clamp)",
455  "balanced", "minimizes max distance from curve to convexification",
456  "min-area", "minimizes total area of the two convexifications",
457  "mid-point", "convex combination of current point and mid point",
458  "no-branch", "do not branch, return null infeasibility; for testing purposes only",
459  "");
460 
461  std::string br_ops [] = {"prod", "div", "exp", "log", "trig",
462  "pow", "negpow", "sqr", "cube", ""};
463 
464  for (int i=0; br_ops [i] != ""; i++) {
465 
466  char optname [40], optname2 [40], description [90];
467  sprintf (optname, "branch_pt_select_%s", br_ops [i].c_str ());
468  sprintf (optname2, "branch_lp_clamp_%s", br_ops [i].c_str ());
469  sprintf (description, "Chooses branching point selection strategy for operator %s.",
470  br_ops [i].c_str ());
471 
472  roptions -> AddStringOption7
473  (optname,
474  description,
475  "common",
476  "common", "use strategy defined for generic operators",
477  "lp-clamped", "LP point clamped in [k,1-k] of the bound intervals "
478  "(k defined by lp_clamp_${this operator}$)",
479  "lp-central", "LP point if within [k,1-k] of the bound intervals, middle point otherwise"
480  "(k defined by branch_lp_clamp_${this operator}$)",
481  "balanced", "minimizes max distance from curve to convexification",
482  "min-area", "minimizes total area of the two convexifications",
483  "mid-point", "convex combination of current point and mid point",
484  "no-branch", "do not branch, return null infeasibility; for testing purposes only",
485  "");
486 
487  roptions -> AddBoundedNumberOption
488  (optname2,
489  "Defines safe interval percentage [0,0.5] for using LP point as a branching point.",
490  0.,false,
491  0.5,false,
492  0.2);
493  }
494 
495  roptions -> AddBoundedNumberOption
496  ("branch_midpoint_alpha",
497  "Defines convex combination of mid point and current LP point: "
498  "b = alpha x_lp + (1-alpha) (lb+ub)/2.",
499  0.,false,
500  1.,false,
501  default_alpha);
502 
503  roptions -> AddBoundedNumberOption
504  ("branch_lp_clamp",
505  "Defines safe interval percentage for using LP point as a branching point.",
506  0.,false,
507  1.,false,
508  0.2);
509 
510  // Setting priorities slightly below CbcBranchingObjects' priority,
511  // so that Couenne's integer branching is used
512 
513  roptions -> AddLowerBoundedIntegerOption
514  ("cont_var_priority",
515  "Priority of continuous variable branching",
516  1, 99,
517  "When branching, this is compared to the priority of integer variables, whose priority is given by int_var_priority, and SOS, whose priority is 10. "
518  "Higher values mean smaller priority."
519  );
520 
521  roptions -> AddLowerBoundedIntegerOption
522  ("int_var_priority",
523  "Priority of integer variable branching",
524  1, 98,
525  "When branching, this is compared to the priority of continuous variables, whose priority is given by cont_var_priority, and SOS, whose priority is 10. "
526  "Higher values mean smaller priority."
527  );
528 
529  roptions -> AddStringOption2
530  ("red_cost_branching",
531  "Apply Reduced Cost Branching (instead of the Violation Transfer) -- MUST have vt_obj enabled",
532  "no",
533  "no", "Use Violation Transfer with $\\sum |\\pi_i a_{ij}|$",
534  "yes","Use Reduced cost branching with $|\\sum \\pi_i a_{ij}|$");
535 
536  roptions -> AddStringOption2
537  ("orbital_branching",
538  "detect symmetries and apply orbital branching",
539  "no",
540  "yes", "",
541  "no", "");
542 
543  roptions -> AddLowerBoundedIntegerOption
544  ("orbital_branching_depth",
545  "Maximum depth at which the symmetry group is computed",
546  -1, 10,
547  "Select -1 if you want to compute the symmetry group at all nodes");
548 }
549 
550 
551 // Cbc adds automatically objects for integer variables, but we did
552 // not ask for it. In order to overcome this, we add objects the usual
553 // way and then eliminate the CbcSimpleInteger objects one by one.
554 
555 int gutsofEIO (OsiObject **objects, int nco) {
556 
557  int
558  nRealObj,
559  currObj = 0;
560 
561  for (; currObj < nco; ++currObj)
562 
563  if ((NULL != dynamic_cast <CbcSimpleInteger *> (objects [currObj])) ||
564  (NULL != dynamic_cast <OsiSimpleInteger *> (objects [currObj]))) {
565 
566  // At [currObj] is a Cbc integer variable object. Kill it! Kill it with fire!
567  delete objects [currObj];
568  objects [currObj] = NULL;
569  }
570 
571  // squeeze the sparse vector into a dense one with only non-NULL entries
572 
573  for (nRealObj = 0, currObj = -1; nRealObj < nco; ++nRealObj)
574 
575  if (NULL == objects [nRealObj]) {
576 
577  if (currObj < 0)
578  currObj = nRealObj + 1;
579 
580  while ((currObj < nco) &&
581  (NULL == objects [currObj]))
582  ++currObj;
583 
584  if (currObj >= nco)
585  break;
586 
587  objects [nRealObj] =
588  objects [currObj];
589 
590  objects [currObj] = NULL;
591  }
592 
593  //printf ("%d real objects out of %d (s.co %d)\n", nRealObj, currObj, s.continuousSolver () -> numberObjects ());
594 
595  return nRealObj;
596 }
597 
598 void eliminateIntegerObjects (OsiSolverInterface *model) {model -> setNumberObjects (gutsofEIO (model -> objects (), model -> numberObjects ()));}
599 void eliminateIntegerObjects (CbcModel *model) {model -> setNumberObjects (gutsofEIO (model -> objects (), model -> numberObjects ()));}
CouenneProblem * problem_
Pointer to the associated MINLP problem.
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
JnlstPtr jnlst_
journalist for detailed debug information
bool checkNLP2(const double *solution, const double obj, const bool careAboutObj, const bool stopAtFirstViol, const bool checkAll, const double precision) const
Return true if either solution or recomputed_solution obtained using getAuxs() from the original vari...
Definition: checkNLP.cpp:571
const Ipopt::EJournalCategory J_BRANCHING(Ipopt::J_USER1)
static char * j
Definition: OSdtoa.cpp:3622
const CouNumber default_alpha
CouenneChooseVariable & operator=(const CouenneChooseVariable &)
Assignment operator.
int gutsofEIO(OsiObject **objects, int nco)
virtual int setupList(OsiBranchingInformation *, bool)
Sets up strong list and clears all if initialize is true.
Class for MINLP problems with symbolic information.
virtual bool feasibleSolution(const OsiBranchingInformation *info, const double *solution, int numberObjects, const OsiObject **objects)
Returns true if solution looks feasible against given objects.
bool compPri(struct objPri *one, struct objPri *two)
Choose a variable for branching.
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Add list of options to be read from file.
void eliminateIntegerObjects(OsiSolverInterface *model)
void fint * n
CouenneChooseVariable()
Default Constructor.