source: trunk/Couenne/src/main/BonCouenneSetup.cpp @ 972

Last change on this file since 972 was 936, checked in by pbelotti, 7 years ago

added option to fill matrices for SDP cuts. removed delete_ field from CouenneScalar?

  • Property svn:keywords set to Author Date Id Revision
File size: 36.2 KB
Line 
1// $Id: BonCouenneSetup.cpp 936 2012-12-31 01:25:14Z tkr $
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"
47#include "CouenneIterativeRounding.hpp"
48#include "BonCouenneInterface.hpp"
49#include "BonInitHeuristic.hpp"
50#include "BonNlpHeuristic.hpp"
51
52#include "BonFixAndSolveHeuristic.hpp"
53#include "BonDummyPump.hpp"
54#include "BonPumpForMinlp.hpp"
55#include "BonHeuristicRINS.hpp"
56#include "BonHeuristicLocalBranching.hpp"
57#include "BonHeuristicFPump.hpp"
58#include "BonHeuristicDiveFractional.hpp"
59#include "BonHeuristicDiveVectorLength.hpp"
60#include "BonHeuristicDiveMIPFractional.hpp"
61#include "BonHeuristicDiveMIPVectorLength.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"
71#include "CouenneChooseVariable.hpp"
72#include "CouenneChooseStrong.hpp"
73#include "CouenneSolverInterface.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
93using namespace Ipopt;
94using namespace Couenne;
95
96CouenneSetup::~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
105bool CouenneSetup::InitializeCouenne (char ** argv,
106                                      CouenneProblem *couenneProb,
107                                      Ipopt::SmartPtr<Bonmin::TMINLP> tminlp,
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
133  /** Change default value for failure behavior so that code doesn't crash
134      when Ipopt does not solve a sub-problem.*/
135
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
166  /** Set the output level of the journalist for all Couenne
167      categories.  We probably want to make that a bit more flexible
168      later. */
169
170  int i;
171
172  /// trying to avoid repetitions here...
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  /* Initialize Couenne cut generator.*/
189  //int ivalue, num_points;
190  //options()->GetEnumValue("convexification_type", ivalue,"couenne.");
191  //options()->GetIntegerValue("convexification_points",num_points,"couenne.");
192
193  if (!couenneProb_)
194    couenneProb_ = new CouenneProblem (aslfg_ -> asl, this, journalist ());
195
196  CouenneCutGenerator * couenneCg = 
197    new CouenneCutGenerator (ci, this, couenneProb_, NULL);
198
199  options_ -> GetStringValue ("lp_solver", s, "couenne.");
200
201  if (s == "clp") {
202
203    CouenneSolverInterface <OsiClpSolverInterface> *CSI = new CouenneSolverInterface <OsiClpSolverInterface>;
204    continuousSolver_ = CSI;
205    CSI -> setCutGenPtr (couenneCg);
206
207  } else if (s == "cplex") {
208
209#ifdef COIN_HAS_CPX
210    CouenneSolverInterface <OsiCpxSolverInterface> *CSI = new CouenneSolverInterface <OsiCpxSolverInterface>;
211    continuousSolver_ = CSI;
212    CSI -> setCutGenPtr (couenneCg);
213#else
214    journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without CPLEX interface. Please reconfigure, recompile, and try again.\n");
215    exit (-1);
216#endif
217  } else if (s == "xpress-mp") {
218
219#ifdef COIN_HAS_XPR
220    CouenneSolverInterface <OsiXprSolverInterface> *CSI = new CouenneSolverInterface <OsiXprSolverInterface>;
221    continuousSolver_ = CSI;
222    CSI -> setCutGenPtr (couenneCg);
223#else
224    journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without Xpress-MP interface. Please reconfigure, recompile, and try again.\n");
225    exit (-1);
226#endif
227  } else if (s == "gurobi") {
228
229#ifdef COIN_HAS_GRB
230    CouenneSolverInterface <OsiGrbSolverInterface> *CSI = new CouenneSolverInterface <OsiGrbSolverInterface>;
231    continuousSolver_ = CSI;
232    CSI -> setCutGenPtr (couenneCg);
233#else
234    journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without GUROBI interface. Please reconfigure, recompile, and try again.\n");
235    exit (-1);
236#endif
237  } else if (s == "soplex") {
238
239#ifdef COIN_HAS_SPX
240    CouenneSolverInterface <OsiSpxSolverInterface> *CSI = new CouenneSolverInterface <OsiSpxSolverInterface>;
241    continuousSolver_ = CSI;
242    CSI -> setCutGenPtr (couenneCg);
243#else
244    journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without Soplex. Please reconfigure, recompile, and try again.\n");
245    exit (-1);
246#endif
247  } else {
248    journalist ()-> Printf (J_ERROR, J_INITIALIZATION, "The LP solver you specified hasn't been added to Couenne yet.\n");
249    exit (-1);
250  }
251
252  continuousSolver_ -> passInMessageHandler(ci -> messageHandler());
253
254  couenneProb_ -> setBase (this);
255
256  assert (couenneProb_);
257
258  couenneProb_ -> reformulate (couenneCg);
259
260  Bonmin::BabInfo * extraStuff = new CouenneInfo (0);
261
262  // as per instructions by John Forrest, to get changed bounds
263  extraStuff -> setExtraCharacteristics (extraStuff -> extraCharacteristics () | 2);
264
265  continuousSolver_ -> setAuxiliaryInfo (extraStuff);
266  delete extraStuff;
267   
268  extraStuff = dynamic_cast <Bonmin::BabInfo *> (continuousSolver_ -> getAuxiliaryInfo ());
269
270  // Setup log level of LP solver
271  int lpLogLevel;
272  options () -> GetIntegerValue ("lp_log_level", lpLogLevel, "couenne.");
273  continuousSolver_ -> messageHandler () -> setLogLevel (lpLogLevel);
274
275  // Add Couenne SOS ///////////////////////////////////////////////////////////////
276
277  int 
278    nSOS  = 0,
279    nVars = couenneProb_ -> nVars ();
280
281  OsiObject ** objects = NULL;
282
283  options () -> GetStringValue ("enable_sos", s, "couenne.");
284
285  if (s == "yes") {
286
287    // allocate sufficient space for both nonlinear variables and SOS's
288    objects = new OsiObject* [couenneProb_ -> nCons () + nVars];
289
290    nSOS = couenneProb_ -> findSOS (&(bb -> model()), dynamic_cast <OsiSolverInterface *> (nonlinearSolver ()), objects);
291
292    nonlinearSolver () -> addObjects (nSOS, objects);
293
294    //printf ("boncouennesetup 1: %d SOS objects --> %d\n", nSOS, nonlinearSolver () -> numberObjects ());
295
296    //printf ("==================== found %d SOS\n", nSOS);
297    //nonlinearSolver () -> addObjects (nSOS, objects);
298    //continuousSolver () -> addObjects (nSOS, objects);
299
300    //printf ("found %d SOS!\n", nSOS);
301
302    /*for (int i=0; i<nSOS; i++)
303      delete objects [i];
304      delete [] objects;*/
305
306    if (!nSOS) {
307      delete [] objects;
308      objects = NULL;
309    } 
310  }
311
312  //model -> assignSolver (continuousSolver_, true);
313  //continuousSolver_ = model -> solver();
314
315  // Add Couenne objects for branching /////////////////////////////////////////////
316
317  options () -> GetStringValue ("display_stats", s, "couenne.");
318  displayStats_ = (s == "yes");
319
320  options () -> GetStringValue ("branching_object", s, "couenne.");
321
322  enum CouenneObject::branch_obj objType = CouenneObject::VAR_OBJ;
323
324  if      (s ==   "vt_obj") objType = CouenneObject::VT_OBJ;
325  else if (s ==  "var_obj") objType = CouenneObject::VAR_OBJ;
326  else if (s == "expr_obj") objType = CouenneObject::EXPR_OBJ;
327  else {
328    printf ("CouenneSetup: Unknown branching object type\n");
329    exit (-1);
330  }
331
332  int 
333    nobj = nSOS; // if no SOS then objects is empty
334
335  if (!objects)
336    objects = new OsiObject* [nVars];
337
338  int 
339    contObjPriority, 
340    intObjPriority;
341
342  options () -> GetIntegerValue ("cont_var_priority", contObjPriority, "couenne.");
343  options () -> GetIntegerValue ( "int_var_priority",  intObjPriority, "couenne.");
344
345  int varSelection;
346  if (!options_ -> GetEnumValue ("variable_selection", varSelection, "couenne.")) {
347    // change the default for Couenne
348    varSelection = Bonmin::BabSetupBase::OSI_SIMPLE;
349  }
350
351  for (int i = 0; i < nVars; i++) { // for each variable
352
353    exprVar *var = couenneProb_ -> Var (i);
354
355    // we only want enabled variables
356    if (var -> Multiplicity () <= 0) 
357      continue;
358
359    switch (objType) {
360
361    case CouenneObject::EXPR_OBJ:
362
363      // if this variable is associated with a nonlinear function
364      if (var -> isInteger () || 
365          ((var -> Type  () == AUX) && 
366           (var -> Image () -> Linearity () > LINEAR))) {
367
368        /*if ((var -> Image () -> code () == COU_EXPRMUL) &&
369          (var -> Image () -> ArgList () [0] -> Index () >= 0) &&
370          (var -> Image () -> ArgList () [1] -> Index () >= 0) &&
371          (fabs (var -> lb ()) < COUENNE_EPS) &&
372          (fabs (var -> ub ()) < COUENNE_EPS))
373
374          // it's a complementarity constraint object!
375          objects    [nobj] = new CouenneComplObject (couenneProb_, var, this, journalist ());
376          else*/
377        objects [nobj] = new CouenneObject (couenneCg, couenneProb_, var, this, journalist ());
378
379        objects [nobj++] -> setPriority (var -> isInteger () ? intObjPriority : contObjPriority);
380        //objects [nobj++] -> setPriority (contObjPriority + var -> rank ());
381      }
382
383      break;
384
385    case CouenneObject::VAR_OBJ:
386
387      // branching objects on variables
388      if // comment three lines below for linear variables too
389        (var -> isInteger () || 
390         (couenneProb_ -> Dependence () [var -> Index ()] . size () > 0)) {  // has indep
391        //|| ((var -> Type () == AUX) &&                                  // or, aux
392        //    (var -> Image () -> Linearity () > LINEAR))) {              // of nonlinear
393
394        objects [nobj] = new CouenneVarObject (couenneCg, couenneProb_, var, this, journalist (), varSelection);
395        objects [nobj++] -> setPriority (var -> isInteger () ? intObjPriority : contObjPriority);
396        //objects [nobj++] -> setPriority (contObjPriority + var -> rank ());
397      }
398
399      break;
400
401    default:
402    case CouenneObject::VT_OBJ:
403
404      // branching objects on variables
405      if // comment three lines below for linear variables too
406        (var -> isInteger () || 
407         (couenneProb_ -> Dependence () [var -> Index ()] . size () > 0)) { // has indep
408        //|| ((var -> Type () == AUX) &&                      // or, aux
409        //(var -> Image () -> Linearity () > LINEAR))) { // of nonlinear
410
411        objects [nobj] = new CouenneVTObject (couenneCg, couenneProb_, var, this, journalist ());
412        objects [nobj++] -> setPriority (var -> isInteger () ? intObjPriority : contObjPriority);
413        //objects [nobj++] -> setPriority (contObjPriority + var -> rank ());
414      }
415
416      break;
417    }
418  }
419
420  // // Experimental: orbital branching //////////////////////////////////////////////
421
422  // options () -> GetStringValue ("orbital_branching", s, "couenne.");
423
424  // if (s == "yes") {
425
426  //   objects [nobj] = new CouenneOrbitObj (couenneCg, couenneProb_, NULL, this, journalist ());
427  //   objects [nobj++] -> setPriority (contObjPriority);
428  // }
429
430#ifdef COIN_HAS_NTY
431  if (couenneProb_ -> orbitalBranching ()) {
432
433    couenneProb_ -> ChangeBounds (couenneProb_ -> Lb (), couenneProb_ -> Ub (), couenneProb_ -> nVars ());
434    couenneProb_ -> Compute_Symmetry ();
435  }
436#endif
437
438  //couenneProb_ -> Print_Orbits ();
439
440  // Add objects /////////////////////////////////
441
442  continuousSolver_ -> addObjects (nobj, objects);
443
444  //printf ("boncouennesetup: %d objects --> %d\n", nobj, continuousSolver_ -> numberObjects ());
445
446  for (int i = 0 ; i < nobj ; i++)
447    delete objects [i];
448
449  delete [] objects;
450
451  // Setup Fix Point bound tightener /////////////////////////////////////////////
452
453  options () -> GetIntegerValue ("fixpoint_bt", freq, "couenne.");
454
455  if (freq != 0) {
456
457    CuttingMethod cg;
458    cg.frequency = freq;
459    cg.cgl = new CouenneFixPoint (couenneProb_, options ());
460    cg.id = "Couenne fixed point FBBT";
461    cutGenerators (). push_back (cg);
462  }
463
464  // Setup Convexifier generators ////////////////////////////////////////////////
465
466  options () -> GetIntegerValue ("convexification_cuts", freq, "couenne.");
467
468  if (freq != 0) {
469
470    CuttingMethod cg;
471    cg.frequency = freq;
472    cg.cgl = couenneCg;
473    cg.id = "Couenne convexifier cuts";
474    cutGenerators().push_back (cg);
475
476    // set cut gen pointer
477    //dynamic_cast <CouenneSolverInterface <OsiClpSolverInterface> *>
478    //(continuousSolver_)
479
480    // this is done on an explicitly declared CSI pointer, however
481    // CSI == continuousSolver_
482  }
483
484  // add other cut generators -- test for integer variables first
485  if (couenneCg -> Problem () -> nIntVars () > 0)
486    addMilpCutGenerators ();
487
488  CouennePtr_ = couenneCg;
489
490  // Add two-inequalities based bound tightening ///////////////////////////////////////////////////////
491
492  options () -> GetIntegerValue ("two_implied_bt", freq, "couenne.");
493
494  if (freq != 0) {
495
496    CouenneTwoImplied * couenne2I = 
497      new CouenneTwoImplied (couenneProb_,
498                             journalist (),
499                             options    ());
500    CuttingMethod cg;
501    cg.frequency = freq;
502    cg.cgl = couenne2I;
503    cg.id = "Couenne two-implied cuts";
504    cutGenerators (). push_back(cg);
505  }
506
507  // check branch variable selection for disjunctive cuts
508
509  // Setup heuristic to solve MINLP problems. /////////////////////////////////
510
511  std::string doHeuristic;
512  options () -> GetStringValue ("local_optimization_heuristic", doHeuristic, "couenne.");
513
514  // ----------------------------------------------------------------
515
516  //////////////////////////////////////////////////////////////
517
518  couenneCg -> Problem () -> setMaxCpuTime (getDoubleParameter (BabSetupBase::MaxTime));
519
520  ci -> extractLinearRelaxation (*continuousSolver_, *couenneCg, true, doHeuristic == "yes");
521
522  // In case there are no discrete variables, we have already a
523  // heuristic solution for which create a initialization heuristic
524  if (!(extraStuff -> infeasibleNode ()) &&
525      ci -> isProvenOptimal () && 
526      ci -> haveNlpSolution ()) {
527
528    /// setup initial heuristic (in principle it should only run once...)
529    InitHeuristic* initHeuristic = new InitHeuristic
530      (ci -> getObjValue (), ci -> getColSolution (), *couenneProb_);
531    HeuristicMethod h;
532    h.id = "Couenne Rounding NLP"; // same name as the real rounding one
533    h.heuristic = initHeuristic;
534    heuristics_.push_back(h);
535  }
536
537  if (extraStuff -> infeasibleNode ()){
538    journalist() -> Printf (J_SUMMARY, J_PROBLEM, "Linear relaxation infeasible, the problem is infeasible.\n");
539    retval = false;
540  }
541
542  // ----------------------------------------------------------------
543
544  //continuousSolver_ -> findIntegersAndSOS (false);
545  //addSos (); // only adds embedded SOS objects
546
547  if (doHeuristic == "yes") {
548
549    int numSolve;
550    options()->GetIntegerValue("log_num_local_optimization_per_level",numSolve,"couenne.");
551    NlpSolveHeuristic * nlpHeuristic = new NlpSolveHeuristic;
552    nlpHeuristic->setNlp(*ci,false);
553    nlpHeuristic->setCouenneProblem(couenneProb_);
554    nlpHeuristic->setMaxNlpInf(maxNlpInf_0);
555    nlpHeuristic->setNumberSolvePerLevel(numSolve);
556    HeuristicMethod h;
557    h.id = "Couenne Rounding NLP";
558    h.heuristic = nlpHeuristic;
559    heuristics_.push_back(h);
560  }
561
562  options () -> GetStringValue ("iterative_rounding_heuristic", doHeuristic, "couenne.");
563 
564  if (doHeuristic == "yes") {
565    CouenneIterativeRounding * nlpHeuristic = new CouenneIterativeRounding(nonlinearSolver_, ci, couenneProb_, options());
566    HeuristicMethod h;
567    h.id = "Couenne Iterative Rounding";
568    h.heuristic = nlpHeuristic;
569    heuristics_.push_back(h);
570  }
571
572  options () -> GetStringValue ("feas_pump_heuristic", doHeuristic, "couenne.");
573
574  if (doHeuristic == "yes") {
575
576    int numSolve;
577    options () -> GetIntegerValue ("feas_pump_level", numSolve, "couenne.");
578
579    CouenneFeasPump *nlpHeuristic = new CouenneFeasPump (couenneProb_, couenneCg, options ());
580
581    nlpHeuristic -> setNumberSolvePerLevel (numSolve);
582
583    HeuristicMethod h;
584
585    h.id = "Couenne Feasibility Pump";
586    h.heuristic = nlpHeuristic;
587    heuristics_. push_back (h);
588  }
589
590
591  if (0) { // inactive as of yet -- segfaults
592
593    Ipopt::Index doHeuristicDiveFractional = false;
594    options()->GetEnumValue("heuristic_dive_fractional",doHeuristicDiveFractional,prefix_.c_str());
595    if(doHeuristicDiveFractional){
596      Bonmin::HeuristicDiveFractional* dive_fractional = new Bonmin::HeuristicDiveFractional(this);
597      HeuristicMethod h;
598      h.heuristic = dive_fractional;
599      h.id = "DiveFractional";
600      heuristics_.push_back(h);
601    }
602
603    Ipopt::Index doHeuristicDiveVectorLength = false;
604    options()->GetEnumValue("heuristic_dive_vectorLength",doHeuristicDiveVectorLength,prefix_.c_str());
605    if(doHeuristicDiveVectorLength){
606      Bonmin::HeuristicDiveVectorLength* dive_vectorLength = new Bonmin::HeuristicDiveVectorLength(this);
607      HeuristicMethod h;
608      h.heuristic = dive_vectorLength;
609      h.id = "DiveVectorLength";
610      heuristics_.push_back(h);
611    }
612
613    Ipopt::Index doHeuristicDiveMIPFractional = false;
614    if(!options()->GetEnumValue("heuristic_dive_MIP_fractional",doHeuristicDiveMIPFractional,prefix_.c_str())){
615      doHeuristicDiveMIPFractional = true;
616      std::string o_name = prefix_ + "heuristic_dive_MIP_fractional";
617      options_->SetStringValue(o_name.c_str(), "yes",true,true);
618    }
619    if(doHeuristicDiveMIPFractional){
620      Bonmin::HeuristicDiveMIPFractional* dive_MIP_fractional = new Bonmin::HeuristicDiveMIPFractional(this);
621      HeuristicMethod h;
622      h.heuristic = dive_MIP_fractional;
623      h.id = "DiveMIPFractional";
624      heuristics_.push_back(h);
625    }
626
627    Ipopt::Index doHeuristicDiveMIPVectorLength = false;
628    options()->GetEnumValue("heuristic_dive_MIP_vectorLength",doHeuristicDiveMIPVectorLength,prefix_.c_str());
629    if(doHeuristicDiveMIPVectorLength){
630      Bonmin::HeuristicDiveMIPVectorLength* dive_MIP_vectorLength = new Bonmin::HeuristicDiveMIPVectorLength(this);
631      HeuristicMethod h;
632      h.heuristic = dive_MIP_vectorLength;
633      h.id = "DiveMIPVectorLength";
634      heuristics_.push_back(h);
635    }
636    Ipopt::Index doHeuristicFPump = false;
637    if(!nonlinearSolver_->model()->hasGeneralInteger() && !options()->GetEnumValue("heuristic_feasibility_pump",doHeuristicFPump,prefix_.c_str())){
638      doHeuristicFPump = true;
639      std::string o_name = prefix_ + "heuristic_feasibility_pump";
640      options_->SetStringValue(o_name.c_str(), "yes",true,true);
641    }
642    if(doHeuristicFPump){
643      Bonmin::HeuristicFPump* feasibility_pump = new Bonmin::HeuristicFPump(this);
644      HeuristicMethod h;
645      h.heuristic = feasibility_pump;
646      h.id = "FPump";
647      heuristics_.push_back(h);
648    }
649
650    Ipopt::Index doFixAndSolve = false;
651    options()->GetEnumValue("fix_and_solve_heuristic",doFixAndSolve,prefix_.c_str());
652    if(doFixAndSolve){
653      Bonmin::FixAndSolveHeuristic* fix_and_solve = new Bonmin::FixAndSolveHeuristic(this);
654      HeuristicMethod h;
655      h.heuristic = fix_and_solve;
656      h.id = "Fix and Solve";
657      heuristics_.push_back(h);
658    }
659
660    Ipopt::Index doDummyPump = false;
661    options()->GetEnumValue("dummy_pump_heuristic",doDummyPump,prefix_.c_str());
662    if(doDummyPump){
663      Bonmin::DummyPump* fix_and_solve = new Bonmin::DummyPump(this);
664      HeuristicMethod h;
665      h.heuristic = fix_and_solve;
666      h.id = "Dummy pump";
667      heuristics_.push_back(h);
668    }
669
670    Ipopt::Index doHeuristicRINS = false;
671    options()->GetEnumValue("heuristic_RINS",doHeuristicRINS,prefix_.c_str());
672    if(doHeuristicRINS){
673      Bonmin::HeuristicRINS* rins = new Bonmin::HeuristicRINS(this);
674      HeuristicMethod h;
675      h.heuristic = rins;
676      h.id = "RINS";
677      heuristics_.push_back(h);
678    }
679
680    Ipopt::Index doHeuristicLocalBranching = false;
681    options()->GetEnumValue("heuristic_local_branching",doHeuristicLocalBranching,prefix_.c_str());
682    if(doHeuristicLocalBranching){
683      Bonmin::HeuristicLocalBranching* local_branching = new Bonmin::HeuristicLocalBranching(this);
684      HeuristicMethod h;
685      h.heuristic = local_branching;
686      h.id = "LocalBranching";
687      heuristics_.push_back(h);
688    }
689
690    Ipopt::Index doHeuristicPumpForMinlp = false;
691    options()->GetEnumValue("pump_for_minlp",doHeuristicPumpForMinlp,prefix_.c_str());
692    if(doHeuristicPumpForMinlp){
693      Bonmin::PumpForMinlp * pump = new Bonmin::PumpForMinlp(this);
694      HeuristicMethod h;
695      h.heuristic = pump;
696      h.id = "Pump for MINLP";
697      heuristics_.push_back(h);
698    }
699
700    Ipopt::Index doHeuristicMilpRounding = false;
701    options()->GetEnumValue("MILP_rounding_heuristic",doHeuristicMilpRounding,prefix_.c_str());
702    if(doHeuristicMilpRounding){
703      Bonmin::MilpRounding * round = new Bonmin::MilpRounding(this);
704      HeuristicMethod h;
705      h.heuristic = round;
706      h.id = "MILP Rounding";
707      heuristics_.push_back(h);
708    }
709  }
710
711  // Add Branching rules ///////////////////////////////////////////////////////
712
713  switch (varSelection) {
714
715  case OSI_STRONG: { // strong branching
716    CouenneChooseStrong * chooseVariable = new CouenneChooseStrong
717      (*this, couenneProb_, journalist ());
718    chooseVariable->setTrustStrongForSolution(false);
719    chooseVariable->setTrustStrongForBound(false);
720    chooseVariable->setOnlyPseudoWhenTrusted(true);
721    branchingMethod_ = chooseVariable;
722    break;
723  }
724
725  case OSI_SIMPLE: // default choice
726    branchingMethod_ = new CouenneChooseVariable
727      (continuousSolver_, couenneProb_, journalist ());
728    break;
729
730  default:
731    std::cerr << "Unknown variable_selection for Couenne\n" << std::endl;
732    throw;
733    break;
734  }
735
736  // Node comparison method ///////////////////////////////////////////////////////////////////////////
737
738  int ival;
739  if (!options_->GetEnumValue("node_comparison", ival, "bonmin.")) {
740    // change default for Couenne
741    nodeComparisonMethod_ = bestBound;
742  }
743  else {
744    nodeComparisonMethod_ = NodeComparison(ival);
745  }
746
747  if (intParam_[NumCutPasses] < 2)
748    intParam_[NumCutPasses] = 2;
749
750  // Tell Cbc not to check again if a solution returned from
751  // heuristic is indeed feasible
752  intParam_ [BabSetupBase::SpecialOption] = 16 | 4;
753
754  // Add PSD cut handler ///////////////////////////////////////////////////////
755
756  options () -> GetIntegerValue ("sdp_cuts", freq, "couenne.");
757
758  if (freq != 0) {
759
760    CouenneSdpCuts * couenneSDP = 
761      new CouenneSdpCuts (couenneProb_,
762                          journalist (),
763                          options    ());
764    CuttingMethod cg;
765    cg.frequency = freq;
766    cg.cgl = couenneSDP;
767    cg.id = "Couenne SDP cuts";
768    cutGenerators (). push_back (cg);
769  }
770
771  // Add disjunctive cuts ///////////////////////////////////////////////////////
772
773  options () -> GetIntegerValue ("minlp_disj_cuts", freq, "couenne.");
774
775  if (freq != 0) {
776
777    CouenneDisjCuts * couenneDisj = 
778      new CouenneDisjCuts (ci, this, 
779                           couenneCg, 
780                           branchingMethod_, 
781                           varSelection == OSI_STRONG, // if true, use strong branching candidates
782                           journalist (),
783                           options ());
784
785    CuttingMethod cg;
786    cg.frequency = freq;
787    cg.cgl = couenneDisj;
788    cg.id = "Couenne disjunctive cuts";
789    cutGenerators (). push_back(cg);
790  }
791
792  // Add cross-aux redundant cuts ///////////////////////////////////////////////////////
793
794  options () -> GetIntegerValue ("crossconv_cuts", freq, "couenne.");
795
796  if (freq != 0) {
797
798    CouenneCrossConv * couenneCross = 
799      new CouenneCrossConv (couenneProb,
800                            journalist (),
801                            options ());
802
803    CuttingMethod cg;
804    cg.frequency = freq;
805    cg.cgl = couenneCross;
806    cg.id = "Couenne cross-aux cuts";
807    cutGenerators (). push_back(cg);
808  }
809
810  return retval;
811}
812 
813void CouenneSetup::registerOptions ()
814{registerAllOptions (roptions ());}
815
816
817void CouenneSetup::registerAllOptions (Ipopt::SmartPtr <Bonmin::RegisteredOptions> roptions) {
818
819  roptions -> SetRegisteringCategory ("Couenne options", Bonmin::RegisteredOptions::CouenneCategory);
820
821  BabSetupBase        ::registerAllOptions (roptions);
822  Bonmin::BonCbcFullNodeInfo  ::registerOptions (roptions);
823
824  /// Heuristics
825  Bonmin::LocalSolverBasedHeuristic    ::registerOptions (roptions);
826  Bonmin::FixAndSolveHeuristic         ::registerOptions (roptions);
827  Bonmin::DummyPump                    ::registerOptions (roptions);
828  Bonmin::MilpRounding                 ::registerOptions (roptions);
829  Bonmin::PumpForMinlp                 ::registerOptions (roptions);
830  Bonmin::HeuristicRINS                ::registerOptions (roptions);
831  Bonmin::HeuristicLocalBranching      ::registerOptions (roptions);
832  Bonmin::HeuristicFPump               ::registerOptions (roptions);
833  Bonmin::HeuristicDiveFractional      ::registerOptions (roptions);
834  Bonmin::HeuristicDiveVectorLength    ::registerOptions (roptions);
835  Bonmin::HeuristicDiveMIPFractional   ::registerOptions (roptions);
836  Bonmin::HeuristicDiveMIPVectorLength ::registerOptions (roptions); 
837
838  roptions -> AddStringOption3 ("milp_solver",
839                                "Choose the subsolver to solve MILP sub-problems in OA decompositions.",
840                                "Cbc_D",
841                                "Cbc_D","Coin Branch and Cut with its default",
842                                "Cbc_Par", "Coin Branch and Cut with passed parameters",
843                                "Cplex","Cplex",
844                                " To use Cplex, a valid license is required and you should have compiled OsiCpx in COIN-OR  (see Osi documentation).");
845
846  roptions -> setOptionExtraInfo ("milp_solver",64);
847
848  roptions -> AddStringOption2 ("milp_strategy",
849                                "Choose a strategy for MILPs.",
850                                "find_good_sol",
851                                "find_good_sol","Stop sub milps when a solution improving the incumbent is found",
852                                "solve_to_optimality", "Solve MILPs to optimality",
853                                "");
854
855  roptions -> AddStringOption6 ("algorithm",
856                                "Choice of the algorithm.",
857                                "B-BB",
858                                "B-BB","simple branch-and-bound algorithm,",
859                                "B-OA","OA Decomposition algorithm,",
860                                "B-QG","Quesada and Grossmann branch-and-cut algorithm,",
861                                "B-Hyb","hybrid outer approximation based branch-and-cut,",
862                                "B-Ecp","ecp cuts based branch-and-cut a la FilMINT.",
863                                "B-iFP","Iterated Feasibility Pump for MINLP.",
864                                "This will preset some of the options of bonmin depending on the algorithm choice."
865                                );
866
867  CouenneProblem          ::registerOptions (roptions);
868  CouenneCutGenerator     ::registerOptions (roptions);
869  CouenneChooseStrong     ::registerOptions (roptions);
870  CouenneChooseVariable   ::registerOptions (roptions);
871  CouenneFixPoint         ::registerOptions (roptions);
872  CouenneDisjCuts         ::registerOptions (roptions);
873  CouenneCrossConv        ::registerOptions (roptions);
874  CouenneSdpCuts          ::registerOptions (roptions);
875  CouenneTwoImplied       ::registerOptions (roptions);
876  NlpSolveHeuristic       ::registerOptions (roptions);
877  CouenneFeasPump         ::registerOptions (roptions);
878  CouenneIterativeRounding::registerOptions (roptions);
879
880  /// TODO: move later!
881  roptions -> AddStringOption2
882    ("local_branching_heuristic",
883     "Apply local branching heuristic",
884     "no",
885     "no","",
886     "yes","",
887     "A local-branching heuristic based is used to find feasible solutions.");
888
889
890  roptions -> AddNumberOption  ("couenne_check",
891                                "known value of a global optimum (for debug purposes only)",
892                                COIN_DBL_MAX,
893                                "Default value is +infinity.");
894
895  roptions -> AddStringOption2 ("display_stats",
896                                "display statistics at the end of the run",
897                                "no",
898                                "yes", "",
899                                "no", "");
900
901  roptions -> AddStringOption2 ("test_mode",
902                                "set to true if this is Couenne unit test",
903                                "no",
904                                "yes", "",
905                                "no", "");
906
907  roptions -> AddStringOption5 ("lp_solver",
908                                "Linear Programming solver for the linearization",
909                                "clp",
910                                "clp",    "Use the COIN-OR Open Source solver CLP",
911                                "cplex",  "Use the commercial solver Cplex (license is needed)",
912                                "gurobi", "Use the commercial solver Gurobi (license is needed)",
913                                "soplex", "Use the freely available Soplex",
914                               "xpress-mp", "Use the commercial solver Xpress MP (license is needed)"
915                                );
916
917#define addLevOption(optname,comment) roptions -> AddBoundedIntegerOption (optname, comment, -2, J_LAST_LEVEL-1, J_NONE, "")
918
919  addLevOption ("output_level",                "Output level");
920  addLevOption ("branching_print_level",       "Output level for braching code in Couenne");
921  addLevOption ("boundtightening_print_level", "Output level for bound tightening code in Couenne");
922  addLevOption ("convexifying_print_level",    "Output level for convexifying code in Couenne");
923  addLevOption ("problem_print_level",         "Output level for problem manipulation code in Couenne");
924  addLevOption ("nlpheur_print_level",         "Output level for NLP heuristic in Couenne");
925  addLevOption ("disjcuts_print_level",        "Output level for disjunctive cuts in Couenne");
926  addLevOption ("reformulate_print_level",     "Output level for reformulating problems in Couenne");
927
928  roptions -> AddNumberOption
929    ("feas_tolerance",
930     "Tolerance for constraints/auxiliary variables",
931     feas_tolerance_default,
932     "Default value is 1e-5.");
933
934  roptions -> AddStringOption2
935    ("feasibility_bt",
936     "Feasibility-based (cheap) bound tightening (FBBT)",
937     "yes",
938     "no","",
939     "yes","",
940     "A pre-processing technique to reduce the bounding box, before the generation of linearization cuts. "
941     "This is a quick and effective way to reduce the solution set, and it is highly recommended to keep it active."
942    );
943
944  // copied from BonminSetup::registerMilpCutGenerators(), in
945  // BonBonminSetup.cpp
946
947  struct cutOption_ {
948
949    const char *cgname;
950    int         defaultFreq;
951
952  } cutOption [] = {
953    {(const char *) "Gomory_cuts",             0},
954    {(const char *) "probing_cuts",            0},
955    {(const char *) "cover_cuts",              0},
956    {(const char *) "mir_cuts",                0},
957    {(const char *) "2mir_cuts",               0},
958    {(const char *) "flow_covers_cuts",        0},
959    {(const char *) "lift_and_project_cuts",   0},
960    {(const char *) "reduce_split_cuts",       0},
961    {(const char *) "clique_cuts",             0},
962    {NULL, 0}};
963
964  for (int i=0; cutOption [i].cgname; i++) {
965
966    char descr [150];
967
968    sprintf (descr, "Frequency k (in terms of nodes) for generating %s cuts in branch-and-cut.",
969             cutOption [i].cgname);
970
971    roptions -> AddLowerBoundedIntegerOption
972      (cutOption [i].cgname,
973       descr,
974       -100, cutOption [i].defaultFreq,
975       "If k > 0, cuts are generated every k nodes, "
976       "if -99 < k < 0 cuts are generated every -k nodes but "
977       "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
978       "if k=-99 generate cuts only at the root node, if k=0 or 100 do not generate cuts.");
979
980    roptions->setOptionExtraInfo (cutOption [i].cgname, 5);
981  }
982}
983
984
985
986/** Add milp cut generators according to options.*/
987void CouenneSetup::addMilpCutGenerators () {
988
989  enum extraInfo_ {CUTINFO_NONE, CUTINFO_MIG, CUTINFO_PROBING, CUTINFO_CLIQUE};
990
991  // extra data structure to avoid repeated code below
992
993  struct cutInfo {
994
995    const char      *optname;
996    CglCutGenerator *cglptr;
997    const char      *cglId;
998    enum extraInfo_  extraInfo;
999
1000  } cutList [] = {
1001    {(const char*)"Gomory_cuts",new CglGomory,      (const char*)"Mixed Integer Gomory",CUTINFO_MIG},
1002    {(const char*)"probing_cuts",new CglProbing,        (const char*) "Probing", CUTINFO_PROBING},
1003    {(const char*)"mir_cuts",new CglMixedIntegerRounding2, (const char*) "Mixed Integer Rounding", 
1004     CUTINFO_NONE},
1005    {(const char*)"2mir_cuts",    new CglTwomir,         (const char*) "2-MIR",    CUTINFO_NONE},
1006    {(const char*)"cover_cuts",   new CglKnapsackCover,  (const char*) "Cover",    CUTINFO_NONE},
1007    {(const char*)"clique_cuts",  new CglClique,         (const char*) "Clique",   CUTINFO_CLIQUE},
1008    {(const char*)"lift_and_project_cuts",new CglLandP,(const char*)"Lift and Project",CUTINFO_NONE},
1009    {(const char*)"reduce_split_cuts",new CglRedSplit,(const char*) "Reduce and Split",CUTINFO_NONE},
1010    {(const char*)"flow_covers_cuts",new CglFlowCover,(const char*) "Flow cover cuts", CUTINFO_NONE},
1011    {NULL, NULL, NULL, CUTINFO_NONE}};
1012
1013  int freq;
1014
1015  for (int i=0; cutList [i]. optname; i++) {
1016
1017    options_ -> GetIntegerValue (std::string (cutList [i]. optname), freq, "couenne.");
1018
1019    if (!freq) {
1020      delete cutList [i].cglptr;
1021      continue;
1022    }
1023
1024    CuttingMethod cg;
1025    cg.frequency = freq;
1026    cg.cgl       = cutList [i].cglptr;
1027    cg.id        = std::string (cutList [i]. cglId);
1028    cutGenerators_.push_back (cg);
1029
1030    // options for particular cases
1031    switch (cutList [i].extraInfo) {
1032
1033    case CUTINFO_MIG: {
1034      CglGomory *gc = dynamic_cast <CglGomory *> (cutList [i].cglptr);
1035
1036      if (!gc) break;
1037
1038      gc -> setLimitAtRoot(512);
1039      gc -> setLimit(50);
1040    }
1041      break;
1042
1043    case CUTINFO_PROBING: {
1044      CglProbing *pc = dynamic_cast <CglProbing *> (cutList [i].cglptr);
1045
1046      if (!pc) break;
1047
1048      pc->setUsingObjective(1);
1049      pc->setMaxPass(3);
1050      pc->setMaxPassRoot(3);
1051      // Number of unsatisfied variables to look at
1052      pc->setMaxProbe(10);
1053      pc->setMaxProbeRoot(50);
1054      // How far to follow the consequences
1055      pc->setMaxLook(10);
1056      pc->setMaxLookRoot(50);
1057      pc->setMaxLookRoot(10);
1058      // Only look at rows with fewer than this number of elements
1059      pc->setMaxElements(200);
1060      pc->setRowCuts(3);
1061    }
1062      break;
1063
1064    case CUTINFO_CLIQUE: {
1065      CglClique *clique = dynamic_cast <CglClique *> (cutList [i].cglptr);
1066
1067      if (!clique) break;
1068
1069      clique -> setStarCliqueReport(false);
1070      clique -> setRowCliqueReport(false);
1071      clique -> setMinViolation(0.1);
1072    }
1073      break;
1074
1075      //case CUTINFO_NONE:
1076    default:
1077      break;
1078    }
1079  }
1080
1081  double givenAllowFGap2 = 0.0;
1082  options_->GetNumericValue(std::string("allowable_fraction_gap"), 
1083                            givenAllowFGap2, "bonmin.");
1084  double upval = 1e50;
1085
1086#ifdef FM_UP_BND
1087  printf("CutOff value:\n");
1088  scanf("%lf", &upval);
1089#else /* not FM_UP_BND */
1090  options_->GetNumericValue(std::string("art_cutoff"), upval, "bonmin.");
1091#endif /* FM_UP_BND */
1092
1093  if(upval < 1e50) {
1094    double newCO = (1-givenAllowFGap2) * upval;
1095    couenneProb_->setCutOff(newCO);
1096    printf("CutOff set to %f\n", newCO);
1097
1098#ifdef FM_TRACE_OPTSOL
1099    if(couenneProb_->getRecordBestSol()->getHasSol()) {
1100      if(newCO < couenneProb_->getRecordBestSol()->getVal()) {
1101        couenneProb_->getRecordBestSol()->setVal(newCO);
1102      }
1103    }
1104#endif
1105  }
1106}
Note: See TracBrowser for help on using the repository browser.