00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "CouenneAggrProbing.hpp"
00012 #include "CouenneProblemElem.hpp"
00013 #include "CouenneExprVar.hpp"
00014 #include "CouenneExprOpp.hpp"
00015
00016 #include "CouenneBab.hpp"
00017 #include "CouenneCutGenerator.hpp"
00018 #include <string>
00019
00020 #define COUENNE_AGGR_PROBING_FINITE_BOUND 1.0e+10
00021 #define COUENNE_AGGR_PROBING_MIN_INTERVAL 1.0e-2
00022 #define COUENNE_AGGR_PROBING_BND_RELAX COUENNE_EPS
00023
00024 using namespace Couenne;
00025
00026 CouenneAggrProbing::CouenneAggrProbing(CouenneSetup *setup,
00027 const Ipopt::SmartPtr<Ipopt::OptionsList> options)
00028 {
00029 couenne_ = setup;
00030 numCols_ = couenne_->couennePtr()->Problem()->nVars();
00031 maxTime_ = COIN_DBL_MAX;
00032 maxFailedSteps_ = 10;
00033 maxNodes_ = 1000;
00034 initCutoff_ = COUENNE_INFINITY;
00035 restoreCutoff_ = false;
00036
00037 }
00038
00039 CouenneAggrProbing::CouenneAggrProbing(const CouenneAggrProbing &rhs){
00040 couenne_ = new CouenneSetup(*rhs.couenne_);
00041 numCols_ = rhs.numCols_;
00042 maxTime_ = rhs.maxTime_;
00043 maxFailedSteps_ = rhs.maxFailedSteps_;
00044 maxNodes_ = rhs.maxNodes_;
00045 initCutoff_ = rhs.initCutoff_;
00046 restoreCutoff_ = rhs.restoreCutoff_;
00047 }
00048
00049 CouenneAggrProbing::~CouenneAggrProbing(){
00050 }
00051
00052 void CouenneAggrProbing::registerOptions(Ipopt::SmartPtr <Bonmin::RegisteredOptions> roptions) {
00053
00054 }
00055
00056 double CouenneAggrProbing::getMaxTime() const {
00057 return maxTime_;
00058 }
00059
00060 void CouenneAggrProbing::setMaxTime(double value){
00061 maxTime_ = value;
00062 }
00063
00064 int CouenneAggrProbing::getMaxFailedSteps() const {
00065 return maxFailedSteps_;
00066 }
00067
00068 void CouenneAggrProbing::setMaxFailedSteps(int value){
00069 maxFailedSteps_ = value;
00070 }
00071
00072 int CouenneAggrProbing::getMaxNodes() const {
00073 return maxNodes_;
00074 }
00075
00076 void CouenneAggrProbing::setMaxNodes(int value){
00077 maxNodes_ = value;
00078 }
00079
00080 bool CouenneAggrProbing::getRestoreCutoff() const {
00081 return restoreCutoff_;
00082 }
00083
00084 void CouenneAggrProbing::setRestoreCutoff(bool value){
00085 restoreCutoff_ = value;
00086 }
00087
00088 double CouenneAggrProbing::probeVariable(int index, bool probeLower){
00089
00090
00091 OsiSolverInterface* nlp = couenne_->nonlinearSolver();
00092 OsiSolverInterface* lp = couenne_->continuousSolver();
00093 CouenneProblem* problem = couenne_->couennePtr()->Problem();
00094
00095
00096 double initUpper = lp->getColUpper()[index];
00097 double initLower = lp->getColLower()[index];
00098
00099 double* initLowerLp = new double[numCols_];
00100 double* initUpperLp = new double[numCols_];
00101
00102 memcpy(initLowerLp, lp->getColLower(), numCols_*sizeof(double));
00103 memcpy(initUpperLp, lp->getColUpper(), numCols_*sizeof(double));
00104
00105 if (initUpper < initLower + COUENNE_EPS){
00106
00107 return ((probeLower) ? initLower : initUpper);
00108 }
00109
00110
00111 int indobj = problem->Obj(0)->Body()->Index();
00112
00113
00114 double initCutoff = problem->getCutOff ();
00115
00116 double* initCutoffSol = NULL;
00117
00118 if (restoreCutoff_ && problem->getCutOff() < COUENNE_INFINITY){
00119 initCutoffSol = new double[numCols_];
00120 memcpy(initCutoffSol, problem->getCutOffSol(), numCols_*sizeof(double));
00121 }
00122
00123
00124 Bonmin::BabSetupBase::NodeComparison initNodeComparison =
00125 couenne_->nodeComparisonMethod();
00126 int initMaxNodes = couenne_->getIntParameter(Bonmin::BabSetupBase::MaxNodes);
00127 double initMaxTime = couenne_->getDoubleParameter(Bonmin::BabSetupBase::MaxTime);
00128 int initMaxSol = couenne_->getIntParameter(Bonmin::BabSetupBase::MaxSolutions);
00129 couenne_->setNodeComparisonMethod(Bonmin::BabSetupBase::bestBound);
00130
00131 couenne_->setIntParameter(Bonmin::BabSetupBase::MaxNodes, maxNodes_);
00132 couenne_->setIntParameter(Bonmin::BabSetupBase::MaxSolutions, COIN_INT_MAX);
00133 problem->setCheckAuxBounds(true);
00134
00136 Bonmin::BabSetupBase::HeuristicMethods heuristics = couenne_->heuristics();
00137 couenne_->heuristics().clear();
00138
00139 double currentBound = (probeLower) ? initLower : initUpper;
00140 double startTime = CoinCpuTime();
00141 int failedSteps = 0;
00142 double intervalSize = 0.0;
00143 double tryBound = 0.0;
00144
00145 int iter = 0;
00146
00147 if (probeLower)
00148 std::cout << "Probing lower on var " << index << std::endl;
00149 else
00150 std::cout << "Probing upper on var " << index << std::endl;
00151
00152 if ((fabs(currentBound) > COUENNE_AGGR_PROBING_FINITE_BOUND) &&
00153 ((probeLower && initUpper > -COUENNE_AGGR_PROBING_FINITE_BOUND) ||
00154 (!probeLower && initLower < COUENNE_AGGR_PROBING_FINITE_BOUND))){
00155
00156
00157
00158
00159 if (probeLower){
00160 tryBound = -COUENNE_AGGR_PROBING_FINITE_BOUND;
00161 lp->setColLower(index, currentBound);
00162 problem->Lb()[index] = currentBound;
00163 lp->setColUpper(index, tryBound);
00164 problem->Ub()[index] = tryBound;
00165 if (index < problem->nOrigVars()){
00166 nlp->setColLower(index, currentBound);
00167 nlp->setColUpper(index, tryBound);
00168 }
00169 }
00170 else{
00171 tryBound = COUENNE_AGGR_PROBING_FINITE_BOUND;
00172 lp->setColLower(index, tryBound);
00173 problem->Lb()[index] = tryBound;
00174 lp->setColUpper(index, currentBound);
00175 problem->Ub()[index] = currentBound;
00176 if (index < problem->nOrigVars()){
00177 nlp->setColLower(index, tryBound);
00178 nlp->setColUpper(index, currentBound);
00179 }
00180 }
00181
00183 couenne_->setDoubleParameter(Bonmin::BabSetupBase::MaxTime,
00184 CoinMin(maxTime_-(CoinCpuTime()-startTime),
00185 maxTime_*0.5));
00186
00187 if (restoreCutoff_){
00188 problem->resetCutOff(initCutoff);
00189 if (indobj >= 0)
00190 problem->Ub(indobj) = initCutoff;
00191 problem->installCutOff();
00192 }
00193
00194 std::cout << "Iteration " << iter << ", current bound " << currentBound
00195 << ", try bound " << tryBound << std::endl;
00196
00198
00199
00200
00201 CouenneBab bb;
00202
00203 bb(couenne_);
00204 if (bb.model().isProvenInfeasible()){
00206 currentBound = tryBound;
00207 std::cout << "Probing succeeded; brought to finite" << std::endl;
00208 }
00209 else{
00211 std::cout << "Probing failed; still infinity, exit" << std::endl;
00212 }
00213 iter++;
00214 }
00215
00216
00217
00218
00219
00220 intervalSize = 0.1;
00221
00222 if (intervalSize < COUENNE_AGGR_PROBING_MIN_INTERVAL){
00223 intervalSize = COUENNE_AGGR_PROBING_MIN_INTERVAL;
00224 }
00225
00226 while ((fabs(currentBound) <= COUENNE_AGGR_PROBING_FINITE_BOUND) &&
00227 ((CoinCpuTime() - startTime) < maxTime_) &&
00228 (failedSteps < maxFailedSteps_) &&
00229 (intervalSize >= COUENNE_AGGR_PROBING_MIN_INTERVAL) &&
00230 iter < 100){
00231
00233 if (probeLower){
00234 tryBound = currentBound + intervalSize;
00235 if (tryBound > initUpper){
00236
00237
00238 tryBound = initUpper;
00239 }
00240 if (lp->isInteger(index)){
00241 tryBound = floor(tryBound);
00242 }
00243
00244 lp->setColLower(index, currentBound - COUENNE_AGGR_PROBING_BND_RELAX);
00245 problem->Lb()[index] = currentBound - COUENNE_AGGR_PROBING_BND_RELAX;
00246 lp->setColUpper(index, tryBound + COUENNE_AGGR_PROBING_BND_RELAX);
00247 problem->Ub()[index] = tryBound + COUENNE_AGGR_PROBING_BND_RELAX;
00248 if (index < problem->nOrigVars()){
00249 nlp->setColLower(index, currentBound - COUENNE_AGGR_PROBING_BND_RELAX);
00250 nlp->setColUpper(index, tryBound + COUENNE_AGGR_PROBING_BND_RELAX);
00251 }
00252 }
00253 else{
00254 tryBound = currentBound - intervalSize;
00255 if (tryBound < initLower){
00256
00257
00258 tryBound = initLower;
00259 }
00260 if (lp->isInteger(index)){
00261 tryBound = ceil(tryBound);
00262 }
00263
00264 lp->setColLower(index, tryBound - COUENNE_AGGR_PROBING_BND_RELAX);
00265 problem->Lb()[index] = tryBound - COUENNE_AGGR_PROBING_BND_RELAX;
00266 lp->setColUpper(index, currentBound + COUENNE_AGGR_PROBING_BND_RELAX);
00267 problem->Ub()[index] = currentBound + COUENNE_AGGR_PROBING_BND_RELAX;
00268 if (index < problem->nOrigVars()){
00269 nlp->setColLower(index, tryBound - COUENNE_AGGR_PROBING_BND_RELAX);
00270 nlp->setColUpper(index, currentBound + COUENNE_AGGR_PROBING_BND_RELAX);
00271 }
00272 }
00273
00274 lp->resolve();
00275 problem->domain()->push(numCols_, lp->getColSolution(),
00276 lp->getColLower(), lp->getColUpper());
00277
00279 couenne_->setDoubleParameter(Bonmin::BabSetupBase::MaxTime,
00280 CoinMin(maxTime_-(CoinCpuTime()-startTime),
00281 maxTime_*0.5));
00282
00283 if (restoreCutoff_){
00284 if (indobj >= 0)
00285 problem->Ub(indobj) = initCutoff;
00286 problem->resetCutOff(initCutoff);
00287 problem->installCutOff();
00288 }
00289
00290 std::cout << "Iteration " << iter << ", current bound " << currentBound
00291 << ", try bound " << tryBound << std::endl;
00292
00294
00295
00296
00297 CouenneBab bb;
00298 bb(couenne_);
00299
00300 problem->domain()->pop();
00301
00302 double obj = 0.0;
00304 bool intervalSearched = (bb.model().isProvenOptimal() ||
00305 bb.model().isProvenInfeasible());
00306
00307 if ((!intervalSearched) ||
00308 (restoreCutoff_ &&
00309 problem->getCutOffSol() &&
00310 problem->checkNLP(problem->getCutOffSol(), obj, true))){
00312 if (lp->isInteger(index) && fabs(tryBound-currentBound) < 0.5){
00314 failedSteps = maxFailedSteps_;
00315 }
00316 else{
00317 intervalSize /= 2;
00318 }
00319 failedSteps++;
00320 std::cout << "Probing failed; shrinking interval" << std::endl;
00321 }
00322 else{
00327 if (lp->isInteger(index) && fabs(tryBound-currentBound) < 0.5){
00330 intervalSize = 1.0;
00331 }
00332 else{
00333 intervalSize *= 2;
00334 }
00335 currentBound = tryBound;
00336 if (lp->isInteger(index)){
00337 if (probeLower){
00338 currentBound += 1.0;
00339 }
00340 else {
00341 currentBound -= 1.0;
00342 }
00343 }
00344 failedSteps = 0;
00345 std::cout << "Probing succeeded; enlarging interval" << std::endl;
00346 }
00347
00348
00349
00350 if ((probeLower && fabs(currentBound-initUpper) < COUENNE_EPS) ||
00351 (!probeLower && fabs(currentBound-initLower) < COUENNE_EPS)){
00352 failedSteps = maxFailedSteps_;
00353 }
00354
00355
00356 if (restoreCutoff_){
00357 if (indobj >= 0)
00358 problem->Ub(indobj) = initCutoff;
00359 problem->resetCutOff(initCutoff);
00360 problem->installCutOff();
00361 }
00362
00363 problem->domain()->pop();
00364
00365 iter++;
00366 }
00367
00370 lp->setColLower(initLowerLp);
00371 lp->setColUpper(initUpperLp);
00372 nlp->setColLower(initLowerLp);
00373 nlp->setColUpper(initUpperLp);
00374 memcpy(problem->Lb(), initLowerLp, numCols_*sizeof(double));
00375 memcpy(problem->Ub(), initUpperLp, numCols_*sizeof(double));
00376
00378 problem->setCheckAuxBounds(false);
00379
00380 couenne_->setNodeComparisonMethod(initNodeComparison);
00381 couenne_->setIntParameter(Bonmin::BabSetupBase::MaxSolutions, initMaxSol);
00382 couenne_->setIntParameter(Bonmin::BabSetupBase::MaxNodes, initMaxNodes);
00383 couenne_->setDoubleParameter(Bonmin::BabSetupBase::MaxTime, initMaxTime);
00384 couenne_->heuristics() = heuristics;
00385
00387 if (restoreCutoff_){
00388 problem->resetCutOff();
00389 problem->setCutOff(initCutoff, initCutoffSol);
00390 if (initCutoffSol){
00391 delete[] initCutoffSol;
00392 }
00393 }
00394
00395 delete[] initLowerLp;
00396 delete[] initUpperLp;
00397
00399 return currentBound;
00400
00401 }
00402
00403 double CouenneAggrProbing::probeVariable2(int index, bool probeLower){
00404
00405
00406
00407
00408 OsiSolverInterface* lp = couenne_->continuousSolver();
00409 CouenneProblem* problem = couenne_->couennePtr()->Problem();
00410
00411
00412 double initUpper = lp->getColUpper()[index];
00413 double initLower = lp->getColLower()[index];
00414
00415 if (initUpper < initLower + COUENNE_EPS){
00416
00417 return ((probeLower) ? initLower : initUpper);
00418 }
00419
00423 Bonmin::BabSetupBase::NodeComparison initNodeComparison =
00424 couenne_->nodeComparisonMethod();
00425 int initMaxNodes = couenne_->getIntParameter(Bonmin::BabSetupBase::MaxNodes);
00426 double initMaxTime = couenne_->getDoubleParameter(Bonmin::BabSetupBase::MaxTime);
00427 int initMaxSol = couenne_->getIntParameter(Bonmin::BabSetupBase::MaxSolutions);
00428 couenne_->setNodeComparisonMethod (Bonmin::BabSetupBase::bestBound);
00429 couenne_->setIntParameter(Bonmin::BabSetupBase::MaxNodes, maxNodes_);
00430 couenne_->setIntParameter(Bonmin::BabSetupBase::MaxSolutions, COIN_INT_MAX);
00431
00435 Bonmin::BabSetupBase::HeuristicMethods heuristics = couenne_->heuristics();
00436 couenne_->heuristics().clear();
00437
00439 double* initLpObj = new double[numCols_];
00440 memcpy(initLpObj, lp->getObjCoefficients(), numCols_*sizeof(double));
00441 expression* initProbObj = problem->Obj(0)->Body();
00442
00443 double* newLpObj = new double[numCols_];
00444 memset(newLpObj, 0, numCols_*sizeof(double));
00445
00446
00447 expression* extraVar = NULL;
00448
00449 lp->writeLp("before");
00450
00451 if (probeLower){
00452 std::cout << "Probing LOWER" << std::endl;
00453
00454 newLpObj[index] = 1.0;
00455 lp->setObjective(newLpObj);
00456
00457 lp->writeLp("lower");
00458
00459
00460 problem->Obj(0)->Body(problem->Variables()[index]);
00461
00462
00463
00464
00465 }
00466 else{
00467
00468
00469
00470
00471
00472 int extraCol = numCols_;
00473 lp->setObjective(newLpObj);
00474 lp->addCol(0, NULL, NULL, -initUpper, -initLower, 1.0);
00475
00476
00477 int rowIndices[2] = {index, extraCol};
00478 double rowElements[2] = {1.0, 1.0};
00479 lp->addRow(2, rowIndices, rowElements, 0.0, 0.0);
00480 lp->resolve();
00481
00482
00483 extraVar = problem->addVariable(lp->isInteger(index), NULL);
00484
00485
00486 problem->Obj(0)->Body(extraVar);
00487
00488
00489
00490
00491
00492 lp->writeLp("upper");
00493 }
00494
00495 couenne_->setNodeComparisonMethod (Bonmin::BabSetupBase::bestBound);
00496 couenne_->setIntParameter(Bonmin::BabSetupBase::MaxNodes, maxNodes_);
00497 couenne_->setDoubleParameter(Bonmin::BabSetupBase::MaxTime,
00498 maxTime_);
00499
00500
00501
00502
00503 CouenneBab bb;
00504 bb(couenne_);
00505
00506 double bestBound = bb.model().getBestPossibleObjValue();
00507
00508 std::cout << "Obtained bound: " << bb.model().getBestPossibleObjValue() << std::endl;
00509
00510
00512 couenne_->setNodeComparisonMethod (initNodeComparison);
00513 couenne_->setIntParameter(Bonmin::BabSetupBase::MaxNodes, initMaxNodes);
00514 couenne_->setDoubleParameter(Bonmin::BabSetupBase::MaxTime, initMaxTime);
00515 couenne_->setIntParameter(Bonmin::BabSetupBase::MaxSolutions, initMaxSol);
00516 couenne_->heuristics() = heuristics;
00517
00518 if (!probeLower){
00519 int extra = lp->getNumCols()-1;
00520 lp->deleteCols(1, &extra);
00521 extra = lp->getNumRows()-1;
00522 lp->deleteRows(1, &extra);
00523 problem->Variables().pop_back();
00524 delete extraVar;
00525
00526 }
00527
00528 lp->setObjective(initLpObj);
00529 problem->Obj(0)->Body(initProbObj);
00530
00531 delete[] initLpObj;
00532 delete[] newLpObj;
00533
00534 return ((probeLower) ? bestBound : -bestBound);
00535
00536 }