BonCouenneSetup.cpp
Go to the documentation of this file.
1 // $Id: BonCouenneSetup.cpp 1273 2019-02-23 17:29:55Z stefan $
2 //
3 // (C) Copyright International Business Machines Corporation 2007
4 // All Rights Reserved.
5 // This code is published under the Eclipse Public License (EPL).
6 //
7 // Authors :
8 // Pierre Bonami, International Business Machines Corporation
9 // Pietro Belotti, Clemson University
10 //
11 // Date : 04/18/2007
12 
13 // Ampl includes
14 
15 #include "CouenneConfig.h"
16 
17 #include "OsiClpSolverInterface.hpp"
18 
19 #ifdef COIN_HAS_CPX
20 #include "OsiCpxSolverInterface.hpp"
21 #endif
22 #ifdef COIN_HAS_GRB
23 #include "OsiGrbSolverInterface.hpp"
24 #endif
25 #ifdef COIN_HAS_SPX
26 #include "OsiSpxSolverInterface.hpp"
27 #endif
28 #ifdef COIN_HAS_XPR
29 #include "OsiXprSolverInterface.hpp"
30 #endif
31 
32 // MILP cuts
33 #include "CglGomory.hpp"
34 #include "CglProbing.hpp"
35 #include "CglKnapsackCover.hpp"
36 #include "CglOddHole.hpp"
37 #include "CglClique.hpp"
38 #include "CglFlowCover.hpp"
39 #include "CglMixedIntegerRounding2.hpp"
40 #include "CglTwomir.hpp"
41 #include "CglPreProcess.hpp"
42 #include "CglLandP.hpp"
43 #include "CglRedSplit.hpp"
44 
45 #include "BonCouenneSetup.hpp"
46 #include "CouenneFeasPump.hpp"
48 #include "BonCouenneInterface.hpp"
49 #include "BonInitHeuristic.hpp"
50 #include "BonNlpHeuristic.hpp"
51 
53 #include "BonDummyPump.hpp"
54 #include "BonPumpForMinlp.hpp"
55 #include "BonHeuristicRINS.hpp"
57 #include "BonHeuristicFPump.hpp"
62 #include "BonMilpRounding.hpp"
63 
64 #include "BonGuessHeuristic.hpp"
65 #include "CbcCompareActual.hpp"
66 
67 #include "CouenneObject.hpp"
68 #include "CouenneVarObject.hpp"
69 #include "CouenneVTObject.hpp"
70 #include "CouenneOrbitObj.hpp"
72 #include "CouenneChooseStrong.hpp"
74 #include "CouenneFixPoint.hpp"
75 #include "CouenneCutGenerator.hpp"
76 #include "CouenneDisjCuts.hpp"
77 #include "CouenneCrossConv.hpp"
78 #include "CouenneSdpCuts.hpp"
79 #include "CouenneTwoImplied.hpp"
80 
81 #include "BonCouenneInfo.hpp"
82 #include "BonCbcNode.hpp"
83 #include "BonCbc.hpp"
84 
85 // ASL includes need to come behind OsiClp and Bonmin, because it defines "filename",
86 // which is used as variablename in Clp
87 // (similar bad as windows.h, which defines "small")
88 #ifdef COIN_HAS_ASL
89 #include "asl.h"
90 #include "getstub.h"
91 #endif
92 
93 using namespace Ipopt;
94 using namespace Couenne;
95 
96 CouenneSetup::~CouenneSetup(){
97  if (couenneProb_ && couenneProb_is_own_)
98  delete couenneProb_;
99 
100 #ifdef COIN_HAS_ASL
101  // free (aslfg_ -> asl); // triggers segfault -- apparently freed in ancestor class
102 #endif
103 }
104 
105 bool CouenneSetup::InitializeCouenne (char ** argv,
106  CouenneProblem *couenneProb,
108  CouenneInterface *ci,
109  Bonmin::Bab *bb) {
110  int freq;
111 
112  bool retval = true;
113 
114  std::string s;
115 
116  if (couenneProb) {
117  //TODO create a copy of user problem, since we modify it?
118  couenneProb_ = couenneProb;
119  couenneProb_is_own_ = false;
120  }
121 
122  /* Get the basic options. */
123  readOptionsFile();
124 
125  // Suppress iteration output from nonlinear solver
126  options () -> SetStringValue ("sb", "yes", false, true);
127 
128  // in check mode, avoid pop-up error message (there are quite a few messages)
129  //options_ -> GetStringValue ("test_mode", s, "couenne.");
130  //if (s == "yes")
131  //WindowsErrorPopupBlocker();
132 
136  options_ -> SetStringValue ("nlp_failure_behavior", "fathom", "couenne.");
137 
138  gatherParametersValues (options_);
139 
140  if (!ci) {
141 
142  ci = new CouenneInterface;
143 
144  if (!couenneProb_ && argv) {
145 #ifdef COIN_HAS_ASL
146  /* Read the model in various places. */
147  ci -> readAmplNlFile (argv, roptions (), options (), journalist ());
148  aslfg_ = new SmartAsl;
149  aslfg_ -> asl = readASLfg (argv);
150 #else
151  std::cerr <<
152  "Couenne was compiled without AMPL Solver Library. Cannot initialize from AMPL NL File."
153  << std::endl;
154  exit (-1);
155 #endif
156  } else {
157  assert (couenneProb_ != NULL);
158  assert (IsValid (tminlp)); //TODO would be great to setup own TMINLP based on CouenneProblem formulation
159  ci -> initialize (roptions_, options_, journalist_,
160  Ipopt::SmartPtr <Bonmin::TMINLP> (dynamic_cast <Bonmin::TMINLP *> (Ipopt::GetRawPtr (tminlp))));
161  }
162  }
163 
164  nonlinearSolver_ = ci;
165 
170  int i;
171 
173 
174 #define addJournalist(optname,jlevel) { \
175  options () -> GetIntegerValue ((optname), i, "couenne."); \
176  journalist () -> GetJournal ("console") -> SetPrintLevel ((jlevel), (EJournalLevel) i); \
177 }
178 
179  addJournalist ("output_level", J_COUENNE);
180  addJournalist ("boundtightening_print_level", J_BOUNDTIGHTENING);
181  addJournalist ("branching_print_level", J_BRANCHING);
182  addJournalist ("convexifying_print_level", J_CONVEXIFYING);
183  addJournalist ("problem_print_level", J_PROBLEM);
184  addJournalist ("nlpheur_print_level", J_NLPHEURISTIC);
185  addJournalist ("disjcuts_print_level", J_DISJCUTS);
186  addJournalist ("reformulate_print_level", J_REFORMULATE);
187 
188  options_ -> SetIntegerValue ("print_level", 0);
189 
190  /* Initialize Couenne cut generator.*/
191  //int ivalue, num_points;
192  //options()->GetEnumValue("convexification_type", ivalue,"couenne.");
193  //options()->GetIntegerValue("convexification_points",num_points,"couenne.");
194 
195  if (!couenneProb_)
196  couenneProb_ = new CouenneProblem (aslfg_ -> asl, this, journalist ());
197 
198  CouenneCutGenerator * couenneCg =
199  new CouenneCutGenerator (ci, this, couenneProb_, NULL);
200 
201  options_ -> GetStringValue ("lp_solver", s, "couenne.");
202 
203  if (s == "clp") {
204 
206  continuousSolver_ = CSI;
207  CSI -> setCutGenPtr (couenneCg);
208 
209  } else if (s == "cplex") {
210 
211 #ifdef COIN_HAS_CPX
213  continuousSolver_ = CSI;
214  CSI -> setCutGenPtr (couenneCg);
215 #else
216  journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without CPLEX interface. Please reconfigure, recompile, and try again.\n");
217  exit (-1);
218 #endif
219  } else if (s == "xpress-mp") {
220 
221 #ifdef COIN_HAS_XPR
223  continuousSolver_ = CSI;
224  CSI -> setCutGenPtr (couenneCg);
225 #else
226  journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without Xpress-MP interface. Please reconfigure, recompile, and try again.\n");
227  exit (-1);
228 #endif
229  } else if (s == "gurobi") {
230 
231 #ifdef COIN_HAS_GRB
233  continuousSolver_ = CSI;
234  CSI -> setCutGenPtr (couenneCg);
235 #else
236  journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without GUROBI interface. Please reconfigure, recompile, and try again.\n");
237  exit (-1);
238 #endif
239  } else if (s == "soplex") {
240 
241 #ifdef COIN_HAS_SPX
243  continuousSolver_ = CSI;
244  CSI -> setCutGenPtr (couenneCg);
245 #else
246  journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without Soplex. Please reconfigure, recompile, and try again.\n");
247  exit (-1);
248 #endif
249  } else {
250  journalist ()-> Printf (J_ERROR, J_INITIALIZATION, "The LP solver you specified hasn't been added to Couenne yet.\n");
251  exit (-1);
252  }
253 
254  continuousSolver_ -> passInMessageHandler(ci -> messageHandler());
255 
256  couenneProb_ -> setBase (this);
257 
258  assert (couenneProb_);
259 
260  couenneProb_ -> reformulate (couenneCg);
261 
262  Bonmin::BabInfo * extraStuff = new CouenneInfo (0);
263 
264  // as per instructions by John Forrest, to get changed bounds
265  extraStuff -> setExtraCharacteristics (extraStuff -> extraCharacteristics () | 2);
266 
267  continuousSolver_ -> setAuxiliaryInfo (extraStuff);
268  delete extraStuff;
269 
270  extraStuff = dynamic_cast <Bonmin::BabInfo *> (continuousSolver_ -> getAuxiliaryInfo ());
271 
272  // Setup log level of LP solver
273  int lpLogLevel;
274  options () -> GetIntegerValue ("lp_log_level", lpLogLevel, "couenne.");
275  continuousSolver_ -> messageHandler () -> setLogLevel (lpLogLevel);
276 
277  // Add Couenne SOS ///////////////////////////////////////////////////////////////
278 
279  int
280  nSOS = 0,
281  nVars = couenneProb_ -> nVars ();
282 
283  OsiObject ** objects = NULL;
284 
285  options () -> GetStringValue ("enable_sos", s, "couenne.");
286 
287  if (s == "yes") {
288 
289  // allocate sufficient space for both nonlinear variables and SOS's
290  objects = new OsiObject* [couenneProb_ -> nCons () + nVars];
291 
292  nSOS = couenneProb_ -> findSOS (&(bb -> model()), dynamic_cast <OsiSolverInterface *> (nonlinearSolver ()), objects);
293 
294  nonlinearSolver () -> addObjects (nSOS, objects);
295 
296  //printf ("boncouennesetup 1: %d SOS objects --> %d\n", nSOS, nonlinearSolver () -> numberObjects ());
297 
298  //printf ("==================== found %d SOS\n", nSOS);
299  //nonlinearSolver () -> addObjects (nSOS, objects);
300  //continuousSolver () -> addObjects (nSOS, objects);
301 
302  //printf ("found %d SOS!\n", nSOS);
303 
304  /*for (int i=0; i<nSOS; i++)
305  delete objects [i];
306  delete [] objects;*/
307 
308  if (!nSOS) {
309  delete [] objects;
310  objects = NULL;
311  }
312  }
313 
314  //model -> assignSolver (continuousSolver_, true);
315  //continuousSolver_ = model -> solver();
316 
317  // Add Couenne objects for branching /////////////////////////////////////////////
318 
319  options () -> GetStringValue ("display_stats", s, "couenne.");
320  displayStats_ = (s == "yes");
321 
322  options () -> GetStringValue ("branching_object", s, "couenne.");
323 
324  enum CouenneObject::branch_obj objType = CouenneObject::VAR_OBJ;
325 
326  if (s == "vt_obj") objType = CouenneObject::VT_OBJ;
327  else if (s == "var_obj") objType = CouenneObject::VAR_OBJ;
328  else if (s == "expr_obj") objType = CouenneObject::EXPR_OBJ;
329  else {
330  printf ("CouenneSetup: Unknown branching object type\n");
331  exit (-1);
332  }
333 
334  int
335  nobj = nSOS; // if no SOS then objects is empty
336 
337  if (!objects)
338  objects = new OsiObject* [nVars];
339 
340  int
341  contObjPriority,
342  intObjPriority;
343 
344  options () -> GetIntegerValue ("cont_var_priority", contObjPriority, "couenne.");
345  options () -> GetIntegerValue ( "int_var_priority", intObjPriority, "couenne.");
346 
347  int varSelection;
348  if (!options_ -> GetEnumValue ("variable_selection", varSelection, "couenne.")) {
349  // change the default for Couenne
350  varSelection = Bonmin::BabSetupBase::OSI_SIMPLE;
351  }
352 
353 #ifdef TO_BE_REMOVED
354  if ((Bonmin::BabSetupBase::OSI_STRONG == varSelection) &&
355  (CouenneObject::VT_OBJ == objType)){
356 
357  printf ("Warning: Violation Transfer and strong branching are mutually exclusive.\nResetting to Violation Transfer only.");
358  varSelection = Bonmin::BabSetupBase::OSI_SIMPLE;
359  }
360 #endif
361 
362  for (int i = 0; i < nVars; i++) { // for each variable
363 
364  exprVar *var = couenneProb_ -> Var (i);
365 
366  // we only want enabled variables
367  if (var -> Multiplicity () <= 0)
368  continue;
369 
370  switch (objType) {
371 
372  case CouenneObject::EXPR_OBJ:
373 
374  // if this variable is associated with a nonlinear function
375  if (var -> isInteger () ||
376  ((var -> Type () == AUX) &&
377  (var -> Image () -> Linearity () > LINEAR))) {
378 
379  /*if ((var -> Image () -> code () == COU_EXPRMUL) &&
380  (var -> Image () -> ArgList () [0] -> Index () >= 0) &&
381  (var -> Image () -> ArgList () [1] -> Index () >= 0) &&
382  (fabs (var -> lb ()) < COUENNE_EPS) &&
383  (fabs (var -> ub ()) < COUENNE_EPS))
384 
385  // it's a complementarity constraint object!
386  objects [nobj] = new CouenneComplObject (couenneProb_, var, this, journalist ());
387  else*/
388  objects [nobj] = new CouenneObject (couenneCg, couenneProb_, var, this, journalist ());
389 
390  objects [nobj++] -> setPriority (var -> isInteger () ? intObjPriority : contObjPriority);
391  //objects [nobj++] -> setPriority (contObjPriority + var -> rank ());
392  }
393 
394  break;
395 
396  case CouenneObject::VAR_OBJ:
397 
398  // branching objects on variables
399  if // comment three lines below for linear variables too
400  (var -> isInteger () ||
401  (couenneProb_ -> Dependence () [var -> Index ()] . size () > 0)) { // has indep
402  //|| ((var -> Type () == AUX) && // or, aux
403  // (var -> Image () -> Linearity () > LINEAR))) { // of nonlinear
404 
405  int ind = var -> Index ();
406 
407  objects [nobj] = new CouenneVarObject (couenneCg, couenneProb_, var, this, journalist (), varSelection);
408  objects [nobj++] -> setPriority (var -> isInteger () ? intObjPriority : contObjPriority);
409  //objects [nobj++] -> setPriority (contObjPriority + var -> rank ());
410  }
411 
412  break;
413 
414  default:
415  case CouenneObject::VT_OBJ:
416 
417  // branching objects on variables
418  if // comment three lines below for linear variables too
419  (var -> isInteger () ||
420  (couenneProb_ -> Dependence () [var -> Index ()] . size () > 0)) { // has indep
421  //|| ((var -> Type () == AUX) && // or, aux
422  //(var -> Image () -> Linearity () > LINEAR))) { // of nonlinear
423 
424  objects [nobj] = new CouenneVTObject (couenneCg, couenneProb_, var, this, journalist (), varSelection);
425  objects [nobj++] -> setPriority (var -> isInteger () ? intObjPriority : contObjPriority);
426  //objects [nobj++] -> setPriority (contObjPriority + var -> rank ());
427  }
428 
429  break;
430  }
431  }
432 
433  // // Experimental: orbital branching //////////////////////////////////////////////
434 
435  // options () -> GetStringValue ("orbital_branching", s, "couenne.");
436 
437  // if (s == "yes") {
438 
439  // objects [nobj] = new CouenneOrbitObj (couenneCg, couenneProb_, NULL, this, journalist ());
440  // objects [nobj++] -> setPriority (contObjPriority);
441  // }
442 
443 #ifdef COIN_HAS_NTY
444  if (couenneProb_ -> orbitalBranching ()) {
445 
446  couenneProb_ -> ChangeBounds (couenneProb_ -> Lb (), couenneProb_ -> Ub (), couenneProb_ -> nVars ());
447  couenneProb_ -> Compute_Symmetry ();
448  }
449 #endif
450 
451  //couenneProb_ -> Print_Orbits ();
452 
453  // Add objects /////////////////////////////////
454 
455  continuousSolver_ -> addObjects (nobj, objects);
456 
457  //printf ("boncouennesetup: %d objects --> %d\n", nobj, continuousSolver_ -> numberObjects ());
458 
459  for (int i = 0 ; i < nobj ; i++)
460  delete objects [i];
461 
462  delete [] objects;
463 
464  // Setup Fix Point bound tightener /////////////////////////////////////////////
465 
466  options () -> GetIntegerValue ("fixpoint_bt", freq, "couenne.");
467 
468  if (freq != 0) {
469 
470  CuttingMethod cg;
471  cg.frequency = (freq > 0) ? freq : 1; // Do it always if freq < 0, check within generateCuts() against tree depth
472  cg.cgl = new CouenneFixPoint (couenneProb_, options ());
473  cg.id = "Couenne fixed point FBBT";
474  cutGenerators (). push_back (cg);
475  }
476 
477  // Setup Convexifier generators ////////////////////////////////////////////////
478 
479  options () -> GetIntegerValue ("convexification_cuts", freq, "couenne.");
480 
481  if (freq != 0) {
482 
483  CuttingMethod cg;
484  cg.frequency = freq;
485  cg.cgl = couenneCg;
486  cg.id = "Couenne convexifier cuts";
487  cutGenerators().push_back (cg);
488 
489  // set cut gen pointer
490  //dynamic_cast <CouenneSolverInterface <OsiClpSolverInterface> *>
491  //(continuousSolver_)
492 
493  // this is done on an explicitly declared CSI pointer, however
494  // CSI == continuousSolver_
495  }
496 
497  // add other cut generators -- test for integer variables first
498  if (couenneCg -> Problem () -> nIntVars () > 0)
499  addMilpCutGenerators ();
500 
501  CouennePtr_ = couenneCg;
502 
503  // Add two-inequalities based bound tightening ///////////////////////////////////////////////////////
504 
505  options () -> GetIntegerValue ("two_implied_bt", freq, "couenne.");
506 
507  if (freq != 0) {
508 
509  CouenneTwoImplied * couenne2I =
510  new CouenneTwoImplied (couenneProb_,
511  journalist (),
512  options ());
513  CuttingMethod cg;
514  cg.frequency = freq;
515  cg.cgl = couenne2I;
516  cg.id = "Couenne two-implied cuts";
517  cutGenerators (). push_back(cg);
518  }
519 
520  // check branch variable selection for disjunctive cuts
521 
522  // Setup heuristic to solve MINLP problems. /////////////////////////////////
523 
524  std::string doHeuristic;
525  options () -> GetStringValue ("local_optimization_heuristic", doHeuristic, "couenne.");
526 
527  // ----------------------------------------------------------------
528 
530 
531  couenneCg -> Problem () -> setMaxCpuTime (getDoubleParameter (BabSetupBase::MaxTime));
532 
533  ci -> extractLinearRelaxation (*continuousSolver_, *couenneCg, true, doHeuristic == "yes");
534 
535  // In case there are no discrete variables, we have already a
536  // heuristic solution for which create a initialization heuristic
537  if (!(extraStuff -> infeasibleNode ()) &&
538  ci -> isProvenOptimal () &&
539  ci -> haveNlpSolution ()) {
540 
542  InitHeuristic* initHeuristic = new InitHeuristic
543  (ci -> getObjValue (), ci -> getColSolution (), *couenneProb_);
544  HeuristicMethod h;
545  h.id = "Couenne Rounding NLP"; // same name as the real rounding one
546  h.heuristic = initHeuristic;
547  heuristics_.push_back(h);
548  }
549 
550  if (extraStuff -> infeasibleNode ()){
551  journalist() -> Printf (J_SUMMARY, J_PROBLEM, "Linear relaxation infeasible, the problem is infeasible.\n");
552  retval = false;
553  }
554 
555  // ----------------------------------------------------------------
556 
557  //continuousSolver_ -> findIntegersAndSOS (false);
558  //addSos (); // only adds embedded SOS objects
559 
560  if (doHeuristic == "yes") {
561 
562  int numSolve;
563  options()->GetIntegerValue("log_num_local_optimization_per_level",numSolve,"couenne.");
564  NlpSolveHeuristic * nlpHeuristic = new NlpSolveHeuristic;
565  nlpHeuristic->setNlp(*ci,false);
566  nlpHeuristic->setCouenneProblem(couenneProb_);
567  nlpHeuristic->setMaxNlpInf(maxNlpInf_0);
568  nlpHeuristic->setNumberSolvePerLevel(numSolve);
569  HeuristicMethod h;
570  h.id = "Couenne Rounding NLP";
571  h.heuristic = nlpHeuristic;
572  heuristics_.push_back(h);
573  }
574 
575  options () -> GetStringValue ("iterative_rounding_heuristic", doHeuristic, "couenne.");
576 
577  if (doHeuristic == "yes") {
578  CouenneIterativeRounding * nlpHeuristic = new CouenneIterativeRounding(nonlinearSolver_, ci, couenneProb_, options());
579  HeuristicMethod h;
580  h.id = "Couenne Iterative Rounding";
581  h.heuristic = nlpHeuristic;
582  heuristics_.push_back(h);
583  }
584 
585  options () -> GetStringValue ("feas_pump_heuristic", doHeuristic, "couenne.");
586 
587  if (doHeuristic != "no") {
588 
589  int numSolve;
590 
591  CouenneFeasPump *nlpHeuristic = new CouenneFeasPump (couenneProb_, couenneCg, options ());
592 
593  options () -> GetIntegerValue ("feas_pump_level", numSolve, "couenne.");
594 
595  nlpHeuristic -> setNumberSolvePerLevel (numSolve);
596 
597  nlpHeuristic -> nCalls () =
598  ("yes" == doHeuristic) ? -1 : // run it every time Cbc wants
599  ("once" == doHeuristic) ? 1 : -2; // second case means the answer was "only"
600 
601  HeuristicMethod h;
602 
603  h.id = "Couenne Feasibility Pump";
604  h.heuristic = nlpHeuristic;
605  heuristics_. push_back (h);
606  }
607 
608  if (0) { // inactive as of yet -- segfaults
609 
610  Ipopt::Index doHeuristicDiveFractional = false;
611  options()->GetEnumValue("heuristic_dive_fractional",doHeuristicDiveFractional,prefix_.c_str());
612  if(doHeuristicDiveFractional){
614  HeuristicMethod h;
615  h.heuristic = dive_fractional;
616  h.id = "DiveFractional";
617  heuristics_.push_back(h);
618  }
619 
620  Ipopt::Index doHeuristicDiveVectorLength = false;
621  options()->GetEnumValue("heuristic_dive_vectorLength",doHeuristicDiveVectorLength,prefix_.c_str());
622  if(doHeuristicDiveVectorLength){
624  HeuristicMethod h;
625  h.heuristic = dive_vectorLength;
626  h.id = "DiveVectorLength";
627  heuristics_.push_back(h);
628  }
629 
630  Ipopt::Index doHeuristicDiveMIPFractional = false;
631  if(!options()->GetEnumValue("heuristic_dive_MIP_fractional",doHeuristicDiveMIPFractional,prefix_.c_str())){
632  doHeuristicDiveMIPFractional = true;
633  std::string o_name = prefix_ + "heuristic_dive_MIP_fractional";
634  options_->SetStringValue(o_name.c_str(), "yes",true,true);
635  }
636  if(doHeuristicDiveMIPFractional){
638  HeuristicMethod h;
639  h.heuristic = dive_MIP_fractional;
640  h.id = "DiveMIPFractional";
641  heuristics_.push_back(h);
642  }
643 
644  Ipopt::Index doHeuristicDiveMIPVectorLength = false;
645  options()->GetEnumValue("heuristic_dive_MIP_vectorLength",doHeuristicDiveMIPVectorLength,prefix_.c_str());
646  if(doHeuristicDiveMIPVectorLength){
648  HeuristicMethod h;
649  h.heuristic = dive_MIP_vectorLength;
650  h.id = "DiveMIPVectorLength";
651  heuristics_.push_back(h);
652  }
653  Ipopt::Index doHeuristicFPump = false;
654  if(!nonlinearSolver_->model()->hasGeneralInteger() && !options()->GetEnumValue("heuristic_feasibility_pump",doHeuristicFPump,prefix_.c_str())){
655  doHeuristicFPump = true;
656  std::string o_name = prefix_ + "heuristic_feasibility_pump";
657  options_->SetStringValue(o_name.c_str(), "yes",true,true);
658  }
659  if(doHeuristicFPump){
660  Bonmin::HeuristicFPump* feasibility_pump = new Bonmin::HeuristicFPump(this);
661  HeuristicMethod h;
662  h.heuristic = feasibility_pump;
663  h.id = "FPump";
664  heuristics_.push_back(h);
665  }
666 
667  Ipopt::Index doFixAndSolve = false;
668  options()->GetEnumValue("fix_and_solve_heuristic",doFixAndSolve,prefix_.c_str());
669  if(doFixAndSolve){
671  HeuristicMethod h;
672  h.heuristic = fix_and_solve;
673  h.id = "Fix and Solve";
674  heuristics_.push_back(h);
675  }
676 
677  Ipopt::Index doDummyPump = false;
678  options()->GetEnumValue("dummy_pump_heuristic",doDummyPump,prefix_.c_str());
679  if(doDummyPump){
680  Bonmin::DummyPump* fix_and_solve = new Bonmin::DummyPump(this);
681  HeuristicMethod h;
682  h.heuristic = fix_and_solve;
683  h.id = "Dummy pump";
684  heuristics_.push_back(h);
685  }
686 
687  Ipopt::Index doHeuristicRINS = false;
688  options()->GetEnumValue("heuristic_RINS",doHeuristicRINS,prefix_.c_str());
689  if(doHeuristicRINS){
691  HeuristicMethod h;
692  h.heuristic = rins;
693  h.id = "RINS";
694  heuristics_.push_back(h);
695  }
696 
697  Ipopt::Index doHeuristicLocalBranching = false;
698  options()->GetEnumValue("heuristic_local_branching",doHeuristicLocalBranching,prefix_.c_str());
699  if(doHeuristicLocalBranching){
701  HeuristicMethod h;
702  h.heuristic = local_branching;
703  h.id = "LocalBranching";
704  heuristics_.push_back(h);
705  }
706 
707  Ipopt::Index doHeuristicPumpForMinlp = false;
708  options()->GetEnumValue("pump_for_minlp",doHeuristicPumpForMinlp,prefix_.c_str());
709  if(doHeuristicPumpForMinlp){
710  Bonmin::PumpForMinlp * pump = new Bonmin::PumpForMinlp(this);
711  HeuristicMethod h;
712  h.heuristic = pump;
713  h.id = "Pump for MINLP";
714  heuristics_.push_back(h);
715  }
716 
717  Ipopt::Index doHeuristicMilpRounding = false;
718  options()->GetEnumValue("MILP_rounding_heuristic",doHeuristicMilpRounding,prefix_.c_str());
719  if(doHeuristicMilpRounding){
720  Bonmin::MilpRounding * round = new Bonmin::MilpRounding(this);
721  HeuristicMethod h;
722  h.heuristic = round;
723  h.id = "MILP Rounding";
724  heuristics_.push_back(h);
725  }
726  }
727 
728  // Add Branching rules ///////////////////////////////////////////////////////
729 
730  switch (varSelection) {
731 
732  case OSI_STRONG: { // strong branching
733  CouenneChooseStrong * chooseVariable = new CouenneChooseStrong
734  (*this, couenneProb_, journalist ());
735  chooseVariable->setTrustStrongForSolution(false);
736  chooseVariable->setTrustStrongForBound(false);
737  chooseVariable->setOnlyPseudoWhenTrusted(true);
738  branchingMethod_ = chooseVariable;
739  break;
740  }
741 
742  case OSI_SIMPLE: // default choice
743  branchingMethod_ = new CouenneChooseVariable
744  (continuousSolver_, couenneProb_, journalist ());
745  break;
746 
747  default:
748  std::cerr << "Unknown variable_selection for Couenne\n" << std::endl;
749  throw;
750  break;
751  }
752 
753  // Node comparison method ///////////////////////////////////////////////////////////////////////////
754 
755  int ival;
756  if (!options_->GetEnumValue("node_comparison", ival, "bonmin.")) {
757  // change default for Couenne
758  nodeComparisonMethod_ = bestBound;
759  }
760  else {
761  nodeComparisonMethod_ = NodeComparison(ival);
762  }
763 
764  if (intParam_[NumCutPasses] < 2)
765  intParam_[NumCutPasses] = 2;
766 
767  // Tell Cbc not to check again if a solution returned from
768  // heuristic is indeed feasible
769  intParam_ [BabSetupBase::SpecialOption] = 16 | 4;
770 
771  // Add PSD cut handler ///////////////////////////////////////////////////////
772 
773  options () -> GetIntegerValue ("sdp_cuts", freq, "couenne.");
774 
775  if (freq != 0) {
776 
777  CouenneSdpCuts * couenneSDP =
778  new CouenneSdpCuts (couenneProb_,
779  journalist (),
780  options ());
781  CuttingMethod cg;
782  cg.frequency = freq;
783  cg.cgl = couenneSDP;
784  cg.id = "Couenne SDP cuts";
785  cutGenerators (). push_back (cg);
786  }
787 
788  // Add disjunctive cuts ///////////////////////////////////////////////////////
789 
790  options () -> GetIntegerValue ("minlp_disj_cuts", freq, "couenne.");
791 
792  if (freq != 0) {
793 
794  CouenneDisjCuts * couenneDisj =
795  new CouenneDisjCuts (ci, this,
796  couenneCg,
797  branchingMethod_,
798  varSelection == OSI_STRONG, // if true, use strong branching candidates
799  journalist (),
800  options ());
801 
802  CuttingMethod cg;
803  cg.frequency = freq;
804  cg.cgl = couenneDisj;
805  cg.id = "Couenne disjunctive cuts";
806  cutGenerators (). push_back(cg);
807  }
808 
809  // Add cross-aux redundant cuts ///////////////////////////////////////////////////////
810 
811  options () -> GetIntegerValue ("crossconv_cuts", freq, "couenne.");
812 
813  if (freq != 0) {
814 
815  CouenneCrossConv * couenneCross =
816  new CouenneCrossConv (couenneProb,
817  journalist (),
818  options ());
819 
820  CuttingMethod cg;
821  cg.frequency = freq;
822  cg.cgl = couenneCross;
823  cg.id = "Couenne cross-aux cuts";
824  cutGenerators (). push_back(cg);
825  }
826 
827  return retval;
828 }
829 
830 void CouenneSetup::registerOptions ()
831 {registerAllOptions (roptions ());}
832 
833 
834 void CouenneSetup::registerAllOptions (Ipopt::SmartPtr <Bonmin::RegisteredOptions> roptions) {
835 
836  roptions -> SetRegisteringCategory ("Couenne options", Bonmin::RegisteredOptions::CouenneCategory);
837 
838  BabSetupBase ::registerAllOptions (roptions);
840 
854 
855  roptions -> AddStringOption3 ("milp_solver",
856  "Choose the subsolver to solve MILP sub-problems in OA decompositions.",
857  "Cbc_D",
858  "Cbc_D","Coin Branch and Cut with its default",
859  "Cbc_Par", "Coin Branch and Cut with passed parameters",
860  "Cplex","Cplex",
861  " To use Cplex, a valid license is required and you should have compiled OsiCpx in COIN-OR (see Osi documentation).");
862 
863  roptions -> setOptionExtraInfo ("milp_solver",64);
864 
865  roptions -> AddStringOption2 ("milp_strategy",
866  "Choose a strategy for MILPs.",
867  "find_good_sol",
868  "find_good_sol","Stop sub milps when a solution improving the incumbent is found",
869  "solve_to_optimality", "Solve MILPs to optimality",
870  "");
871 
872  roptions -> AddStringOption6 ("algorithm",
873  "Choice of the algorithm.",
874  "B-BB",
875  "B-BB","simple branch-and-bound algorithm,",
876  "B-OA","OA Decomposition algorithm,",
877  "B-QG","Quesada and Grossmann branch-and-cut algorithm,",
878  "B-Hyb","hybrid outer approximation based branch-and-cut,",
879  "B-Ecp","ecp cuts based branch-and-cut a la FilMINT.",
880  "B-iFP","Iterated Feasibility Pump for MINLP.",
881  "This will preset some of the options of bonmin depending on the algorithm choice."
882  );
883 
884  CouenneProblem ::registerOptions (roptions);
885  CouenneCutGenerator ::registerOptions (roptions);
886  CouenneChooseStrong ::registerOptions (roptions);
887  CouenneChooseVariable ::registerOptions (roptions);
888  CouenneFixPoint ::registerOptions (roptions);
889  CouenneDisjCuts ::registerOptions (roptions);
890  CouenneCrossConv ::registerOptions (roptions);
891  CouenneSdpCuts ::registerOptions (roptions);
892  CouenneTwoImplied ::registerOptions (roptions);
893  NlpSolveHeuristic ::registerOptions (roptions);
894  CouenneFeasPump ::registerOptions (roptions);
895  CouenneIterativeRounding::registerOptions (roptions);
896 
898  roptions -> AddStringOption2
899  ("local_branching_heuristic",
900  "Apply local branching heuristic",
901  "no",
902  "no","",
903  "yes","",
904  "A local-branching heuristic based is used to find feasible solutions.");
905 
906 
907  roptions -> AddNumberOption ("couenne_check",
908  "known value of a global optimum (for debug purposes only)",
909  COIN_DBL_MAX,
910  "Default value is +infinity.");
911 
912  roptions -> AddStringOption2 ("display_stats",
913  "display statistics at the end of the run",
914  "no",
915  "yes", "",
916  "no", "");
917 
918  roptions -> AddStringOption2 ("save_soltext",
919  "save pairs (index, value) of the solution at the end of the solve",
920  "no",
921  "yes", "",
922  "no", "");
923 
924  roptions -> AddStringOption2 ("test_mode",
925  "set to true if this is Couenne unit test",
926  "no",
927  "yes", "",
928  "no", "");
929 
930  roptions -> AddStringOption5 ("lp_solver",
931  "Linear Programming solver for the linearization",
932  "clp",
933  "clp", "Use the COIN-OR Open Source solver CLP (default)",
934  "cplex", "Use the commercial solver Cplex (license is needed)",
935  "gurobi", "Use the commercial solver Gurobi (license is needed)",
936  "soplex", "Use the freely available Soplex",
937  "xpress-mp", "Use the commercial solver Xpress MP (license is needed)"
938  );
939 
940 #define addLevOption(optname,comment,default) roptions -> AddBoundedIntegerOption (optname, comment, -2, J_LAST_LEVEL-1, default, "")
941 
942  addLevOption ("output_level", "Output level", J_WARNING);
943  addLevOption ("branching_print_level", "Output level for braching code in Couenne", J_NONE);
944  addLevOption ("boundtightening_print_level", "Output level for bound tightening code in Couenne", J_NONE);
945  addLevOption ("convexifying_print_level", "Output level for convexifying code in Couenne", J_NONE);
946  addLevOption ("problem_print_level", "Output level for problem manipulation code in Couenne", J_NONE);
947  addLevOption ("nlpheur_print_level", "Output level for NLP heuristic in Couenne", J_NONE);
948  addLevOption ("disjcuts_print_level", "Output level for disjunctive cuts in Couenne", J_NONE);
949  addLevOption ("reformulate_print_level", "Output level for reformulating problems in Couenne", J_NONE);
950 
951  roptions -> AddNumberOption
952  ("feas_tolerance",
953  "Tolerance for constraints/auxiliary variables",
955  "Default value is 1e-5.");
956 
957  roptions -> AddStringOption2
958  ("feasibility_bt",
959  "Feasibility-based (cheap) bound tightening (FBBT)",
960  "yes",
961  "no","",
962  "yes","",
963  "A pre-processing technique to reduce the bounding box, before the generation of linearization cuts. "
964  "This is a quick and effective way to reduce the solution set, and it is highly recommended to keep it active."
965  );
966 
967  // copied from BonminSetup::registerMilpCutGenerators(), in
968  // BonBonminSetup.cpp
969 
970  struct cutOption_ {
971 
972  const char *cgname;
973  int defaultFreq;
974 
975  } cutOption [] = {
976  {(const char *) "Gomory_cuts", 0},
977  {(const char *) "probing_cuts", 0},
978  {(const char *) "cover_cuts", 0},
979  {(const char *) "mir_cuts", 0},
980  {(const char *) "2mir_cuts", 0},
981  {(const char *) "flow_covers_cuts", 0},
982  {(const char *) "lift_and_project_cuts", 0},
983  {(const char *) "reduce_split_cuts", 0},
984  {(const char *) "clique_cuts", 0},
985  {NULL, 0}};
986 
987  for (int i=0; cutOption [i].cgname; i++) {
988 
989  char descr [150];
990 
991  sprintf (descr, "Frequency k (in terms of nodes) for generating %s cuts in branch-and-cut.",
992  cutOption [i].cgname);
993 
994  roptions -> AddLowerBoundedIntegerOption
995  (cutOption [i].cgname,
996  descr,
997  -100, cutOption [i].defaultFreq,
998  "If k > 0, cuts are generated every k nodes, "
999  "if -99 < k < 0 cuts are generated every -k nodes but "
1000  "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
1001  "if k=-99 generate cuts only at the root node, if k=0 or 100 do not generate cuts.");
1002 
1003  roptions->setOptionExtraInfo (cutOption [i].cgname, 5);
1004  }
1005 }
1006 
1007 
1008 
1010 void CouenneSetup::addMilpCutGenerators () {
1011 
1012  enum extraInfo_ {CUTINFO_NONE, CUTINFO_MIG, CUTINFO_PROBING, CUTINFO_CLIQUE};
1013 
1014  // extra data structure to avoid repeated code below
1015 
1016  struct cutInfo {
1017 
1018  const char *optname;
1019  CglCutGenerator *cglptr;
1020  const char *cglId;
1021  enum extraInfo_ extraInfo;
1022 
1023  } cutList [] = {
1024  {(const char*)"Gomory_cuts",new CglGomory, (const char*)"Mixed Integer Gomory",CUTINFO_MIG},
1025  {(const char*)"probing_cuts",new CglProbing, (const char*) "Probing", CUTINFO_PROBING},
1026  {(const char*)"mir_cuts",new CglMixedIntegerRounding2, (const char*) "Mixed Integer Rounding",
1027  CUTINFO_NONE},
1028  {(const char*)"2mir_cuts", new CglTwomir, (const char*) "2-MIR", CUTINFO_NONE},
1029  {(const char*)"cover_cuts", new CglKnapsackCover, (const char*) "Cover", CUTINFO_NONE},
1030  {(const char*)"clique_cuts", new CglClique, (const char*) "Clique", CUTINFO_CLIQUE},
1031  {(const char*)"lift_and_project_cuts",new CglLandP,(const char*)"Lift and Project",CUTINFO_NONE},
1032  {(const char*)"reduce_split_cuts",new CglRedSplit,(const char*) "Reduce and Split",CUTINFO_NONE},
1033  {(const char*)"flow_covers_cuts",new CglFlowCover,(const char*) "Flow cover cuts", CUTINFO_NONE},
1034  {NULL, NULL, NULL, CUTINFO_NONE}};
1035 
1036  int freq;
1037 
1038  for (int i=0; cutList [i]. optname; i++) {
1039 
1040  options_ -> GetIntegerValue (std::string (cutList [i]. optname), freq, "couenne.");
1041 
1042  if (!freq) {
1043  delete cutList [i].cglptr;
1044  continue;
1045  }
1046 
1047  CuttingMethod cg;
1048  cg.frequency = freq;
1049  cg.cgl = cutList [i].cglptr;
1050  cg.id = std::string (cutList [i]. cglId);
1051  cutGenerators_.push_back (cg);
1052 
1053  // options for particular cases
1054  switch (cutList [i].extraInfo) {
1055 
1056  case CUTINFO_MIG: {
1057  CglGomory *gc = dynamic_cast <CglGomory *> (cutList [i].cglptr);
1058 
1059  if (!gc) break;
1060 
1061  gc -> setLimitAtRoot(512);
1062  gc -> setLimit(50);
1063  }
1064  break;
1065 
1066  case CUTINFO_PROBING: {
1067  CglProbing *pc = dynamic_cast <CglProbing *> (cutList [i].cglptr);
1068 
1069  if (!pc) break;
1070 
1071  pc->setUsingObjective(1);
1072  pc->setMaxPass(3);
1073  pc->setMaxPassRoot(3);
1074  // Number of unsatisfied variables to look at
1075  pc->setMaxProbe(10);
1076  pc->setMaxProbeRoot(50);
1077  // How far to follow the consequences
1078  pc->setMaxLook(10);
1079  pc->setMaxLookRoot(50);
1080  pc->setMaxLookRoot(10);
1081  // Only look at rows with fewer than this number of elements
1082  pc->setMaxElements(200);
1083  pc->setRowCuts(3);
1084  }
1085  break;
1086 
1087  case CUTINFO_CLIQUE: {
1088  CglClique *clique = dynamic_cast <CglClique *> (cutList [i].cglptr);
1089 
1090  if (!clique) break;
1091 
1092  clique -> setStarCliqueReport(false);
1093  clique -> setRowCliqueReport(false);
1094  clique -> setMinViolation(0.1);
1095  }
1096  break;
1097 
1098  //case CUTINFO_NONE:
1099  default:
1100  break;
1101  }
1102  }
1103 
1104  double givenAllowFGap2 = 0.0;
1105  options_->GetNumericValue(std::string("allowable_fraction_gap"),
1106  givenAllowFGap2, "bonmin.");
1107  double upval = 1e50;
1108 
1109 #ifdef FM_UP_BND
1110  printf("CutOff value:\n");
1111  scanf("%lf", &upval);
1112 #else /* not FM_UP_BND */
1113  options_->GetNumericValue(std::string("art_cutoff"), upval, "bonmin.");
1114 #endif /* FM_UP_BND */
1115 
1116  if(upval < 1e50) {
1117  double newCO = (1-givenAllowFGap2) * upval;
1118  couenneProb_->setCutOff(newCO);
1119  printf("CutOff set to %f\n", newCO);
1120 
1121 #ifdef FM_TRACE_OPTSOL
1122  if(couenneProb_->getRecordBestSol()->getHasSol()) {
1123  if(newCO < couenneProb_->getRecordBestSol()->getVal()) {
1124  couenneProb_->getRecordBestSol()->setVal(newCO);
1125  }
1126  }
1127 #endif
1128  }
1129 }
Cut Generator for linear convexifications.
void setCouenneProblem(CouenneProblem *)
set the couenne problem to use.
const CouNumber feas_tolerance_default
void setOnlyPseudoWhenTrusted(bool only_pseudo_when_trusted)
Type for heuristic method with its string identification.
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register all the options for class instance.
Definition: BonCbcNode.cpp:71
An iterative rounding heuristic, tailored for nonconvex MINLPs.
OsiObject for auxiliary variables $w=f(x)$.
OsiObject for violation transfer on variables in a MINLP.
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
void setNlp(Bonmin::OsiTMINLPInterface &nlp, bool cloneNlp=true)
Set the nlp solver.
bool IsValid(const OSSmartPtr< U > &smart_ptr)
Definition: OSSmartPtr.hpp:465
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
A heuristic that stores the initial solution of the NLP.
These are cuts of the form.
const Ipopt::EJournalCategory J_DISJCUTS(Ipopt::J_USER6)
const Ipopt::EJournalCategory J_BRANCHING(Ipopt::J_USER1)
const Ipopt::EJournalCategory J_CONVEXIFYING(Ipopt::J_USER3)
ASL * readASLfg(char **argv)
Definition: readASLfg.cpp:27
const double maxNlpInf_0
A heuristic to call an NlpSolver if all CouenneObjects are close to be satisfied (for other integer o...
#define addJournalist(optname, jlevel)
#define addLevOption(optname, comment, default)
An implementation of the Feasibility pump that uses linearization and Ipopt to find the two sequences...
Type for cut generation method with its frequency and string identification.
Bonmin class for passing info between components of branch-and-cuts.
Cut Generator for FBBT fixpoint.
Cut Generator for linear convexifications.
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
Solver interface class with a pointer to a Couenne cut generator.
void setNumberSolvePerLevel(int value)
set number of nlp&#39;s solved for each given level of the tree
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
const Ipopt::EJournalCategory J_BOUNDTIGHTENING(Ipopt::J_USER2)
Class for MINLP problems with symbolic information.
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
void fint fint fint fint fint fint fint fint fint fint real real real real real real real real * s
const Ipopt::EJournalCategory J_REFORMULATE(Ipopt::J_USER7)
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options for this heuristic.
U * GetRawPtr(const OSSmartPtr< U > &smart_ptr)
Definition: OSSmartPtr.hpp:452
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
Cut Generator for implied bounds derived from pairs of linear (in)equalities.
Choose a variable for branching.
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
NodeComparison
Strategies for comparing the nodes on the heap.
const Ipopt::EJournalCategory J_NLPHEURISTIC(Ipopt::J_USER5)
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
variable-type operator
Cut Generator that uses relationships between auxiliaries.
branch_obj
type of object (for branching variable selection)
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
void setMaxNlpInf(double value)
set maxNlpInf.
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
const Ipopt::EJournalCategory J_COUENNE(Ipopt::J_USER8)
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
const Ipopt::EJournalCategory J_PROBLEM(Ipopt::J_USER4)
Bonmin class for passing info between components of branch-and-cuts.
Definition: BonBabInfos.hpp:19
OsiObject for variables in a MINLP.
bool isInteger(CouNumber x)
is this number integer?