/home/coin/SVN-release/OS-2.4.0/Couenne/src/heuristics/CouenneFeasPumpConstructors.cpp

Go to the documentation of this file.
00001 /* $Id: CouenneFeasPumpConstructors.cpp 720 2011-06-27 13:31:26Z pbelotti $
00002  *
00003  * Name:    CouenneFeasPump.cpp
00004  * Authors: Pietro Belotti
00005  *          Timo Berthold, ZIB Berlin
00006  * Purpose: Constructors and service methods of the Feasibility Pump class
00007  *
00008  * This file is licensed under the Eclipse Public License (EPL)
00009  */
00010 
00011 #include <string>
00012 
00013 #include "CouenneConfig.h"
00014 #include "CouenneFeasPump.hpp"
00015 #include "CouenneFPpool.hpp"
00016 #include "CouenneMINLPInterface.hpp"
00017 #include "CouenneObject.hpp"
00018 #include "CouenneProblemElem.hpp"
00019 #include "CouenneProblem.hpp"
00020 #include "CouenneExprClone.hpp"
00021 #include "CouenneExprSub.hpp"
00022 #include "CouenneExprPow.hpp"
00023 #include "CouenneExprSum.hpp"
00024 #include "CouenneTNLP.hpp"
00025 #include "CouenneSparseMatrix.hpp"
00026 
00027 using namespace Ipopt;
00028 using namespace Couenne;
00029 
00030 // common code for initializing ipopt application
00031 void CouenneFeasPump::initIpoptApp () {
00032 
00033   // Although app_ is only used in CouenneFPSolveNLP, we need to have
00034   // an object lasting the program's lifetime as otherwise it appears
00035   // to delete the nlp pointer at deletion.
00036 
00037   if (!app_)
00038     app_ = IpoptApplicationFactory ();
00039 
00040   ApplicationReturnStatus status = app_ -> Initialize ();
00041 
00042   app_ -> Options () -> SetIntegerValue ("max_iter", 1000);
00043   app_ -> Options () -> SetIntegerValue // 0 for none, 4 for summary, 5 for iteration output
00044     ("print_level", (problem_ -> Jnlst () -> ProduceOutput (J_ERROR,         J_NLPHEURISTIC) ? 4 : 
00045                      problem_ -> Jnlst () -> ProduceOutput (J_STRONGWARNING, J_NLPHEURISTIC) ? 5 : 0));
00046 
00047   app_ -> Options () -> SetStringValue ("fixed_variable_treatment", "make_parameter");
00048 
00049   if (status != Solve_Succeeded)
00050     printf ("FP: Error in initialization\n");
00051 }
00052 
00053 
00054 // Constructor ////////////////////////////////////////////////// 
00055 CouenneFeasPump::CouenneFeasPump (CouenneProblem *couenne,
00056                                   CouenneCutGenerator *cg,
00057                                   Ipopt::SmartPtr<Ipopt::OptionsList> options):
00058   CbcHeuristic         (),
00059 
00060   problem_             (couenne),
00061   couenneCG_           (cg),
00062   nlp_                 (NULL),
00063   app_                 (NULL),
00064   milp_                (NULL),
00065   postlp_              (NULL),
00066   pool_                (NULL),
00067 
00068   numberSolvePerLevel_ (5), // if options are not valid, don't overuse FP
00069 
00070   multDistNLP_         (1.), // settings for classical FP
00071   multHessNLP_         (0.),
00072   multObjFNLP_         (0.),
00073 
00074   multDistMILP_        (1.),
00075   multHessMILP_        (0.),
00076   multObjFMILP_        (0.),
00077 
00078   compDistInt_         (FP_DIST_INT),
00079   milpCuttingPlane_    (FP_CUT_NONE),
00080   nSepRounds_          (0),
00081   maxIter_             (COIN_INT_MAX),
00082   useSCIP_             (false),
00083   milpMethod_          (0),
00084   tabuMgt_             (FP_TABU_NONE) {
00085 
00086   if (IsValid (options)) {
00087 
00088     std::string s;
00089 
00090     int compareTerm;
00091 
00092     options -> GetIntegerValue ("feas_pump_iter",       maxIter_,             "couenne.");
00093     options -> GetIntegerValue ("feas_pump_level",      numberSolvePerLevel_, "couenne.");
00094     options -> GetIntegerValue ("feas_pump_milpmethod", milpMethod_,          "couenne.");
00095 
00096     options -> GetNumericValue ("feas_pump_mult_dist_nlp",  multDistNLP_,     "couenne.");
00097     options -> GetNumericValue ("feas_pump_mult_hess_nlp",  multHessNLP_,     "couenne.");
00098     options -> GetNumericValue ("feas_pump_mult_objf_nlp",  multObjFNLP_,     "couenne.");
00099 
00100     options -> GetNumericValue ("feas_pump_mult_dist_milp", multDistMILP_,    "couenne.");
00101     options -> GetNumericValue ("feas_pump_mult_hess_milp", multHessMILP_,    "couenne.");
00102     options -> GetNumericValue ("feas_pump_mult_objf_milp", multObjFMILP_,    "couenne.");
00103 
00104     options -> GetStringValue  ("feas_pump_convcuts", s, "couenne."); 
00105 
00106     milpCuttingPlane_ = 
00107       (s == "none")       ? FP_CUT_NONE       :
00108       (s == "integrated") ? FP_CUT_INTEGRATED : 
00109       (s == "postcut")    ? FP_CUT_POST       : FP_CUT_EXTERNAL;
00110 
00111     options -> GetIntegerValue ("feas_pump_nseprounds", nSepRounds_, "couenne."); 
00112 
00113     options -> GetStringValue  ("feas_pump_vardist",  s, "couenne."); 
00114 
00115     compDistInt_ = 
00116       (s == "integer") ? FP_DIST_INT : 
00117       (s == "all")     ? FP_DIST_ALL : FP_DIST_POST;
00118 
00119     options -> GetIntegerValue ("feas_pump_milpmethod", milpMethod_, "couenne."); 
00120     options -> GetIntegerValue ("feas_pump_poolcomp",   compareTerm, "couenne."); 
00121 
00122     pool_ = new CouenneFPpool ((enum what_to_compare) compareTerm);
00123 
00124     options -> GetStringValue  ("feas_pump_tabumgt", s, "couenne.");
00125 
00126     tabuMgt_ = 
00127       (s == "pool")    ? FP_TABU_POOL    :
00128       (s == "perturb") ? FP_TABU_PERTURB : 
00129       (s == "cut")     ? FP_TABU_CUT     : FP_TABU_NONE;
00130 
00131     options -> GetStringValue  ("feas_pump_usescip", s, "couenne."); 
00132 
00133 #ifdef COIN_HAS_SCIP
00134     useSCIP_ = (s == "yes");
00135     if (milpMethod_ < 0)
00136       milpMethod_ = 0;
00137 #else
00138     if (s == "yes") 
00139       problem_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, "Warning: you have set feas_pump_usescip to true, but SCIP is not installed.\n");
00140 #endif
00141 
00142   } else
00143     pool_ = new CouenneFPpool (SUM_NINF);
00144 
00145   setHeuristicName ("Couenne Feasibility Pump");
00146 
00147   initIpoptApp ();
00148 }
00149 
00150   
00151 // Copy constructor ///////////////////////////////////////////// 
00152 CouenneFeasPump::CouenneFeasPump (const CouenneFeasPump &other) {
00153 
00154   operator= (other);
00155 
00156   // CbcHeuristic         (other),
00157 
00158   // problem_             (other. problem_),
00159   // couenneCG_           (other. couenneCG_),
00160   // nlp_                 (other. nlp_),
00161   // app_                 (NULL),
00162   // milp_                (other.milp_   ? other. milp_   -> clone () : NULL),
00163   // postlp_              (other.postlp_ ? other. postlp_ -> clone () : NULL),
00164   // pool_                (NULL),
00165 
00166   // numberSolvePerLevel_ (other. numberSolvePerLevel_),
00167 
00168   // multDistNLP_         (other. multDistNLP_),
00169   // multHessNLP_         (other. multHessNLP_),
00170   // multObjFNLP_         (other. multObjFNLP_),
00171                                        
00172   // multDistMILP_        (other. multDistMILP_),
00173   // multHessMILP_        (other. multHessMILP_),
00174   // multObjFMILP_        (other. multObjFMILP_),
00175 
00176   // compDistInt_         (other. compDistInt_),
00177   // milpCuttingPlane_    (other. milpCuttingPlane_),
00178   // nSepRounds_          (other. nSepRounds_),
00179 
00180   // maxIter_             (other. maxIter_),
00181   // useSCIP_             (other. useSCIP_),
00182   // milpMethod_          (other. milpMethod_),
00183   // tabuMgt_             (other. tabuMgt_) {
00184 
00185   // if (other. pool_)
00186   //   pool_ = new CouenneFPpool (*(other. pool_));
00187 
00188   // for (std::set <CouenneFPsolution, compareSol>::const_iterator i = other.tabuPool_.begin (); 
00189   //      i != other.tabuPool_.end ();
00190   //      ++i)
00191   //   tabuPool_. insert (CouenneFPsolution (*i));
00192 
00193   // initIpoptApp ();
00194 }
00195 
00196 
00197 // Clone //////////////////////////////////////////////////////// 
00198 CbcHeuristic *CouenneFeasPump::clone () const
00199 {return new CouenneFeasPump (*this);}
00200 
00201 
00202 // Assignment operator ////////////////////////////////////////// 
00203 CouenneFeasPump &CouenneFeasPump::operator= (const CouenneFeasPump & rhs) {
00204 
00205   if (this != &rhs) {
00206 
00207     CbcHeuristic::operator= (rhs);
00208 
00209     problem_             = rhs. problem_;
00210     couenneCG_           = rhs. couenneCG_;
00211     nlp_                 = rhs. nlp_;
00212     app_                 = NULL;
00213     milp_                = rhs. milp_   ? rhs. milp_   -> clone () : NULL;
00214     postlp_              = rhs. postlp_ ? rhs. postlp_ -> clone () : NULL;
00215     pool_                = NULL;
00216 
00217     numberSolvePerLevel_ = rhs. numberSolvePerLevel_;
00218 
00219     multDistNLP_         = rhs. multDistNLP_;
00220     multHessNLP_         = rhs. multHessNLP_;
00221     multObjFNLP_         = rhs. multObjFNLP_;
00222                                        
00223     multDistMILP_        = rhs. multDistMILP_;
00224     multHessMILP_        = rhs. multHessMILP_;
00225     multObjFMILP_        = rhs. multObjFMILP_;
00226 
00227     compDistInt_         = rhs. compDistInt_;
00228     milpCuttingPlane_    = rhs. milpCuttingPlane_;
00229     nSepRounds_          = rhs. nSepRounds_;
00230     maxIter_             = rhs. maxIter_;
00231     useSCIP_             = rhs. useSCIP_;
00232     milpMethod_          = rhs. milpMethod_;
00233     tabuMgt_             = rhs. tabuMgt_;
00234 
00235     if (rhs. pool_)
00236       pool_ = new CouenneFPpool (*(rhs. pool_));
00237 
00238     for (std::set <CouenneFPsolution, compareSol>::const_iterator i = rhs.tabuPool_.begin (); 
00239          i != rhs.tabuPool_.end ();
00240          ++i)
00241       tabuPool_. insert (CouenneFPsolution (*i));
00242 
00243     initIpoptApp ();
00244   }
00245 
00246   return *this;
00247 }
00248 
00249 
00250 // Destructor /////////////////////////////////////////////////// 
00251 CouenneFeasPump::~CouenneFeasPump () {
00252 
00253   if (pool_)   delete pool_;
00254   if (app_)    delete app_;
00255   if (milp_)   delete milp_;
00256   if (postlp_) delete postlp_;
00257 
00258   //if (nlp_) delete nlp_; // already deleted by "delete app_;"
00259 }
00260 
00261 
00265 expression *CouenneFeasPump::updateNLPObj (const double *iSol) {
00266 
00267   expression **list = NULL; 
00268 
00269   int nTerms = 0;
00270 
00271   const double *iS = iSol;
00272 
00273   if ((multHessNLP_ == 0.) || 
00274       (nlp_ -> optHessian () == NULL)) {
00275 
00276     list = new expression * [1 + problem_ -> nVars ()];
00277 
00278     // here the objective function is ||x-x^0||_2^2
00279 
00280     // create the argument list (x_i - x_i^0)^2 for all i's
00281     for (int i=0; i<problem_ -> nVars (); i++) {
00282 
00283       if (compDistInt_ == FP_DIST_INT && 
00284           !(problem_ -> Var (i) -> isInteger ()))
00285         continue;
00286 
00287       expression *base;
00288 
00289       if      (*iS == 0.) base =              new exprClone (problem_ -> Var (i));
00290       else if (*iS <  0.) base = new exprSum (new exprClone (problem_ -> Var (i)), new exprConst (-*iS));
00291       else                base = new exprSub (new exprClone (problem_ -> Var (i)), new exprConst  (*iS));
00292 
00293       ++iS;
00294 
00295       list [nTerms++] = new exprPow (base, new exprConst (2.));
00296     }
00297 
00298   } else {
00299 
00300     // possibly a much larger set of operands
00301 
00302     list = new expression * [problem_ -> nVars () * 
00303                              problem_ -> nVars ()];
00304 
00305     // here the objective function is 
00306     //
00307     // ||P(x-x^0)||_2^2 = (x-x^0)' P'P (x-x^0)
00308     //
00309     // with P'P positive semidefinite stored in CouenneTNLP::optHessian_
00310 
00311     // P is a convex combination, with weights multDistMILP_ and
00312     // multHessMILP_, of the distance and the Hessian respectively
00313 
00314     bool *diag = NULL;
00315 
00316     if (multDistNLP_ > 0.) { // only use this if distance is used
00317 
00318       diag = new bool [problem_ -> nVars ()];
00319       CoinFillN (diag, problem_ -> nVars (), false);
00320     }
00321 
00322     int    *row = nlp_ -> optHessian () -> row ();
00323     int    *col = nlp_ -> optHessian () -> col ();
00324     double *val = nlp_ -> optHessian () -> val ();
00325 
00326     int     num = nlp_ -> optHessian () -> num ();
00327 
00328     // Add Hessian part -- only lower triangular part
00329     for (int i=0; i<num; ++i, ++row, ++col, ++val) {
00330 
00331       // check if necessary given options
00332 
00333       if (compDistInt_ == FP_DIST_INT && 
00334           !(problem_ -> Var (*row) -> isInteger () &&
00335             problem_ -> Var (*col) -> isInteger ()))
00336         continue;
00337 
00338       // second, only do subdiagonal elements
00339 
00340       if (*col < *row) { // that is, lower triangular
00341 
00342         if (2. * *val == 1.) // check if this would have trivial coefficient when doubled (off-diagonal element)
00343 
00344           list [nTerms++] = new exprMul (new exprSub (new exprClone (problem_ -> Var (*row)), new exprConst (iSol [*row])),
00345                                          new exprSub (new exprClone (problem_ -> Var (*col)), new exprConst (iSol [*col])));
00346 
00347         else if (fabs (*val) > COUENNE_EPS) { // we don't need extreme precision...
00348 
00349           expression **mlist = new expression * [3];
00350 
00351           mlist [0] = new exprConst (2. * *val);  // twice elements off diagonal
00352           mlist [1] = new exprSub (new exprClone (problem_ -> Var (*row)), new exprConst (iSol [*row]));
00353           mlist [2] = new exprSub (new exprClone (problem_ -> Var (*col)), new exprConst (iSol [*col]));
00354 
00355           list [nTerms++] = new exprMul (mlist, 3);
00356         }
00357 
00358       } else if (*col == *row) { // or diagonal elements
00359 
00360         if (multDistNLP_ > 0.)
00361           diag [*col] = true;
00362 
00363         if (*val + multDistNLP_ == 1.)
00364 
00365           list [nTerms++] = new exprPow (new exprSub (new exprClone (problem_ -> Var (*row)), 
00366                                                       new exprConst (iSol [*row])), new exprConst (2.));
00367 
00368         else if (fabs (*val + multDistNLP_) > COUENNE_EPS)
00369 
00370           list [nTerms++] = new exprMul (new exprConst (*val + multDistNLP_),
00371                                          new exprPow (new exprSub (new exprClone (problem_ -> Var (*row)), 
00372                                                                    new exprConst (iSol [*row])), new exprConst (2.)));
00373       }
00374     }
00375 
00376     // third, add missing diagonal elements
00377       
00378     if (multDistNLP_ > 0.) {
00379 
00380       // create the argument list (x_i - x_i^0)^2 for all i's
00381       for (int i=0; i<problem_ -> nVars (); i++) {
00382           
00383         if ((compDistInt_ == FP_DIST_INT && 
00384              !(problem_ -> Var (i) -> isInteger ())) ||
00385             diag [i])
00386           continue;
00387           
00388         expression *base;
00389 
00390         if      (*iS == 0.) base =              new exprClone (problem_ -> Var (i));
00391         else if (*iS <  0.) base = new exprSum (new exprClone (problem_ -> Var (i)), new exprConst (-*iS));
00392         else                base = new exprSub (new exprClone (problem_ -> Var (i)), new exprConst  (*iS));
00393 
00394         ++iS;
00395 
00396         list [nTerms++] = new exprPow (base, new exprConst (2.));
00397       }
00398 
00399       delete [] diag;
00400     }
00401   }
00402 
00403   if (multObjFNLP_ != 0.) 
00404     list [nTerms++] = new exprMul (new exprConst (multObjFNLP_),
00405                                    new exprClone (problem_ -> Obj (0) -> Body ()));
00406 
00407   // resize list
00408 
00409   expression **tmp = list;
00410   list = CoinCopyOfArray (tmp, nTerms);
00411   delete [] tmp;
00412 
00413   return new exprSum (list, nTerms);
00414 }
00415 
00416 
00419 void CouenneFeasPump::fixIntVariables (double *sol) {
00420 
00421   assert (sol);
00422 
00423   t_chg_bounds *chg_bds = new t_chg_bounds [problem_ -> nVars ()];
00424 
00425   for (int i = problem_ -> nVars (); i--;)
00426 
00427     if (problem_ -> Var (i) -> isInteger ()) {
00428 
00429       double 
00430         value = sol [i],
00431         rUp   = ceil  (value - COUENNE_EPS),
00432         rDn   = floor (value + COUENNE_EPS);
00433 
00434       // If numerics or sol[i] fractional, set to closest
00435 
00436       value = 
00437         (rUp < rDn + 0.5)           ? rUp : 
00438         (rUp - value < value - rDn) ? rUp : rDn;
00439 
00440 #define INT_NLP_BRACKET 1e-6
00441 
00442       problem_ -> Lb (i) = value - INT_NLP_BRACKET;
00443       problem_ -> Ub (i) = value + INT_NLP_BRACKET;
00444 
00445       chg_bds [i].setLower (t_chg_bounds::CHANGED); 
00446       chg_bds [i].setUpper (t_chg_bounds::CHANGED); 
00447     }
00448 
00449   // Now, to restrict the bounding box even more (and hopefully make
00450   // it easier) apply BT
00451 
00452   problem_ -> btCore (chg_bds);
00453 
00454   delete [] chg_bds;
00455 }
00456 
00457 
00459 void CouenneFeasPump::registerOptions (Ipopt::SmartPtr <Bonmin::RegisteredOptions> roptions) {
00460 
00461   roptions -> AddStringOption2
00462     ("feas_pump_heuristic",
00463      "Apply the nonconvex Feasibility Pump",
00464      "no",
00465      "no","",
00466      "yes","",
00467      "An implementation of the Feasibility Pump for nonconvex MINLPs");
00468 
00469   roptions -> AddLowerBoundedIntegerOption
00470     ("feas_pump_level",
00471      "Specify the logarithm of the number of feasibility pumps to perform" 
00472      " on average for each level of given depth of the tree.",
00473      -1,
00474      3, "Solve as many nlp's at the nodes for each level of the tree. "
00475      "Nodes are randomly selected. If for a "
00476      "given level there are less nodes than this number nlp are solved for every nodes. "
00477      "For example if parameter is 8, nlp's are solved for all node until level 8, " 
00478      "then for half the node at level 9, 1/4 at level 10.... "
00479      "Set to -1 to perform at all nodes.");
00480 
00481   roptions -> AddLowerBoundedIntegerOption
00482     ("feas_pump_iter",
00483      "Number of iterations in the main Feasibility Pump loop",
00484      -1,
00485      10, "-1 means no limit");
00486 
00487   // six options
00488 
00489   char option [40];
00490   char help   [250];
00491 
00492   std::string terms [] = {"dist", "hess", "objf"};
00493   std::string types [] = {"nlp",  "milp"};
00494 
00495   for   (int j=0; j<3; j++) 
00496     for (int i=0; i<2; i++) {
00497 
00498       sprintf (option, "feas_pump_mult_%s_%s",                                              terms [j].c_str (), types [i].c_str ());
00499       sprintf (help,       "Weight of the %s in the distance function of the %s problem", 
00500                !(strcmp ("dist", terms [j].c_str ())) ? "distance" : 
00501                !(strcmp ("hess", terms [j].c_str ())) ? "Hessian"  : "original objective function",             types [i].c_str ());
00502 
00503       roptions -> AddBoundedNumberOption
00504         (option, help,
00505          0., false,
00506          1., false,
00507          0., "0: no weight, 1: full weight");
00508     }
00509 
00510   roptions -> AddStringOption3
00511     ("feas_pump_vardist",
00512      "Distance computed on integer-only or on both types of variables, in different flavors.",
00513      "integer",
00514      "integer",         "Only compute the distance based on integer coordinates (use post-processing if numerical errors occur)",
00515      "all",             "Compute the distance using continuous and integer variables",
00516      "int-postprocess", "Use a post-processing fixed-IP LP to determine a closest-point solution");
00517 
00518   roptions -> AddStringOption4
00519     ("feas_pump_convcuts",
00520      "Separate MILP-feasible, MINLP-infeasible solution during or after MILP solver.",
00521      "none",
00522      "integrated", "Done within the MILP solver in a branch-and-cut fashion",
00523      "external",   "Done after the MILP solver, in a Benders-like fashion",
00524      "postcut",    "Do one round of cuts and proceed with NLP",
00525      "none",       "Just proceed to the NLP");
00526 
00527   roptions -> AddBoundedIntegerOption
00528     ("feas_pump_nseprounds",
00529      "Number of rounds that separate convexification cuts. Must be at least 1",
00530      1, 1e5, 4,
00531      "");
00532 
00533   roptions -> AddStringOption4
00534     ("feas_pump_tabumgt",
00535      "Retrieval of MILP solutions when the one returned is unsatisfactory",
00536      "pool",
00537      "pool",       "Use a solution pool and replace unsatisfactory solution with Euclidean-closest in pool",
00538      "perturb",    "Randomly perturb unsatisfactory solution",
00539      "cut",        "Separate convexification cuts",
00540      "none",       "Bail out of feasibility pump");
00541 
00542   roptions -> AddStringOption2
00543     ("feas_pump_usescip",
00544      "Should SCIP be used to solve the MILPs?",
00545 #ifdef COIN_HAS_SCIP
00546      "yes", // we want it by default if SCIP is available
00547 #else
00548      "no",  // otherwise switch it off and warn the user if turned on
00549 #endif
00550      "no",  "Use Cbc's branch-and-cut to solve the MILP",
00551      "yes", "Use SCIP's branch-and-cut or heuristics (see feas_pump_milpmethod option) to solve the MILP",
00552      "");
00553 
00554   roptions -> AddBoundedIntegerOption
00555     ("feas_pump_milpmethod",
00556      "How should the integral solution be constructed?",
00557      -1, 4, -1, 
00558        "0: automatic, 1: aggressive heuristics, large node limit, 2: default, node limit, 3: RENS, 4: Objective Feasibility Pump,  -1: solve MILP completely");
00559 
00560   roptions -> AddBoundedIntegerOption
00561     ("feas_pump_poolcomp",
00562      "Priority field to compare solutions in FP pool",
00563      0, 2, 0, 
00564        "0: total number of infeasible objects (integer and nonlinear), 1: maximum infeasibility (integer or nonlinear), 2: objective value.");
00565 }

Generated on Thu Sep 22 03:05:58 2011 by  doxygen 1.4.7