00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "BonCouenneSetup.hpp"
00011 #include "BonNlpHeuristic.hpp"
00012 #include "BonInitHeuristic.hpp"
00013 #include "BonCouenneInterface.hpp"
00014
00015 #include "CouenneObject.hpp"
00016 #include "CouenneVarObject.hpp"
00017 #include "CouenneVTObject.hpp"
00018 #include "CouenneChooseVariable.hpp"
00019 #include "CouenneChooseStrong.hpp"
00020 #include "CouenneSolverInterface.hpp"
00021 #include "CouenneCutGenerator.hpp"
00022 #include "CouenneDisjCuts.hpp"
00023 #include "BonCouenneInfo.hpp"
00024 #include "BonCbcNode.hpp"
00025
00026
00027 #include "CglGomory.hpp"
00028 #include "CglProbing.hpp"
00029 #include "CglKnapsackCover.hpp"
00030 #include "CglOddHole.hpp"
00031 #include "CglClique.hpp"
00032 #include "CglFlowCover.hpp"
00033 #include "CglMixedIntegerRounding2.hpp"
00034 #include "CglTwomir.hpp"
00035 #include "CglPreProcess.hpp"
00036 #include "CglLandP.hpp"
00037 #include "CglRedSplit.hpp"
00038
00039
00040 #include "asl.h"
00041 #include "getstub.h"
00042
00043
00044 namespace Bonmin{
00045
00046 SmartAsl::~SmartAsl(){
00047
00048 if(asl != NULL){
00049 if (X0) {
00050 delete [] X0;
00051 X0 = NULL;
00052 }
00053 if (havex0) {
00054 delete [] havex0;
00055 havex0 = NULL;
00056 }
00057 if (pi0) {
00058 delete [] pi0;
00059 pi0 = NULL;
00060 }
00061 if (havepi0) {
00062 delete [] havepi0;
00063 havepi0 = NULL;
00064 }
00065 ASL* asl_to_free = (ASL*)asl;
00066 ASL_free(&asl_to_free);
00067 asl = NULL;
00068 }
00069 ASL_free(&asl);
00070 }
00071
00072 CouenneSetup::~CouenneSetup(){
00073
00074
00075 }
00076
00077 void CouenneSetup::InitializeCouenne (char **& argv) {
00078
00079 readOptionsFile();
00080
00084 options_->SetStringValue ("nlp_failure_behavior", "fathom", "bonmin.");
00085
00086 gatherParametersValues(options_);
00087
00088 continuousSolver_ = new CouenneSolverInterface;
00089 CouenneInterface * ci = new CouenneInterface;
00090 nonlinearSolver_ = ci;
00091
00092 ci->readAmplNlFile(argv,roptions(),options(),journalist());
00093 aslfg_ = new SmartAsl;
00094 aslfg_->asl = readASLfg (argv);
00095
00099 int i;
00100
00101 options()->GetIntegerValue("boundtightening_print_level", i, "bonmin.");
00102 journalist()->GetJournal("console")->
00103 SetPrintLevel(J_BOUNDTIGHTENING, (EJournalLevel)i);
00104 options()->GetIntegerValue("branching_print_level", i, "bonmin.");
00105 journalist()->GetJournal("console")->
00106 SetPrintLevel(J_BRANCHING, (EJournalLevel)i);
00107 options()->GetIntegerValue("convexifying_print_level", i, "bonmin.");
00108 journalist()->GetJournal("console")->
00109 SetPrintLevel(J_CONVEXIFYING, (EJournalLevel)i);
00110 options()->GetIntegerValue("problem_print_level", i, "bonmin.");
00111 journalist()->GetJournal("console")->
00112 SetPrintLevel(J_PROBLEM, (EJournalLevel)i);
00113
00114
00115
00116
00117
00118
00119 CouenneCutGenerator * couenneCg =
00120 new CouenneCutGenerator (ci, this, aslfg_->asl, journalist());
00121
00122 CouenneProblem * couenneProb = couenneCg -> Problem();
00123
00124 Bonmin::BabInfo * extraStuff = new Bonmin::CouenneInfo(0);
00125
00126
00127 extraStuff -> setExtraCharacteristics (extraStuff -> extraCharacteristics () | 2);
00128
00129 continuousSolver_ -> setAuxiliaryInfo (extraStuff);
00130 delete extraStuff;
00131
00132 extraStuff = dynamic_cast <Bonmin::BabInfo *> (continuousSolver_ -> getAuxiliaryInfo ());
00133
00134
00135 int lpLogLevel;
00136 options()->GetIntegerValue("lp_log_level",lpLogLevel,"bonmin.");
00137 continuousSolver_->messageHandler()->setLogLevel(lpLogLevel);
00138
00140
00141 couenneCg -> Problem () -> setMaxCpuTime (getDoubleParameter (BabSetupBase::MaxTime));
00142
00143 ci -> extractLinearRelaxation (*continuousSolver_, *couenneCg);
00144
00145
00146
00147 if (ci -> isProvenOptimal () &&
00148 ci -> haveNlpSolution ()) {
00149
00151 InitHeuristic* initHeuristic = new InitHeuristic
00152 (ci -> getObjValue (), ci -> getColSolution (), *couenneProb);
00153 HeuristicMethod h;
00154 h.id = "Init Rounding NLP";
00155 h.heuristic = initHeuristic;
00156 heuristics_.push_back(h);
00157 }
00158
00159 if(extraStuff->infeasibleNode()){
00160 std::cout<<"Initial linear relaxation constructed by Couenne is infeasible, quit"<<std::endl;
00161 return;
00162 }
00163
00164 continuousSolver_ -> findIntegersAndSOS (false);
00165 addSos ();
00166
00167
00168
00169 std::string s;
00170 int nSOS = 0;
00171
00172
00173 OsiObject ** objects = new OsiObject* [couenneProb -> nVars ()];
00174
00175 options () -> GetStringValue ("enable_sos", s, "couenne.");
00176 if (s == "yes") {
00177
00178 nSOS = couenneProb -> findSOS (nonlinearSolver (), objects);
00179
00180
00181 continuousSolver () -> addObjects (nSOS, objects);
00182
00183 for (int i=0; i<nSOS; i++)
00184 delete objects [i];
00185 delete [] objects;
00186 }
00187
00188
00189
00190
00191
00192
00193 options () -> GetStringValue ("display_stats", s, "couenne.");
00194 displayStats_ = (s == "yes");
00195
00196 options () -> GetStringValue ("branching_object", s, "couenne.");
00197
00198 enum CouenneObject::branch_obj objType = CouenneObject::VAR_OBJ;
00199
00200 if (s == "vt_obj") objType = CouenneObject::VT_OBJ;
00201 else if (s == "var_obj") objType = CouenneObject::VAR_OBJ;
00202 else if (s == "expr_obj") objType = CouenneObject::EXPR_OBJ;
00203 else {
00204 printf ("CouenneSetup: Unknown branching object type\n");
00205 exit (-1);
00206 }
00207
00208 int
00209 nobj = 0,
00210 nVars = couenneProb -> nVars ();
00211
00212 objects = new OsiObject* [couenneProb -> nVars ()];
00213
00214 int contObjPriority = 2000;
00215
00216 options () -> GetIntegerValue ("cont_var_priority", contObjPriority, "bonmin.");
00217
00218 for (int i = 0; i < nVars; i++) {
00219
00220 exprVar *var = couenneProb -> Var (i);
00221
00222
00223 if (var -> Multiplicity () == 0)
00224 continue;
00225
00226 switch (objType) {
00227
00228 case CouenneObject::EXPR_OBJ:
00229
00230
00231 if ((var -> Type () == AUX) &&
00232 (var -> Image () -> Linearity () > LINEAR)) {
00233
00234 objects [nobj] = new CouenneObject (couenneProb, var, this, journalist ());
00235 objects [nobj++] -> setPriority (contObjPriority);
00236 }
00237
00238 break;
00239
00240 case CouenneObject::VAR_OBJ:
00241
00242
00243 if
00244 (couenneProb -> Dependence () [var -> Index ()] . size () > 0) {
00245
00246
00247
00248 objects [nobj] = new CouenneVarObject (couenneProb, var, this, journalist ());
00249 objects [nobj++] -> setPriority (contObjPriority);
00250 }
00251
00252 break;
00253
00254 default:
00255 case CouenneObject::VT_OBJ:
00256
00257
00258 if
00259 (couenneProb -> Dependence () [var -> Index ()] . size () > 0) {
00260
00261
00262
00263 objects [nobj] = new CouenneVTObject (couenneProb, var, this, journalist ());
00264 objects [nobj++] -> setPriority (contObjPriority);
00265 }
00266
00267 break;
00268 }
00269 }
00270
00271
00272
00273 continuousSolver_ -> addObjects (nobj, objects);
00274
00275 for (int i = 0 ; i < nobj ; i++)
00276 delete objects [i];
00277
00278 delete [] objects;
00279
00280
00281
00282 int freq;
00283
00284 options()->GetIntegerValue("convexification_cuts",freq,"couenne.");
00285
00286 if (freq != 0) {
00287
00288 CuttingMethod cg;
00289 cg.frequency = freq;
00290 cg.cgl = couenneCg;
00291 cg.id = "Couenne convexifier cuts";
00292 cutGenerators().push_back(cg);
00293
00294
00295 dynamic_cast <CouenneSolverInterface *>
00296 (continuousSolver_) -> setCutGenPtr (couenneCg);
00297 }
00298
00299
00300
00301
00302 if (couenneCg -> Problem () -> nIntVars () > 0)
00303 addMilpCutGenerators ();
00304
00305 CouennePtr_ = couenneCg;
00306
00307
00308
00309 int doNlpHeurisitic = 0;
00310 options()->GetEnumValue("local_optimization_heuristic", doNlpHeurisitic, "couenne.");
00311 if(doNlpHeurisitic)
00312 {
00313 int numSolve;
00314 options()->GetIntegerValue("log_num_local_optimization_per_level",numSolve,"couenne.");
00315 NlpSolveHeuristic * nlpHeuristic = new NlpSolveHeuristic;
00316 nlpHeuristic->setNlp(*ci,false);
00317 nlpHeuristic->setCouenneProblem(couenneProb);
00318
00319 nlpHeuristic->setMaxNlpInf(maxNlpInf_0);
00320 nlpHeuristic->setNumberSolvePerLevel(numSolve);
00321 HeuristicMethod h;
00322 h.id = "Couenne Rounding NLP";
00323 h.heuristic = nlpHeuristic;
00324 heuristics_.push_back(h);
00325 }
00326
00327
00328
00329 int varSelection;
00330 if (!options_->GetEnumValue("variable_selection",varSelection,"bonmin.")) {
00331
00332 varSelection = OSI_SIMPLE;
00333 }
00334
00335 switch (varSelection) {
00336
00337 case OSI_STRONG: {
00338 CouenneChooseStrong * chooseVariable = new CouenneChooseStrong
00339 (*this, couenneProb, journalist ());
00340 chooseVariable->setTrustStrongForSolution(false);
00341 chooseVariable->setTrustStrongForBound(false);
00342 chooseVariable->setOnlyPseudoWhenTrusted(true);
00343 branchingMethod_ = chooseVariable;
00344 break;
00345 }
00346
00347 case OSI_SIMPLE:
00348 branchingMethod_ = new CouenneChooseVariable
00349 (continuousSolver_, couenneProb, journalist ());
00350 break;
00351
00352 default:
00353 std::cerr << "Unknown variable_selection for Couenne\n" << std::endl;
00354 throw;
00355 break;
00356 }
00357
00358
00359
00360 options () -> GetIntegerValue ("minlp_disj_cuts", freq, "couenne.");
00361
00362 if (freq != 0) {
00363
00364 CouenneDisjCuts * couenneDisj =
00365 new CouenneDisjCuts (ci, this,
00366 couenneCg -> Problem (),
00367 branchingMethod_,
00368 varSelection == OSI_STRONG,
00369 journalist ());
00370
00371 CuttingMethod cg;
00372 cg.frequency = freq;
00373 cg.cgl = couenneDisj;
00374 cg.id = "Couenne disjunctive cuts";
00375 cutGenerators (). push_back(cg);
00376 }
00377
00378 int ival;
00379 if (!options_->GetEnumValue("node_comparison",ival,"bonmin.")) {
00380
00381 nodeComparisonMethod_ = bestBound;
00382 }
00383 else {
00384 nodeComparisonMethod_ = NodeComparison(ival);
00385 }
00386
00387 if(intParam_[NumCutPasses] < 2)
00388 intParam_[NumCutPasses] = 2;
00389
00390
00391
00392 intParam_[BabSetupBase::SpecialOption] = 16 | 4;
00393 }
00394
00395 void CouenneSetup::registerOptions(){
00396 registerAllOptions(roptions());
00397 }
00398
00399
00400 void
00401 CouenneSetup::registerAllOptions(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions){
00402 BabSetupBase::registerAllOptions(roptions);
00403 BonCbcFullNodeInfo::registerOptions(roptions);
00404 CouenneCutGenerator::registerOptions (roptions);
00405 CouenneDisjCuts::registerOptions (roptions);
00406
00407 roptions -> AddStringOption2 (
00408 "display_stats",
00409 "display statistics at the end of the run",
00410 "no",
00411 "yes", "",
00412 "no", "");
00413
00414 roptions->AddBoundedIntegerOption(
00415 "branching_print_level",
00416 "Output level for braching code in Couenne",
00417 -2, J_LAST_LEVEL-1, J_NONE,
00418 "");
00419 roptions->AddBoundedIntegerOption(
00420 "boundtightening_print_level",
00421 "Output level for bound tightening code in Couenne",
00422 -2, J_LAST_LEVEL-1, J_NONE,
00423 "");
00424 roptions->AddBoundedIntegerOption(
00425 "convexifying_print_level",
00426 "Output level for convexifying code in Couenne",
00427 -2, J_LAST_LEVEL-1, J_NONE,
00428 "");
00429 roptions->AddBoundedIntegerOption(
00430 "problem_print_level",
00431 "Output level for problem manipulation code in Couenne",
00432 -2, J_LAST_LEVEL-1, J_WARNING,
00433 "");
00434
00435
00436
00437
00438
00439 struct cutOption_ {
00440
00441 const char *cgname;
00442 int defaultFreq;
00443
00444 } cutOption [] = {
00445 {(const char *) "Gomory_cuts", 0},
00446 {(const char *) "probing_cuts", 0},
00447 {(const char *) "cover_cuts", 0},
00448 {(const char *) "mir_cuts", 0},
00449 {(const char *) "2mir_cuts", 0},
00450 {(const char *) "flow_covers_cuts", 0},
00451 {(const char *) "lift_and_project_cuts", 0},
00452 {(const char *) "reduce_split_cuts", 0},
00453 {(const char *) "clique_cuts", 0},
00454 {NULL, 0}};
00455
00456 for (int i=0; cutOption [i].cgname; i++) {
00457
00458 char descr [150];
00459
00460 sprintf (descr, "Frequency k (in terms of nodes) for generating %s cuts in branch-and-cut.",
00461 cutOption [i].cgname);
00462
00463 roptions -> AddLowerBoundedIntegerOption
00464 (cutOption [i].cgname,
00465 descr,
00466 -100, cutOption [i].defaultFreq,
00467 "If k > 0, cuts are generated every k nodes, "
00468 "if -99 < k < 0 cuts are generated every -k nodes but "
00469 "Cbc may decide to stop generating cuts, if not enough are generated at the root node, "
00470 "if k=-99 generate cuts only at the root node, if k=0 or 100 do not generate cuts.");
00471
00472 roptions->setOptionExtraInfo (cutOption [i].cgname, 5);
00473 }
00474 }
00475
00476
00477
00479 void CouenneSetup::addMilpCutGenerators () {
00480
00481 enum extraInfo_ {CUTINFO_NONE, CUTINFO_MIG, CUTINFO_PROBING, CUTINFO_CLIQUE};
00482
00483 struct cutInfo {
00484
00485 const char *optname;
00486 CglCutGenerator *cglptr;
00487 const char *cglId;
00488 enum extraInfo_ extraInfo;
00489
00490 } cutList [] = {
00491 {(const char*)"Gomory_cuts",new CglGomory, (const char*)"Mixed Integer Gomory",CUTINFO_MIG},
00492 {(const char*)"probing_cuts",new CglProbing, (const char*) "Probing", CUTINFO_PROBING},
00493 {(const char*)"mir_cuts",new CglMixedIntegerRounding2, (const char*) "Mixed Integer Rounding",
00494 CUTINFO_NONE},
00495 {(const char*)"2mir_cuts", new CglTwomir, (const char*) "2-MIR", CUTINFO_NONE},
00496 {(const char*)"cover_cuts", new CglKnapsackCover, (const char*) "Cover", CUTINFO_NONE},
00497 {(const char*)"clique_cuts", new CglClique, (const char*) "Clique", CUTINFO_CLIQUE},
00498 {(const char*)"lift_and_project_cuts",new CglLandP,(const char*)"Lift and Project",CUTINFO_NONE},
00499 {(const char*)"reduce_split_cuts",new CglRedSplit,(const char*) "Reduce and Split",CUTINFO_NONE},
00500 {(const char*)"flow_covers_cuts",new CglFlowCover,(const char*) "Flow cover cuts", CUTINFO_NONE},
00501 {NULL, NULL, NULL, CUTINFO_NONE}};
00502
00503 int freq;
00504
00505 for (int i=0; cutList [i]. optname; i++) {
00506
00507 options_ -> GetIntegerValue (std::string (cutList [i]. optname), freq, "bonmin.");
00508
00509 if (!freq) {
00510
00511 delete cutList [i].cglptr;
00512 continue;
00513 }
00514
00515 CuttingMethod cg;
00516 cg.frequency = freq;
00517 cg.cgl = cutList [i].cglptr;
00518 cg.id = std::string (cutList [i]. cglId);
00519 cutGenerators_.push_back (cg);
00520
00521 switch (cutList [i].extraInfo) {
00522
00523 case CUTINFO_MIG: {
00524 CglGomory *gc = dynamic_cast <CglGomory *> (cutList [i].cglptr);
00525
00526 if (!gc) break;
00527
00528 gc -> setLimitAtRoot(512);
00529 gc -> setLimit(50);
00530 }
00531 break;
00532
00533 case CUTINFO_PROBING: {
00534 CglProbing *pc = dynamic_cast <CglProbing *> (cutList [i].cglptr);
00535
00536 if (!pc) break;
00537
00538 pc->setUsingObjective(1);
00539 pc->setMaxPass(3);
00540 pc->setMaxPassRoot(3);
00541
00542 pc->setMaxProbe(10);
00543 pc->setMaxProbeRoot(50);
00544
00545 pc->setMaxLook(10);
00546 pc->setMaxLookRoot(50);
00547 pc->setMaxLookRoot(10);
00548
00549 pc->setMaxElements(200);
00550 pc->setRowCuts(3);
00551 }
00552 break;
00553
00554 case CUTINFO_CLIQUE: {
00555 CglClique *clique = dynamic_cast <CglClique *> (cutList [i].cglptr);
00556
00557 if (!clique) break;
00558
00559 clique -> setStarCliqueReport(false);
00560 clique -> setRowCliqueReport(false);
00561 clique -> setMinViolation(0.1);
00562 }
00563 break;
00564
00565
00566 default:
00567 break;
00568 }
00569 }
00570 }
00571 }