00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "CouenneCutGenerator.hpp"
00013
00014 #include "BonCouenneInterface.hpp"
00015 #include "CouenneObject.hpp"
00016 #include "CouenneProblem.hpp"
00017 #include "CbcCutGenerator.hpp"
00018
00019 #include "BonAuxInfos.hpp"
00020 #include "CoinHelperFunctions.hpp"
00021 #include "BonOsiTMINLPInterface.hpp"
00022 #include "BonNlpHeuristic.hpp"
00023 #include "CouenneRecordBestSol.hpp"
00024
00025 using namespace Ipopt;
00026 using namespace Couenne;
00027
00028 NlpSolveHeuristic::NlpSolveHeuristic():
00029 CbcHeuristic(),
00030 nlp_(NULL),
00031 hasCloned_(false),
00032 maxNlpInf_(maxNlpInf_0),
00033 numberSolvePerLevel_(-1),
00034 couenne_(NULL){
00035 setHeuristicName("NlpSolveHeuristic");
00036 }
00037
00038 NlpSolveHeuristic::NlpSolveHeuristic(CbcModel & model, Bonmin::OsiTMINLPInterface &nlp, bool cloneNlp, CouenneProblem * couenne):
00039 CbcHeuristic(model), nlp_(&nlp), hasCloned_(cloneNlp),maxNlpInf_(maxNlpInf_0),
00040 numberSolvePerLevel_(-1),
00041 couenne_(couenne){
00042 setHeuristicName("NlpSolveHeuristic");
00043 if(cloneNlp)
00044 nlp_ = dynamic_cast <Bonmin::OsiTMINLPInterface *> (nlp.clone());
00045 }
00046
00047 NlpSolveHeuristic::NlpSolveHeuristic(const NlpSolveHeuristic & other):
00048 CbcHeuristic(other), nlp_(other.nlp_),
00049 hasCloned_(other.hasCloned_),
00050 maxNlpInf_(other.maxNlpInf_),
00051 numberSolvePerLevel_(other.numberSolvePerLevel_),
00052 couenne_(other.couenne_){
00053 if(hasCloned_ && nlp_ != NULL)
00054 nlp_ = dynamic_cast <Bonmin::OsiTMINLPInterface *> (other.nlp_->clone());
00055 }
00056
00057 CbcHeuristic *
00058 NlpSolveHeuristic::clone() const{
00059 return new NlpSolveHeuristic(*this);
00060 }
00061
00062 NlpSolveHeuristic &
00063 NlpSolveHeuristic::operator=(const NlpSolveHeuristic & rhs){
00064 if(this != &rhs){
00065 CbcHeuristic::operator=(rhs);
00066 if(hasCloned_ && nlp_)
00067 delete nlp_;
00068
00069 hasCloned_ = rhs.hasCloned_;
00070 if(nlp_ != NULL){
00071 if(hasCloned_)
00072 nlp_ = dynamic_cast <Bonmin::OsiTMINLPInterface *> (rhs.nlp_->clone());
00073 else
00074 nlp_ = rhs.nlp_;
00075 }
00076 }
00077 maxNlpInf_ = rhs.maxNlpInf_;
00078 numberSolvePerLevel_ = rhs.numberSolvePerLevel_;
00079 couenne_ = rhs.couenne_;
00080 return *this;
00081 }
00082
00083 NlpSolveHeuristic::~NlpSolveHeuristic(){
00084 if(hasCloned_)
00085 delete nlp_;
00086 nlp_ = NULL;
00087 }
00088
00089 void
00090 NlpSolveHeuristic::setNlp (Bonmin::OsiTMINLPInterface &nlp, bool cloneNlp){
00091 if(hasCloned_ && nlp_ != NULL)
00092 delete nlp_;
00093 hasCloned_ = cloneNlp;
00094 if(cloneNlp)
00095 nlp_ = dynamic_cast <Bonmin::OsiTMINLPInterface *> (nlp.clone());
00096 else
00097 nlp_ = &nlp;
00098 }
00099
00100 void
00101 NlpSolveHeuristic::setCouenneProblem(CouenneProblem * couenne)
00102 {couenne_ = couenne;}
00103
00104
00105 int
00106 NlpSolveHeuristic::solution (double & objectiveValue, double * newSolution) {
00107
00108 int noSolution = 1, maxTime = 2;
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 const int depth = (model_ -> currentNode ()) ? model_ -> currentNode () -> depth () : 0;
00121
00122 if (depth <= 0)
00123 couenne_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, "NLP Heuristic: "); fflush (stdout);
00124
00125 try {
00126
00127 if (CoinCpuTime () > couenne_ -> getMaxCpuTime ())
00128 throw maxTime;
00129
00130 OsiSolverInterface * solver = model_ -> solver();
00131
00132 OsiAuxInfo * auxInfo = solver->getAuxiliaryInfo();
00133 Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (auxInfo);
00134
00135 if(babInfo){
00136 babInfo->setHasNlpSolution(false);
00137 if(babInfo->infeasibleNode()){
00138 throw noSolution;
00139 }
00140 }
00141
00142
00143
00144 bool too_deep = false;
00145
00146
00147 if (numberSolvePerLevel_ > -1) {
00148
00149 if (numberSolvePerLevel_ == 0)
00150 throw maxTime;
00151
00152
00153 if (CoinDrand48 () > 1. / CoinMax
00154 (1., (double) ((depth - numberSolvePerLevel_) *
00155 (depth - numberSolvePerLevel_))))
00156 too_deep = true;
00157 }
00158
00159 if (too_deep)
00160 throw maxTime;
00161
00162 double *lower = new double [couenne_ -> nVars ()];
00163 double *upper = new double [couenne_ -> nVars ()];
00164
00165 CoinFillN (lower, couenne_ -> nVars (), -COUENNE_INFINITY);
00166 CoinFillN (upper, couenne_ -> nVars (), COUENNE_INFINITY);
00167
00168 CoinCopyN (solver->getColLower(), nlp_ -> getNumCols (), lower);
00169 CoinCopyN (solver->getColUpper(), nlp_ -> getNumCols (), upper);
00170
00171
00172
00173
00174
00175
00176 const double * solution = solver->getColSolution();
00177 OsiBranchingInformation info (solver, true);
00178 const int & numberObjects = model_->numberObjects();
00179 OsiObject ** objects = model_->objects();
00180 double maxInfeasibility = 0;
00181
00182 bool haveRoundedIntVars = false;
00183
00184 for (int i = 0 ; i < numberObjects ; i++) {
00185
00186 CouenneObject * couObj = dynamic_cast <CouenneObject *> (objects [i]);
00187
00188 if (couObj) {
00189 if (too_deep) {
00190 int dummy;
00191 double infeas;
00192 maxInfeasibility = CoinMax ( maxInfeasibility, infeas = couObj->infeasibility(&info, dummy));
00193
00194 if (maxInfeasibility > maxNlpInf_){
00195 delete [] lower;
00196 delete [] upper;
00197 throw noSolution;
00198 }
00199 }
00200 } else {
00201
00202 OsiSimpleInteger * intObj = dynamic_cast<OsiSimpleInteger *>(objects[i]);
00203
00204 if (intObj) {
00205 const int & i = intObj -> columnNumber ();
00206
00207 double value = solution [i];
00208 if (value < lower[i])
00209 value = lower[i];
00210 else if (value > upper[i])
00211 value = upper[i];
00212
00213 double rounded = floor (value + 0.5);
00214
00215 if (fabs (value - rounded) > COUENNE_EPS) {
00216 haveRoundedIntVars = true;
00217
00218 }
00219
00220
00221
00222
00223 }
00224 else{
00225
00226
00227
00228
00229 }
00230 }
00231 }
00232
00233
00234
00235
00236 bool skipOnInfeasibility = false;
00237
00238 double *Y = new double [couenne_ -> nVars ()];
00239 CoinFillN (Y, couenne_ -> nVars (), 0.);
00240 CoinCopyN (solution, nlp_ -> getNumCols (), Y);
00241
00242
00243
00244
00245
00246
00247
00248
00249 if (haveRoundedIntVars)
00250 skipOnInfeasibility = (couenne_ -> getIntegerCandidate (solution, Y, lower, upper) < 0);
00251
00252
00253
00254
00255
00256
00257
00258
00259 bool foundSolution = false;
00260
00261 if (haveRoundedIntVars && skipOnInfeasibility)
00262
00263
00264 for (int i = couenne_ -> nOrigVars (); i--;)
00265
00266 if (couenne_ -> Var (i) -> isDefinedInteger ())
00267 lower [i] = upper [i] = Y [i] =
00268 (CoinDrand48 () < 0.5) ?
00269 floor (Y [i] + COUENNE_EPS) :
00270 ceil (Y [i] - COUENNE_EPS);
00271
00272 else if (lower [i] > upper [i]) {
00273
00274
00275
00276
00277 double swap = lower [i];
00278 lower [i] = upper [i];
00279 upper [i] = swap;
00280 }
00281
00282 {
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 double * saveColLower = CoinCopyOfArray (nlp_ -> getColLower (), nlp_ -> getNumCols ());
00294 double * saveColUpper = CoinCopyOfArray (nlp_ -> getColUpper (), nlp_ -> getNumCols ());
00295
00296 for (int i = nlp_ -> getNumCols (); i--;) {
00297
00298 if (lower [i] > upper [i]) {
00299 double swap = lower [i];
00300 lower [i] = upper [i];
00301 upper [i] = swap;
00302 }
00303
00304 if (Y [i] < lower [i]) Y [i] = lower [i];
00305 else if (Y [i] > upper [i]) Y [i] = upper [i];
00306 }
00307
00308 nlp_ -> setColLower (lower);
00309 nlp_ -> setColUpper (upper);
00310 nlp_ -> setColSolution (Y);
00311
00312
00313 try {
00314 nlp_ -> options () -> SetNumericValue ("max_cpu_time", CoinMax (0.1, couenne_ -> getMaxCpuTime () - CoinCpuTime ()));
00315 nlp_ -> initialSolve ();
00316 }
00317 catch (Bonmin::TNLPSolver::UnsolvedError *E) {}
00318
00319 double obj = (nlp_ -> isProvenOptimal()) ? nlp_ -> getObjValue (): COIN_DBL_MAX;
00320
00321 if (nlp_ -> isProvenOptimal () &&
00322 couenne_ -> checkNLP (nlp_ -> getColSolution (), obj, true) &&
00323 (obj < couenne_ -> getCutOff ())) {
00324
00325
00326
00327 const int nVars = solver->getNumCols();
00328 double* tmpSolution = new double [nVars];
00329 CoinCopyN (nlp_ -> getColSolution(), nlp_ -> getNumCols(), tmpSolution);
00330
00331
00332 CouenneInterface * couenne = dynamic_cast <CouenneInterface *> (nlp_);
00333
00334 if (couenne)
00335 couenne_ -> getAuxs (tmpSolution);
00336
00337 #ifdef FM_CHECKNLP2
00338 if(!couenne_->checkNLP2(tmpSolution,
00339 0, false,
00340 true,
00341 false,
00342 couenne_->getFeasTol())) {
00343 #ifdef FM_USE_REL_VIOL_CONS
00344 printf("NlpSolveHeuristic::solution(): ### ERROR: checkNLP(): returns true, checkNLP2() returns false\n");
00345 exit(1);
00346 #endif
00347 }
00348 obj = couenne_->getRecordBestSol()->getModSolVal();
00349 couenne_->getRecordBestSol()->update();
00350 #else
00351 couenne_->getRecordBestSol()->update(tmpSolution, nVars,
00352 obj, couenne_->getFeasTol());
00353 #endif
00354
00355 if (babInfo){
00356 babInfo->setNlpSolution (tmpSolution, nVars, obj);
00357 babInfo->setHasNlpSolution (true);
00358 }
00359
00360 if (obj < objectiveValue) {
00361
00362 const CouNumber
00363 *lb = solver -> getColLower (),
00364 *ub = solver -> getColUpper ();
00365
00366
00367
00368 for (int i=0; i < nVars; i++, lb++, ub++) {
00369
00370 CouNumber &t = tmpSolution [i];
00371 if (t < *lb) t = *lb;
00372 else if (t > *ub) t = *ub;
00373 }
00374
00375
00376 couenne_ -> setCutOff (obj);
00377 foundSolution = true;
00378 objectiveValue = obj;
00379 CoinCopyN (tmpSolution, nVars, newSolution);
00380 }
00381 delete [] tmpSolution;
00382 }
00383
00384 nlp_ -> setColLower (saveColLower);
00385 nlp_ -> setColUpper (saveColUpper);
00386
00387 delete [] saveColLower;
00388 delete [] saveColUpper;
00389 }
00390
00391 delete [] Y;
00392
00393 delete [] lower;
00394 delete [] upper;
00395
00396 if (depth <= 0) {
00397
00398 if (foundSolution) couenne_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, "solution found, obj. %g\n", objectiveValue);
00399 else couenne_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, "no solution.\n");
00400 }
00401
00402 return foundSolution;
00403
00404 }
00405 catch (int &e) {
00406
00407
00408
00409
00410 if (e==noSolution) {if (depth <= 0) couenne_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, "no solution.\n"); return 0;}
00411 else if (e==maxTime) {if (depth <= 0) couenne_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, "time limit reached.\n"); return 0;}
00412 else {if (depth <= 0) couenne_ -> Jnlst () -> Printf (J_ERROR, J_COUENNE, "solution found, obj. %g\n", objectiveValue); return 1;}
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 }
00428 }
00429
00430
00432 void NlpSolveHeuristic::registerOptions (Ipopt::SmartPtr <Bonmin::RegisteredOptions> roptions) {
00433
00434 roptions -> AddStringOption2
00435 ("local_optimization_heuristic",
00436 "Search for local solutions of MINLPs",
00437 "yes",
00438 "no","",
00439 "yes","",
00440 "If enabled, a heuristic based on Ipopt is used to find feasible solutions for the problem. "
00441 "It is highly recommended that this option is left enabled, as it would be difficult to find feasible solutions otherwise.");
00442
00443 roptions -> AddLowerBoundedIntegerOption
00444 ("log_num_local_optimization_per_level",
00445 "Specify the logarithm of the number of local optimizations to perform"
00446 " on average for each level of given depth of the tree.",
00447 -1,
00448 2, "Solve as many nlp's at the nodes for each level of the tree. "
00449 "Nodes are randomly selected. If for a "
00450 "given level there are less nodes than this number nlp are solved for every nodes. "
00451 "For example if parameter is 8, nlp's are solved for all node until level 8, "
00452 "then for half the node at level 9, 1/4 at level 10.... "
00453 "Value -1 specify to perform at all nodes.");
00454 }