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

Last change on this file since 593 was 593, checked in by fmargot, 9 years ago

Make sure artificial cutoff from option file works; fix small bug in CouenneChooseStrong?.cpp; Add ifdef FM_ALWAYS_SORT

  • Property svn:keywords set to Author Date Id Revision
File size: 28.3 KB
Line 
1// $Id: BonCouenneSetup.cpp 593 2011-06-01 12:16:35Z fmargot $
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//
10// Date : 04/18/2007
11
12// Ampl includes
13
14#include "CouenneConfig.h"
15
16#include "OsiClpSolverInterface.hpp"
17#ifdef COIN_HAS_CPX
18#include "OsiCpxSolverInterface.hpp"
19#endif
20#ifdef COIN_HAS_GRB
21#include "OsiGrbSolverInterface.hpp"
22#endif
23#ifdef COIN_HAS_SPX
24#include "OsiSpxSolverInterface.hpp"
25#endif
26#ifdef COIN_HAS_XPR
27#include "OsiXprSolverInterface.hpp"
28#endif
29
30// MILP cuts
31#include "CglGomory.hpp"
32#include "CglProbing.hpp"
33#include "CglKnapsackCover.hpp"
34#include "CglOddHole.hpp"
35#include "CglClique.hpp"
36#include "CglFlowCover.hpp"
37#include "CglMixedIntegerRounding2.hpp"
38#include "CglTwomir.hpp"
39#include "CglPreProcess.hpp"
40#include "CglLandP.hpp"
41#include "CglRedSplit.hpp"
42
43#include "BonCouenneSetup.hpp"
44#include "CouenneFeasPump.hpp"
45#include "CouenneIterativeRounding.hpp"
46#include "BonCouenneInterface.hpp"
47#include "BonInitHeuristic.hpp"
48#include "BonNlpHeuristic.hpp"
49
50#include "BonGuessHeuristic.hpp"
51#include "CbcCompareActual.hpp"
52
53#include "CouenneObject.hpp"
54#include "CouenneVarObject.hpp"
55#include "CouenneVTObject.hpp"
56#include "CouenneOrbitObj.hpp"
57#include "CouenneChooseVariable.hpp"
58#include "CouenneChooseStrong.hpp"
59#include "CouenneSolverInterface.hpp"
60#include "CouenneFixPoint.hpp"
61#include "CouenneCutGenerator.hpp"
62#include "CouenneDisjCuts.hpp"
63#include "CouenneCrossConv.hpp"
64#include "CouenneTwoImplied.hpp"
65
66#include "BonCouenneInfo.hpp"
67#include "BonCbcNode.hpp"
68#include "BonCbc.hpp"
69
70// ASL includes need to come behind OsiClp and Bonmin, because it defines "filename",
71// which is used as variablename in Clp
72// (similar bad as windows.h, which defines "small")
73#ifdef COIN_HAS_ASL
74#include "asl.h"
75#include "getstub.h"
76#endif
77
78using namespace Couenne;
79 
80CouenneSetup::~CouenneSetup(){
81  if (couenneProb_ && couenneProb_is_own_)
82    delete couenneProb_;
83}
84
85bool CouenneSetup::InitializeCouenne (char ** argv,
86                                      CouenneProblem *couenneProb,
87                                      Ipopt::SmartPtr<Bonmin::TMINLP> tminlp,
88                                      CouenneInterface *ci,
89                                      Bonmin::Bab *bb) {
90
91  std::string s;
92
93  if (couenneProb) {
94    //TODO create a copy of user problem, since we modify it?
95    couenneProb_ = couenneProb;
96    couenneProb_is_own_ = false;
97  }
98
99  /* Get the basic options. */
100  readOptionsFile();
101 
102  // in check mode, avoid pop-up error message (there are quite a few messages)
103  options_ -> GetStringValue ("test_mode", s, "couenne.");
104  if (s == "yes")
105    WindowsErrorPopupBlocker();
106
107  /** Change default value for failure behavior so that code doesn't crash
108      when Ipopt does not solve a sub-problem.*/
109
110  options_ -> SetStringValue ("nlp_failure_behavior", "fathom", "couenne.");
111
112  gatherParametersValues (options_);
113
114  if (!ci) {
115
116    ci = new CouenneInterface;
117
118    if (!couenneProb_ && argv) {
119#ifdef COIN_HAS_ASL
120      /* Read the model in various places. */
121      ci -> readAmplNlFile (argv, roptions (), options (), journalist ());
122      aslfg_ = new SmartAsl;
123      aslfg_ -> asl = readASLfg (argv);
124#else
125      std::cerr << 
126        "Couenne was compiled without AMPL Solver Library. Cannot initialize from AMPL NL File." 
127                << std::endl;
128      return false;
129#endif
130    } else {
131      assert (couenneProb_ != NULL);
132      assert (IsValid (tminlp)); //TODO would be great to setup own TMINLP based on CouenneProblem formulation
133      ci -> initialize (roptions_, options_, journalist_, tminlp);
134    }
135  }
136
137  nonlinearSolver_ = ci;
138
139  /** Set the output level for the journalist for all Couenne
140      categories.  We probably want to make that a bit more flexible
141      later. */
142
143  int i;
144
145  /// trying to avoid repetitions here...
146
147  // FIXME: doesn't work if suppress_all_output is true (gives
148  // segfault on options(), but checking options()!=NULL won't work as
149  // options() is a SmartPtr
150
151#define addJournalist(optname,jlevel) {                         \
152    options    () -> GetIntegerValue ((optname), i, "couenne."); \
153    journalist () -> GetJournal      ("console") -> SetPrintLevel ((jlevel), (EJournalLevel) i); \
154}
155
156  addJournalist ("output_level",                J_COUENNE);
157  addJournalist ("boundtightening_print_level", J_BOUNDTIGHTENING);
158  addJournalist ("branching_print_level",       J_BRANCHING);
159  addJournalist ("convexifying_print_level",    J_CONVEXIFYING);
160  addJournalist ("problem_print_level",         J_PROBLEM);
161  addJournalist ("nlpheur_print_level",         J_NLPHEURISTIC);
162  addJournalist ("disjcuts_print_level",        J_DISJCUTS);
163  addJournalist ("reformulate_print_level",     J_REFORMULATE);
164
165  /* Initialize Couenne cut generator.*/
166  //int ivalue, num_points;
167  //options()->GetEnumValue("convexification_type", ivalue,"couenne.");
168  //options()->GetIntegerValue("convexification_points",num_points,"couenne.");
169
170  if (!couenneProb_)
171    couenneProb_ = new CouenneProblem (aslfg_ -> asl, this, journalist ());
172
173  CouenneCutGenerator * couenneCg = 
174    new CouenneCutGenerator (ci, this, couenneProb_, NULL);
175
176  options_ -> GetStringValue ("lp_solver", s, "couenne.");
177
178  if (s == "clp") {
179
180    CouenneSolverInterface <OsiClpSolverInterface> *CSI = new CouenneSolverInterface <OsiClpSolverInterface>;
181    continuousSolver_ = CSI;
182    CSI -> setCutGenPtr (couenneCg);
183
184  } else if (s == "cplex") {
185
186#ifdef COIN_HAS_CPX
187    CouenneSolverInterface <OsiCpxSolverInterface> *CSI = new CouenneSolverInterface <OsiCpxSolverInterface>;
188    continuousSolver_ = CSI;
189    CSI -> setCutGenPtr (couenneCg);
190#else
191    journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without CPLEX interface. Please reconfigure, recompile, and try again.\n");
192    return false;
193#endif
194  } else if (s == "xpress-mp") {
195
196#ifdef COIN_HAS_XPR
197    CouenneSolverInterface <OsiXprSolverInterface> *CSI = new CouenneSolverInterface <OsiXprSolverInterface>;
198    continuousSolver_ = CSI;
199    CSI -> setCutGenPtr (couenneCg);
200#else
201    journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without Xpress-MP interface. Please reconfigure, recompile, and try again.\n");
202    return false;
203#endif
204  } else if (s == "gurobi") {
205
206#ifdef COIN_HAS_GRB
207    CouenneSolverInterface <OsiGrbSolverInterface> *CSI = new CouenneSolverInterface <OsiGrbSolverInterface>;
208    continuousSolver_ = CSI;
209    CSI -> setCutGenPtr (couenneCg);
210#else
211    journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without GUROBI interface. Please reconfigure, recompile, and try again.\n");
212    return false;
213#endif
214  } else if (s == "soplex") {
215
216#ifdef COIN_HAS_SPX
217    CouenneSolverInterface <OsiSpxSolverInterface> *CSI = new CouenneSolverInterface <OsiSpxSolverInterface>;
218    continuousSolver_ = CSI;
219    CSI -> setCutGenPtr (couenneCg);
220#else
221    journalist()->Printf(J_ERROR, J_INITIALIZATION, "Couenne was compiled without Soplex. Please reconfigure, recompile, and try again.\n");
222    return false;
223#endif
224  } else {
225    journalist ()-> Printf (J_ERROR, J_INITIALIZATION, "The LP solver you specified hasn't been added to Couenne yet.\n");
226    return false;
227  }
228
229  continuousSolver_ -> passInMessageHandler(ci -> messageHandler());
230
231  couenneProb_ -> setBase (this);
232
233  assert (couenneProb_);
234
235  couenneProb_ -> reformulate (couenneCg);
236
237  Bonmin::BabInfo * extraStuff = new CouenneInfo (0);
238
239  // as per instructions by John Forrest, to get changed bounds
240  extraStuff -> setExtraCharacteristics (extraStuff -> extraCharacteristics () | 2);
241
242  continuousSolver_ -> setAuxiliaryInfo (extraStuff);
243  delete extraStuff;
244   
245  extraStuff = dynamic_cast <Bonmin::BabInfo *> (continuousSolver_ -> getAuxiliaryInfo ());
246
247  // Setup log level of LP solver
248  int lpLogLevel;
249  options () -> GetIntegerValue ("lp_log_level", lpLogLevel, "couenne.");
250  continuousSolver_ -> messageHandler () -> setLogLevel (lpLogLevel);
251
252  //////////////////////////////////////////////////////////////
253
254  couenneCg -> Problem () -> setMaxCpuTime (getDoubleParameter (BabSetupBase::MaxTime));
255
256  ci -> extractLinearRelaxation (*continuousSolver_, *couenneCg);
257
258  // In case there are no discrete variables, we have already a
259  // heuristic solution for which create a initialization heuristic
260  if (!(extraStuff -> infeasibleNode ()) &&
261      ci -> isProvenOptimal () && 
262      ci -> haveNlpSolution ()) {
263
264    /// setup initial heuristic (in principle it should only run once...)
265    InitHeuristic* initHeuristic = new InitHeuristic
266      (ci -> getObjValue (), ci -> getColSolution (), *couenneProb_);
267    HeuristicMethod h;
268    h.id = "Couenne Rounding NLP"; // same name as the real rounding one
269    h.heuristic = initHeuristic;
270    heuristics_.push_back(h);
271  }
272
273  if (extraStuff -> infeasibleNode ()){
274    journalist() -> Printf(J_SUMMARY, J_PROBLEM, "Initial linear relaxation constructed by Couenne is infeasible, exiting...\n");
275    return false;
276  }
277
278  //continuousSolver_ -> findIntegersAndSOS (false);
279  //addSos (); // only adds embedded SOS objects
280
281  // Add Couenne SOS ///////////////////////////////////////////////////////////////
282
283  int 
284    nSOS  = 0,
285    nVars = couenneProb_ -> nVars ();
286
287  OsiObject ** objects = NULL;
288
289  options () -> GetStringValue ("enable_sos", s, "couenne.");
290
291  if (s == "yes") {
292
293    // allocate sufficient space for both nonlinear variables and SOS's
294    objects = new OsiObject* [couenneProb_ -> nCons () + nVars];
295
296    nSOS = couenneProb_ -> findSOS (&(bb -> model()), dynamic_cast <OsiSolverInterface *> (nonlinearSolver ()), objects);
297
298    nonlinearSolver () -> addObjects (nSOS, objects);
299
300    //printf ("==================== found %d SOS\n", nSOS);
301    //nonlinearSolver () -> addObjects (nSOS, objects);
302    //continuousSolver () -> addObjects (nSOS, objects);
303
304    //printf ("found %d SOS!\n", nSOS);
305
306    /*for (int i=0; i<nSOS; i++)
307      delete objects [i];
308      delete [] objects;*/
309
310    if (!nSOS) {
311      delete [] objects;
312      objects = NULL;
313    } 
314  }
315
316  //model -> assignSolver (continuousSolver_, true);
317  //continuousSolver_ = model -> solver();
318
319  // Add Couenne objects for branching /////////////////////////////////////////////
320
321  options () -> GetStringValue ("display_stats", s, "couenne.");
322  displayStats_ = (s == "yes");
323
324  options () -> GetStringValue ("branching_object", s, "couenne.");
325
326  enum CouenneObject::branch_obj objType;// = CouenneObject::VAR_OBJ;
327
328  if      (s ==   "vt_obj") objType = CouenneObject::VT_OBJ;
329  else if (s ==  "var_obj") objType = CouenneObject::VAR_OBJ;
330  else if (s == "expr_obj") objType = CouenneObject::EXPR_OBJ;
331  else {
332    printf ("CouenneSetup: Unknown branching object type\n");
333    exit (-1);
334  }
335
336  int 
337    nobj = nSOS; // if no SOS then objects is empty
338
339  if (!objects)
340    objects = new OsiObject* [nVars];
341
342  int 
343    contObjPriority, 
344    intObjPriority;
345
346  options () -> GetIntegerValue ("cont_var_priority", contObjPriority, "couenne.");
347  options () -> GetIntegerValue ( "int_var_priority",  intObjPriority, "couenne.");
348
349  int varSelection;
350  if (!options_ -> GetEnumValue ("variable_selection", varSelection, "couenne.")) {
351    // change the default for Couenne
352    varSelection = Bonmin::BabSetupBase::OSI_SIMPLE;
353  }
354
355  for (int i = 0; i < nVars; i++) { // for each variable
356
357    exprVar *var = couenneProb_ -> Var (i);
358
359    // we only want enabled variables
360    if (var -> Multiplicity () <= 0) 
361      continue;
362
363    switch (objType) {
364
365    case CouenneObject::EXPR_OBJ:
366
367      // if this variable is associated with a nonlinear function
368      if (var -> isInteger () || 
369          ((var -> Type  () == AUX) && 
370           (var -> Image () -> Linearity () > LINEAR))) {
371
372        /*if ((var -> Image () -> code () == COU_EXPRMUL) &&
373          (var -> Image () -> ArgList () [0] -> Index () >= 0) &&
374          (var -> Image () -> ArgList () [1] -> Index () >= 0) &&
375          (fabs (var -> lb ()) < COUENNE_EPS) &&
376          (fabs (var -> ub ()) < COUENNE_EPS))
377
378          // it's a complementarity constraint object!
379          objects    [nobj] = new CouenneComplObject (couenneProb_, var, this, journalist ());
380          else*/
381        objects [nobj] = new CouenneObject (couenneCg, couenneProb_, var, this, journalist ());
382
383        objects [nobj++] -> setPriority (var -> isInteger () ? intObjPriority : contObjPriority);
384        //objects [nobj++] -> setPriority (contObjPriority + var -> rank ());
385      }
386
387      break;
388
389    case CouenneObject::VAR_OBJ:
390
391      // branching objects on variables
392      if // comment three lines below for linear variables too
393        (var -> isInteger () || 
394         (couenneProb_ -> Dependence () [var -> Index ()] . size () > 0)) {  // has indep
395        //|| ((var -> Type () == AUX) &&                                  // or, aux
396        //    (var -> Image () -> Linearity () > LINEAR))) {              // of nonlinear
397
398        objects [nobj] = new CouenneVarObject (couenneCg, couenneProb_, var, this, journalist (), varSelection);
399        objects [nobj++] -> setPriority (var -> isInteger () ? intObjPriority : contObjPriority);
400        //objects [nobj++] -> setPriority (contObjPriority + var -> rank ());
401      }
402
403      break;
404
405    default:
406    case CouenneObject::VT_OBJ:
407
408      // branching objects on variables
409      if // comment three lines below for linear variables too
410        (var -> isInteger () || 
411         (couenneProb_ -> Dependence () [var -> Index ()] . size () > 0)) { // has indep
412        //|| ((var -> Type () == AUX) &&                      // or, aux
413        //(var -> Image () -> Linearity () > LINEAR))) { // of nonlinear
414
415        objects [nobj] = new CouenneVTObject (couenneCg, couenneProb_, var, this, journalist ());
416        objects [nobj++] -> setPriority (var -> isInteger () ? intObjPriority : contObjPriority);
417        //objects [nobj++] -> setPriority (contObjPriority + var -> rank ());
418      }
419
420      break;
421    }
422  }
423
424  // // Experimental: orbital branching //////////////////////////////////////////////
425
426  // options () -> GetStringValue ("orbital_branching", s, "couenne.");
427
428  // if (s == "yes") {
429
430  //   objects [nobj] = new CouenneOrbitObj (couenneCg, couenneProb_, NULL, this, journalist ());
431  //   objects [nobj++] -> setPriority (contObjPriority);
432  // }
433
434  // Add objects /////////////////////////////////
435
436  continuousSolver_ -> addObjects (nobj, objects);
437
438  for (int i = 0 ; i < nobj ; i++)
439    delete objects [i];
440
441  delete [] objects;
442
443  int freq;
444
445  // Setup Fix Point bound tightener /////////////////////////////////////////////
446
447  options () -> GetIntegerValue ("fixpoint_bt", freq, "couenne.");
448
449  if (freq != 0) {
450
451    CuttingMethod cg;
452    cg.frequency = freq;
453    cg.cgl = new CouenneFixPoint (couenneProb_, options ());
454    cg.id = "Couenne fixed point FBBT";
455    cutGenerators (). push_back (cg);
456  }
457
458  // Setup Convexifier generators ////////////////////////////////////////////////
459
460  options () -> GetIntegerValue ("convexification_cuts", freq, "couenne.");
461
462  if (freq != 0) {
463
464    CuttingMethod cg;
465    cg.frequency = freq;
466    cg.cgl = couenneCg;
467    cg.id = "Couenne convexifier cuts";
468    cutGenerators().push_back (cg);
469
470    // set cut gen pointer
471    //dynamic_cast <CouenneSolverInterface <OsiClpSolverInterface> *>
472    //(continuousSolver_)
473
474    // this is done on an explicitly declared CSI pointer, however
475    // CSI == continuousSolver_
476  }
477
478  // add other cut generators -- test for integer variables first
479  if (couenneCg -> Problem () -> nIntVars () > 0)
480    addMilpCutGenerators ();
481
482  CouennePtr_ = couenneCg;
483
484  // Add two-inequalities based bound tightening ///////////////////////////////////////////////////////
485
486  options () -> GetIntegerValue ("two_implied_bt", freq, "couenne.");
487
488  if (freq != 0) {
489
490    CouenneTwoImplied * couenne2I = 
491      new CouenneTwoImplied (couenneProb_,
492                             journalist (),
493                             options    ());
494    CuttingMethod cg;
495    cg.frequency = freq;
496    cg.cgl = couenne2I;
497    cg.id = "Couenne two-implied cuts";
498    cutGenerators (). push_back(cg);
499  }
500
501  // check branch variable selection for disjunctive cuts
502
503  // Setup heuristic to solve MINLP problems. /////////////////////////////////
504
505  // TODO: add Cbc heuristics
506
507  int doHeuristic = 0;
508
509  options () -> GetEnumValue ("local_optimization_heuristic", doHeuristic, "couenne.");
510
511  if (doHeuristic) {
512
513    int numSolve;
514    options()->GetIntegerValue("log_num_local_optimization_per_level",numSolve,"couenne.");
515    NlpSolveHeuristic * nlpHeuristic = new NlpSolveHeuristic;
516    nlpHeuristic->setNlp(*ci,false);
517    nlpHeuristic->setCouenneProblem(couenneProb_);
518    nlpHeuristic->setMaxNlpInf(maxNlpInf_0);
519    nlpHeuristic->setNumberSolvePerLevel(numSolve);
520    HeuristicMethod h;
521    h.id = "Couenne Rounding NLP";
522    h.heuristic = nlpHeuristic;
523    heuristics_.push_back(h);
524  }
525
526  options () -> GetEnumValue ("iterative_rounding_heuristic", doHeuristic, "couenne.");
527 
528  if (doHeuristic) {
529    CouenneIterativeRounding * nlpHeuristic = new CouenneIterativeRounding(nonlinearSolver_, ci, couenneProb_, options());
530    HeuristicMethod h;
531    h.id = "Couenne Iterative Rounding";
532    h.heuristic = nlpHeuristic;
533    heuristics_.push_back(h);
534  }
535
536  options () -> GetEnumValue ("feas_pump_heuristic", doHeuristic, "couenne.");
537
538  if (doHeuristic) {
539
540    int numSolve;
541    options () -> GetIntegerValue ("feas_pump_level", numSolve, "couenne.");
542
543    CouenneFeasPump *nlpHeuristic = new CouenneFeasPump (couenneProb_, couenneCg, options ());
544
545    nlpHeuristic -> setNumberSolvePerLevel (numSolve);
546
547    HeuristicMethod h;
548
549    h.id = "Couenne Feasibility Pump";
550    h.heuristic = nlpHeuristic;
551    heuristics_. push_back (h);
552  }
553
554  // Add Branching rules ///////////////////////////////////////////////////////
555
556  switch (varSelection) {
557
558  case OSI_STRONG: { // strong branching
559    CouenneChooseStrong * chooseVariable = new CouenneChooseStrong
560      (*this, couenneProb_, journalist ());
561    chooseVariable->setTrustStrongForSolution(false);
562    chooseVariable->setTrustStrongForBound(false);
563    chooseVariable->setOnlyPseudoWhenTrusted(true);
564    branchingMethod_ = chooseVariable;
565    break;
566  }
567
568  case OSI_SIMPLE: // default choice
569    branchingMethod_ = new CouenneChooseVariable
570      (continuousSolver_, couenneProb_, journalist ());
571    break;
572
573  default:
574    std::cerr << "Unknown variable_selection for Couenne\n" << std::endl;
575    throw;
576    break;
577  }
578
579  // Node comparison method ///////////////////////////////////////////////////////////////////////////
580
581  int ival;
582  if (!options_->GetEnumValue("node_comparison", ival, "bonmin.")) {
583    // change default for Couenne
584    nodeComparisonMethod_ = bestBound;
585  }
586  else {
587    nodeComparisonMethod_ = NodeComparison(ival);
588  }
589
590  if (intParam_[NumCutPasses] < 2)
591    intParam_[NumCutPasses] = 2;
592
593  // Tell Cbc not to check again if a solution returned from
594  // heuristic is indeed feasible
595  intParam_ [BabSetupBase::SpecialOption] = 16 | 4;
596
597  // Add disjunctive cuts ///////////////////////////////////////////////////////
598
599  options () -> GetIntegerValue ("minlp_disj_cuts", freq, "couenne.");
600
601  if (freq != 0) {
602
603    CouenneDisjCuts * couenneDisj = 
604      new CouenneDisjCuts (ci, this, 
605                           couenneCg, 
606                           branchingMethod_, 
607                           varSelection == OSI_STRONG, // if true, use strong branching candidates
608                           journalist (),
609                           options ());
610
611    CuttingMethod cg;
612    cg.frequency = freq;
613    cg.cgl = couenneDisj;
614    cg.id = "Couenne disjunctive cuts";
615    cutGenerators (). push_back(cg);
616  }
617
618  // Add cross-aux redundant cuts ///////////////////////////////////////////////////////
619
620  options () -> GetIntegerValue ("crossconv_cuts", freq, "couenne.");
621
622  if (freq != 0) {
623
624    CouenneCrossConv * couenneCross = 
625      new CouenneCrossConv (couenneProb,
626                            journalist (),
627                            options ());
628
629    CuttingMethod cg;
630    cg.frequency = freq;
631    cg.cgl = couenneCross;
632    cg.id = "Couenne cross-aux cuts";
633    cutGenerators (). push_back(cg);
634  }
635
636  // Add sdp cuts ///////////////////////////////////////////////////////
637
638  // options () -> GetIntegerValue ("sdp_cuts", freq, "couenne.");
639
640  // if (freq != 0) {
641
642  //   CouenneDisjCuts * couenneDisj =
643  //     new CouenneDisjCuts (ci, this,
644  //                       couenneCg,
645  //                       branchingMethod_,
646  //                       varSelection == OSI_STRONG, // if true, use strong branching candidates
647  //                       journalist (),
648  //                       options ());
649
650  //   CuttingMethod cg;
651  //   cg.frequency = freq;
652  //   cg.cgl = couenneDisj;
653  //   cg.id = "Couenne disjunctive cuts";
654  //   cutGenerators (). push_back(cg);
655  // }
656
657  return true;
658}
659 
660void CouenneSetup::registerOptions ()
661{registerAllOptions (roptions ());}
662
663
664void CouenneSetup::registerAllOptions (Ipopt::SmartPtr <Bonmin::RegisteredOptions> roptions) {
665
666  roptions -> SetRegisteringCategory ("Couenne options", Bonmin::RegisteredOptions::CouenneCategory);
667
668  BabSetupBase        ::registerAllOptions (roptions);
669  Bonmin::BonCbcFullNodeInfo  ::registerOptions (roptions);
670
671  CouenneProblem          ::registerOptions (roptions);
672  CouenneCutGenerator     ::registerOptions (roptions);
673  CouenneChooseStrong     ::registerOptions (roptions);
674  CouenneChooseVariable   ::registerOptions (roptions);
675  CouenneFixPoint         ::registerOptions (roptions);
676  CouenneDisjCuts         ::registerOptions (roptions);
677  CouenneCrossConv        ::registerOptions (roptions);
678  CouenneTwoImplied       ::registerOptions (roptions);
679  NlpSolveHeuristic       ::registerOptions (roptions);
680  CouenneFeasPump         ::registerOptions (roptions);
681  CouenneIterativeRounding::registerOptions (roptions);
682
683  /// TODO: move later!
684  roptions -> AddStringOption2
685    ("local_branching_heuristic",
686     "Apply local branching heuristic",
687     "no",
688     "no","",
689     "yes","",
690     "A local-branching heuristic based is used to find feasible solutions.");
691
692
693  roptions -> AddNumberOption  ("couenne_check",
694                                "known value of a global optimum (for debug purposes only)",
695                                COIN_DBL_MAX,
696                                "Default value is +infinity.");
697
698  roptions -> AddStringOption2 ("display_stats",
699                                "display statistics at the end of the run",
700                                "no",
701                                "yes", "",
702                                "no", "");
703
704  roptions -> AddStringOption2 ("test_mode",
705                                "set to true if this is Couenne unit test",
706                                "no",
707                                "yes", "",
708                                "no", "");
709
710  roptions -> AddStringOption4 ("lp_solver",
711                                "Linear Programming solver for the linearization",
712                                "clp",
713                                "clp",    "Use the Coin-OR Open Source solver CLP",
714                                "cplex",  "Use the commercial solver Cplex (license is needed)",
715                                "gurobi", "Use the commercial solver Gurobi (license is needed)",
716                                "soplex", "Use the freely available Soplex");
717
718#define addLevOption(optname,comment) roptions -> AddBoundedIntegerOption (optname, comment, -2, J_LAST_LEVEL-1, J_NONE, "")
719
720  addLevOption ("output_level",                "Output level");
721  addLevOption ("branching_print_level",       "Output level for braching code in Couenne");
722  addLevOption ("boundtightening_print_level", "Output level for bound tightening code in Couenne");
723  addLevOption ("convexifying_print_level",    "Output level for convexifying code in Couenne");
724  addLevOption ("problem_print_level",         "Output level for problem manipulation code in Couenne");
725  addLevOption ("nlpheur_print_level",         "Output level for NLP heuristic in Couenne");
726  addLevOption ("disjcuts_print_level",        "Output level for disjunctive cuts in Couenne");
727  addLevOption ("reformulate_print_level",     "Output level for reformulating problems in Couenne");
728
729  roptions -> AddNumberOption
730    ("feas_tolerance",
731     "Tolerance for constraints/auxiliary variables",
732     feas_tolerance_default,
733     "Default value is 1e-5.");
734
735  roptions -> AddStringOption2
736    ("feasibility_bt",
737     "Feasibility-based (cheap) bound tightening (FBBT)",
738     "yes",
739     "no","",
740     "yes","",
741     "A pre-processing technique to reduce the bounding box, before the generation of linearization cuts. "
742     "This is a quick and effective way to reduce the solution set, and it is highly recommended to keep it active."
743    );
744
745  // copied from BonminSetup::registerMilpCutGenerators(), in
746  // BonBonminSetup.cpp
747
748  struct cutOption_ {
749
750    const char *cgname;
751    int         defaultFreq;
752
753  } cutOption [] = {
754    {(const char *) "Gomory_cuts",             0},
755    {(const char *) "probing_cuts",            0},
756    {(const char *) "cover_cuts",              0},
757    {(const char *) "mir_cuts",                0},
758    {(const char *) "2mir_cuts",               0},
759    {(const char *) "flow_covers_cuts",        0},
760    {(const char *) "lift_and_project_cuts",   0},
761    {(const char *) "reduce_split_cuts",       0},
762    {(const char *) "clique_cuts",             0},
763    {NULL, 0}};
764
765  for (int i=0; cutOption [i].cgname; i++) {
766
767    char descr [150];
768
769    sprintf (descr, "Frequency k (in terms of nodes) for generating %s cuts in branch-and-cut.",
770             cutOption [i].cgname);
771
772    roptions -> AddLowerBoundedIntegerOption
773      (cutOption [i].cgname,
774       descr,
775       -100, cutOption [i].defaultFreq,
776       "If k > 0, cuts are generated every k nodes, "
777       "if -99 < k < 0 cuts are generated every -k nodes but "
778       "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
779       "if k=-99 generate cuts only at the root node, if k=0 or 100 do not generate cuts.");
780
781    roptions->setOptionExtraInfo (cutOption [i].cgname, 5);
782  }
783}
784
785
786
787/** Add milp cut generators according to options.*/
788void CouenneSetup::addMilpCutGenerators () {
789
790  enum extraInfo_ {CUTINFO_NONE, CUTINFO_MIG, CUTINFO_PROBING, CUTINFO_CLIQUE};
791
792  // extra data structure to avoid repeated code below
793
794  struct cutInfo {
795
796    const char      *optname;
797    CglCutGenerator *cglptr;
798    const char      *cglId;
799    enum extraInfo_  extraInfo;
800
801  } cutList [] = {
802    {(const char*)"Gomory_cuts",new CglGomory,      (const char*)"Mixed Integer Gomory",CUTINFO_MIG},
803    {(const char*)"probing_cuts",new CglProbing,        (const char*) "Probing", CUTINFO_PROBING},
804    {(const char*)"mir_cuts",new CglMixedIntegerRounding2, (const char*) "Mixed Integer Rounding", 
805     CUTINFO_NONE},
806    {(const char*)"2mir_cuts",    new CglTwomir,         (const char*) "2-MIR",    CUTINFO_NONE},
807    {(const char*)"cover_cuts",   new CglKnapsackCover,  (const char*) "Cover",    CUTINFO_NONE},
808    {(const char*)"clique_cuts",  new CglClique,         (const char*) "Clique",   CUTINFO_CLIQUE},
809    {(const char*)"lift_and_project_cuts",new CglLandP,(const char*)"Lift and Project",CUTINFO_NONE},
810    {(const char*)"reduce_split_cuts",new CglRedSplit,(const char*) "Reduce and Split",CUTINFO_NONE},
811    {(const char*)"flow_covers_cuts",new CglFlowCover,(const char*) "Flow cover cuts", CUTINFO_NONE},
812    {NULL, NULL, NULL, CUTINFO_NONE}};
813
814  int freq;
815
816  for (int i=0; cutList [i]. optname; i++) {
817
818    options_ -> GetIntegerValue (std::string (cutList [i]. optname), freq, "couenne.");
819
820    if (!freq) {
821      delete cutList [i].cglptr;
822      continue;
823    }
824
825    CuttingMethod cg;
826    cg.frequency = freq;
827    cg.cgl       = cutList [i].cglptr;
828    cg.id        = std::string (cutList [i]. cglId);
829    cutGenerators_.push_back (cg);
830
831    // options for particular cases
832    switch (cutList [i].extraInfo) {
833
834    case CUTINFO_MIG: {
835      CglGomory *gc = dynamic_cast <CglGomory *> (cutList [i].cglptr);
836
837      if (!gc) break;
838
839      gc -> setLimitAtRoot(512);
840      gc -> setLimit(50);
841    }
842      break;
843
844    case CUTINFO_PROBING: {
845      CglProbing *pc = dynamic_cast <CglProbing *> (cutList [i].cglptr);
846
847      if (!pc) break;
848
849      pc->setUsingObjective(1);
850      pc->setMaxPass(3);
851      pc->setMaxPassRoot(3);
852      // Number of unsatisfied variables to look at
853      pc->setMaxProbe(10);
854      pc->setMaxProbeRoot(50);
855      // How far to follow the consequences
856      pc->setMaxLook(10);
857      pc->setMaxLookRoot(50);
858      pc->setMaxLookRoot(10);
859      // Only look at rows with fewer than this number of elements
860      pc->setMaxElements(200);
861      pc->setRowCuts(3);
862    }
863      break;
864
865    case CUTINFO_CLIQUE: {
866      CglClique *clique = dynamic_cast <CglClique *> (cutList [i].cglptr);
867
868      if (!clique) break;
869
870      clique -> setStarCliqueReport(false);
871      clique -> setRowCliqueReport(false);
872      clique -> setMinViolation(0.1);
873    }
874      break;
875
876      //case CUTINFO_NONE:
877    default:
878      break;
879    }
880  }
881
882  double givenAllowFGap2 = 0.0;
883  options_->GetNumericValue(std::string("allowable_fraction_gap"), 
884                            givenAllowFGap2, "bonmin.");
885  double upval = 1e50;
886
887#ifdef FM_UP_BND
888  printf("CutOff value:\n");
889  scanf("%lf", &upval);
890#else /* not FM_UP_BND */
891  options_->GetNumericValue(std::string("art_cutoff"), upval, "bonmin.");
892#endif /* FM_UP_BND */
893
894  if(upval < 1e50) {
895    double newCO = (1-givenAllowFGap2) * upval;
896    couenneProb_->setCutOff(newCO);
897    printf("CutOff set to %f\n", newCO);
898
899#ifdef FM_TRACE_OPTSOL
900    if(couenneProb_->getRecordBestSol()->getHasSol()) {
901      if(newCO < couenneProb_->getRecordBestSol()->getVal()) {
902        couenneProb_->getRecordBestSol()->setVal(newCO);
903      }
904    }
905#endif
906  }
907}
Note: See TracBrowser for help on using the repository browser.