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