/home/coin/SVN-release/OS-1.1.1/Bonmin/experimental/NotConvex/BonCouenneSetup.cpp

Go to the documentation of this file.
00001 // (C) Copyright International Business Machines Corporation 2007
00002 // All Rights Reserved.
00003 // This code is published under the Common Public License.
00004 //
00005 // Authors :
00006 // Pierre Bonami, International Business Machines Corporation
00007 //
00008 // Date : 04/18/2007
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 // MILP cuts
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 // Ampl includes
00040 #include "asl.h"
00041 #include "getstub.h"
00042 
00043 
00044 namespace Bonmin{
00045   
00046   SmartAsl::~SmartAsl(){
00047     //Code from Ipopt::AmplTNLP to free asl
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     //if (CouennePtr_)
00074     //delete CouennePtr_;
00075   }
00076 
00077   void CouenneSetup::InitializeCouenne (char **& argv) {
00078     /* Get the basic options. */
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     /* Read the model in various places. */
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     /* Initialize Couenne cut generator.*/
00115     //int ivalue, num_points;
00116     //options()->GetEnumValue("convexification_type", ivalue,"bonmin.");
00117     //options()->GetIntegerValue("convexification_points",num_points,"bonmin.");
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     // as per instructions by John Forrest, to get changed bounds
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     /* Setup log level*/
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     // In case there are no discrete variables, we have already a
00146     // heuristic solution for which create a initialization heuristic
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 (); // only adds embedded SOS objects
00166 
00167     // Add Couenne SOS ///////////////////////////////////////////////////////////////
00168 
00169     std::string s;
00170     int nSOS = 0;
00171 
00172     // allocate sufficient space for both nonlinear variables and SOS's
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       //printf ("==================== found %d SOS\n", nSOS);
00180       //nonlinearSolver () -> addObjects (nSOS, objects);
00181       continuousSolver () -> addObjects (nSOS, objects);
00182 
00183       for (int i=0; i<nSOS; i++)
00184         delete objects [i];
00185       delete [] objects;
00186     }
00187 
00188     //model -> assignSolver (continuousSolver_, true);
00189     //continuousSolver_ = model -> solver();
00190 
00191     // Add Couenne objects for branching /////////////////////////////////////////////
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, // if no SOS then objects is empty
00210       nVars = couenneProb -> nVars ();
00211 
00212     objects = new OsiObject* [couenneProb -> nVars ()];
00213 
00214     int contObjPriority = 2000; // default object priority -- it is 1000 for integers and 10 for SOS
00215 
00216     options () -> GetIntegerValue ("cont_var_priority", contObjPriority, "bonmin.");
00217 
00218     for (int i = 0; i < nVars; i++) { // for each variable
00219 
00220       exprVar *var = couenneProb -> Var (i);
00221 
00222       // we only want enabled variables
00223       if (var -> Multiplicity () == 0) 
00224         continue;
00225 
00226       switch (objType) {
00227 
00228       case CouenneObject::EXPR_OBJ:
00229 
00230         // if this variable is associated with a nonlinear function
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         // branching objects on variables
00243         if // comment three lines below for linear variables too
00244           (couenneProb -> Dependence () [var -> Index ()] . size () > 0) {  // has indep
00245            //|| ((var -> Type () == AUX) &&                                  // or, aux 
00246            //    (var -> Image () -> Linearity () > LINEAR))) {              // of nonlinear
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         // branching objects on variables
00258         if // comment three lines below for linear variables too
00259           (couenneProb -> Dependence () [var -> Index ()] . size () > 0) { // has indep
00260           //|| ((var -> Type () == AUX) &&                      // or, aux 
00261           //(var -> Image () -> Linearity () > LINEAR))) { // of nonlinear
00262 
00263           objects [nobj] = new CouenneVTObject (couenneProb, var, this, journalist ());
00264           objects [nobj++] -> setPriority (contObjPriority);
00265         }
00266 
00267         break;
00268       }
00269     }
00270 
00271     // Add objects /////////////////////////////////
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     // Setup Convexifier generators ////////////////////////////////////////////////
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       // set cut gen pointer
00295       dynamic_cast <CouenneSolverInterface *> 
00296         (continuousSolver_) -> setCutGenPtr (couenneCg);
00297     }
00298 
00299     // disjunctive cuts generator added AFTER 
00300 
00301     // add other cut generators -- test for integer variables first
00302     if (couenneCg -> Problem () -> nIntVars () > 0)
00303       addMilpCutGenerators ();
00304 
00305     CouennePtr_ = couenneCg;
00306 
00307     // Setup heuristic to solve nlp problems. /////////////////////////////////
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       //nlpHeuristic->setMaxNlpInf(1e-4);
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     // Add Branching rules ///////////////////////////////////////////////////////
00328 
00329     int varSelection;
00330     if (!options_->GetEnumValue("variable_selection",varSelection,"bonmin.")) {
00331       // change the default for Couenne
00332       varSelection = OSI_SIMPLE;
00333     }
00334 
00335     switch (varSelection) {
00336 
00337     case OSI_STRONG: { // strong branching
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: // default choice
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     // Add disjunctive cuts ///////////////////////////////////////////////////////
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, // if true, use strong branching candidates
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       // change default for Couenne
00381       nodeComparisonMethod_ = bestBound;
00382     }
00383     else {
00384       nodeComparisonMethod_ = NodeComparison(ival);
00385     }
00386 
00387     if(intParam_[NumCutPasses] < 2)
00388     intParam_[NumCutPasses] = 2;
00389 
00390     // Tell Cbc not to check again if a solution returned from
00391     // heuristic is indeed feasible
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     // copied from BonminSetup::registerMilpCutGenerators(), in
00437     // BonBonminSetup.cpp
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         // Number of unsatisfied variables to look at
00542         pc->setMaxProbe(10);
00543         pc->setMaxProbeRoot(50);
00544         // How far to follow the consequences
00545         pc->setMaxLook(10);
00546         pc->setMaxLookRoot(50);
00547         pc->setMaxLookRoot(10);
00548         // Only look at rows with fewer than this number of elements
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         //case CUTINFO_NONE:
00566       default:
00567         break;
00568       }
00569     }
00570   }
00571 }

Generated on Tue Sep 30 03:01:22 2008 by  doxygen 1.4.7