00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "BonCbc.hpp"
00012 #include "BonOACutGenerator2.hpp"
00013 #include "BonCbcNlpStrategy.hpp"
00014 #include "BonBabInfos.hpp"
00015 #include "CbcModel.hpp"
00016 #include "CbcBranchActual.hpp"
00017 #include "CbcCutGenerator.hpp"
00018 #include "CbcCompareActual.hpp"
00019
00020 #include "BonExitCodes.hpp"
00021
00022 #include "BonChooseVariable.hpp"
00023 #include "BonGuessHeuristic.hpp"
00024
00025 #include "BonDiver.hpp"
00026
00027
00028 #define CUTOFF_TOL 1e-6
00029
00030
00031 static CbcModel * currentBranchModel = NULL;
00032 Bonmin::OACutGenerator2 * currentOA = NULL;
00033 CbcModel * OAModel;
00034 bool BonminAbortAll;
00035
00036 #define SIGNAL
00037 #ifdef SIGNAL
00038 #include "CoinSignal.hpp"
00039
00040 extern "C"
00041 {
00042
00043 static bool BonminInteruptedOnce =false;
00044 static void signal_handler(int whichSignal) {
00045 if (BonminInteruptedOnce) {
00046 std::cerr<<"User forced interuption"<<std::endl;
00047 exit(0);
00048 }
00049 if (currentBranchModel!=NULL)
00050 currentBranchModel->setMaximumNodes(0);
00051 if (OAModel!=NULL)
00052 OAModel->setMaximumNodes(0);
00053 if (currentOA!=NULL)
00054 currentOA->parameter().maxLocalSearchTime_ = 0.;
00055 BonminAbortAll = true;
00056 BonminInteruptedOnce = true;
00057 return;
00058 }
00059 }
00060 #endif
00061
00062 namespace Bonmin
00063 {
00064
00066 Bab::Bab():
00067 bestSolution_(NULL),
00068 mipStatus_(),
00069 bestObj_(1e200),
00070 bestBound_(-1e200),
00071 continuousRelaxation_(-COIN_DBL_MAX),
00072 numNodes_(0),
00073 mipIterationCount_(0),
00074 model_(),
00075 modelHandler_(NULL),
00076 objects_(0),
00077 nObjects_(0),
00078 usingCouenne_(false)
00079 {}
00080
00082 Bab::~Bab()
00083 {
00084 if (bestSolution_) delete [] bestSolution_;
00085 bestSolution_ = NULL;
00086 for ( int i = 0 ; i < nObjects_ ; i++) {
00087 delete objects_[i];
00088 }
00089 delete [] objects_;
00090 delete modelHandler_;
00091 }
00092
00094 void
00095 Bab::operator()(BabSetupBase & s)
00096 {
00097 branchAndBound(s);
00098 }
00099
00101 void
00102 Bab::branchAndBound(BabSetupBase & s)
00103 {
00104
00105 OsiBabSolver * babInfo = dynamic_cast<OsiBabSolver *>(s.continuousSolver()->getAuxiliaryInfo());
00106 assert(babInfo);
00107 Bonmin::BabInfo * bonBabInfoPtr = dynamic_cast<Bonmin::BabInfo*>(babInfo);
00108 if (bonBabInfoPtr == NULL) {
00109 bonBabInfoPtr = new Bonmin::BabInfo(*babInfo);
00110 s.continuousSolver()->setAuxiliaryInfo(bonBabInfoPtr);
00111 delete bonBabInfoPtr;
00112 bonBabInfoPtr = dynamic_cast<Bonmin::BabInfo*>(s.continuousSolver()->getAuxiliaryInfo());
00113 }
00114 bonBabInfoPtr->setBabPtr(this);
00115
00116 OsiSolverInterface * solver = s.continuousSolver()->clone();
00117 delete modelHandler_;
00118 modelHandler_ = s.continuousSolver()->messageHandler()->clone();
00119 model_.passInMessageHandler(modelHandler_);
00120 model_.assignSolver(solver, true);
00121
00122
00123
00124
00125
00126
00127 int specOpt = s.getIntParameter(BabSetupBase::SpecialOption);
00128 if (specOpt) {
00129 model_.setSpecialOptions(specOpt);
00130 if (specOpt==16) {
00131 CbcNlpStrategy strat(s.getIntParameter(BabSetupBase::MaxFailures),
00132 s.getIntParameter(BabSetupBase::MaxInfeasible),
00133 s.getIntParameter(BabSetupBase::FailureBehavior));
00134 model_.setStrategy(strat);
00135 }
00136 }
00137
00138 model_.setMaximumCutPasses(s.getIntParameter(BabSetupBase::NumCutPasses));
00139 model_.setMaximumCutPassesAtRoot(s.getIntParameter(BabSetupBase::NumCutPassesAtRoot));
00140
00141
00142 for (BabSetupBase::CuttingMethods::iterator i = s.cutGenerators().begin() ;
00143 i != s.cutGenerators().end() ; i++) {
00144
00145 OaDecompositionBase * oa = dynamic_cast<OaDecompositionBase *>(i->cgl);
00146 if (oa && oa->reassignLpsolver())
00147 oa->assignLpInterface(model_.solver());
00148 model_.addCutGenerator(i->cgl,i->frequency,i->id.c_str(), i->normal,
00149 i->atSolution);
00150 }
00151
00152 for (BabSetupBase::HeuristicMethods::iterator i = s.heuristics().begin() ;
00153 i != s.heuristics().end() ; i++) {
00154 CbcHeuristic * heu = i->heuristic;
00155 heu->setModel(&model_);
00156 model_.addHeuristic(heu, i->id.c_str());
00157 }
00158
00159
00160
00161 int logLevel = s.continuousSolver()->messageHandler()->logLevel();
00162
00163
00164 model_.setLogLevel(s.getIntParameter(BabSetupBase::BabLogLevel));
00165
00166
00167 model_.solver()->messageHandler()->setLogLevel(logLevel);
00168
00169 model_.setPrintFrequency(s.getIntParameter(BabSetupBase::BabLogInterval));
00170
00171 bool ChangedObject = false;
00172
00173 if (s.continuousSolver()->objects()==NULL) {
00174
00175 const OsiTMINLPInterface * nlpSolver = s.nonlinearSolver();
00176
00177 const int * priorities = nlpSolver->getPriorities();
00178 const double * upPsCosts = nlpSolver->getUpPsCosts();
00179 const double * downPsCosts = nlpSolver->getDownPsCosts();
00180 const int * directions = nlpSolver->getBranchingDirections();
00181 bool hasPseudo = (upPsCosts!=NULL);
00182 model_.findIntegers(true,hasPseudo);
00183 OsiObject ** simpleIntegerObjects = model_.objects();
00184 int numberObjects = model_.numberObjects();
00185 if (priorities != NULL || directions != NULL || hasPseudo) {
00186 ChangedObject = true;
00187 for (int i = 0 ; i < numberObjects ; i++) {
00188 CbcObject * object = dynamic_cast<CbcObject *>
00189 (simpleIntegerObjects[i]);
00190 int iCol = object->columnNumber();
00191 if (priorities)
00192 object->setPriority(priorities[iCol]);
00193 if (directions)
00194 object->setPreferredWay(directions[iCol]);
00195 if (upPsCosts) {
00196 CbcSimpleIntegerPseudoCost * pscObject =
00197 dynamic_cast<CbcSimpleIntegerPseudoCost*> (object);
00198 pscObject->setUpPseudoCost(upPsCosts[iCol]);
00199 pscObject->setDownPseudoCost(downPsCosts[iCol]);
00200 }
00201 }
00202 }
00203
00204 #if 1
00205
00206 const TMINLP::SosInfo * sos = s.nonlinearSolver()->model()->sosConstraints();
00207 if (!s.getIntParameter(BabSetupBase::DisableSos) && sos && sos->num > 0)
00208
00209 {
00210 const OsiTMINLPInterface * nlpSolver = s.nonlinearSolver();
00211 const int & numSos = sos->num;
00212 (*nlpSolver->messageHandler())<<"Adding "<<sos->num<<" sos constraints."
00213 <<CoinMessageEol;
00214
00215 CbcObject ** objects = new CbcObject*[numSos];
00216 const int * starts = sos->starts;
00217 const int * indices = sos->indices;
00218 const char * types = sos->types;
00219 const double * weights = sos->weights;
00220
00221 bool hasPriorities = false;
00222 const int * varPriorities = nlpSolver->getPriorities();
00223 int numberObjects = model_.numberObjects();
00224 if (varPriorities)
00225 {
00226 for (int i = 0 ; i < numberObjects ; i++) {
00227 if (varPriorities[i]) {
00228 hasPriorities = true;
00229 break;
00230 }
00231 }
00232 }
00233 const int * sosPriorities = sos->priorities;
00234 if (sosPriorities)
00235 {
00236 for (int i = 0 ; i < numSos ; i++) {
00237 if (sosPriorities[i]) {
00238 hasPriorities = true;
00239 break;
00240 }
00241 }
00242 }
00243 for (int i = 0 ; i < numSos ; i++)
00244 {
00245 int start = starts[i];
00246 int length = starts[i + 1] - start;
00247 objects[i] = new CbcSOS(&model_, length, &indices[start],
00248 &weights[start], i, types[i]);
00249
00250 objects[i]->setPriority(10);
00251 if (hasPriorities && sosPriorities && sosPriorities[i]) {
00252 objects[i]->setPriority(sosPriorities[i]);
00253 }
00254 }
00255 model_.addObjects(numSos, objects);
00256 for (int i = 0 ; i < numSos ; i++)
00257 delete objects[i];
00258 delete [] objects;
00259 }
00260 #endif
00261
00262 if (s.objects().size()) {
00263 CbcObject ** objects = new CbcObject *[s.objects().size()];
00264 for (unsigned int i = 0 ; i < s.objects().size() ; i++) {
00265 objects[i] = dynamic_cast<CbcObject *> (s.objects()[i]);
00266 assert(objects[i]);
00267 objects[i]->setModel(&model_);
00268 }
00269 model_.addObjects(s.objects().size(), objects);
00270 delete [] objects;
00271 }
00272
00273 replaceIntegers(model_.objects(), model_.numberObjects());
00274 }
00275 else {
00276
00277 assert (s.branchingMethod() != NULL);
00278
00279 if (!usingCouenne_)
00280 model_.addObjects (s.continuousSolver()->numberObjects(),
00281 s.continuousSolver()->objects());
00282 else {
00283
00284 int nco = s.continuousSolver () -> numberObjects ();
00285 OsiObject **objs = new OsiObject * [nco];
00286 for (int i=0; i<nco; i++)
00287 objs [i] = s.continuousSolver () -> objects () [i];
00288 model_.addObjects (nco, objs);
00289 delete [] objs;
00290 }
00291
00292 CbcBranchDefaultDecision branch;
00293 s.branchingMethod()->setSolver(model_.solver());
00294 BonChooseVariable * strong2 = dynamic_cast<BonChooseVariable *>(s.branchingMethod());
00295 if (strong2)
00296 strong2->setCbcModel(&model_);
00297 branch.setChooseMethod(*s.branchingMethod());
00298
00299 model_.setBranchingMethod(&branch);
00300
00301 model_.solver()->deleteObjects();
00302 }
00303
00304 model_.setDblParam(CbcModel::CbcCutoffIncrement, s.getDoubleParameter(BabSetupBase::CutoffDecr));
00305
00306 model_.setCutoff(s.getDoubleParameter(BabSetupBase::Cutoff) + CUTOFF_TOL);
00307
00308 model_.setDblParam(CbcModel::CbcAllowableGap, s.getDoubleParameter(BabSetupBase::AllowableGap));
00309 model_.setDblParam(CbcModel::CbcAllowableFractionGap, s.getDoubleParameter(BabSetupBase::AllowableFractionGap));
00310
00311
00312
00313 if (s.nodeComparisonMethod()==BabSetupBase::bestBound) {
00314 CbcCompareObjective compare;
00315 model_.setNodeComparison(compare);
00316 }
00317 else if (s.nodeComparisonMethod()==BabSetupBase::DFS) {
00318 CbcCompareDepth compare;
00319 model_.setNodeComparison(compare);
00320 }
00321 else if (s.nodeComparisonMethod()==BabSetupBase::BFS) {
00322 CbcCompareDefault compare;
00323 compare.setWeight(0.0);
00324 model_.setNodeComparison(compare);
00325 }
00326 else if (s.nodeComparisonMethod()==BabSetupBase::dynamic) {
00327 CbcCompareDefault compare;
00328 model_.setNodeComparison(compare);
00329 }
00330 else if (s.nodeComparisonMethod()==BabSetupBase::bestGuess) {
00331
00332
00333 CbcCompareEstimate compare;
00334 model_.setNodeComparison(compare);
00335 GuessHeuristic * guessHeu = new GuessHeuristic(model_);
00336 model_.addHeuristic(guessHeu);
00337 delete guessHeu;
00338 }
00339
00340 if (s.treeTraversalMethod() == BabSetupBase::HeapOnly) {
00341
00342 }
00343 else if (s.treeTraversalMethod() == BabSetupBase::DiveFromBest) {
00344 CbcDiver treeTraversal;
00345 treeTraversal.initialize(s.options());
00346 model_.passInTreeHandler(treeTraversal);
00347 }
00348 else if (s.treeTraversalMethod() == BabSetupBase::ProbedDive) {
00349 CbcProbedDiver treeTraversal;
00350 treeTraversal.initialize(s.options());
00351 model_.passInTreeHandler(treeTraversal);
00352 }
00353 else if (s.treeTraversalMethod() == BabSetupBase::DfsDiveFromBest) {
00354 CbcDfsDiver treeTraversal;
00355 treeTraversal.initialize(s.options());
00356 model_.passInTreeHandler(treeTraversal);
00357 }
00358 else if (s.treeTraversalMethod() == BabSetupBase::DfsDiveDynamic) {
00359 CbcDfsDiver treeTraversal;
00360 treeTraversal.initialize(s.options());
00361 model_.passInTreeHandler(treeTraversal);
00362
00363 DiverCompare compare;
00364 compare.setComparisonDive(*model_.nodeComparison());
00365 compare.setComparisonBound(CbcCompareObjective());
00366 CbcDfsDiver * dfs = dynamic_cast<CbcDfsDiver *> (model_.tree());
00367 assert(dfs);
00368 compare.setDiver(dfs);
00369 model_.setNodeComparison(compare);
00370 }
00371
00372 model_.setNumberStrong(s.getIntParameter(BabSetupBase::NumberStrong));
00373
00374 model_.setNumberBeforeTrust(s.getIntParameter(BabSetupBase::MinReliability));
00375 model_.setNumberPenalties(8);
00376
00377 model_.setDblParam(CbcModel::CbcMaximumSeconds, s.getDoubleParameter(BabSetupBase::MaxTime));
00378
00379 model_.setMaximumNodes(s.getIntParameter(BabSetupBase::MaxNodes));
00380
00381 model_.setMaximumNumberIterations(s.getIntParameter(BabSetupBase::MaxIterations));
00382
00383 model_.setMaximumSolutions(s.getIntParameter(BabSetupBase::MaxSolutions));
00384
00385 model_.setIntegerTolerance(s.getDoubleParameter(BabSetupBase::IntTol));
00386
00387
00388
00389
00390
00391 OsiObject ** objects = model_.objects();
00392 if (specOpt!=16 && objects) {
00393 int numberObjects = model_.numberObjects();
00394 if (objects_ != NULL) {
00395 for (int i = 0 ; i < nObjects_; i++)
00396 delete objects_[i];
00397 }
00398 delete [] objects_;
00399 objects_ = new OsiObject*[numberObjects];
00400 nObjects_ = numberObjects;
00401 for (int i = 0 ; i < numberObjects; i++) {
00402 OsiObject * obj = objects[i];
00403 CbcSimpleInteger * intObj = dynamic_cast<CbcSimpleInteger *> (obj);
00404 if (intObj) {
00405 objects_[i] = intObj->osiObject();
00406 }
00407 else {
00408 CbcSOS * sosObj = dynamic_cast<CbcSOS *>(obj);
00409 if (sosObj) objects_[i] = sosObj->osiObject(model_.solver());
00410 else {
00411 CbcObject * cbcObj = dynamic_cast<CbcObject *>(obj);
00412 if (cbcObj) {
00413 std::cerr<<"Unsupported CbcObject appears in the code"<<std::endl;
00414 throw UNSUPPORTED_CBC_OBJECT;
00415 }
00416 else {
00417 objects_[i]=obj->clone();
00418 }
00419 }
00420 }
00421 }
00422 CbcCutGenerator ** gen = model_.cutGenerators();
00423 int numGen = model_.numberCutGenerators();
00424 for (int i = 0 ; i < numGen ; i++) {
00425 OaDecompositionBase * oa = dynamic_cast<OaDecompositionBase * >(gen[i]->generator());
00426 if (oa)
00427 oa->setObjects(objects_,nObjects_);
00428 }
00429 }
00430
00431 try {
00432
00433 model_.initialSolve();
00434
00435
00436 if (usingCouenne_)
00437 model_.passInSolverCharacteristics (bonBabInfoPtr);
00438
00439 continuousRelaxation_ =model_.solver()->getObjValue();
00440 if (specOpt==16)
00441 {
00442 #if 1
00443 const double * colsol = model_.solver()->getColSolution();
00444 const double * duals = model_.solver()->getRowPrice();
00445 model_.solver()->setColSolution(colsol);
00446 model_.solver()->setRowPrice(duals);
00447 #else
00448 OsiTMINLPInterface * tnlpSolver = dynamic_cast<OsiTMINLPInterface *>(model_.solver());
00449 CoinWarmStart * warm = tnlpSolver->solver()->getWarmStart(tnlpSolver->problem());
00450 tnlpSolver->solver()->setWarmStart(warm, tnlpSolver->problem());
00451 delete warm;
00452 #endif
00453 }
00454
00455 #ifdef SIGNAL
00456 CoinSighandler_t saveSignal=SIG_DFL;
00457
00458 saveSignal = signal(SIGINT,signal_handler);
00459 #endif
00460
00461 currentBranchModel = &model_;
00462
00463
00464
00465 model_.branchAndBound();
00466 }
00467 catch(TNLPSolver::UnsolvedError *E){
00468 s.nonlinearSolver()->model()->finalize_solution(TMINLP::MINLP_ERROR,
00469 0,
00470 NULL,
00471 DBL_MAX);
00472 throw E;
00473
00474 }
00475 numNodes_ = model_.getNodeCount();
00476 bestObj_ = model_.getObjValue();
00477 bestBound_ = model_.getBestPossibleObjValue();
00478 mipIterationCount_ = model_.getIterationCount();
00479
00480 bool hasFailed = false;
00481 if (specOpt==16)
00482 {
00483 CbcNlpStrategy * nlpStrategy = dynamic_cast<CbcNlpStrategy *>(model_.strategy());
00484 if (nlpStrategy)
00485 hasFailed = nlpStrategy->hasFailed();
00486 else
00487 throw -1;
00488 }
00489 else
00490 hasFailed = s.nonlinearSolver()->hasContinuedOnAFailure();
00491
00492
00493
00494
00495
00496
00497 int numberGenerators = model_.numberCutGenerators();
00498 for (int iGenerator=0;iGenerator<numberGenerators;iGenerator++) {
00499 CbcCutGenerator * generator = model_.cutGenerator(iGenerator);
00500
00501 if (true&&!generator->numberCutsInTotal())
00502 continue;
00503 if(modelHandler_->logLevel() >= 1) {
00504 *modelHandler_ << generator->cutGeneratorName()
00505 << "was tried" << generator->numberTimesEntered()
00506 << "times and created" << generator->numberCutsInTotal()+generator->numberColumnCuts()
00507 << "cuts of which" << generator->numberCutsActive()
00508 << "were active after adding rounds of cuts";
00509 if (generator->timing()) {
00510 char timebuf[20];
00511 sprintf(timebuf, "(%.3fs)", generator->timeInCutGenerator());
00512 *modelHandler_ << timebuf << CoinMessageEol;
00513 }
00514 else {
00515 *modelHandler_ << CoinMessageEol;
00516 }
00517 }
00518 }
00519
00520 if (hasFailed) {
00521 *model_.messageHandler()
00522 << "************************************************************" << CoinMessageEol
00523 << "WARNING : Optimization failed on an NLP during optimization" << CoinMessageEol
00524 << " (no optimal value found within tolerances)." << CoinMessageEol
00525 << " Optimization was not stopped because option" << CoinMessageEol
00526 << "\"nlp_failure_behavior\" has been set to fathom but" << CoinMessageEol
00527 << " beware that reported solution may not be optimal" << CoinMessageEol
00528 << "************************************************************" << CoinMessageEol;
00529 }
00530 TMINLP::SolverReturn status = TMINLP::MINLP_ERROR;
00531
00532 if (model_.numberObjects()==0) {
00533 if (bestSolution_)
00534 delete [] bestSolution_;
00535 OsiSolverInterface * solver =
00536 (s.nonlinearSolver() == s.continuousSolver())?
00537 model_.solver() : s.nonlinearSolver();
00538 bestObj_ = bestBound_ = solver->getObjValue();
00539 }
00540
00541 if (bonBabInfoPtr->bestSolution2().size() > 0) {
00542 assert((int) bonBabInfoPtr->bestSolution2().size() == s.nonlinearSolver()->getNumCols());
00543 if (bestSolution_)
00544 delete [] bestSolution_;
00545 bestSolution_ = new double[s.nonlinearSolver()->getNumCols()];
00546 std::copy(bonBabInfoPtr->bestSolution2().begin(), bonBabInfoPtr->bestSolution2().end(),
00547 bestSolution_);
00548 bestObj_ = (bonBabInfoPtr->bestObj2());
00549 (*s.nonlinearSolver()->messageHandler())<<"\nReal objective function: "
00550 <<bestObj_<<CoinMessageEol;
00551 }
00552 else if (model_.bestSolution()) {
00553 if (bestSolution_)
00554 delete [] bestSolution_;
00555 bestSolution_ = new double[s.nonlinearSolver()->getNumCols()];
00556 CoinCopyN(model_.bestSolution(), s.nonlinearSolver()->getNumCols(), bestSolution_);
00557 }
00558 if (model_.status() == 0) {
00559 if(model_.isContinuousUnbounded()){
00560 status = TMINLP::CONTINUOUS_UNBOUNDED;
00561 mipStatus_ = UnboundedOrInfeasible;
00562 }
00563 else
00564 if (bestSolution_) {
00565 status = TMINLP::SUCCESS;
00566 mipStatus_ = FeasibleOptimal;
00567 }
00568 else {
00569 status = TMINLP::INFEASIBLE;
00570 mipStatus_ = ProvenInfeasible;
00571 }
00572 }
00573 else if (model_.status() == 1) {
00574 status = TMINLP::LIMIT_EXCEEDED;
00575 if (bestSolution_) {
00576 mipStatus_ = Feasible;
00577 }
00578 else {
00579 mipStatus_ = NoSolutionKnown;
00580 }
00581 }
00582 else if (model_.status()==2) {
00583 status = TMINLP::MINLP_ERROR;
00584 }
00585 s.nonlinearSolver()->model()->finalize_solution(status,
00586 s.nonlinearSolver()->getNumCols(),
00587 bestSolution_,
00588 bestObj_);
00589 }
00590
00591
00593 double
00594 Bab::bestBound()
00595 {
00596 if (mipStatus_ == FeasibleOptimal) return bestObj_;
00597 else if (mipStatus_ == ProvenInfeasible) return 1e200;
00598 else return bestBound_;
00599 }
00600 }