1 // (C) Copyright International Business Machines Corporation 2007
2 // All Rights Reserved.
3 // This code is published under the Eclipse Public License.
4 //
5 // Authors :
6 // Pierre Bonami, International Business Machines Corporation
7 //
8 // Date : 04/13/2007
9 
10 #include "BonminConfig.h"
11 #include "OsiClpSolverInterface.hpp"
12 
13 #include "BonBonminSetup.hpp"
14 #ifdef BONMIN_CURVATURE_BRANCHING
15 #include "BonCurvBranchingSolver.hpp"
16 #endif
17 #include "BonChooseVariable.hpp"
18 #include "BonRandomChoice.hpp"
19 #include "BonDiver.hpp"
20 #include "BonQpBranchingSolver.hpp"
21 #include "BonLpBranchingSolver.hpp"
22 
23 //OA machinery
24 #include "BonDummyHeuristic.hpp"
25 #include "BonOACutGenerator2.hpp"
26 #include "BonFpForMinlp.hpp"
27 #include "BonOaFeasChecker.hpp"
28 #include "BonOaNlpOptim.hpp"
29 #include "BonEcpCuts.hpp"
30 
31 #include "BonCbcNode.hpp"
32 #ifdef COIN_HAS_FILTERSQP
33 # include "BonFilterSolver.hpp"
34 #endif
35 
36 //MILP cuts
37 #include "CglGomory.hpp"
38 #include "CglProbing.hpp"
39 #include "CglKnapsackCover.hpp"
40 #include "CglOddHole.hpp"
41 #include "CglClique.hpp"
42 #include "CglFlowCover.hpp"
43 #include "CglMixedIntegerRounding2.hpp"
44 #include "CglTwomir.hpp"
45 #include "CglPreProcess.hpp"
46 #include "CglLandP.hpp"
47 #include "CglRedSplit.hpp"
48 #include "BonLinearCutsGenerator.hpp"
49 
50 #include "BonFixAndSolveHeuristic.hpp"
51 #include "BonDummyPump.hpp"
52 #include "BonPumpForMinlp.hpp"
53 #include "BonHeuristicRINS.hpp"
54 #include "BonHeuristicLocalBranching.hpp"
55 #include "BonHeuristicFPump.hpp"
56 #include "BonHeuristicDiveFractional.hpp"
57 #include "BonHeuristicDiveVectorLength.hpp"
58 #include "BonHeuristicDiveMIPFractional.hpp"
59 #include "BonHeuristicDiveMIPVectorLength.hpp"
60 #include "BonMilpRounding.hpp"
61 //#include "BonInnerApproximation.hpp"
62 namespace Bonmin
63 {
BonminSetup(const CoinMessageHandler * handler)64   BonminSetup::BonminSetup(const CoinMessageHandler * handler):BabSetupBase(handler),algo_(Dummy)
65   {}
66 
BonminSetup(const BonminSetup & other)67   BonminSetup::BonminSetup(const BonminSetup &other):BabSetupBase(other),
68       algo_(other.algo_)
69   {}
70 
BonminSetup(const BonminSetup & other,OsiTMINLPInterface & nlp)71   BonminSetup::BonminSetup(const BonminSetup &other,
72                            OsiTMINLPInterface &nlp):
73       BabSetupBase(other, nlp),
74       algo_(other.algo_)
75   {
76     if(algo_ != B_BB){
77       assert(continuousSolver_ == NULL);
78       continuousSolver_ = new OsiClpSolverInterface;
79       int lpLogLevel;
80       options_->GetIntegerValue("lp_log_level",lpLogLevel,prefix_.c_str());
81       if(messageHandler_)
82         continuousSolver_->passInMessageHandler(messageHandler_);
83       continuousSolver_->messageHandler()->setLogLevel(lpLogLevel);
84 
85       nonlinearSolver_->extractLinearRelaxation(*continuousSolver_);
86       // say bound dubious, does cuts at solution
87       OsiBabSolver * extraStuff = new OsiBabSolver(3);
88       continuousSolver_->setAuxiliaryInfo(extraStuff);
89       delete extraStuff;
90     }
91   }
BonminSetup(const BonminSetup & other,OsiTMINLPInterface & nlp,const std::string & prefix)92   BonminSetup::BonminSetup(const BonminSetup &other,
93                            OsiTMINLPInterface &nlp,
94                            const std::string &prefix):
95     BabSetupBase(other, nlp, prefix),
96     algo_(Dummy)
97   {
98    algo_ = getAlgorithm();
99     if (algo_ == B_BB)
100       initializeBBB();
101     else
102       initializeBHyb(true);
103   }
registerAllOptions(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions)104   void BonminSetup::registerAllOptions(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions)
105   {
106     BabSetupBase::registerAllOptions(roptions);
107 
108     /* Outer Approximation options.*/
109     OACutGenerator2::registerOptions(roptions);
110     OaFeasibilityChecker::registerOptions(roptions);
111     MinlpFeasPump::registerOptions(roptions);
112     EcpCuts::registerOptions(roptions);
113     OaNlpOptim::registerOptions(roptions);
114     SubMipSolver::registerOptions(roptions);
115 
116 
117     BonCbcFullNodeInfo::registerOptions(roptions);
118 
119 
120     registerMilpCutGenerators(roptions);
121 
122 
123     /** Heursitics.*/
124     LocalSolverBasedHeuristic::registerOptions(roptions);
125     FixAndSolveHeuristic::registerOptions(roptions);
126     DummyPump::registerOptions(roptions);
127     MilpRounding::registerOptions(roptions);
128     PumpForMinlp::registerOptions(roptions);
129     HeuristicRINS::registerOptions(roptions);
130     HeuristicLocalBranching::registerOptions(roptions);
131     HeuristicFPump::registerOptions(roptions);
132     HeuristicDiveFractional::registerOptions(roptions);
133     HeuristicDiveVectorLength::registerOptions(roptions);
134     HeuristicDiveMIPFractional::registerOptions(roptions);
135     HeuristicDiveMIPVectorLength::registerOptions(roptions);
136 
137     roptions->SetRegisteringCategory("Algorithm choice", RegisteredOptions::BonminCategory);
138     roptions->AddStringOption6("algorithm",
139         "Choice of the algorithm.",
140         "B-BB",
141         "B-BB","simple branch-and-bound algorithm,",
142         "B-OA","OA Decomposition algorithm,",
143         "B-QG","Quesada and Grossmann branch-and-cut algorithm,",
144         "B-Hyb","hybrid outer approximation based branch-and-cut,",
145         "B-Ecp","ECP cuts based branch-and-cut a la FilMINT.",
146         "B-iFP","Iterated Feasibility Pump for MINLP.",
147         "This will preset some of the options of bonmin depending on the algorithm choice."
148                               );
149     roptions->setOptionExtraInfo("algorithm",127);
150 
151 
152   }
153 
154   /** Register all the Bonmin options.*/
155   void
registerOptions()156   BonminSetup::registerOptions()
157   {
158     registerAllOptions(roptions_);
159   }
160 
161   /** Initialize, read options and create appropriate bonmin setup using initialized tminlp.*/
162   void
initialize(Ipopt::SmartPtr<TMINLP> tminlp,bool createContinuousSolver)163   BonminSetup::initialize(Ipopt::SmartPtr<TMINLP> tminlp, bool createContinuousSolver /*= false*/)
164   {
165 
166     use(tminlp);
167     BabSetupBase::gatherParametersValues(options_);
168     algo_ = getAlgorithm();
169     if (algo_ == B_BB)
170       initializeBBB();
171     else
172       initializeBHyb(createContinuousSolver);
173   }
174 
175   /** Initialize, read options and create appropriate bonmin setup using initialized tminlp.*/
176   void
initialize(const OsiTMINLPInterface & nlpSi,bool createContinuousSolver)177   BonminSetup::initialize(const OsiTMINLPInterface &nlpSi, bool createContinuousSolver /*= false*/)
178   {
179     use(nlpSi);
180     BabSetupBase::gatherParametersValues(options_);
181     Algorithm algo = getAlgorithm();
182     if (algo == B_BB)
183       initializeBBB();
184     else
185       initializeBHyb(createContinuousSolver);
186   }
187 
188   /** Register standard MILP cut generators. */
189   void
registerMilpCutGenerators(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions)190   BonminSetup::registerMilpCutGenerators(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions)
191   {
192     roptions->SetRegisteringCategory("MILP cutting planes in hybrid algorithm", RegisteredOptions::BonminCategory);
193 
194     roptions->AddLowerBoundedIntegerOption("Gomory_cuts",
195         "Frequency (in terms of nodes) for generating Gomory cuts in branch-and-cut.",
196         -100,-5,
197         "If $k > 0$, cuts are generated every $k$ nodes, if $-99 < k < 0$ cuts are generated every $-k$ nodes but "
198         "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
199         "if $k=-99$ generate cuts only at the root node, if $k=0$ or $100$ do not generate cuts.");
200     roptions->setOptionExtraInfo("Gomory_cuts",119);
201 #if 0
202     roptions->AddBoundedIntegerOption("probing_cuts",
203         "Frequency (in terms of nodes) for generating probing cuts in branch-and-cut",
204         0,0,0,
205         "If $k > 0$, cuts are generated every $k$ nodes, if $-99 < k < 0$ cuts are generated every $-k$ nodes but "
206         "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
207         "if $k=-99$ generate cuts only at the root node, if $k=0$ or $100$ do not generate cuts.");
208     roptions->setOptionExtraInfo("probing_cuts",0);
209 #endif
210     roptions->AddLowerBoundedIntegerOption("cover_cuts",
211         "Frequency (in terms of nodes) for generating cover cuts in branch-and-cut",
212         -100,0,
213         "If $k > 0$, cuts are generated every $k$ nodes, if $-99 < k < 0$ cuts are generated every $-k$ nodes but "
214         "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
215         "if $k=-99$ generate cuts only at the root node, if $k=0$ or $100$ do not generate cuts.");
216     roptions->setOptionExtraInfo("cover_cuts",119);
217 
218     roptions->AddLowerBoundedIntegerOption("mir_cuts",
219         "Frequency (in terms of nodes) for generating MIR cuts in branch-and-cut",
220         -100,-5,
221         "If $k > 0$, cuts are generated every $k$ nodes, if $-99 < k < 0$ cuts are generated every $-k$ nodes but "
222         "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
223         "if $k=-99$ generate cuts only at the root node, if $k=0$ or $100$ do not generate cuts.");
224     roptions->setOptionExtraInfo("mir_cuts",119);
225     roptions->AddLowerBoundedIntegerOption("2mir_cuts",
226         "Frequency (in terms of nodes) for generating 2-MIR cuts in branch-and-cut",
227         -100,0,
228         "If $k > 0$, cuts are generated every $k$ nodes, if $-99 < k < 0$ cuts are generated every $-k$ nodes but "
229         "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
230         "if $k=-99$ generate cuts only at the root node, if $k=0$ or $100$ do not generate cuts.");
231     roptions->setOptionExtraInfo("2mir_cuts",119);
232 
233     roptions->AddLowerBoundedIntegerOption("flow_cover_cuts",
234         "Frequency (in terms of nodes) for generating flow cover cuts in branch-and-cut",
235         -100,-5,
236         "If $k > 0$, cuts are generated every $k$ nodes, if $-99 < k < 0$ cuts are generated every $-k$ nodes but "
237         "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
238         "if $k=-99$ generate cuts only at the root node, if $k=0$ or $100$ do not generate cuts.");
239     roptions->setOptionExtraInfo("flow_cover_cuts",119);
240     roptions->AddLowerBoundedIntegerOption("lift_and_project_cuts",
241         "Frequency (in terms of nodes) for generating lift-and-project cuts in branch-and-cut",
242         -100,0,
243         "If $k > 0$, cuts are generated every $k$ nodes, if $-99 < k < 0$ cuts are generated every $-k$ nodes but "
244         "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
245         "if $k=-99$ generate cuts only at the root node, if $k=0$ or $100$ do not generate cuts.");
246     roptions->setOptionExtraInfo("lift_and_project_cuts", 119);
247     roptions->AddLowerBoundedIntegerOption("reduce_and_split_cuts",
248         "Frequency (in terms of nodes) for generating reduce-and-split cuts in branch-and-cut",
249         -100,0,
250         "If $k > 0$, cuts are generated every $k$ nodes, if $-99 < k < 0$ cuts are generated every $-k$ nodes but "
251         "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
252         "if $k=-99$ generate cuts only at the root node, if $k=0$ or $100$ do not generate cuts.");
253     roptions->setOptionExtraInfo("reduce_and_split_cuts", 119);
254 
255 
256     roptions->AddLowerBoundedIntegerOption("clique_cuts",
257         "Frequency (in terms of nodes) for generating clique cuts in branch-and-cut",
258         -100,-5,
259         "If $k > 0$, cuts are generated every $k$ nodes, if $-99 < k < 0$ cuts are generated every $-k$ nodes but "
260         "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
261         "if $k=-99$ generate cuts only at the root node, if $k=0$ or $100$ do not generate cuts.");
262     roptions->setOptionExtraInfo("clique_cuts", 119);
263 
264   }
265 
266 
267   /** Add milp cut generators according to options.*/
268   void
addMilpCutGenerators()269   BonminSetup::addMilpCutGenerators()
270   {
271 
272     int freq;
273 
274     options_->GetIntegerValue("Gomory_cuts", freq,prefix_.c_str());
275 
276     if (freq) {
277       CuttingMethod cg;
278       cg.frequency = freq;
279       CglGomory * gom = new CglGomory;
280       cg.cgl = gom;
281       gom->setLimitAtRoot(5000);
282       gom->setLimit(500);
283       gom->setLargestFactorMultiplier(1e-08);
284       cg.id = "Mixed Integer Gomory";
285       cutGenerators_.push_back(cg);
286     }
287 
288 #if 0
289     options_->GetIntegerValue("probing_cuts",freq,prefix_.c_str());
290     if (freq) {
291       CuttingMethod cg;
292       cg.frequency = freq;
293       CglProbing * probe = new CglProbing;
294       cg.cgl = probe;
295       probe->setUsingObjective(1);
296       probe->setMaxPass(3);
297       probe->setMaxPassRoot(3);
298       // Number of unsatisfied variables to look at
299       probe->setMaxProbe(10);
300       probe->setMaxProbeRoot(50);
301       // How far to follow the consequences
302       probe->setMaxLook(10);
303       probe->setMaxLookRoot(50);
304       probe->setMaxLookRoot(10);
305       // Only look at rows with fewer than this number of elements
306       probe->setMaxElements(200);
307       probe->setRowCuts(3);
308       cg.id = "Probing";
309       cutGenerators_.push_back(cg);
310     }
311 #endif
312 
313     options_->GetIntegerValue("mir_cuts",freq,prefix_.c_str());
314 
315     if (freq) {
316       CuttingMethod cg;
317       cg.frequency = freq;
318       CglMixedIntegerRounding2 * mir = new CglMixedIntegerRounding2;
319       //CglMixedIntegerRounding2 * mir = new CglMixedIntegerRounding2(1, true, 1);
320       cg.cgl = mir;
321       cg.id = "Mixed Integer Rounding";
322       cutGenerators_.push_back(cg);
323     }
324 
325     options_->GetIntegerValue("2mir_cuts",freq,prefix_.c_str());
326 
327     if (freq) {
328       CuttingMethod cg;
329       cg.frequency = freq;
330       CglTwomir * mir2 = new CglTwomir;
331       cg.cgl = mir2;
332       cg.id = "2-MIR";
333       cutGenerators_.push_back(cg);
334     }
335 
336     options_->GetIntegerValue("cover_cuts",freq,prefix_.c_str());
337 
338     if (freq) {
339       CuttingMethod cg;
340       cg.frequency = freq;
341       CglKnapsackCover * cover = new CglKnapsackCover;
342       cg.cgl = cover;
343       cg.id = "Cover";
344       cutGenerators_.push_back(cg);
345     }
346 
347     options_->GetIntegerValue("clique_cuts",freq,prefix_.c_str());
348 
349     if (freq) {
350       CuttingMethod cg;
351       cg.frequency = freq;
352       CglClique * clique = new CglClique;
353       clique->setStarCliqueReport(false);
354       clique->setRowCliqueReport(false);
355       clique->setMinViolation(0.1);
356 
357       cg.cgl = clique;
358       cg.id = "Clique";
359       cutGenerators_.push_back(cg);
360     }
361 
362     options_->GetIntegerValue("flow_cover_cuts",freq,prefix_.c_str());
363 
364     if (freq) {
365       CuttingMethod cg;
366       cg.frequency = freq;
367       CglFlowCover * flow = new CglFlowCover;
368       cg.cgl = flow;
369       cg.id = "Flow Covers";
370       cutGenerators_.push_back(cg);
371     }
372 
373     options_->GetIntegerValue("lift_and_project_cuts",freq,prefix_.c_str());
374 
375     if (freq) {
376       CuttingMethod cg;
377       cg.frequency = freq;
378       CglLandP * landp = new CglLandP;
379       cg.cgl = landp;
380       cg.id = "Lift-and-Project";
381       cutGenerators_.push_back(cg);
382     }
383 
384     options_->GetIntegerValue("reduce_and_split_cuts",freq,prefix_.c_str());
385 
386     if (freq) {
387       CuttingMethod cg;
388       cg.frequency = freq;
389       CglRedSplit * rands = new CglRedSplit;
390       cg.cgl = rands;
391       cg.id = "Reduce-and-Split";
392       cutGenerators_.push_back(cg);
393     }
394   }
395 
396 
397   void
initializeBBB()398   BonminSetup::initializeBBB()
399   {
400     continuousSolver_ = nonlinearSolver_;
401     nonlinearSolver_->ignoreFailures();
402     OsiBabSolver extraStuff(2);
403     continuousSolver_->setAuxiliaryInfo(&extraStuff);
404 
405     intParam_[BabSetupBase::SpecialOption] = 16;
406     if (!options_->GetIntegerValue("number_before_trust",intParam_[BabSetupBase::MinReliability],prefix_.c_str())) {
407       intParam_[BabSetupBase::MinReliability] = 1;
408       std::string o_name = prefix_ + "number_before_trust";
409       options_->SetIntegerValue(o_name.c_str(),intParam_[BabSetupBase::MinReliability],true,true);
410     }
411     if (!options_->GetIntegerValue("number_strong_branch",intParam_[BabSetupBase::NumberStrong],prefix_.c_str())) {
412       intParam_[BabSetupBase::NumberStrong] = 1000;
413       std::string o_name = prefix_ + "number_strong_branch";
414       options_->SetIntegerValue(o_name.c_str(),intParam_[BabSetupBase::NumberStrong],true,true);
415     }
416     int varSelection;
417     bool val = options_->GetEnumValue("variable_selection",varSelection,prefix_.c_str());
418     if (!val){// || varSelection == STRONG_BRANCHING || varSelection == RELIABILITY_BRANCHING ) {
419       std::string o_name = prefix_ + "variable_selection";
420       options_->SetStringValue(o_name.c_str(), "nlp-strong-branching",true,true);
421       varSelection = NLP_STRONG_BRANCHING;
422     }
423 
424     switch (varSelection) {
425 #ifdef BONMIN_CURVATURE_BRANCHING
426     case CURVATURE_ESTIMATOR:
427 #endif
428     case QP_STRONG_BRANCHING:
429     case LP_STRONG_BRANCHING:
430     case NLP_STRONG_BRANCHING: {
431         continuousSolver_->findIntegersAndSOS(false);
432         setPriorities();
433         addSos();
434         Ipopt::SmartPtr<StrongBranchingSolver> strong_solver = NULL;
435         BonChooseVariable * chooseVariable = new BonChooseVariable(*this, nonlinearSolver_);
436         chooseVariable->passInMessageHandler(nonlinearSolver_->messageHandler());
437         switch (varSelection) {
438 #ifdef BONMIN_CURVATURE_BRANCHING
439         case CURVATURE_ESTIMATOR:
440           strong_solver = new CurvBranchingSolver(nonlinearSolver_);
441           chooseVariable->setTrustStrongForSolution(false);
442           chooseVariable->setTrustStrongForBound(false);
443           //chooseVariable->setOnlyPseudoWhenTrusted(true);
444           chooseVariable->setOnlyPseudoWhenTrusted(false);
445           break;
446 #endif
447         case QP_STRONG_BRANCHING:
448           chooseVariable->setTrustStrongForSolution(false);
449           strong_solver = new QpBranchingSolver(nonlinearSolver_);
450           // The bound returned from the QP can be wrong, since the
451           // objective is not guaranteed to be an underestimator:
452           chooseVariable->setTrustStrongForBound(false);
453           //chooseVariable->setOnlyPseudoWhenTrusted(true);
454           chooseVariable->setOnlyPseudoWhenTrusted(false);
455           break;
456         case LP_STRONG_BRANCHING:
457           chooseVariable->setTrustStrongForSolution(false);
458           strong_solver = new LpBranchingSolver(this);
459           //chooseVariable->setOnlyPseudoWhenTrusted(true);
460           chooseVariable->setOnlyPseudoWhenTrusted(false);
461           break;
462          case NLP_STRONG_BRANCHING:
463           chooseVariable->setTrustStrongForSolution(false);
464           chooseVariable->setTrustStrongForBound(true);
465           chooseVariable->setOnlyPseudoWhenTrusted(false);
466           break;
467         }
468         nonlinearSolver_->SetStrongBrachingSolver(strong_solver);
469         branchingMethod_ = chooseVariable;
470       }
471       break;
472     case OSI_SIMPLE:
473       continuousSolver_->findIntegersAndSOS(false);
474       setPriorities();
475       addSos();
476       branchingMethod_ = new OsiChooseVariable(nonlinearSolver_);
477 
478       break;
479     case OSI_STRONG:
480       continuousSolver_->findIntegersAndSOS(false);
481       setPriorities();
482       addSos();
483       branchingMethod_ = new OsiChooseStrong(nonlinearSolver_);
484       break;
485     case RANDOM:
486       continuousSolver_->findIntegersAndSOS(false);
487       setPriorities();
488       addSos();
489       branchingMethod_ = new BonRandomChoice(nonlinearSolver_);
490       break;
491       //default:
492       //abort();
493     }
494     if (branchingMethod_ != NULL) {
495       branchingMethod_->setNumberStrong(intParam_[NumberStrong]);
496     }
497 
498 
499     Ipopt::Index doHeuristicDiveFractional = false;
500     options()->GetEnumValue("heuristic_dive_fractional",doHeuristicDiveFractional,prefix_.c_str());
501     if(doHeuristicDiveFractional){
502       HeuristicDiveFractional* dive_fractional = new HeuristicDiveFractional(this);
503       HeuristicMethod h;
504       h.heuristic = dive_fractional;
505       h.id = "DiveFractional";
506       heuristics_.push_back(h);
507     }
508 
509     Ipopt::Index doHeuristicDiveVectorLength = false;
510     options()->GetEnumValue("heuristic_dive_vectorLength",doHeuristicDiveVectorLength,prefix_.c_str());
511     if(doHeuristicDiveVectorLength){
512       HeuristicDiveVectorLength* dive_vectorLength = new HeuristicDiveVectorLength(this);
513       HeuristicMethod h;
514       h.heuristic = dive_vectorLength;
515       h.id = "DiveVectorLength";
516       heuristics_.push_back(h);
517     }
518 
519     Ipopt::Index doHeuristicDiveMIPFractional = false;
520     if(!options()->GetEnumValue("heuristic_dive_MIP_fractional",doHeuristicDiveMIPFractional,prefix_.c_str())){
521       doHeuristicDiveMIPFractional = true;
522       std::string o_name = prefix_ + "heuristic_dive_MIP_fractional";
523       options_->SetStringValue(o_name.c_str(), "yes",true,true);
524     }
525     if(doHeuristicDiveMIPFractional){
526       HeuristicDiveMIPFractional* dive_MIP_fractional = new HeuristicDiveMIPFractional(this);
527       HeuristicMethod h;
528       h.heuristic = dive_MIP_fractional;
529       h.id = "DiveMIPFractional";
530       heuristics_.push_back(h);
531     }
532 
533     Ipopt::Index doHeuristicDiveMIPVectorLength = false;
534     options()->GetEnumValue("heuristic_dive_MIP_vectorLength",doHeuristicDiveMIPVectorLength,prefix_.c_str());
535     if(doHeuristicDiveMIPVectorLength){
536       HeuristicDiveMIPVectorLength* dive_MIP_vectorLength = new HeuristicDiveMIPVectorLength(this);
537       HeuristicMethod h;
538       h.heuristic = dive_MIP_vectorLength;
539       h.id = "DiveMIPVectorLength";
540       heuristics_.push_back(h);
541     }
542     Ipopt::Index doHeuristicFPump = false;
543     if(!nonlinearSolver_->model()->hasGeneralInteger() && !options()->GetEnumValue("heuristic_feasibility_pump",doHeuristicFPump,prefix_.c_str())){
544       doHeuristicFPump = true;
545       std::string o_name = prefix_ + "heuristic_feasibility_pump";
546       options_->SetStringValue(o_name.c_str(), "yes",true,true);
547     }
548     if(doHeuristicFPump){
549       HeuristicFPump* feasibility_pump = new HeuristicFPump(this);
550       HeuristicMethod h;
551       h.heuristic = feasibility_pump;
552       h.id = "FPump";
553       heuristics_.push_back(h);
554     }
555 
556     Ipopt::Index doFixAndSolve = false;
557     options()->GetEnumValue("fix_and_solve_heuristic",doFixAndSolve,prefix_.c_str());
558     if(doFixAndSolve){
559       FixAndSolveHeuristic* fix_and_solve = new FixAndSolveHeuristic(this);
560       HeuristicMethod h;
561       h.heuristic = fix_and_solve;
562       h.id = "Fix and Solve";
563       heuristics_.push_back(h);
564     }
565 
566     Ipopt::Index doDummyPump = false;
567     options()->GetEnumValue("dummy_pump_heuristic",doDummyPump,prefix_.c_str());
568     if(doDummyPump){
569       DummyPump* fix_and_solve = new DummyPump(this);
570       HeuristicMethod h;
571       h.heuristic = fix_and_solve;
572       h.id = "Dummy pump";
573       heuristics_.push_back(h);
574     }
575 
576     Ipopt::Index doHeuristicRINS = false;
577     options()->GetEnumValue("heuristic_RINS",doHeuristicRINS,prefix_.c_str());
578     if(doHeuristicRINS){
579       HeuristicRINS* rins = new HeuristicRINS(this);
580       HeuristicMethod h;
581       h.heuristic = rins;
582       h.id = "RINS";
583       heuristics_.push_back(h);
584     }
585 
586     Ipopt::Index doHeuristicLocalBranching = false;
587     options()->GetEnumValue("heuristic_local_branching",doHeuristicLocalBranching,prefix_.c_str());
588     if(doHeuristicLocalBranching){
589       HeuristicLocalBranching* local_branching = new HeuristicLocalBranching(this);
590       HeuristicMethod h;
591       h.heuristic = local_branching;
592       h.id = "LocalBranching";
593       heuristics_.push_back(h);
594     }
595 
596     Ipopt::Index doHeuristicPumpForMinlp = false;
597     options()->GetEnumValue("pump_for_minlp",doHeuristicPumpForMinlp,prefix_.c_str());
598     if(doHeuristicPumpForMinlp){
599       PumpForMinlp * pump = new PumpForMinlp(this);
600       HeuristicMethod h;
601       h.heuristic = pump;
602       h.id = "Pump for MINLP";
603       heuristics_.push_back(h);
604     }
605 
606     Ipopt::Index doHeuristicMilpRounding = false;
607     options()->GetEnumValue("MILP_rounding_heuristic",doHeuristicMilpRounding,prefix_.c_str());
608     if(doHeuristicMilpRounding){
609       MilpRounding * round = new MilpRounding(this);
610       HeuristicMethod h;
611       h.heuristic = round;
612       h.id = "MILP Rounding";
613       heuristics_.push_back(h);
614     }
615   }
616 
617 
618   void
initializeBHyb(bool createContinuousSolver)619   BonminSetup::initializeBHyb(bool createContinuousSolver /*= false*/)
620   {
621     double setup_time = -CoinCpuTime();
622     if (createContinuousSolver) {
623       /* Create linear solver */
624       continuousSolver_ = new OsiClpSolverInterface;
625       int lpLogLevel;
626       options_->GetIntegerValue("lp_log_level",lpLogLevel,prefix_.c_str());
627       if(messageHandler_)
628         continuousSolver_->passInMessageHandler(messageHandler_);
629       continuousSolver_->messageHandler()->setLogLevel(lpLogLevel);
630       nonlinearSolver_->forceSolverOutput(intParam_[RootLogLevel]);
631 
632       if(IsValid(linearizer_))//Use user provided linearizer
633         nonlinearSolver_->set_linearizer(linearizer_);
634 
635       nonlinearSolver_->extractLinearRelaxation(*continuousSolver_);
636       nonlinearSolver_->setSolverOutputToDefault();
637 
638       // say bound dubious, does cuts at solution
639       OsiBabSolver * extraStuff = new OsiBabSolver(3);
640       continuousSolver_->setAuxiliaryInfo(extraStuff);
641       delete extraStuff;
642     }
643     Algorithm algo = getAlgorithm();
644     std::string prefix = (prefix_ == "bonmin.") ? "" : prefix_;
645     if (algo == B_Hyb) {
646       std::string o_name = prefix_ + "oa_decomposition";
647       options_->SetStringValue(o_name.c_str(),"no", true, true);
648       o_name = prefix_ + "pump_for_minlp";
649       options_->SetStringValue(o_name.c_str(),"yes", true, true);
650       o_name = prefix + "pump_for_minlp.time_limit";
651       options_->SetNumericValue(o_name.c_str(),10, true, true);
652       o_name = prefix + "pump_for_minlp.solution_limit";
653       options_->SetIntegerValue(o_name.c_str(),3, true, true);
654     }
655     else if (algo == B_OA) {
656       std::string o_name = prefix_ + "oa_decomposition";
657       options_->SetStringValue(o_name.c_str(),"yes", true, true);
658       o_name = prefix + "oa_decomposition.time_limit";
659       options_->SetNumericValue(o_name.c_str(),DBL_MAX, true, true);
660       o_name = prefix_ + "pump_for_minlp";
661       options_->SetStringValue(o_name.c_str(),"no", true, true);
662       o_name = prefix + "nlp_solve_frequency";
663       options_->SetIntegerValue(o_name.c_str(), 0, true, true);
664       o_name = prefix + "bb_log_level";
665       options_->SetIntegerValue(o_name.c_str(), 0, true, true);
666     }
667     else if (algo == B_IFP) {
668       std::string o_name = prefix_ + "oa_decomposition";
669       options_->SetStringValue(o_name.c_str(),"no", true, true);
670       o_name = prefix_ + "pump_for_minlp";
671       options_->SetStringValue(o_name.c_str(),"yes", true, true);
672       o_name = prefix + "pump_for_minlp.time_limit";
673       options_->SetNumericValue(o_name.c_str(),DBL_MAX, true, true);
674       o_name = prefix_ + "nlp_solve_frequency";
675       options_->SetIntegerValue(o_name.c_str(), 0, true, true);
676       o_name = prefix_ + "fp_pass_infeasible";
677       options_->SetStringValue(o_name.c_str(), "yes", true, true);
678       //o_name = prefix_ + "cutoff_decr";
679       //options_->SetNumericValue(o_name.c_str(), 1e-02, true, true);
680       intParam_[BabLogLevel] = 0;
681     }
682     else if (algo==B_QG) {
683       std::string o_name = prefix_ + "oa_decomposition";
684       options_->SetStringValue(o_name.c_str(),"no", true, true);
685       o_name = prefix_ + "pump_for_minlp";
686       options_->SetStringValue(o_name.c_str(),"no", true, true);
687       o_name = prefix_ + "nlp_solve_frequency";
688       options_->SetIntegerValue(o_name.c_str(), 0, true, true);
689     }
690     else if (algo==B_Ecp) {
691       std::string o_name = prefix_ + "oa_decomposition";
692       options_->SetStringValue(o_name.c_str(),"no", true, true);
693       o_name = prefix_ + "pump_for_minlp";
694       options_->SetStringValue(o_name.c_str(),"no", true, true);
695       o_name = prefix_ + "nlp_solve_frequency";
696       options_->SetIntegerValue(o_name.c_str(), 0, true, true);
697       o_name = prefix_ + "filmint_ecp_cuts";
698       options_->SetIntegerValue(o_name.c_str(), 1, true, true);
699     }
700 //#define GREAT_STUFF_FOR_ANDREAS
701 #ifdef GREAT_STUFF_FOR_ANDREAS
702     printf("ToDo: Clean me up in Bab::branchAndBound\n");
703     OsiCuts cuts;
704     nonlinearSolver_->getOuterApproximation(cuts, true, NULL, true);
705     continuousSolver_->applyCuts(cuts);
706 #endif
707 
708 
709     int varSelection;
710     options_->GetEnumValue("variable_selection",varSelection,prefix_.c_str());
711     if (varSelection > RELIABILITY_BRANCHING) {
712       switch (varSelection){
713         case OSI_SIMPLE:
714           continuousSolver_->findIntegersAndSOS(false);
715           setPriorities();
716           addSos();
717           branchingMethod_ = new OsiChooseVariable(nonlinearSolver_);
718 
719           break;
720         case OSI_STRONG:
721           {
722           continuousSolver_->findIntegersAndSOS(false);
723           setPriorities();
724           addSos();
725           OsiChooseStrong * chooser = new OsiChooseStrong(nonlinearSolver_);
726           branchingMethod_ = chooser;
727           chooser->setNumberStrong(intParam_[NumberStrong]);
728           chooser->setTrustStrongForSolution(false);
729           chooser->setNumberBeforeTrusted(intParam_[MinReliability]);
730           }
731           break;
732         default:
733           std::cout<<"Variable selection stragey not available with oa branch-and-cut."<<std::endl;
734           break;
735      }
736     }
737     /* Populate cut generation and heuristic procedures.*/
738     int ival;
739     options_->GetIntegerValue("nlp_solve_frequency",ival,prefix_.c_str());
740     if (ival != 0) {
741       CuttingMethod cg;
742       cg.frequency = ival;
743       OaNlpOptim * nlpsol = new OaNlpOptim(*this);
744       nlpsol->passInMessageHandler(messageHandler_);
745       cg.cgl = nlpsol;
746       cg.id="NLP solution based oa cuts";
747       cutGenerators_.push_back(cg);
748     }
749 
750     options_->GetIntegerValue("filmint_ecp_cuts",ival, prefix_.c_str());
751     if (ival != 0) {
752       CuttingMethod cg;
753       cg.frequency = ival;
754       EcpCuts * ecp = new EcpCuts(*this);
755       ecp->passInMessageHandler(messageHandler_);
756       cg.cgl = ecp;
757       cg.id = "Ecp cuts";
758       cutGenerators_.push_back(cg);
759     }
760 
761     if (algo == B_Hyb || algo == B_Ecp)
762       addMilpCutGenerators();
763 
764     int doFp;
765     options_->GetEnumValue("pump_for_minlp",doFp,prefix_.c_str());
766     if (doFp) {
767       CuttingMethod cg;
768       cg.frequency = -99;
769       MinlpFeasPump * oa = new MinlpFeasPump(*this);
770       oa->passInMessageHandler(messageHandler_);
771       cg.cgl = oa;
772       cg.id = "Feasibility Pump for MINLP.";
773       cutGenerators_.push_back(cg);
774 
775     }
776     int doOa;
777     options_->GetEnumValue("oa_decomposition",doOa,prefix_.c_str());
778     if (doOa) {
779       CuttingMethod cg;
780       cg.frequency = -99;
781       OACutGenerator2 * oa = new OACutGenerator2(*this);
782       oa->passInMessageHandler(messageHandler_);
783       cg.cgl = oa;
784       cg.id = "Outer Approximation decomposition.";
785       cutGenerators_.push_back(cg);
786 
787     }
788 
789     {
790       CuttingMethod cg;
791       cg.frequency = 1;
792       OaFeasibilityChecker * oa = new OaFeasibilityChecker(*this);
793       oa->passInMessageHandler(messageHandler_);
794       oa->setReassignLpSolver(false);
795       cg.cgl = oa;
796       cg.id = "Outer Approximation feasibility check.";
797       cg.atSolution = false;
798       cg.normal = true;
799       cg.always = true;
800       cutGenerators_.push_back(cg);
801     }
802 
803     {
804       CuttingMethod cg;
805       cg.frequency = 1;
806       OaFeasibilityChecker * oa = new OaFeasibilityChecker(*this);
807       oa->passInMessageHandler(messageHandler_);
808       oa->setReassignLpSolver(true);
809       cg.cgl = oa;
810       cg.id = "Outer Approximation strong branching solution check.";
811       cg.atSolution = true;
812       cg.normal = false;
813       cutGenerators_.push_back(cg);
814     }
815 
816     DummyHeuristic * oaHeu = new DummyHeuristic;
817     oaHeu->setNlp(nonlinearSolver_);
818     HeuristicMethod h;
819     h.heuristic = oaHeu;
820     h.id = "nonlinear program";
821     heuristics_.push_back(h);
822 
823     Ipopt::Index doHeuristicRINS = false;
824     options()->GetEnumValue("heuristic_RINS",doHeuristicRINS,prefix_.c_str());
825     if(doHeuristicRINS){
826       HeuristicRINS* rins = new HeuristicRINS(this);
827       HeuristicMethod h;
828       h.heuristic = rins;
829       h.id = "RINS";
830       heuristics_.push_back(h);
831     }
832 
833     Ipopt::Index doHeuristicLocalBranching = false;
834     options()->GetEnumValue("heuristic_local_branching",doHeuristicLocalBranching,prefix_.c_str());
835     if(doHeuristicLocalBranching){
836       HeuristicLocalBranching* local_branching = new HeuristicLocalBranching(this);
837       HeuristicMethod h;
838       h.heuristic = local_branching;
839       h.id = "LocalBranching";
840       heuristics_.push_back(h);
841     }
842 
843     Ipopt::Index doHeuristicFPump = false;
844     options()->GetEnumValue("heuristic_feasibility_pump",doHeuristicFPump,prefix_.c_str());
845     if(doHeuristicFPump){
846       HeuristicFPump* feasibility_pump = new HeuristicFPump(this);
847       HeuristicMethod h;
848       h.heuristic = feasibility_pump;
849       h.id = "FPump";
850       heuristics_.push_back(h);
851     }
852 
853     Ipopt::Index doHeuristicDiveFractional = false;
854     options()->GetEnumValue("heuristic_dive_fractional",doHeuristicDiveFractional,prefix_.c_str());
855     if(doHeuristicDiveFractional){
856       HeuristicDiveFractional* dive_fractional = new HeuristicDiveFractional(this);
857       HeuristicMethod h;
858       h.heuristic = dive_fractional;
859       h.id = "DiveFractional";
860       heuristics_.push_back(h);
861     }
862 
863     Ipopt::Index doHeuristicDiveVectorLength = false;
864     options()->GetEnumValue("heuristic_dive_vectorLength",doHeuristicDiveVectorLength,prefix_.c_str());
865     if(doHeuristicDiveVectorLength){
866       HeuristicDiveVectorLength* dive_vectorLength = new HeuristicDiveVectorLength(this);
867       HeuristicMethod h;
868       h.heuristic = dive_vectorLength;
869       h.id = "DiveVectorLength";
870       heuristics_.push_back(h);
871     }
872 
873     Ipopt::Index doHeuristicDiveMIPFractional = false;
874     options()->GetEnumValue("heuristic_dive_MIP_fractional",doHeuristicDiveMIPFractional,prefix_.c_str());
875     if(doHeuristicDiveMIPFractional){
876       HeuristicDiveMIPFractional* dive_MIP_fractional = new HeuristicDiveMIPFractional(this);
877       HeuristicMethod h;
878       h.heuristic = dive_MIP_fractional;
879       h.id = "DiveMIPFractional";
880       heuristics_.push_back(h);
881     }
882 
883     Ipopt::Index doHeuristicDiveMIPVectorLength = false;
884     options()->GetEnumValue("heuristic_dive_MIP_vectorLength",doHeuristicDiveMIPVectorLength,prefix_.c_str());
885     if(doHeuristicDiveMIPVectorLength){
886       HeuristicDiveMIPVectorLength* dive_MIP_vectorLength = new HeuristicDiveMIPVectorLength(this);
887       HeuristicMethod h;
888       h.heuristic = dive_MIP_vectorLength;
889       h.id = "DiveMIPVectorLength";
890       heuristics_.push_back(h);
891     }
892 
893 #if 0
894     if(true){
895       InnerApproximation * inner = new InnerApproximation(this);
896       HeuristicMethod h;
897       h.heuristic = inner;
898       h.id = "InnerApproximation";
899       heuristics_.push_back(h);
900     }
901 #endif
902     setup_time += CoinCpuTime();
903     doubleParam_[MaxTime] -= setup_time;
904   }
905 
906 
getAlgorithm()907   Algorithm BonminSetup::getAlgorithm()
908   {
909     if (algo_ != Dummy)
910       return algo_;
911     if (IsValid(options_)) {
912       int ival;
913       options_->GetEnumValue("algorithm", ival,prefix_.c_str());
914       return Algorithm(ival);
915     }
916     else return Algorithm(3);
917   }
918 
919 }/* end namespace Bonmin*/
920 
921