source: trunk/Bonmin/src/CbcBonmin/BonCbc.cpp @ 1512

Last change on this file since 1512 was 1512, checked in by pbonami, 11 years ago

For ticket 38

File size: 22.2 KB
Line 
1// (C) Copyright International Business Machines Corporation 2007
2// All Rights Reserved.
3// This code is published under the Common Public License.
4//
5// Authors :
6// Pierre Bonami, International Business Machines Corporation
7//
8// Date : 04/19/2007
9
10
11#include "BonCbc.hpp"
12#include "BonOACutGenerator2.hpp"
13#include "BonCbcNlpStrategy.hpp"
14#include "BonBabInfos.hpp"
15#include "CbcModel.hpp"
16#include "CbcBranchActual.hpp"
17#include "CbcCutGenerator.hpp"
18#include "CbcCompareActual.hpp"
19
20#include "BonExitCodes.hpp"
21
22#include "BonChooseVariable.hpp"
23#include "BonGuessHeuristic.hpp"
24
25#include "BonDiver.hpp"
26#include "BonLinearCutsGenerator.hpp"
27#include "BonTMINLPLinObj.hpp"
28// sets cutoff a bit above real one, to avoid single-point feasible sets
29#define CUTOFF_TOL 1e-6
30
31// Code to enable user interuption
32static CbcModel * currentBranchModel = NULL; //pointer to the main b&b
33Bonmin::OACutGenerator2 * currentOA = NULL; //pointer to the OA generator
34CbcModel * OAModel; // pointer to the submip if using Cbc
35bool BonminAbortAll;
36
37#define SIGNAL
38#ifdef SIGNAL
39#include "CoinSignal.hpp"
40
41extern "C"
42{
43
44  static bool BonminInteruptedOnce =false;
45  static void signal_handler(int whichSignal) {
46    if (BonminInteruptedOnce) {
47      std::cerr<<"User forced interuption"<<std::endl;
48      exit(0);
49    }
50    if (currentBranchModel!=NULL)
51      currentBranchModel->setMaximumNodes(0); // stop at next node
52    if (OAModel!=NULL)
53      OAModel->setMaximumNodes(0); // stop at next node
54    if (currentOA!=NULL)
55      currentOA->parameter().maxLocalSearchTime_ = 0.; // stop OA
56    BonminAbortAll = true;
57    BonminInteruptedOnce = true;
58    return;
59  }
60}
61#endif
62
63namespace Bonmin
64{
65
66  /** Constructor.*/
67  Bab::Bab():
68      bestSolution_(NULL),
69      mipStatus_(),
70      bestObj_(1e200),
71      bestBound_(-1e200),
72      continuousRelaxation_(-COIN_DBL_MAX),
73      numNodes_(0),
74      mipIterationCount_(0),
75      model_(),
76      modelHandler_(NULL),
77      objects_(0),
78      nObjects_(0),
79      usingCouenne_(false)
80  {}
81
82  /** Destructor.*/
83  Bab::~Bab()
84  {
85    if (bestSolution_) delete [] bestSolution_;
86    bestSolution_ = NULL;
87    for ( int i = 0 ; i < nObjects_ ; i++) {
88      delete objects_[i];
89    }
90    delete [] objects_;
91    delete modelHandler_;
92  }
93
94  /**operator() performs the branchAndBound*/
95  void
96  Bab::operator()(BabSetupBase & s)
97  {
98    branchAndBound(s);
99  }
100
101  /** Perform a branch-and-bound on given setup.*/
102  void
103  Bab::branchAndBound(BabSetupBase & s)
104  {
105    /* Put a link to this into solver.*/
106    OsiBabSolver *  babInfo = dynamic_cast<OsiBabSolver *>(s.continuousSolver()->getAuxiliaryInfo());
107    assert(babInfo);
108    Bonmin::BabInfo *  bonBabInfoPtr = dynamic_cast<Bonmin::BabInfo*>(babInfo);
109    if (bonBabInfoPtr == NULL) {//Replace with a Bonmin::babInfo
110      bonBabInfoPtr = new Bonmin::BabInfo(*babInfo);
111      s.continuousSolver()->setAuxiliaryInfo(bonBabInfoPtr);
112      delete bonBabInfoPtr;
113      bonBabInfoPtr = dynamic_cast<Bonmin::BabInfo*>(s.continuousSolver()->getAuxiliaryInfo());
114    }
115    bonBabInfoPtr->setBabPtr(this);
116
117    s.nonlinearSolver()->solver()->setup_global_time_limit(s.getDoubleParameter(BabSetupBase::MaxTime));
118    OsiSolverInterface * solver = s.continuousSolver()->clone();
119    delete modelHandler_;
120    modelHandler_ = s.continuousSolver()->messageHandler()->clone();
121    model_.passInMessageHandler(modelHandler_);
122    model_.assignSolver(solver, true);
123
124
125    //  s.continuousSolver() = model_.solver();
126    //   if(s.continuousSolver()->objects()!=NULL){
127    //     model_.addObjects(s.continuousSolver()->numberObjects(),s.continuousSolver()->objects());
128    //   }
129
130    int specOpt = s.getIntParameter(BabSetupBase::SpecialOption);
131    if (specOpt) {
132      model_.setSpecialOptions(specOpt);
133      if (specOpt==16) {
134        CbcNlpStrategy strat(s.getIntParameter(BabSetupBase::MaxFailures), 
135                             s.getIntParameter(BabSetupBase::MaxInfeasible), 
136                             s.getIntParameter(BabSetupBase::FailureBehavior));
137        model_.setStrategy(strat);
138      }
139    }
140
141    model_.setMaximumCutPasses(s.getIntParameter(BabSetupBase::NumCutPasses));
142    model_.setMaximumCutPassesAtRoot(s.getIntParameter(BabSetupBase::NumCutPassesAtRoot));
143
144    //Setup cutting plane methods
145    for (BabSetupBase::CuttingMethods::iterator i = s.cutGenerators().begin() ;
146        i != s.cutGenerators().end() ; i++) {
147
148      OaDecompositionBase * oa = dynamic_cast<OaDecompositionBase *>(i->cgl);
149      if (oa && oa->reassignLpsolver())
150        oa->assignLpInterface(model_.solver());
151        model_.addCutGenerator(i->cgl,i->frequency,i->id.c_str(), i->normal,
152                               i->atSolution);
153    }
154
155    for (BabSetupBase::HeuristicMethods::iterator i = s.heuristics().begin() ;
156        i != s.heuristics().end() ; i++) {
157      CbcHeuristic * heu = i->heuristic;
158      heu->setModel(&model_);
159      model_.addHeuristic(heu, i->id.c_str());
160    }
161
162
163    //need to record solver logLevel here
164    int logLevel = s.continuousSolver()->messageHandler()->logLevel();
165
166    //Set true branch-and-bound parameters
167    model_.setLogLevel(s.getIntParameter(BabSetupBase::BabLogLevel));
168
169    // Put back solver logLevel
170    model_.solver()->messageHandler()->setLogLevel(logLevel);
171
172    model_.setPrintFrequency(s.getIntParameter(BabSetupBase::BabLogInterval));
173
174    bool ChangedObject = false;
175    //Pass over user set branching priorities to Cbc
176    if (s.continuousSolver()->objects()==NULL) {
177      //assert (s.branchingMethod() == NULL);
178      const OsiTMINLPInterface * nlpSolver = s.nonlinearSolver();
179      //set priorities, prefered directions...
180      const int * priorities = nlpSolver->getPriorities();
181      const double * upPsCosts = nlpSolver->getUpPsCosts();
182      const double * downPsCosts = nlpSolver->getDownPsCosts();
183      const int * directions = nlpSolver->getBranchingDirections();
184      bool hasPseudo = (upPsCosts!=NULL);
185      model_.findIntegers(true,hasPseudo);
186      OsiObject ** simpleIntegerObjects = model_.objects();
187      int numberObjects = model_.numberObjects();
188      if (priorities != NULL || directions != NULL || hasPseudo) {
189        ChangedObject = true;
190        for (int i = 0 ; i < numberObjects ; i++) {
191          CbcObject * object = dynamic_cast<CbcObject *>
192              (simpleIntegerObjects[i]);
193          int iCol = object->columnNumber();
194          if (priorities)
195            object->setPriority(priorities[iCol]);
196          if (directions)
197            object->setPreferredWay(directions[iCol]);
198          if (upPsCosts) {
199            CbcSimpleIntegerPseudoCost * pscObject =
200              dynamic_cast<CbcSimpleIntegerPseudoCost*> (object);
201            pscObject->setUpPseudoCost(upPsCosts[iCol]);
202            pscObject->setDownPseudoCost(downPsCosts[iCol]);
203          }
204        }
205      }
206
207#if 1
208      // Now pass user set Sos constraints (code inspired from CoinSolve.cpp)
209      const TMINLP::SosInfo * sos = s.nonlinearSolver()->model()->sosConstraints();
210      if (!s.getIntParameter(BabSetupBase::DisableSos) && sos && sos->num > 0) 
211        //we have some sos constraints
212      {
213        const OsiTMINLPInterface * nlpSolver = s.nonlinearSolver();
214        const int & numSos = sos->num;
215       (*nlpSolver->messageHandler())<<"Adding "<<sos->num<<" sos constraints."
216                                     <<CoinMessageEol;
217
218        CbcObject ** objects = new CbcObject*[numSos];
219        const int * starts = sos->starts;
220        const int * indices = sos->indices;
221        const char * types = sos->types;
222        const double * weights = sos->weights;
223        //verify if model has user set priorities
224        bool hasPriorities = false;
225        const int * varPriorities = nlpSolver->getPriorities();
226        int numberObjects = model_.numberObjects();
227        if (varPriorities)
228        {
229          for (int i = 0 ; i < numberObjects ; i++) {
230            if (varPriorities[i]) {
231              hasPriorities = true;
232              break;
233            }
234          }
235        }
236        const int * sosPriorities = sos->priorities;
237        if (sosPriorities)
238        {
239          for (int i = 0 ; i < numSos ; i++) {
240            if (sosPriorities[i]) {
241              hasPriorities = true;
242              break;
243            }
244          }
245        }
246        for (int i = 0 ; i < numSos ; i++)
247        {
248          int start = starts[i];
249          int length = starts[i + 1] - start;
250          objects[i] = new CbcSOS(&model_, length, &indices[start],
251              &weights[start], i, types[i]);
252
253          objects[i]->setPriority(10);
254          if (hasPriorities && sosPriorities && sosPriorities[i]) {
255            objects[i]->setPriority(sosPriorities[i]);
256          }
257        }
258        model_.addObjects(numSos, objects);
259        for (int i = 0 ; i < numSos ; i++)
260          delete objects[i];
261        delete [] objects;
262      }
263#endif
264      //If Setup contains more objects add them to Cbc
265      if (s.objects().size()) {
266        CbcObject ** objects = new CbcObject *[s.objects().size()];
267        for (unsigned int i = 0 ; i < s.objects().size() ; i++) {
268          objects[i] = dynamic_cast<CbcObject *> (s.objects()[i]);
269          assert(objects[i]);
270          objects[i]->setModel(&model_);
271        }
272        model_.addObjects(s.objects().size(), objects);
273        delete [] objects;
274      }
275
276      replaceIntegers(model_.objects(), model_.numberObjects());
277    }
278    else {//Pass in objects to Cbc
279    // Redundant definition of default branching (as Default == User)
280    assert (s.branchingMethod() != NULL);
281
282    if (!usingCouenne_)
283      model_.addObjects (s.continuousSolver()->numberObjects(),
284                         s.continuousSolver()->objects());
285    else {
286      // add nonlinear and integer objects (need to add OsiSOS)
287      int nco = s.continuousSolver () -> numberObjects ();
288      OsiObject **objs = new OsiObject * [nco];
289      for (int i=0; i<nco; i++) 
290        objs [i] = s.continuousSolver () -> objects () [i];
291      model_.addObjects (nco, objs);
292      delete [] objs;
293    }
294
295    CbcBranchDefaultDecision branch;
296    s.branchingMethod()->setSolver(model_.solver());
297    BonChooseVariable * strong2 = dynamic_cast<BonChooseVariable *>(s.branchingMethod());
298    if (strong2)
299      strong2->setCbcModel(&model_);
300    branch.setChooseMethod(*s.branchingMethod());
301
302    model_.setBranchingMethod(&branch);
303        // prevent duplicating object when copying in CbcModel.cpp
304        model_.solver()->deleteObjects();
305    }
306
307    model_.setDblParam(CbcModel::CbcCutoffIncrement, s.getDoubleParameter(BabSetupBase::CutoffDecr));
308
309    model_.setCutoff(s.getDoubleParameter(BabSetupBase::Cutoff) + CUTOFF_TOL);
310
311    model_.setDblParam(CbcModel::CbcAllowableGap, s.getDoubleParameter(BabSetupBase::AllowableGap));
312    model_.setDblParam(CbcModel::CbcAllowableFractionGap, s.getDoubleParameter(BabSetupBase::AllowableFractionGap));
313
314    // Definition of node selection strategy
315
316    if (s.nodeComparisonMethod()==BabSetupBase::bestBound) {
317      CbcCompareObjective compare;
318      model_.setNodeComparison(compare);
319    }
320    else if (s.nodeComparisonMethod()==BabSetupBase::DFS) {
321      CbcCompareDepth compare;
322      model_.setNodeComparison(compare);
323    }
324    else if (s.nodeComparisonMethod()==BabSetupBase::BFS) {
325      CbcCompareDefault compare;
326      compare.setWeight(0.0);
327      model_.setNodeComparison(compare);
328    }
329    else if (s.nodeComparisonMethod()==BabSetupBase::dynamic) {
330      CbcCompareDefault compare;
331      model_.setNodeComparison(compare);
332    }
333    else if (s.nodeComparisonMethod()==BabSetupBase::bestGuess) {
334      // Right now, this is a mess.  We need a separation of the
335      // pseudo costs from the ChooseVariable method
336      CbcCompareEstimate compare;
337      model_.setNodeComparison(compare);
338      GuessHeuristic * guessHeu = new GuessHeuristic(model_);
339      model_.addHeuristic(guessHeu);
340      delete guessHeu;
341    }
342
343    if (s.treeTraversalMethod() == BabSetupBase::HeapOnly) {
344      //Do nothing this is the default of Cbc.
345    }
346    else if (s.treeTraversalMethod() == BabSetupBase::DiveFromBest) {
347      CbcDiver treeTraversal;
348      treeTraversal.initialize(s);
349      model_.passInTreeHandler(treeTraversal);
350    }
351    else if (s.treeTraversalMethod() == BabSetupBase::ProbedDive) {
352      CbcProbedDiver treeTraversal;
353      treeTraversal.initialize(s);
354      model_.passInTreeHandler(treeTraversal);
355    }
356    else if (s.treeTraversalMethod() == BabSetupBase::DfsDiveFromBest) {
357      CbcDfsDiver treeTraversal;
358      treeTraversal.initialize(s);
359      model_.passInTreeHandler(treeTraversal);
360    }
361    else if (s.treeTraversalMethod() == BabSetupBase::DfsDiveDynamic) {
362      CbcDfsDiver treeTraversal;
363      treeTraversal.initialize(s);
364      model_.passInTreeHandler(treeTraversal);
365
366      DiverCompare compare;
367      compare.setComparisonDive(*model_.nodeComparison());
368      compare.setComparisonBound(CbcCompareObjective());
369      CbcDfsDiver * dfs = dynamic_cast<CbcDfsDiver *> (model_.tree());
370      assert(dfs);
371      compare.setDiver(dfs);
372      model_.setNodeComparison(compare);
373    }
374
375    model_.setNumberStrong(s.getIntParameter(BabSetupBase::NumberStrong));
376
377    model_.setNumberBeforeTrust(s.getIntParameter(BabSetupBase::MinReliability));
378    model_.setNumberPenalties(8);
379
380    model_.setDblParam(CbcModel::CbcMaximumSeconds, s.getDoubleParameter(BabSetupBase::MaxTime));
381
382    model_.setMaximumNodes(s.getIntParameter(BabSetupBase::MaxNodes));
383
384    model_.setMaximumNumberIterations(s.getIntParameter(BabSetupBase::MaxIterations));
385
386    model_.setMaximumSolutions(s.getIntParameter(BabSetupBase::MaxSolutions));
387
388    model_.setIntegerTolerance(s.getDoubleParameter(BabSetupBase::IntTol));
389
390
391
392    //Get objects from model_ if it is not null means there are some sos constraints or non-integer branching object
393    // pass them to cut generators.
394    OsiObject ** objects = model_.objects();
395    if (specOpt!=16 && objects) {
396      int numberObjects = model_.numberObjects();
397      if (objects_ != NULL) {
398        for (int i = 0 ; i < nObjects_; i++)
399          delete objects_[i];
400      }
401      delete [] objects_;
402      objects_ = new OsiObject*[numberObjects];
403      nObjects_ = numberObjects;
404      for (int i = 0 ; i < numberObjects; i++) {
405        OsiObject * obj = objects[i];
406        CbcSimpleInteger * intObj = dynamic_cast<CbcSimpleInteger *> (obj);
407        if (intObj) {
408          objects_[i] = intObj->osiObject();
409        }
410        else {
411          CbcSOS * sosObj = dynamic_cast<CbcSOS *>(obj);
412          if (sosObj) objects_[i] = sosObj->osiObject(model_.solver());
413          else {//Maybe an unsupported CbcObject
414            CbcObject * cbcObj = dynamic_cast<CbcObject *>(obj);
415            if (cbcObj) {
416              std::cerr<<"Unsupported CbcObject appears in the code"<<std::endl;
417              throw UNSUPPORTED_CBC_OBJECT;
418            }
419            else {//It has to be an OsiObject.
420              objects_[i]=obj->clone();
421            }
422          }
423        }
424      }
425      CbcCutGenerator ** gen = model_.cutGenerators();
426      int numGen = model_.numberCutGenerators();
427      for (int i = 0 ; i < numGen ; i++) {
428        OaDecompositionBase * oa = dynamic_cast<OaDecompositionBase * >(gen[i]->generator());
429        if (oa)//pass objects
430          oa->setObjects(objects_,nObjects_);
431      }
432    }
433
434
435    try {
436    //Get the time and start.
437    {
438      OsiTMINLPInterface * tmpOsi = NULL;
439      if(s.nonlinearSolver() == s.continuousSolver()){
440        tmpOsi = dynamic_cast<OsiTMINLPInterface *> (model_.solver());
441        tmpOsi->forceSolverOutput(s.getIntParameter(BabSetupBase::RootLogLevel)); 
442      }
443      model_.initialSolve();
444      if(tmpOsi != NULL){
445        tmpOsi->setSolverOutputToDefault(); 
446      }
447    }
448
449    int ival;
450    s.options()->GetEnumValue("enable_dynamic_nlp", ival, "bonmin.");
451    if(s.nonlinearSolver() == s.continuousSolver() && ival)
452    {
453      if(!model_.solver()->isProvenOptimal() ){//Something went wrong check if objective is linear and alternate model
454                                            // can be solved
455        OsiTMINLPInterface * tmpOsi = dynamic_cast<OsiTMINLPInterface *> (model_.solver());
456        TMINLPLinObj * tmp_tminlp = dynamic_cast<TMINLPLinObj *> (tmpOsi->model());
457        tmpOsi->setModel(tmp_tminlp->tminlp());
458        model_.initialSolve();
459      } 
460      else {
461        LinearCutsGenerator cgl;
462        cgl.initialize(s); 
463        OsiCuts cuts;
464        cgl.generateCuts(*model_.solver(), cuts);
465        std::vector<OsiRowCut *> mycuts(cuts.sizeRowCuts());
466        for(int i = 0 ; i < cuts.sizeRowCuts() ; i++){
467          mycuts[i] = cuts.rowCutPtr(i);
468        }
469        model_.solver()->applyRowCuts(mycuts.size(), (const OsiRowCut **) &mycuts[0]);
470      }
471
472    model_.solver()->resolve();
473
474    }
475
476    // for Couenne
477    if (usingCouenne_)
478      model_.passInSolverCharacteristics (bonBabInfoPtr);
479
480    continuousRelaxation_ =model_.solver()->getObjValue();
481    if (specOpt==16)//Set warm start point for Ipopt
482    {
483#if 1
484      const double * colsol = model_.solver()->getColSolution();
485      const double * duals = model_.solver()->getRowPrice();
486      model_.solver()->setColSolution(colsol);
487      model_.solver()->setRowPrice(duals);
488#else
489      OsiTMINLPInterface * tnlpSolver = dynamic_cast<OsiTMINLPInterface *>(model_.solver());
490      CoinWarmStart * warm = tnlpSolver->solver()->getWarmStart(tnlpSolver->problem());
491      tnlpSolver->solver()->setWarmStart(warm, tnlpSolver->problem());
492      delete warm;
493#endif
494    }
495
496#ifdef SIGNAL
497    CoinSighandler_t saveSignal=SIG_DFL;
498    // register signal handler
499    saveSignal = signal(SIGINT,signal_handler);
500#endif
501
502    currentBranchModel = &model_;
503
504    // to get node parent info in Cbc, pass parameter 3.
505    //model_.branchAndBound(3);
506    model_.branchAndBound();
507    }
508    catch(TNLPSolver::UnsolvedError *E){
509      s.nonlinearSolver()->model()->finalize_solution(TMINLP::MINLP_ERROR,
510           0,
511           NULL,
512           DBL_MAX);
513      throw E;
514   
515    }
516    numNodes_ = model_.getNodeCount();
517    bestObj_ = model_.getObjValue();
518    bestBound_ = model_.getBestPossibleObjValue();
519    mipIterationCount_ = model_.getIterationCount();
520
521    bool hasFailed = false;
522    if (specOpt==16)//Did we continue branching on a failure
523    {
524      CbcNlpStrategy * nlpStrategy = dynamic_cast<CbcNlpStrategy *>(model_.strategy());
525      if (nlpStrategy)
526        hasFailed = nlpStrategy->hasFailed();
527      else
528        throw -1;
529    }
530    else
531      hasFailed = s.nonlinearSolver()->hasContinuedOnAFailure();
532
533    // Output summarizing cut generators (taken from CbcSolver.cpp)
534    // ToDo put into proper print level
535
536   
537
538    int numberGenerators = model_.numberCutGenerators();
539    for (int iGenerator=0;iGenerator<numberGenerators;iGenerator++) {
540      CbcCutGenerator * generator = model_.cutGenerator(iGenerator);
541      //CglStored * stored = dynamic_cast<CglStored*>(generator->generator());
542       if (true&&!generator->numberCutsInTotal())
543        continue;
544       if(modelHandler_->logLevel() >= 1) {
545        *modelHandler_ << generator->cutGeneratorName()
546                << "was tried" << generator->numberTimesEntered()
547                << "times and created" << generator->numberCutsInTotal()+generator->numberColumnCuts()
548                << "cuts of which" << generator->numberCutsActive()
549                << "were active after adding rounds of cuts";
550         if (generator->timing()) {
551                char timebuf[20];
552                sprintf(timebuf, "(%.3fs)", generator->timeInCutGenerator());
553                *modelHandler_ << timebuf << CoinMessageEol;
554         }
555         else {
556                *modelHandler_ << CoinMessageEol;
557         }
558       }
559    }
560
561    if (hasFailed) {
562        *model_.messageHandler()
563      << "************************************************************" << CoinMessageEol
564      << "WARNING : Optimization failed on an NLP during optimization"  << CoinMessageEol
565      << "  (no optimal value found within tolerances)."  << CoinMessageEol
566      << "  Optimization was not stopped because option"  << CoinMessageEol
567      << "\"nlp_failure_behavior\" has been set to fathom but"  << CoinMessageEol
568      << " beware that reported solution may not be optimal"  << CoinMessageEol
569      << "************************************************************" << CoinMessageEol;
570    }
571    TMINLP::SolverReturn status = TMINLP::MINLP_ERROR;
572
573    if (model_.numberObjects()==0) {
574      if (bestSolution_)
575        delete [] bestSolution_;
576      OsiSolverInterface * solver = 
577             (s.nonlinearSolver() == s.continuousSolver())? 
578             model_.solver() : s.nonlinearSolver();
579      bestSolution_ = new double[solver->getNumCols()];
580      CoinCopyN(solver->getColSolution(), solver->getNumCols(),
581          bestSolution_);
582      bestObj_ = bestBound_ = solver->getObjValue();
583    }
584
585    if (bonBabInfoPtr->bestSolution2().size() > 0) {
586      assert((int) bonBabInfoPtr->bestSolution2().size() == s.nonlinearSolver()->getNumCols());
587      if (bestSolution_)
588        delete [] bestSolution_;
589      bestSolution_ = new double[s.nonlinearSolver()->getNumCols()];
590      std::copy(bonBabInfoPtr->bestSolution2().begin(), bonBabInfoPtr->bestSolution2().end(),
591          bestSolution_);
592      bestObj_ = (bonBabInfoPtr->bestObj2());
593       (*s.nonlinearSolver()->messageHandler())<<"\nReal objective function: "
594                                            <<bestObj_<<CoinMessageEol;
595    }
596    else if (model_.bestSolution()) {
597      if (bestSolution_)
598        delete [] bestSolution_;
599      bestSolution_ = new double[s.nonlinearSolver()->getNumCols()];
600      CoinCopyN(model_.bestSolution(), s.nonlinearSolver()->getNumCols(), bestSolution_);
601    }
602    if (model_.status() == 0) {
603      if(model_.isContinuousUnbounded()){
604        status = TMINLP::CONTINUOUS_UNBOUNDED;
605        mipStatus_ = UnboundedOrInfeasible;
606      }
607      else
608      if (bestSolution_) {
609        status = TMINLP::SUCCESS;
610        mipStatus_ = FeasibleOptimal;
611      }
612      else {
613        status = TMINLP::INFEASIBLE;
614        mipStatus_ = ProvenInfeasible;
615      }
616    }
617    else if (model_.status() == 1) {
618      status = TMINLP::LIMIT_EXCEEDED;
619      if (bestSolution_) {
620        mipStatus_ = Feasible;
621      }
622      else {
623        mipStatus_ = NoSolutionKnown;
624      }
625    }
626    else if (model_.status()==2) {
627      status = TMINLP::MINLP_ERROR;
628    }
629    s.nonlinearSolver()->model()->finalize_solution(status,
630        s.nonlinearSolver()->getNumCols(),
631        bestSolution_,
632        bestObj_);
633  }
634
635
636  /** return the best known lower bound on the objective value*/
637  double
638  Bab::bestBound()
639  {
640    if (mipStatus_ == FeasibleOptimal) return bestObj_;
641    else if (mipStatus_ == ProvenInfeasible) return 1e200;
642    else return bestBound_;
643  }
644}
Note: See TracBrowser for help on using the repository browser.