/home/coin/SVN-release/OS-2.4.0/Bonmin/src/Algorithms/OaGenerators/BonOaDecBase.cpp

Go to the documentation of this file.
00001 // (C) Copyright International Business Machines (IBM) 2006
00002 // All Rights Reserved.
00003 // This code is published under the Common Public License.
00004 //
00005 // Authors :
00006 // P. Bonami, International Business Machines
00007 //
00008 // Date :  12/07/2006
00009 
00010 #include <sstream>
00011 #include <climits>
00012 
00013 #include <algorithm>
00014 #include "BonOaDecBase.hpp"
00015 
00016 
00017 #include "BonminConfig.h"
00018 
00019 #include "OsiClpSolverInterface.hpp"
00020 
00021 #include "CbcModel.hpp"
00022 #include "CbcStrategy.hpp"
00023 #include "BonCbcLpStrategy.hpp"
00024 #ifdef COIN_HAS_CPX
00025 #include "OsiCpxSolverInterface.hpp"
00026 #include "cplex.h"
00027 #define CHECK_CPX_STAT(a,b) if(b) throw CoinError("Error in CPLEX call",__FILE__,a);
00028 
00029 #endif
00030 #include "BonCbc.hpp"
00031 #include "BonSolverHelp.hpp"
00032 //The following two are to interupt the solution of sub-mip through CTRL-C
00033 extern CbcModel * OAModel;
00034 
00035 namespace Bonmin {
00036 
00037 
00038   OaDecompositionBase::OaDecompositionBase(BabSetupBase &b, bool leaveSiUnchanged,
00039       bool reassignLpsolver):
00040       CglCutGenerator(),
00041       nlp_(b.nonlinearSolver()),
00042       lp_(NULL),
00043       objects_(NULL),
00044       nObjects_(0),
00045       nLocalSearch_(0),
00046       handler_(NULL),
00047       leaveSiUnchanged_(leaveSiUnchanged),
00048       reassignLpsolver_(reassignLpsolver),
00049       timeBegin_(0),
00050       numSols_(0),
00051       parameters_(),
00052       currentNodeNumber_(-1)
00053   {
00054     handler_ = new CoinMessageHandler();
00055     int logLevel;
00056     b.options()->GetIntegerValue("oa_log_level",logLevel,b.prefix());
00057     b.options()->GetNumericValue("oa_log_frequency",parameters_.logFrequency_,b.prefix());
00058     b.options()->GetNumericValue("allowable_fraction_gap", parameters_.gap_tol_, b.prefix());
00059     handler_ -> setLogLevel(logLevel);
00060     b.options()->GetIntegerValue("solution_limit", parameters_.maxSols_,b.prefix());
00061 
00062     messages_ = OaMessages();
00063     timeBegin_ = CoinCpuTime();
00064     b.options()->GetIntegerValue("milp_log_level",parameters_.subMilpLogLevel_,b.prefix());
00065     b.options()->GetNumericValue("cutoff_decr",parameters_.cbcCutoffIncrement_,b.prefix());
00066     b.options()->GetNumericValue("integer_tolerance",parameters_.cbcIntegerTolerance_,b.prefix());
00067     int ivalue;
00068     b.options()->GetEnumValue("add_only_violated_oa", ivalue,b.prefix());
00069     parameters_.addOnlyViolated_ = ivalue;
00070     b.options()->GetEnumValue("oa_cuts_scope", ivalue,b.prefix());
00071     parameters_.global_ = ivalue;
00072 }
00073 
00074   OaDecompositionBase::OaDecompositionBase
00075   (const OaDecompositionBase & other)
00076       :
00077       CglCutGenerator(other),
00078       nlp_(other.nlp_),
00079       lp_(other.lp_),
00080       objects_(other.objects_),
00081       nObjects_(other.nObjects_),
00082       nLocalSearch_(0),
00083       messages_(other.messages_),
00084       leaveSiUnchanged_(other.leaveSiUnchanged_),
00085       reassignLpsolver_(other.reassignLpsolver_),
00086       timeBegin_(0),
00087       numSols_(other.numSols_),
00088       parameters_(other.parameters_),
00089       currentNodeNumber_(other.currentNodeNumber_)
00090   {
00091     timeBegin_ = CoinCpuTime();
00092     handler_ = other.handler_->clone();
00093   }
00095   OaDecompositionBase::Parameters::Parameters():
00096       global_(true),
00097       addOnlyViolated_(false),
00098       cbcCutoffIncrement_(1e-06),
00099       cbcIntegerTolerance_(1e-05),
00100       maxLocalSearch_(0),
00101       maxLocalSearchTime_(3600),
00102       subMilpLogLevel_(0),
00103       maxSols_(INT_MAX),
00104       logFrequency_(1000.),
00105       gap_tol_(1e-05),
00106       strategy_(NULL)
00107   {}
00108 
00110   OaDecompositionBase::~OaDecompositionBase()
00111   {
00112     delete handler_;
00113   }
00114 
00115 
00117   OaDecompositionBase::Parameters::Parameters(const Parameters & other):
00118       global_(other.global_),
00119       addOnlyViolated_(other.addOnlyViolated_),
00120       cbcCutoffIncrement_(other.cbcCutoffIncrement_),
00121       cbcIntegerTolerance_(other.cbcIntegerTolerance_),
00122       gap_tol_(other.gap_tol_),
00123       maxLocalSearch_(other.maxLocalSearch_),
00124       maxLocalSearchTime_(other.maxLocalSearchTime_),
00125       subMilpLogLevel_(other.subMilpLogLevel_),
00126       maxSols_(other.maxSols_),
00127       logFrequency_(other.logFrequency_),
00128       strategy_(NULL)
00129   {
00130     if (other.strategy_)
00131       strategy_ = other.strategy_->clone();
00132   }
00133 
00134 
00135 
00136 OaDecompositionBase::solverManip::solverManip
00137 (OsiSolverInterface * si,
00138  bool saveNumRows,
00139  bool saveBasis,
00140  bool saveBounds,
00141  bool saveCutoff,
00142  bool resolve):
00143     si_(si),
00144     initialNumberRows_(-1),
00145     colLower_(NULL),
00146     colUpper_(NULL),
00147     warm_(NULL),
00148     cutoff_(DBL_MAX),
00149     deleteSolver_(false),
00150     objects_(NULL),
00151     nObjects_(0)
00152 {
00153   getCached();
00154   if (saveNumRows)
00155     initialNumberRows_ = numrows_;
00156   if (saveBasis)
00157     warm_ = si->getWarmStart();
00158   if (saveBounds) {
00159     colLower_ = new double[numcols_];
00160     colUpper_ = new double[numcols_];
00161     CoinCopyN(si->getColLower(), numcols_ , colLower_);
00162     CoinCopyN(si->getColUpper(), numcols_ , colUpper_);
00163   }
00164   if (saveCutoff)
00165     si->getDblParam(OsiDualObjectiveLimit, cutoff_);
00166   si->messageHandler()->setLogLevel(0);
00167   if (resolve) si->resolve();
00168 }
00169 
00170 
00171 OaDecompositionBase::solverManip::solverManip
00172 (const OsiSolverInterface & si):
00173     si_(NULL),
00174     initialNumberRows_(-1),
00175     colLower_(NULL),
00176     colUpper_(NULL),
00177     warm_(NULL),
00178     cutoff_(DBL_MAX),
00179     deleteSolver_(true),
00180     objects_(NULL),
00181     nObjects_(0)
00182 {
00183   si_ = si.clone();
00184   getCached();
00185 }
00186 
00187 OaDecompositionBase::solverManip::~solverManip()
00188 {
00189   if (warm_) delete warm_;
00190   if (colLower_) delete [] colLower_;
00191   if (colUpper_) delete [] colUpper_;
00192   if (deleteSolver_) delete si_;
00193 }
00194 
00195 void
00196 OaDecompositionBase::solverManip::restore()
00197 {
00198   if (initialNumberRows_ >= 0) {
00199     int nRowsToDelete = si_->getNumRows() - initialNumberRows_;
00200     int * rowsToDelete = new int[nRowsToDelete];
00201     for (int i = 0 ; i < nRowsToDelete ; i++) {
00202       rowsToDelete[i] = i + initialNumberRows_;
00203     }
00204     si_->deleteRows(nRowsToDelete, rowsToDelete);
00205     delete [] rowsToDelete;
00206     numrows_ = si_->getNumRows() ;
00207   }
00208 
00209   if (colLower_) {
00210     si_->setColLower(colLower_);
00211   }
00212 
00213   if (colUpper_) {
00214     si_->setColUpper(colUpper_);
00215   }
00216 
00217   if (cutoff_<COIN_DBL_MAX) {
00218     si_->setDblParam(OsiDualObjectiveLimit, cutoff_);
00219   }
00220 
00221   if (warm_) {
00222     if (si_->setWarmStart(warm_)==false) {
00223       throw CoinError("Fail restoring the warm start at the end of procedure",
00224           "restore","OaDecompositionBase::SaveSolverState") ;
00225     }
00226   }
00227   getCached();
00228 }
00229 
00230 void
00231 OaDecompositionBase::passInMessageHandler(CoinMessageHandler * handler)
00232 {
00233   int logLevel = handler_->logLevel();
00234   delete handler_;
00235   handler_=handler->clone();
00236   handler_->setLogLevel(logLevel);
00237 }
00238 
00240 void
00241 OaDecompositionBase::generateCuts(const OsiSolverInterface &si,  OsiCuts & cs,
00242     const CglTreeInfo info) const{
00243   if (nlp_ == NULL) {
00244     throw CoinError("Error in cut generator for outer approximation no NLP ipopt assigned", "generateCuts", "OaDecompositionBase");
00245   }
00246 
00247   // babInfo is used to communicate with the b-and-b solver (Cbc or Bcp).
00248   BabInfo * babInfo = dynamic_cast<BabInfo *> (si.getAuxiliaryInfo());
00249   assert(babInfo);
00250   assert(babInfo->babPtr());
00251   numSols_ = babInfo->babPtr()->model().getSolutionCount ();
00252   CglTreeInfo info_copy = info;
00253   const CbcNode * node = babInfo->babPtr()->model().currentNode();
00254   info_copy.level = (node == NULL) ? 0 : babInfo->babPtr()->model().currentNode()->depth();
00255   if(babInfo->hasSolution()) numSols_ ++;
00256   if (babInfo)
00257     if (!babInfo->mipFeasible())
00258       return;
00259 
00260   //Get the continuous solution
00261   const double *colsol = si.getColSolution();
00262 
00263 
00264   vector<double> savedColLower(nlp_->getNumCols());
00265   CoinCopyN(nlp_->getColLower(), nlp_->getNumCols(), savedColLower());
00266   vector<double> savedColUpper(nlp_->getNumCols());
00267   CoinCopyN(nlp_->getColUpper(), nlp_->getNumCols(), savedColUpper());
00268 
00269 
00270   OsiBranchingInformation brInfo(nlp_, false);
00271   brInfo.solution_ = colsol;
00272   //Check integer infeasibility
00273   bool isInteger = integerFeasible(*nlp_, brInfo, parameters_.cbcIntegerTolerance_,
00274                               objects_, nObjects_);
00275 
00276 
00277   //Check nodeNumber if it did not change scan savedCuts_ if one is violated force it and exit
00278   int nodeNumber = babInfo->babPtr()->model().getNodeCount();
00279   if(nodeNumber == currentNodeNumber_){
00280 #ifdef OA_DEBUG
00281     printf("OA decomposition recalled from the same node!\n");
00282 #endif
00283     int numCuts = savedCuts_.sizeRowCuts();
00284     for(int i = 0 ; i < numCuts ; i++){
00285        //Check if cuts off solution
00286        if(savedCuts_.rowCut(i).violated(colsol) > 0.){
00287 #ifdef OA_DEBUG
00288          printf("A violated cut has been found\n");
00289 #endif
00290          savedCuts_.rowCut(i).setEffectiveness(9.99e99);
00291          cs.insert(savedCuts_.rowCut(i));
00292          savedCuts_.eraseRowCut(i);
00293          return;
00294          i--; numCuts--;
00295        }
00296     }
00297   }
00298   else {
00299     currentNodeNumber_ = nodeNumber;
00300     savedCuts_.dumpCuts();
00301   } 
00302          
00303   if (!isInteger) {
00304     if (!doLocalSearch(babInfo))//create sub mip solver.
00305       return;
00306   }
00307 
00308   //get the current cutoff
00309   double cutoff;
00310   si.getDblParam(OsiDualObjectiveLimit, cutoff);
00311 
00312   // Save solvers state if needed
00313 
00314   solverManip * lpManip = NULL;
00315   if (lp_ != NULL) {
00316       assert(lp_ == &si);
00317       lpManip = new solverManip(lp_, true, leaveSiUnchanged_, true, true);
00318   }
00319   else {
00320     lpManip = new solverManip(si);
00321   }
00322   lpManip->setObjects(objects_, nObjects_);
00323 
00324   double milpBound = performOa(cs, *lpManip, babInfo, cutoff, info_copy);
00325 
00326   if(babInfo->hasSolution()){
00327      babInfo->babPtr()->model().setSolutionCount (numSols_ - 1);
00328   }
00329 
00330   //Transmit the bound found by the milp
00331   {
00332     if (milpBound>-1e100)
00333     {
00334       // Also store into solver
00335       if (babInfo)
00336         babInfo->setMipBound(milpBound);
00337     }
00338   }  //Clean everything :
00339 
00340   //  Reset the two solvers
00341   if (leaveSiUnchanged_)
00342     lpManip->restore();
00343   delete lpManip;
00344 
00345   nlp_->setColLower(savedColLower());
00346   nlp_->setColUpper(savedColUpper());
00347 
00348   return;
00349 }
00350 
00351 void
00352 OaDecompositionBase::solverManip::getCached(){
00353   numrows_ = si_->getNumRows();
00354   numcols_ = si_->getNumCols();
00355   siColLower_ = si_->getColLower();
00356   siColUpper_ = si_->getColUpper();
00357 }
00358 
00359 
00361 bool
00362 OaDecompositionBase::post_nlp_solve(BabInfo * babInfo, double cutoff) const{
00363   nSolve_++;
00364   bool return_value = false;
00365   if (nlp_->isProvenOptimal()) {
00366     handler_->message(FEASIBLE_NLP, messages_)
00367     <<nlp_->getIterationCount()
00368     <<nlp_->getObjValue()<<CoinMessageEol;
00369 
00370 #ifdef OA_DEBUG
00371     const double * colsol2 = nlp_->getColSolution();
00372     debug_.checkInteger(*nlp_,std::cerr);
00373 #endif
00374 
00375     if ((nlp_->getObjValue() < cutoff) ) {
00376       handler_->message(UPDATE_UB, messages_)
00377       <<nlp_->getObjValue()
00378       <<CoinCpuTime()-timeBegin_
00379       <<CoinMessageEol;
00380 
00381       return_value = true;
00382       // Also pass it to solver
00383       assert(babInfo);
00384       if (babInfo) {
00385         int numcols = nlp_->getNumCols();
00386         double * lpSolution = new double[numcols + 1];
00387         CoinCopyN(nlp_->getColSolution(), numcols, lpSolution);
00388         lpSolution[numcols] = nlp_->getObjValue();
00389         babInfo->setSolution(lpSolution,
00390             numcols + 1, lpSolution[numcols]);
00391         delete [] lpSolution;
00392       }
00393     }
00394   }
00395   else if (nlp_->isAbandoned() || nlp_->isIterationLimitReached()) {
00396     (*handler_)<<"Unsolved NLP... exit"<<CoinMessageEol;
00397   }
00398   else {
00399     handler_->message(INFEASIBLE_NLP, messages_)
00400     <<nlp_->getIterationCount()
00401     <<CoinMessageEol;
00402   }
00403   return return_value;
00404 }
00405 
00406 void 
00407 OaDecompositionBase::setupMipSolver(BabSetupBase &b, const std::string & prefix){
00408 
00409 
00410 }
00411 
00412 #ifdef OA_DEBUG
00413 bool
00414 OaDecompositionBase::OaDebug::checkInteger(const OsiSolverInterface &nlp, 
00415                                            std::ostream & os) const {
00416    const double * colsol = nlp.getColSolution();
00417    int numcols = nlp.getNumCols();
00418   for (int i = 0 ; i < numcols ; i++) {
00419     if (nlp.isInteger(i)) {
00420       if (fabs(colsol[i]) - floor(colsol[i] + 0.5) >
00421           1e-07) {
00422         std::cerr<<"Integer infeasible point (should not be), integer infeasibility for variable "<<i
00423         <<" is, "<<fabs(colsol[i] - floor(colsol[i] + 0.5))<<std::endl;
00424       }
00425     }
00426     return true;
00427   }
00428 
00429 }
00430 
00431 void
00432 OaDecompositionBase::OaDebug::printEndOfProcedureDebugMessage(const OsiCuts &cs,
00433     bool foundSolution,
00434     double solValue,
00435     double milpBound,
00436     bool isInteger,
00437     bool feasible,
00438     std::ostream & os) const{
00439   std::cout<<"------------------------------------------------------------------"
00440   <<std::endl;
00441   std::cout<<"OA procedure finished"<<std::endl;
00442   std::cout<<"Generated "<<cs.sizeRowCuts()<<std::endl;
00443   if (foundSolution)
00444     std::cout <<"Found NLP-integer feasible solution of  value : "<<solValue<<std::endl;
00445   std::cout<<"Current MILP lower bound is : "<<milpBound<<std::endl;
00446   std::cout<<"-------------------------------------------------------------------"<<std::endl;
00447   std::cout<<"Stopped because : isInteger "<<isInteger<<", feasible "<<feasible<<std::endl<<std::endl;
00448 
00449 }
00450 
00451 
00452 
00453 #endif
00454 }/* End namespace Bonmin. */
00455 

Generated on Thu Sep 22 03:05:53 2011 by  doxygen 1.4.7