/home/coin/SVN-release/OS-1.1.1/Bonmin/experimental/NotConvex/BonNlpHeuristic.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/09/2007
00009 
00010 #include "BonNlpHeuristic.hpp"
00011 #include "BonCouenneInterface.hpp"
00012 #include "CouenneObject.hpp"
00013 #include "CouenneProblem.hpp"
00014 #include "CbcCutGenerator.hpp"
00015 #include "CbcBranchActual.hpp"
00016 #include "BonAuxInfos.hpp"
00017 #include "CoinHelperFunctions.hpp"
00018 
00019 #include "CouenneCutGenerator.hpp"
00020 #include "CouenneProblem.hpp"
00021 
00022 namespace Bonmin{
00023   NlpSolveHeuristic::NlpSolveHeuristic():
00024     CbcHeuristic(),
00025     nlp_(NULL),
00026     hasCloned_(false),
00027     maxNlpInf_(maxNlpInf_0),
00028     numberSolvePerLevel_(-1),
00029     couenne_(NULL){
00030     setHeuristicName("NlpSolveHeuristic");
00031   }
00032   
00033   NlpSolveHeuristic::NlpSolveHeuristic(CbcModel & model, OsiSolverInterface &nlp, bool cloneNlp, CouenneProblem * couenne):
00034   CbcHeuristic(model), nlp_(&nlp), hasCloned_(cloneNlp),maxNlpInf_(maxNlpInf_0),
00035   numberSolvePerLevel_(-1),
00036   couenne_(couenne){
00037     setHeuristicName("NlpSolveHeuristic");
00038     if(cloneNlp)
00039       nlp_ = nlp.clone();
00040   }
00041   
00042   NlpSolveHeuristic::NlpSolveHeuristic(const NlpSolveHeuristic & other):
00043   CbcHeuristic(other), nlp_(other.nlp_), 
00044   hasCloned_(other.hasCloned_),
00045   maxNlpInf_(other.maxNlpInf_),
00046   numberSolvePerLevel_(other.numberSolvePerLevel_),
00047   couenne_(other.couenne_){
00048     if(hasCloned_ && nlp_ != NULL)
00049       nlp_ = other.nlp_->clone();
00050   }
00051   
00052   CbcHeuristic * 
00053   NlpSolveHeuristic::clone() const{
00054     return new NlpSolveHeuristic(*this);
00055   }
00056   
00057   NlpSolveHeuristic &
00058   NlpSolveHeuristic::operator=(const NlpSolveHeuristic & rhs){
00059     if(this != &rhs){
00060       CbcHeuristic::operator=(rhs);
00061       if(hasCloned_ && nlp_)
00062         delete nlp_;
00063       
00064       hasCloned_ = rhs.hasCloned_;
00065       if(nlp_ != NULL){
00066         if(hasCloned_)
00067           nlp_ = rhs.nlp_->clone();
00068         else
00069           nlp_ = rhs.nlp_;
00070       }
00071     }
00072     maxNlpInf_ = rhs.maxNlpInf_;
00073     numberSolvePerLevel_ = rhs.numberSolvePerLevel_;
00074     couenne_ = rhs.couenne_;
00075     return *this;
00076   }
00077   
00078   NlpSolveHeuristic::~NlpSolveHeuristic(){
00079     if(hasCloned_)
00080       delete nlp_;
00081     nlp_ = NULL;
00082   }
00083   
00084   void
00085   NlpSolveHeuristic::setNlp(OsiSolverInterface &nlp, bool cloneNlp){
00086     if(hasCloned_ && nlp_ != NULL)
00087       delete nlp_;
00088     hasCloned_ = cloneNlp;
00089     if(cloneNlp)
00090       nlp_ = nlp.clone();
00091     else
00092       nlp_ = &nlp;
00093   }
00094   
00095   void
00096   NlpSolveHeuristic::setCouenneProblem(CouenneProblem * couenne){
00097     couenne_ = couenne;}
00098 
00099 
00100   int
00101   NlpSolveHeuristic::solution( double & objectiveValue, double * newSolution){
00102     OsiSolverInterface * solver = model_->solver();
00103 
00104     OsiAuxInfo * auxInfo = solver->getAuxiliaryInfo();
00105     BabInfo * babInfo = dynamic_cast<BabInfo *> (auxInfo);
00106 
00107     if(babInfo){
00108       babInfo->setHasNlpSolution(false);
00109       if(babInfo->infeasibleNode()){
00110         return 0;
00111       }
00112     }
00113 
00114     // if too deep in the BB tree, only run NLP heuristic if
00115     // feasibility is low
00116     bool too_deep = false;
00117 
00118     // check depth
00119     if (numberSolvePerLevel_ > -1){
00120       if (numberSolvePerLevel_ == 0) 
00121         return 0;
00122 
00123       const int depth = (model_ -> currentNode ()) ? model_ -> currentNode () -> depth () : 0;
00124 
00125       //if (CoinDrand48 () > pow (2., numberSolvePerLevel_ - depth))
00126       if (CoinDrand48 () > 1. / CoinMax 
00127           (1., (double) ((depth - numberSolvePerLevel_) * (depth - numberSolvePerLevel_))))
00128         too_deep = true;
00129     }
00130 
00131     if (too_deep)
00132       return 0;
00133 
00134     double *lower = new double [couenne_ -> nVars ()];
00135     double *upper = new double [couenne_ -> nVars ()];
00136 
00137     CoinFillN (lower, couenne_ -> nVars (), -COUENNE_INFINITY);
00138     CoinFillN (upper, couenne_ -> nVars (),  COUENNE_INFINITY);
00139 
00140     CoinCopyN (solver->getColLower(), nlp_ -> getNumCols (), lower);
00141     CoinCopyN (solver->getColUpper(), nlp_ -> getNumCols (), upper);
00142 
00143     /*printf ("-- int candidate, before: ");
00144     for (int i=0; i<couenne_ -> nOrig (); i++) 
00145       printf ("[%g %g] ", lower [i], upper [i]);
00146       printf ("\n");*/
00147 
00148     const double * solution = solver->getColSolution();
00149     OsiBranchingInformation info (solver, true);
00150     const int & numberObjects = model_->numberObjects();
00151     OsiObject ** objects = model_->objects();
00152     double maxInfeasibility = 0;
00153 
00154     bool haveRoundedIntVars = false;
00155 
00156     for(int i = 0 ; i < numberObjects ; i++){
00157       CouenneObject * couObj = dynamic_cast <CouenneObject *> (objects [i]);
00158       if (couObj) {
00159         if (too_deep) { // only test infeasibility if BB level is high
00160           int dummy;
00161           double infeas;
00162           maxInfeasibility = max ( maxInfeasibility, infeas = couObj->infeasibility(&info, dummy));
00163           if(maxInfeasibility > maxNlpInf_){
00164             delete [] lower;
00165             delete [] upper;
00166             return 0;
00167           }
00168         }
00169       } else {
00170 
00171         OsiSimpleInteger * intObj = dynamic_cast<OsiSimpleInteger *>(objects[i]);
00172 
00173         if (intObj) {
00174           const int & i = intObj -> columnNumber ();
00175           // Round the variable in the solver
00176           double value = solution [i];
00177           if (value < lower[i])
00178             value = lower[i];
00179           else if(value > upper[i])
00180             value = upper[i];
00181 
00182           double rounded = floor (value + 0.5);
00183 
00184           if (fabs (value - rounded) > COUENNE_EPS) {
00185             haveRoundedIntVars = true;
00186             //value = rounded;
00187           }
00188 
00189           // fix bounds anyway, if a better candidate is not found
00190           // below at least we have an integer point
00191           //lower[i] = upper[i] = value;
00192         }
00193         else{
00194            throw CoinError("Bonmin::NlpSolveHeuristic","solution",
00195                            "Unknown object.");
00196         }
00197       }
00198     }
00199 
00200     // if here, it means the infeasibility is not too high. Generate a
00201     // better integer point as there are rounded integer variables
00202 
00203     bool skipOnInfeasibility = false;
00204 
00205     double *Y = new double [couenne_ -> nVars ()];
00206     CoinFillN (Y, couenne_ -> nVars (), 0.);
00207     CoinCopyN (solution, nlp_ -> getNumCols (), Y);
00208 
00209     /*printf ("-- int candidate, upon call: ");
00210     for (int i=0; i<couenne_ -> nOrig (); i++) 
00211       if (couenne_ -> Var (i) -> isInteger ())
00212         printf ("[%g <%g> %g] ", lower [i], Y [i], upper [i]);
00213       else printf ("%g ", Y [i]);
00214       printf ("\n");*/
00215 
00216     if (haveRoundedIntVars) // create "good" integer candidate for Ipopt
00217       skipOnInfeasibility = (couenne_ -> getIntegerCandidate (solution, Y, lower, upper) < 0);
00218 
00219     /*printf ("-- int candidate, after: ");
00220     for (int i=0; i<couenne_ -> nOrig (); i++) 
00221       if (couenne_ -> Var (i) -> isInteger ())
00222         printf ("[%g <%g> %g] ", lower [i], Y [i], upper [i]);
00223       else printf ("%g ", Y [i]);
00224       printf ("\n");*/
00225 
00226     bool foundSolution = false;
00227 
00228     if (haveRoundedIntVars && skipOnInfeasibility) 
00229       // no integer initial point could be found, make up some random rounding
00230 
00231       for (int i = couenne_ -> nOrigVars (); i--;) 
00232 
00233         if (couenne_ -> Var (i) -> isDefinedInteger ())
00234           lower [i] = upper [i] = Y [i] = 
00235             (CoinDrand48 () < 0.5) ? 
00236             floor (Y [i] + COUENNE_EPS) : 
00237             ceil  (Y [i] - COUENNE_EPS);
00238 
00239         else if (lower [i] > upper [i]) { 
00240 
00241           // sanity check (should avoid problems in ex1263 with
00242           // couenne.opt.obbt)
00243 
00244           double swap = lower [i];
00245           lower [i] = upper [i];
00246           upper [i] = swap;
00247         }
00248 
00249 
00250     {
00251       //        printf ("[%g <%g> %g] ", lower [i], Y [i], upper [i]);
00252 
00253       /*printf ("int candidate: ");
00254         for (int i=0; i<couenne_ -> nOrig (); i++) 
00255         if (couenne_ -> Var (i) -> isInteger ())
00256         printf ("[%g <%g> %g] ", lower [i], Y [i], upper [i]);
00257         else printf ("%g ", Y [i]);
00258         printf ("\n");*/
00259 
00260       // Now set column bounds and solve the NLP with starting point
00261       double * saveColLower = CoinCopyOfArray (nlp_ -> getColLower (), nlp_ -> getNumCols ());
00262       double * saveColUpper = CoinCopyOfArray (nlp_ -> getColUpper (), nlp_ -> getNumCols ());
00263 
00264       nlp_ -> setColLower    (lower);
00265       nlp_ -> setColUpper    (upper);
00266       nlp_ -> setColSolution (Y);
00267 
00268       // apply NLP solver /////////////////////////////////
00269       nlp_ -> initialSolve ();
00270 
00271       double obj = (nlp_ -> isProvenOptimal()) ? nlp_ -> getObjValue (): COIN_DBL_MAX;
00272 
00273       if (nlp_ -> isProvenOptimal () &&
00274           (obj < couenne_ -> getCutOff ()) &&
00275           couenne_ -> checkNLP (nlp_ -> getColSolution (), obj)) {
00276 
00277         // store solution in Aux info
00278 
00279         const int nVars = solver->getNumCols();
00280         double* tmpSolution = new double [nVars];
00281         CoinCopyN (nlp_ -> getColSolution(), nlp_ -> getNumCols(), tmpSolution);
00282 
00283         //Get correct values for all auxiliary variables
00284         CouenneInterface * couenne = dynamic_cast <CouenneInterface *> (nlp_);
00285 
00286         if (couenne)
00287           couenne_ -> getAuxs (tmpSolution);
00288 
00289         if (babInfo){
00290           babInfo->setNlpSolution (tmpSolution, nVars, obj);
00291           babInfo->setHasNlpSolution (true);
00292         }
00293 
00294         if (obj < objectiveValue) { // found better solution?
00295 
00296           const CouNumber 
00297             *lb = solver -> getColLower (),
00298             *ub = solver -> getColUpper ();
00299 
00300           // check bounds once more after getAux. This avoids false
00301           // asserts in CbcModel.cpp:8305 on integerTolerance violated
00302           for (int i=0; i < nVars; i++, lb++, ub++) {
00303 
00304             CouNumber &t = tmpSolution [i];
00305             if      (t < *lb) t = *lb;
00306             else if (t > *ub) t = *ub;
00307           }
00308 
00309           couenne_ -> setCutOff (obj);
00310           foundSolution = true;
00311           objectiveValue = obj;
00312           CoinCopyN (tmpSolution, nVars, newSolution);
00313         }
00314         delete [] tmpSolution;
00315       }
00316 
00317       nlp_->setColLower(saveColLower);
00318       nlp_->setColUpper(saveColUpper);
00319 
00320       delete [] saveColLower;
00321       delete [] saveColUpper;
00322     }
00323 
00324     delete [] Y;
00325 
00326     delete [] lower;
00327     delete [] upper;
00328 
00329     return foundSolution;
00330   }
00331 }

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