00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "CouenneIterativeRounding.hpp"
00012 #include "BonTMINLP2Quad.hpp"
00013 #include "BonTMINLPLinObj.hpp"
00014 #ifdef COIN_HAS_CPX
00015 #include "OsiCpxSolverInterface.hpp"
00016 #include "cplex.h"
00017 #endif
00018
00019 #include "CouenneRecordBestSol.hpp"
00020
00021 #define MILPTIME 5
00022 #define CBCMILPTIME 20
00023
00024 namespace Couenne{
00025
00026 CouenneIterativeRounding::CouenneIterativeRounding():
00027 CbcHeuristic(),
00028 nlp_(NULL), cinlp_(NULL), milp_(NULL),
00029 maxRoundingIter_(10),
00030 maxFirPoints_(5), maxTime_(60), maxTimeFirstCall_(60), numInitialRows_(0),
00031 numSol_(-1), colLower_(NULL), colUpper_(NULL),
00032 colLowerNlp_(NULL), colUpperNlp_(NULL),
00033 omega_(0.2), baseLbRhs_(15),
00034 couenne_(NULL)
00035 {
00036 setHeuristicName("CouenneIterativeRounding");
00037 }
00038
00039 CouenneIterativeRounding::CouenneIterativeRounding(Bonmin::OsiTMINLPInterface* nlp,
00040 OsiSolverInterface* cinlp,
00041 CouenneProblem* couenne,
00042 Ipopt::SmartPtr<Ipopt::OptionsList> options):
00043 CbcHeuristic(), nlp_(NULL),
00044 cinlp_(NULL), milp_(NULL),
00045 numSol_(-1), colLower_(NULL), colUpper_(NULL),
00046 colLowerNlp_(NULL), colUpperNlp_(NULL),
00047 couenne_(couenne)
00048 {
00049
00050 setNlp(nlp, cinlp);
00051
00052
00053 int irAggressiveness;
00054 options->GetIntegerValue("iterative_rounding_aggressiveness",
00055 irAggressiveness, "couenne.");
00056 setAggressiveness(irAggressiveness);
00057 double maxTime, maxTimeInit;
00058 options->GetNumericValue("iterative_rounding_time", maxTime,
00059 "couenne.");
00060 options->GetNumericValue("iterative_rounding_time_firstcall",
00061 maxTimeInit, "couenne.");
00062 if (maxTime >= 0){
00063 setMaxTime(maxTime);
00064 }
00065 if (maxTimeInit >= 0){
00066 setMaxTimeFirstCall(maxTimeInit);
00067 }
00068 int irLbrhs;
00069 options->GetIntegerValue("iterative_rounding_base_lbrhs",
00070 irLbrhs, "couenne.");
00071 setBaseLbRhs(irLbrhs);
00072 int numFirPoints;
00073 options->GetIntegerValue("iterative_rounding_num_fir_points",
00074 numFirPoints, "couenne.");
00075 setMaxFirPoints(numFirPoints);
00076 double omega;
00077 options->GetNumericValue("iterative_rounding_omega",
00078 omega, "couenne.");
00079 setOmega(omega);
00080 }
00081
00082 CouenneIterativeRounding::CouenneIterativeRounding(const CouenneIterativeRounding & other):
00083 CbcHeuristic(other), nlp_(other.nlp_),
00084 cinlp_(other.cinlp_), milp_(other.milp_),
00085 maxRoundingIter_(other.maxRoundingIter_),
00086 maxFirPoints_(other.maxFirPoints_),
00087 maxTime_(other.maxTime_),
00088 maxTimeFirstCall_(other.maxTimeFirstCall_),
00089 numInitialRows_(other.numInitialRows_),
00090 numSol_(other.numSol_),
00091 omega_(other.omega_), baseLbRhs_(other.baseLbRhs_),
00092 couenne_(other.couenne_)
00093 {
00094 if(nlp_ != NULL){
00095 nlp_ = dynamic_cast<Bonmin::OsiTMINLPInterface*>(other.nlp_->clone());
00096 }
00097 if(milp_ != NULL)
00098 #ifdef COIN_HAS_CPX
00099 milp_ = dynamic_cast<OsiCpxSolverInterface*>(other.milp_->clone());
00100 #else
00101 milp_ = dynamic_cast<OsiClpSolverInterface*>(other.milp_->clone());
00102 #endif
00103 if (other.colLower_ != NULL){
00104 if (colLower_ != NULL)
00105 delete colLower_;
00106 colLower_ = new double[milp_->getNumCols()];
00107 CoinCopyN (other.colLower_, milp_->getNumCols(), colLower_);
00108 }
00109 if (other.colUpper_ != NULL){
00110 if (colUpper_ != NULL)
00111 delete colUpper_;
00112 colUpper_ = new double[milp_->getNumCols()];
00113 CoinCopyN (other.colUpper_, milp_->getNumCols(), colUpper_);
00114 }
00115 if (other.colLowerNlp_ != NULL){
00116 if (colLowerNlp_ != NULL)
00117 delete colLowerNlp_;
00118 colLowerNlp_ = new double[nlp_->getNumCols()];
00119 CoinCopyN (other.colLowerNlp_, nlp_->getNumCols(), colLowerNlp_);
00120 }
00121 if (other.colUpperNlp_ != NULL){
00122 if (colUpperNlp_ != NULL)
00123 delete colUpperNlp_;
00124 colUpperNlp_ = new double[nlp_->getNumCols()];
00125 CoinCopyN (other.colUpperNlp_, nlp_->getNumCols(), colLowerNlp_);
00126 }
00127 }
00128
00129 CbcHeuristic *
00130 CouenneIterativeRounding::clone() const{
00131 return new CouenneIterativeRounding(*this);
00132 }
00133
00134 CouenneIterativeRounding &
00135 CouenneIterativeRounding::operator=(const CouenneIterativeRounding & rhs){
00136 if(this != &rhs){
00137 CbcHeuristic::operator=(rhs);
00138 if(nlp_)
00139 delete nlp_;
00140
00141 if(rhs.nlp_ != NULL){
00142 nlp_ = dynamic_cast<Bonmin::OsiTMINLPInterface*>(rhs.nlp_->clone());
00143 }
00144 cinlp_ = rhs.cinlp_;
00145 maxRoundingIter_ = rhs.maxRoundingIter_;
00146 maxFirPoints_ = rhs.maxFirPoints_;
00147 maxTime_ = rhs.maxTime_;
00148 maxTimeFirstCall_ = rhs.maxTimeFirstCall_;
00149 numSol_ = rhs.numSol_;
00150 numInitialRows_ = rhs.numInitialRows_;
00151 omega_ = rhs.omega_;
00152 baseLbRhs_ = rhs.baseLbRhs_;
00153 couenne_ = rhs.couenne_;
00154 if (rhs.colLower_ != NULL){
00155 if (colLower_ != NULL)
00156 delete colLower_;
00157 colLower_ = new double[milp_->getNumCols()];
00158 CoinCopyN (rhs.colLower_, milp_->getNumCols(), colLower_);
00159 }
00160 if (rhs.colUpper_ != NULL){
00161 if (colUpper_ != NULL)
00162 delete colUpper_;
00163 colUpper_ = new double[milp_->getNumCols()];
00164 CoinCopyN (rhs.colUpper_, milp_->getNumCols(), colLower_);
00165 }
00166 if (rhs.colLowerNlp_ != NULL){
00167 if (colLowerNlp_ != NULL)
00168 delete colLowerNlp_;
00169 colLowerNlp_ = new double[nlp_->getNumCols()];
00170 CoinCopyN (rhs.colLowerNlp_, nlp_->getNumCols(), colLowerNlp_);
00171 }
00172 if (rhs.colUpperNlp_ != NULL){
00173 if (colUpperNlp_ != NULL)
00174 delete colUpperNlp_;
00175 colUpperNlp_ = new double[nlp_->getNumCols()];
00176 CoinCopyN (rhs.colUpperNlp_, nlp_->getNumCols(), colLowerNlp_);
00177 }
00178 }
00179 return *this;
00180 }
00181
00182 CouenneIterativeRounding::~CouenneIterativeRounding(){
00183 delete nlp_;
00184 nlp_ = NULL;
00185 if (colLower_)
00186 delete[] colLower_;
00187 if (colUpper_)
00188 delete[] colUpper_;
00189 if (colLowerNlp_)
00190 delete[] colLowerNlp_;
00191 if (colUpperNlp_)
00192 delete[] colUpperNlp_;
00193 if (milp_)
00194 delete milp_;
00195 milp_ = NULL;
00196 }
00197
00198 void
00199 CouenneIterativeRounding::setNlp(Bonmin::OsiTMINLPInterface* nlp,
00200 OsiSolverInterface * cinlp){
00201
00202
00203 if(nlp_ != NULL)
00204 delete nlp_;
00205 nlp_ = new Bonmin::OsiTMINLPInterface;
00206 Ipopt::SmartPtr<Bonmin::TMINLP> tminlp = nlp->model();
00207 if (tminlp->hasLinearObjective()){
00208 Ipopt::SmartPtr<Bonmin::TMINLPLinObj> linObj =
00209 new Bonmin::TMINLPLinObj;
00210 linObj->setTminlp(GetRawPtr(tminlp));
00211 tminlp = GetRawPtr(linObj);
00212 }
00213 nlp_->initialize(nlp->regOptions(), nlp->options(), nlp->solver()->journalist(), "bonmin.", tminlp);
00214 nlp_->use(new Bonmin::TMINLP2TNLPQuadCuts(tminlp));
00215 cinlp_ = cinlp;
00216 }
00217
00218 void
00219 CouenneIterativeRounding::setMilp(){
00220 if(milp_ != NULL)
00221 delete milp_;
00222
00223
00224
00225 OsiSolverInterface * milp = model_->solver();
00226 int n = milp->getNumCols();
00227
00228 #ifdef COIN_HAS_CPX
00229 milp_ = new OsiCpxSolverInterface();
00230 milp_->loadProblem(*(milp->getMatrixByRow()), milp->getColLower(),
00231 milp->getColUpper(), milp->getObjCoefficients(),
00232 milp->getRowLower(), milp->getRowUpper());
00233 for (int i = 0; i < n; ++i){
00234 if (milp->isInteger(i))
00235 milp_->setInteger(i);
00236 }
00237 #else
00238 milp_ = dynamic_cast<OsiClpSolverInterface*>(milp->clone());
00239 #endif
00240
00241 colLower_ = new double[n];
00242 colUpper_ = new double[n];
00243 memcpy(colLower_, milp->getColLower(), n*sizeof(double));
00244 memcpy(colUpper_, milp->getColUpper(), n*sizeof(double));
00245
00246 int nNlp = cinlp_->getNumCols();
00247
00248 colLowerNlp_ = new double[nNlp];
00249 colUpperNlp_ = new double[nNlp];
00250 memcpy(colLowerNlp_, cinlp_->getColLower(), nNlp*sizeof(double));
00251 memcpy(colUpperNlp_, cinlp_->getColUpper(), nNlp*sizeof(double));
00252
00253 numIntegers_ = 0;
00254 for (int i = 0; i < nNlp; ++i){
00255 if (cinlp_->isInteger(i)){
00256 numIntegers_++;
00257 }
00258 }
00259
00260
00261
00262
00263 double swap;
00264 for (int i = 0; i < n; ++i){
00265 if (colUpper_[i] < colLower_[i]){
00266 swap = colUpper_[i];
00267 colUpper_[i] = colLower_[i];
00268 colLower_[i] = swap;
00269 }
00270 }
00271
00272 numInitialRows_ = milp_->getNumRows();
00273
00274
00275 double * tmpArray = new double[n];
00276 CoinFillN(tmpArray, n, 0.0);
00277 milp_->setObjective(tmpArray);
00278 milp_->setObjSense(1);
00279
00280
00281
00282 for (int i = 0; i < n; ++i){
00283 milp_->addCol(0, NULL, NULL, 0.0, COIN_DBL_MAX, 1.0);
00284 }
00285
00286 milp_->setHintParam(OsiDoDualInResolve,true,OsiHintDo);
00287 milp_->setHintParam(OsiDoPresolveInResolve,true,OsiHintDo);
00288 milp_->setHintParam(OsiDoReducePrint,true,OsiHintDo);
00289 milp_->setDblParam(OsiPrimalTolerance, COUENNE_EPS_INT);
00290 milp_->messageHandler()->setLogLevel(0);
00291 milp_->setDblParam(OsiDualTolerance, COUENNE_EPS_INT);
00292
00293 #ifdef COIN_HAS_CPX
00294
00295 CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_MIPEMPHASIS, CPX_MIPEMPHASIS_HIDDENFEAS);
00296 CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_FPHEUR, 2);
00297 CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_NODESEL, 0);
00298 CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_LBHEUR, 1);
00299 CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_RINSHEUR, 99);
00300 CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_NODELIM, 50);
00301 CPXsetdblparam(milp_->getEnvironmentPtr(), CPX_PARAM_CUTSFACTOR, 1.0);
00302 CPXsetdblparam(milp_->getEnvironmentPtr(), CPX_PARAM_TILIM, MILPTIME);
00303 #else
00304
00305 heuristics_ = new CbcHeuristic*[1];
00306 numHeuristics_ = 1;
00307 CbcHeuristicFPump * feaspump = new CbcHeuristicFPump();
00308 feaspump->setMaximumRetries(2);
00309 feaspump->setMaximumPasses(100);
00310 feaspump->setAccumulate(3);
00311 heuristics_[0] = feaspump;
00312 #endif
00313
00314 delete[] tmpArray;
00315
00316
00317 }
00318
00319 void CouenneIterativeRounding::setAggressiveness(int value){
00320 switch (value){
00321 case 0:
00322 setMaxRoundingIter(5);
00323 setMaxTimeFirstCall(300);
00324 setMaxFirPoints(5);
00325 setMaxTime(60);
00326 break;
00327 case 1:
00328 setMaxRoundingIter(10);
00329 setMaxTimeFirstCall(300);
00330 setMaxFirPoints(5);
00331 setMaxTime(120);
00332 break;
00333 case 2:
00334 setMaxRoundingIter(20);
00335 setMaxTimeFirstCall(1000);
00336 setMaxFirPoints(5);
00337 setMaxTime(300);
00338 break;
00339 default:
00340 std::cerr << "CouenneIterativeRounding::setAggressiveness() : unknown value!\n" << std::endl;
00341 }
00342 }
00343
00344 int
00345 CouenneIterativeRounding::solution(double & objectiveValue, double* newSolution){
00346 if (milp_ == NULL){
00347
00348 setMilp();
00349 return 0;
00350 }
00351
00352 if ((model_->numberIntegers() == 0) ||
00353 (numSol_ == model_->getSolutionCount())){
00354
00355
00356 return 0;
00357 }
00358
00359 numSol_ = model_->getSolutionCount();
00360
00361 std::cout << "Launching IterativeRounding with parameters:" << std::endl;
00362 std::cout << "Max rounding iter: " << maxRoundingIter_ << std::endl;
00363 std::cout << "Max feas point: " << maxFirPoints_ << std::endl;
00364 std::cout << "Base lbrhs: " << baseLbRhs_ << std::endl;
00365 std::cout << "Omega: " << omega_ << std::endl;
00366 std::cout << "Max time firstcall: " << maxTimeFirstCall_ << std::endl;
00367
00368
00369 startTime_ = CoinCpuTime();
00370 endTime_ = ((numSol_ == 0) ? maxTimeFirstCall_ : maxTime_);
00371
00372 const double* bestKnownSolution = model_->bestSolution();
00373 bool found = false;
00374 bool hasSolution = true;
00375 bool improved = true;
00376 if (numSol_ == 0){
00377
00378 hasSolution = feasibilityIR(objectiveValue, newSolution);
00379 if (hasSolution){
00380 bestKnownSolution = newSolution;
00381 found = hasSolution;
00382 }
00383 }
00384 if (!hasSolution){
00385
00386 return found;
00387 }
00388 while (improved && (CoinCpuTime()-startTime_) < (endTime_ - MILPTIME)){
00389
00390 improved = false;
00391 improved = improvementIR(objectiveValue, newSolution, bestKnownSolution);
00392 if (improved){
00393 bestKnownSolution = newSolution;
00394 }
00395 found = (found || improved);
00396 }
00397 if (found){
00398
00399 numSol_++;
00400 }
00401
00402 return found;
00403 }
00404
00405 int
00406 CouenneIterativeRounding::feasibilityIR(double& objectiveValue,
00407 double* newSolution){
00408
00409 std::cout << "starting feasibility IR" << std::endl;
00410
00411 OsiSolverInterface * solver = model_->solver();
00412
00413 OsiAuxInfo * auxInfo = solver->getAuxiliaryInfo();
00414 Bonmin::BabInfo * babInfo = dynamic_cast<Bonmin::BabInfo *> (auxInfo);
00415
00416 if(babInfo){
00417 babInfo->setHasNlpSolution(false);
00418 if(babInfo->infeasibleNode()){
00419 return 0;
00420 }
00421 }
00422
00423 int n = couenne_->nVars();
00424 int nNlp = cinlp_->getNumCols();
00425
00426
00427 int numIntAtBound = 0;
00428
00429 OsiRowCut cut;
00430 OsiRowCut lbcut1;
00431 OsiRowCut lbcut2;
00432 OsiCuts lbcuts;
00433 double obj;
00434
00435 bool boundsChanged = false;
00436 std::vector<int> previousBranches;
00437
00438
00439
00440
00441 nlp_->resolve();
00442 if (nlp_->isProvenPrimalInfeasible() || nlp_->isProvenDualInfeasible() ||
00443 nlp_->isAbandoned()){
00444 nlp_->resolveForRobustness(3);
00445 }
00446
00447 if (nlp_->isProvenPrimalInfeasible() || nlp_->isProvenDualInfeasible() ||
00448 nlp_->isAbandoned()){
00449 obj = COIN_DBL_MAX;
00450 }
00451 else{
00452 obj = nlp_->getObjValue();
00453 }
00454
00455 if (obj == COIN_DBL_MAX){std::cout << " IR: no feasible solution found " << std::endl;
00456 std::cout << " IR: elapsed time " << CoinCpuTime()-startTime_ << std::endl;
00457 return 0;
00458 }
00459
00460 double* xprime = new double [n];
00461 CoinCopyN (nlp_->getColSolution(), nlp_->getNumCols(), xprime);
00462 couenne_ -> getAuxs (xprime);
00463
00464
00465
00466
00467 int constrInd[2];
00468 double constrElem[2];
00469
00470
00471 bool foundSolution = false;
00472 double* tmpSolution = new double[n];
00473 OsiCuts revlb_all;
00474 OsiSolverInterface* curr_milp = milp_;
00475
00476 int outerLoop = maxFirPoints_;
00477 for (int h = 0; h < outerLoop &&
00478 ((CoinCpuTime()-startTime_) < (endTime_ - MILPTIME)); ++h){
00479
00480 OsiCuts cs;
00481 cs.insert(lbcut1);
00482 cs.insert(lbcut2);
00483
00484
00485
00486 for (int i = 0; i < n; i++){
00487 constrInd[0] = i;
00488 constrInd[1] = i+n;
00489 constrElem[0] = -1;
00490 constrElem[1] = -1;
00491 cut.mutableRow().setVector(2, constrInd, constrElem);
00492 cut.setLb(-COIN_DBL_MAX);
00493 cut.setUb(-xprime[i]);
00494 cs.insert(cut);
00495 constrElem[0] = +1;
00496 constrElem[1] = -1;
00497 cut.mutableRow().setVector(2, constrInd, constrElem);
00498 cut.setLb(-COIN_DBL_MAX);
00499 cut.setUb(xprime[i]);
00500 cs.insert(cut);
00501 }
00502 curr_milp->applyCuts(cs);
00503
00504 for (int k = 0; k < maxRoundingIter_ &&
00505 ((CoinCpuTime()-startTime_) < (endTime_ - MILPTIME)); ++k){
00506
00507 curr_milp->restoreBaseModel(numInitialRows_+cs.sizeRowCuts());
00508 curr_milp->applyCuts(revlb_all);
00509 bool solFound = solveMilp(curr_milp,
00510 endTime_-(CoinCpuTime()-startTime_)-2);
00511 if (!solFound && !boundsChanged){
00512 std::cout << " MILP cannot be solved, terminating LB " << std::endl;
00513
00514 curr_milp->restoreBaseModel(numInitialRows_);
00515 delete[] xprime;
00516 delete[] tmpSolution;
00517 if (boundsChanged){
00518 curr_milp->setColLower(colLower_);
00519 curr_milp->setColUpper(colUpper_);
00520 }
00521 std::cout << " IR: elapsed time " << CoinCpuTime()-startTime_ << std::endl;
00522 return foundSolution;
00523 }
00524 else if (!solFound && boundsChanged){
00525
00526
00527
00528 curr_milp->setColLower(colLower_);
00529 curr_milp->setColUpper(colUpper_);
00530 branchToCut(tmpSolution, curr_milp, previousBranches);
00531 continue;
00532 }
00533
00534 const double * xtilde = curr_milp->getColSolution();
00535
00536
00537
00538 CoinCopyN (xtilde, n, tmpSolution);
00539 for (int i = 0; i < nNlp; ++i){
00540 if (model_->isInteger(i)){
00541 tmpSolution[i] = floor(tmpSolution[i]+0.5);
00542 cinlp_->setColLower(i, tmpSolution[i]);
00543 cinlp_->setColUpper(i, tmpSolution[i]);
00544 }
00545 }
00546 cinlp_->setColSolution(tmpSolution);
00547
00548 cinlp_->messageHandler()->setLogLevel(1);
00549 cinlp_->resolve();
00550 obj = ((cinlp_->isProvenOptimal()) ?
00551 cinlp_->getObjValue():COIN_DBL_MAX);
00552 memcpy(tmpSolution, cinlp_->getColSolution(),
00553 nNlp*sizeof(double));
00554
00555
00556
00557 bool isChecked = false;
00558
00559 isChecked = couenne_ -> checkNLP0 (tmpSolution, obj, true,
00560 false,
00561 true,
00562 false);
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576 if (cinlp_->isProvenOptimal () &&
00577 isChecked &&
00578 (obj < couenne_->getCutOff())) {
00579
00580 #ifdef FM_CHECKNLP2
00581 #ifdef FM_TRACE_OPTSOL
00582 couenne_->getRecordBestSol()->update();
00583 CoinCopyN (couenne_->getRecordBestSol()->getSol(), n, tmpSolution);
00584 obj = couenne_->getRecordBestSol()->getVal();
00585 #else
00586 CoinCopyN (couenne_->getRecordBestSol()->getModSol(n), n, tmpSolution);
00587 #endif
00588 #else
00589
00590
00591 couenne_ -> getAuxs (tmpSolution);
00592
00593 #ifdef FM_TRACE_OPTSOL
00594 couenne_->getRecordBestSol()->update(tmpSolution, n,
00595 obj, couenne_->getFeasTol());
00596 CoinCopyN (couenne_->getRecordBestSol()->getSol(), n, tmpSolution);
00597 obj = couenne_->getRecordBestSol()->getVal();
00598 #endif
00599 #endif
00600
00601 if (babInfo){
00602 babInfo->setNlpSolution (tmpSolution, n, obj);
00603 babInfo->setHasNlpSolution (true);
00604 }
00605
00606 std::cout << "Final Nlp solution with objective " << obj << " :" << std::endl;
00607
00608 if (obj < objectiveValue - COUENNE_EPS) {
00609 std::cout << "New incumbent found" << std::endl;
00610 const CouNumber
00611 *lb = solver -> getColLower (),
00612 *ub = solver -> getColUpper ();
00613
00614
00615
00616 for (int i=0; i < n; ++i, ++lb, ++ub) {
00617 CouNumber &t = tmpSolution [i];
00618 if (t < *lb) t = *lb;
00619 else if (t > *ub) t = *ub;
00620 }
00621
00622 couenne_ -> setCutOff (obj);
00623 foundSolution = true;
00624 objectiveValue = obj;
00625 CoinCopyN (tmpSolution, n, newSolution);
00626 cinlp_->setColLower(colLowerNlp_);
00627 cinlp_->setColUpper(colUpperNlp_);
00628
00629 curr_milp->restoreBaseModel(numInitialRows_);
00630 delete[] xprime;
00631 delete[] tmpSolution;
00632 if (boundsChanged){
00633 curr_milp->setColLower(colLower_);
00634 curr_milp->setColUpper(colUpper_);
00635 }
00636
00637 double elapsed = CoinCpuTime()-startTime_;
00638 std::cout << "IR: Heuristic: " << objectiveValue << std::endl;
00639 std::cout << "IR: Heuristic time: " << elapsed << std::endl;
00640 return foundSolution;
00641 }
00642 }
00643 cinlp_->setColLower(colLowerNlp_);
00644 cinlp_->setColUpper(colUpperNlp_);
00645 double avgBound;
00646 numIntAtBound = computeIntAtBound(xtilde, avgBound);
00647
00648 if (numIntAtBound >= 50 ||
00649 numIntAtBound >= ((numIntegers_*0.1 > 5) ? numIntegers_*0.1 : 5)){
00650
00651
00652 avgBound = floor(avgBound + 0.5);
00653 std::cout << "Using reverse LB with rhs " << avgBound << std::endl;
00654 writeLB(cut, xtilde, 'G', avgBound);
00655 revlb_all.insert(cut);
00656 }
00657 else{
00658
00659 branchToCut(xtilde, curr_milp, previousBranches);
00660 boundsChanged = true;
00661 }
00662 }
00663 if (h <= outerLoop -2){
00664
00665
00666 Bonmin::OsiTMINLPInterface * nlp = dynamic_cast<Bonmin::OsiTMINLPInterface *> (nlp_);
00667 Ipopt::SmartPtr< Ipopt::OptionsList > opt = nlp->solver()->options();
00668 nlp->messageHandler()->setLogLevel(10);
00669 double mu_target;
00670 double kappa_d;
00671 opt->GetNumericValue("mu_target", mu_target, "ipopt.");
00672 opt->SetNumericValue("mu_target", omega_*(h+1), "ipopt.");
00673 opt->GetNumericValue("kappa_d", kappa_d, "ipopt.");
00674 opt->SetNumericValue("kappa_d", 0.0, "ipopt.");
00675 nlp_->resolve();
00676 if (nlp_->isProvenPrimalInfeasible() ||
00677 nlp_->isProvenDualInfeasible() ||
00678 nlp_->isAbandoned()){
00679 nlp_->resolveForRobustness(3);
00680 }
00681 opt->SetNumericValue("mu_target", mu_target, "ipopt.");
00682 opt->SetNumericValue("kappa_d", kappa_d, "ipopt.");
00683
00684 if (!nlp->isProvenPrimalInfeasible() &&
00685 !nlp->isProvenDualInfeasible() &&
00686 !nlp->isAbandoned()){
00687 CoinCopyN (nlp_->getColSolution(), nlp_->getNumCols(), xprime);
00688 couenne_ -> getAuxs (xprime);
00689 curr_milp->restoreBaseModel(numInitialRows_);
00690 if (boundsChanged){
00691 curr_milp->setColLower(colLower_);
00692 curr_milp->setColUpper(colUpper_);
00693 }
00694 }
00695 }
00696 }
00697
00698 curr_milp->restoreBaseModel(numInitialRows_);
00699 delete[] xprime;
00700 delete[] tmpSolution;
00701 if (boundsChanged){
00702 curr_milp->setColLower(colLower_);
00703 curr_milp->setColUpper(colUpper_);
00704 }
00705 double elapsed = CoinCpuTime()-startTime_;
00706 std::cout << "IR: Heuristic: " << COUENNE_INFINITY << std::endl;
00707 std::cout << "IR: Heuristic time: " << elapsed << std::endl;
00708 return foundSolution;
00709 }
00710
00711 int
00712 CouenneIterativeRounding::improvementIR(double& objectiveValue,
00713 double* newSolution,
00714 const double* solution){
00715 std::cout << "starting Improvement IR" << std::endl;
00716
00717 OsiSolverInterface * solver = model_->solver();
00718
00719 OsiAuxInfo * auxInfo = solver->getAuxiliaryInfo();
00720 Bonmin::BabInfo * babInfo = dynamic_cast<Bonmin::BabInfo *> (auxInfo);
00721
00722 if(babInfo){
00723 babInfo->setHasNlpSolution(false);
00724 if(babInfo->infeasibleNode()){
00725 return 0;
00726 }
00727 }
00728
00729
00730 int n = couenne_->nVars();
00731 int nNlp = cinlp_->getNumCols();
00732
00733
00734 int numIntAtBound = 0;
00735
00736 double lbrhs = CoinMin(baseLbRhs_, CoinMax(1,numIntegers_/2) );
00737 OsiRowCut cut;
00738 OsiRowCut lbcut1;
00739 OsiRowCut lbcut2;
00740 OsiCuts lbcuts;
00741 int currentIndex = 0;
00742 double obj;
00743
00744 bool boundsChanged = false;
00745 std::vector<int> previousBranches;
00746
00747 double avgBound = 0.0;
00748 numIntAtBound = computeIntAtBound(solution, avgBound);
00749
00750 if (numIntAtBound >= 50 ||
00751 numIntAtBound >= ((numIntegers_*0.1 > 5) ? numIntegers_*0.1 : 5)){
00752
00753 writeLB(lbcut1, solution, 'L', lbrhs + floor(avgBound - 0.5));
00754 lbcuts.insert(lbcut1);
00755 writeLB(lbcut2, solution, 'G', 1);
00756 lbcuts.insert(lbcut2);
00757
00758
00759
00760
00761 nlp_->applyCuts(lbcuts);
00762 }
00763 else{
00764
00765
00766
00767 for (int i = 0; i < nlp_->getNumCols(); ++i){
00768 if (nlp_->isInteger(i)){
00769 nlp_->setColLower(i, colLowerNlp_[i]+(solution[i]-colLower_[i])*0.5);
00770 nlp_->setColUpper(i, colUpperNlp_[i]+(solution[i]-colUpper_[i])*0.5);
00771 }
00772 }
00773 }
00774
00775 nlp_->setColSolution(solution);
00776 nlp_->resolve();
00777 if (nlp_->isProvenPrimalInfeasible() || nlp_->isProvenDualInfeasible() ||
00778 nlp_->isAbandoned()){
00779 nlp_->resolveForRobustness(3);
00780 }
00781
00782 if (nlp_->isProvenPrimalInfeasible() || nlp_->isProvenDualInfeasible() ||
00783 nlp_->isAbandoned()){
00784 obj = COIN_DBL_MAX;
00785 }
00786 else{
00787 obj = nlp_->getObjValue();
00788 }
00789
00790
00791 if (numIntAtBound > 0){
00792 currentIndex = nlp_->getNumRows()-1;
00793 nlp_->deleteRows(1, ¤tIndex);
00794 currentIndex = nlp_->getNumRows()-1;
00795 nlp_->deleteRows(1, ¤tIndex);
00796 }
00797 else{
00798 nlp_->setColLower(colLowerNlp_);
00799 nlp_->setColUpper(colUpperNlp_);
00800 }
00801
00802 if (obj == COIN_DBL_MAX || obj >= objectiveValue - COUENNE_EPS){
00803 std::cout << " IR: no improvement possible " << std::endl;
00804 std::cout << " IR: elapsed time " << CoinCpuTime()-startTime_ << std::endl;
00805 return 0;
00806 }
00807
00808 double* xprime = new double [n];
00809 CoinCopyN (nlp_->getColSolution(), nlp_->getNumCols(), xprime);
00810 couenne_ -> getAuxs (xprime);
00811
00812
00813
00814
00815 int constrInd[2];
00816 double constrElem[2];
00817
00818
00819 bool foundSolution = false;
00820 double* tmpSolution = new double[n];
00821 OsiCuts revlb_all;
00822 OsiSolverInterface* curr_milp = milp_;
00823
00824 OsiCuts cs;
00825 cs.insert(lbcut1);
00826 cs.insert(lbcut2);
00827
00828
00829
00830 for (int i = 0; i < n; i++){
00831 constrInd[0] = i;
00832 constrInd[1] = i+n;
00833 constrElem[0] = -1;
00834 constrElem[1] = -1;
00835 cut.mutableRow().setVector(2, constrInd, constrElem);
00836 cut.setLb(-COIN_DBL_MAX);
00837 cut.setUb(-xprime[i]);
00838 cs.insert(cut);
00839 constrElem[0] = +1;
00840 constrElem[1] = -1;
00841 cut.mutableRow().setVector(2, constrInd, constrElem);
00842 cut.setLb(-COIN_DBL_MAX);
00843 cut.setUb(xprime[i]);
00844 cs.insert(cut);
00845 }
00846 curr_milp->applyCuts(cs);
00847
00848 for (int k = 0; k < maxRoundingIter_ &&
00849 ((CoinCpuTime()-startTime_) < (endTime_ - MILPTIME)); ++k){
00850
00851 curr_milp->restoreBaseModel(numInitialRows_+cs.sizeRowCuts());
00852 curr_milp->applyCuts(revlb_all);
00853 bool solFound = solveMilp(curr_milp,
00854 endTime_-(CoinCpuTime()-startTime_)-2);
00855 if (!solFound && !boundsChanged){
00856 std::cout << " MILP cannot be solved, terminating LB " << std::endl;
00857
00858 curr_milp->restoreBaseModel(numInitialRows_);
00859 delete[] xprime;
00860 delete[] tmpSolution;
00861 if (boundsChanged){
00862 curr_milp->setColLower(colLower_);
00863 curr_milp->setColUpper(colUpper_);
00864 }
00865 std::cout << " IR: elapsed time " << CoinCpuTime()-startTime_ << std::endl;
00866 return foundSolution;
00867 }
00868 else if (!solFound && boundsChanged){
00869
00870
00871
00872 curr_milp->setColLower(colLower_);
00873 curr_milp->setColUpper(colUpper_);
00874 branchToCut(tmpSolution, curr_milp, previousBranches);
00875 continue;
00876 }
00877 const double * xtilde = curr_milp->getColSolution();
00878
00879
00880
00881 CoinCopyN (xtilde, n, tmpSolution);
00882 for (int i = 0; i < nNlp; ++i){
00883 if (model_->isInteger(i)){
00884 tmpSolution[i] = floor(tmpSolution[i]+0.5);
00885 cinlp_->setColLower(i, tmpSolution[i]);
00886 cinlp_->setColUpper(i, tmpSolution[i]);
00887 }
00888 }
00889 cinlp_->setColSolution(tmpSolution);
00890
00891 cinlp_->messageHandler()->setLogLevel(1);
00892 cinlp_->resolve();
00893 obj = ((cinlp_->isProvenOptimal()) ? cinlp_->getObjValue():COIN_DBL_MAX);
00894 memcpy(tmpSolution, cinlp_->getColSolution(),
00895 nNlp*sizeof(double));
00896
00897
00898
00899 bool isChecked = false;
00900
00901 isChecked = couenne_ -> checkNLP0 (tmpSolution, obj, true,
00902 false,
00903 true,
00904 false);
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918 if (cinlp_->isProvenOptimal () &&
00919 isChecked &&
00920 (obj < couenne_->getCutOff())) {
00921
00922 #ifdef FM_CHECKNLP2
00923 #ifdef FM_TRACE_OPTSOL
00924 couenne_->getRecordBestSol()->update();
00925 CoinCopyN (couenne_->getRecordBestSol()->getSol(), n, tmpSolution);
00926 obj = couenne_->getRecordBestSol()->getVal();
00927 #else
00928 CoinCopyN (couenne_->getRecordBestSol()->getModSol(n), n, tmpSolution);
00929 #endif
00930 #else
00931
00932
00933 couenne_ -> getAuxs (tmpSolution);
00934
00935 #ifdef FM_TRACE_OPTSOL
00936 couenne_->getRecordBestSol()->update(tmpSolution, n,
00937 obj, couenne_->getFeasTol());
00938 CoinCopyN (couenne_->getRecordBestSol()->getSol(), n, tmpSolution);
00939 obj = couenne_->getRecordBestSol()->getVal();
00940 #endif
00941 #endif
00942
00943 if (babInfo){
00944 babInfo->setNlpSolution (tmpSolution, n, obj);
00945 babInfo->setHasNlpSolution (true);
00946 }
00947
00948 std::cout << "Final Nlp solution with objective " << obj << " :" << std::endl;
00949
00950 if (obj < objectiveValue - COUENNE_EPS) {
00951 std::cout << "New incumbent found" << std::endl;
00952 const CouNumber
00953 *lb = solver -> getColLower (),
00954 *ub = solver -> getColUpper ();
00955
00956
00957
00958 for (int i=0; i < n; ++i, ++lb, ++ub) {
00959 CouNumber &t = tmpSolution [i];
00960 if (t < *lb) t = *lb;
00961 else if (t > *ub) t = *ub;
00962 }
00963
00964 couenne_ -> setCutOff (obj);
00965 foundSolution = true;
00966 objectiveValue = obj;
00967 CoinCopyN (tmpSolution, n, newSolution);
00968 cinlp_->setColLower(colLowerNlp_);
00969 cinlp_->setColUpper(colUpperNlp_);
00970
00971 curr_milp->restoreBaseModel(numInitialRows_);
00972 delete[] xprime;
00973 delete[] tmpSolution;
00974 if (boundsChanged){
00975 curr_milp->setColLower(colLower_);
00976 curr_milp->setColUpper(colUpper_);
00977 }
00978
00979 double elapsed = CoinCpuTime()-startTime_;
00980 std::cout << "IR: Heuristic: " << objectiveValue << std::endl;
00981 std::cout << "IR: Heuristic time: " << elapsed << std::endl;
00982 return foundSolution;
00983 }
00984 }
00985 cinlp_->setColLower(colLowerNlp_);
00986 cinlp_->setColUpper(colUpperNlp_);
00987 numIntAtBound = computeIntAtBound(xtilde, avgBound);
00988
00989 if (numIntAtBound >= 50 ||
00990 numIntAtBound >= ((numIntegers_*0.1 > 5) ? numIntegers_*0.1 : 5)){
00991
00992
00993 avgBound = floor(avgBound + 0.5);
00994 std::cout << "Using reverse LB with rhs " << avgBound << std::endl;
00995 writeLB(cut, xtilde, 'G', avgBound);
00996 revlb_all.insert(cut);
00997 }
00998 else{
00999
01000 branchToCut(xtilde, curr_milp, previousBranches);
01001 boundsChanged = true;
01002 }
01003 }
01004
01005 curr_milp->restoreBaseModel(numInitialRows_);
01006 delete[] xprime;
01007 delete[] tmpSolution;
01008 if (boundsChanged){
01009 curr_milp->setColLower(colLower_);
01010 curr_milp->setColUpper(colUpper_);
01011 }
01012 double elapsed = CoinCpuTime()-startTime_;
01013 std::cout << "IR: Heuristic: " << COUENNE_INFINITY << std::endl;
01014 std::cout << "IR: Heuristic time: " << elapsed << std::endl;
01015 return foundSolution;
01016 }
01017
01018 int
01019 CouenneIterativeRounding::computeIntAtBound(const double* x){
01020 int numIntAtBound = 0;
01021 for (int i = 0; i < nlp_->getNumCols(); ++i){
01022 if (nlp_->isInteger(i) && (areEqual(x[i], colLower_[i]) ||
01023 areEqual(x[i], colUpper_[i]))){
01024 numIntAtBound++;
01025 }
01026 }
01027 return numIntAtBound;
01028 }
01029
01030 int
01031 CouenneIterativeRounding::computeIntAtBound(const double* x,
01032 double& avgBoundSize){
01033 int numIntAtBound = 0;
01034 avgBoundSize = 0;
01035 for (int i = 0; i < nlp_->getNumCols(); ++i){
01036 if (nlp_->isInteger(i) && (areEqual(x[i], colLower_[i]) ||
01037 areEqual(x[i], colUpper_[i]))){
01038 numIntAtBound++;
01039 avgBoundSize += colUpper_[i] - colLower_[i];
01040 }
01041 }
01042 avgBoundSize /= numIntAtBound;
01043 return numIntAtBound;
01044 }
01045
01046 void
01047 CouenneIterativeRounding::writeLB(OsiRowCut& cut, const double* x,
01048 char sense, double rhs){
01049 cut.mutableRow().clear();
01050 for (int i = 0; i < nlp_->getNumCols(); ++i){
01051 if (nlp_->isInteger(i)){
01052 if (areEqual(x[i], colUpper_[i])){
01053 cut.mutableRow().insert(i, -1);
01054 rhs -= x[i];
01055 }
01056 else if (areEqual(x[i], colLower_[i])){
01057 cut.mutableRow().insert(i, 1);
01058 rhs += x[i];
01059 }
01060 }
01061 }
01062 if (sense == 'L'){
01063 cut.setLb(-COIN_DBL_MAX);
01064 cut.setUb(rhs);
01065 }
01066 else if (sense == 'G'){
01067 cut.setLb(rhs);
01068 cut.setUb(COIN_DBL_MAX);
01069 }
01070 else{
01071 std::cerr << "### ERROR: wrong sense of LB constraint" << std::endl;
01072 exit(1);
01073 }
01074 }
01075
01076 bool
01077 CouenneIterativeRounding::solveMilp(OsiSolverInterface* milp,
01078 double maxTime){
01079 double start = CoinCpuTime();
01080 #ifdef COIN_HAS_CPX
01081 OsiCpxSolverInterface * solver = dynamic_cast<OsiCpxSolverInterface*>(milp);
01082 CPXENVptr env = solver->getEnvironmentPtr();
01083 CPXLPptr cpxlp = solver->getLpPtr(OsiCpxSolverInterface::KEEPCACHED_ALL);
01084 int status = 0;
01085 bool solFound = false;
01086 bool infeasible = false;
01087 while (!solFound && !infeasible && ((CoinCpuTime() - start) < maxTime)){
01088 solver->branchAndBound();
01089 status = CPXgetstat(env, cpxlp);
01090 solFound = ((status == CPXMIP_NODE_LIM_FEAS) ||
01091 (status == CPXMIP_TIME_LIM_FEAS) ||
01092 (status == CPXMIP_MEM_LIM_FEAS) ||
01093 (status == CPXMIP_ABORT_FEAS) ||
01094 (status == CPXMIP_OPTIMAL) ||
01095 (status == CPXMIP_OPTIMAL_TOL) ||
01096 (status == CPXMIP_ABORT_FEAS) ||
01097 (status == CPXMIP_FAIL_FEAS) ||
01098 (status == CPXMIP_FAIL_FEAS_NO_TREE) ||
01099 (status == CPXMIP_FEASIBLE));
01100 infeasible = ((status == CPXMIP_INForUNBD) ||
01101 (status == CPXMIP_OPTIMAL_INFEAS) ||
01102 (status == CPXMIP_INFEASIBLE));
01103 }
01104 if (solFound){
01105 return true;
01106 }
01107 return false;
01108 #else
01109 CbcModel cbcModel(*milp);
01110 for (int i = 0; i < numHeuristics_; ++i){
01111 cbcModel.addHeuristic(heuristics_[i]);
01112 }
01113 cbcModel.setMaximumSeconds(CBCMILPTIME);
01114
01115 while ((cbcModel.getSolutionCount() == 0) &&
01116 (!cbcModel.isProvenInfeasible()) &&
01117 (!cbcModel.isProvenDualInfeasible()) &&
01118 (!cbcModel.isAbandoned()) &&
01119 ((CoinCpuTime() - start) < maxTime)){
01120 cbcModel.branchAndBound();
01121 }
01122
01123 milp = cbcModel.solver();
01124 if (cbcModel.getSolutionCount() > 0){
01125 return true;
01126 }
01127 return false;
01128 #endif
01129 }
01130
01131 int
01132 CouenneIterativeRounding::branchToCut(const double* x,
01133 OsiSolverInterface* solver,
01134 std::vector<int>& previousBranches){
01135 int branch;
01136 bool found = false;
01137 while (!found){
01138 branch = rand()%numIntegers_;
01139 found = true;
01140 for (unsigned int i = 0; i < previousBranches.size(); ++i){
01141 if (branch == previousBranches[i]){
01142 found = false;
01143 break;
01144 }
01145 }
01146 if (found){
01147 previousBranches.push_back(branch);
01148 }
01149 else{
01150 continue;
01151 }
01152 for (int i = 0; i < nlp_->getNumCols(); ++i){
01153 if (model_->isInteger(i)){
01154 if (branch == 0){
01155 branch = i;
01156 break;
01157 }
01158 else{
01159 branch--;
01160 }
01161 }
01162 }
01163 }
01164 double sample = rand();
01165 if (sample <= ((x[branch]-colLower_[branch])/(colUpper_[branch]-colLower_[branch]))){
01166 solver->setColUpper(branch, x[branch]-1);
01167 }
01168 else{
01169 solver->setColLower(branch, x[branch]+1);
01170 }
01171 return branch;
01172 }
01173
01174 void
01175 CouenneIterativeRounding::registerOptions (Ipopt::SmartPtr <Bonmin::RegisteredOptions> roptions){
01176 roptions -> AddStringOption2
01177 ("iterative_rounding_heuristic",
01178 "Do we use the Iterative Rounding heuristic",
01179 "no",
01180 "no","",
01181 "yes","",
01182 "If enabled, a heuristic based on Iterative Rounding is used "
01183 "to find feasible solutions for the problem. "
01184 "The heuristic may take some time, but usually finds good solutions. "
01185 "Recommended if you want good upper bounds and have Cplex. "
01186 "Not recommended if you do not have Cplex");
01187
01188 roptions -> AddNumberOption
01189 ("iterative_rounding_time",
01190 "Specify the maximum time allowed for the Iterative Rounding heuristic",
01191 -1, "Maximum CPU time employed by the Iterative Rounding heuristic; "
01192 "if no solution found in this time, failure is reported. "
01193 "This overrides the CPU time set by Aggressiveness if positive.");
01194
01195 roptions -> AddNumberOption
01196 ("iterative_rounding_time_firstcall",
01197 "Specify the maximum time allowed for the Iterative Rounding heuristic "
01198 "when no feasible solution is known",
01199 -1, "Maximum CPU time employed by the Iterative Rounding heuristic "
01200 "when no solution is known; if no solution found in this time, "
01201 "failure is reported."
01202 "This overrides the CPU time set by Aggressiveness if posive.");
01203
01204 roptions -> AddBoundedIntegerOption
01205 ("iterative_rounding_aggressiveness",
01206 "Aggressiveness of the Iterative Rounding heuristic",
01207 0, 2, 1,
01208 "Set the aggressiveness of the heuristic; i.e., how many iterations "
01209 "should be run, and with which parameters. The maximum time can be "
01210 "overridden by setting the _time and _time_firstcall options. "
01211 "0 = non aggressive, 1 = standard (default), 2 = aggressive.");
01212
01213 roptions -> AddLowerBoundedIntegerOption
01214 ("iterative_rounding_num_fir_points",
01215 "Max number of points rounded at the beginning of Iterative Rounding",
01216 1, 5,
01217 "Number of different points (obtained solving a log-barrier problem) "
01218 "that the heuristic will try to round at most, during its execution "
01219 "at the root node (i.e. the F-IR heuristic). Default 5.");
01220
01221 roptions -> AddBoundedNumberOption
01222 ("iterative_rounding_omega",
01223 "Omega parameter of the Iterative Rounding heuristic",
01224 0, true, 1, true, 0.2,
01225 "Set the omega parameter of the heuristic, which represents a "
01226 "multiplicative factor for the minimum log-barrier parameter "
01227 "of the NLP which is solved to obtain feasible points. This "
01228 "corresponds to $\\omega'$ in the paper. Default 0.2.");
01229
01230 roptions -> AddLowerBoundedIntegerOption
01231 ("iterative_rounding_base_lbrhs",
01232 "Base rhs of the local branching constraint for Iterative Rounding",
01233 0, 15,
01234 "Base rhs for the local branching constraint that defines a "
01235 "neighbourhood of the local incumbent. The base rhs is modified by "
01236 "the algorithm according to variable bounds. This corresponds to "
01237 "k' in the paper. Default 15.");
01238
01239 }
01240
01241 }