BonOaDecBase.cpp
Go to the documentation of this file.
1 // (C) Copyright International Business Machines (IBM) 2006
2 // All Rights Reserved.
3 // This code is published under the Eclipse Public License.
4 //
5 // Authors :
6 // P. Bonami, International Business Machines
7 //
8 // Date : 12/07/2006
9 
10 #include <sstream>
11 #include <climits>
12 
13 #include <algorithm>
14 #include "BonOaDecBase.hpp"
15 
16 
17 #include "BonminConfig.h"
18 
19 #include "OsiClpSolverInterface.hpp"
20 
21 #include "CbcModel.hpp"
22 #include "CbcStrategy.hpp"
23 #include "BonCbcLpStrategy.hpp"
24 #ifdef COIN_HAS_CPX
25 #include "OsiCpxSolverInterface.hpp"
26 #include "cplex.h"
27 #define CHECK_CPX_STAT(a,b) if(b) throw CoinError("Error in CPLEX call",__FILE__,a);
28 
29 #endif
30 #include "BonCbc.hpp"
31 #include "BonSolverHelp.hpp"
32 //The following two are to interupt the solution of sub-mip through CTRL-C
33 extern CbcModel * OAModel;
34 
35 namespace Bonmin {
36 
37 
39  bool reassignLpsolver):
40  CglCutGenerator(),
41  nlp_(b.nonlinearSolver()),
42  s_(&b),
43  lp_(NULL),
44  objects_(NULL),
45  nObjects_(0),
46  nLocalSearch_(0),
47  handler_(NULL),
48  leaveSiUnchanged_(leaveSiUnchanged),
49  reassignLpsolver_(reassignLpsolver),
50  timeBegin_(0),
51  numSols_(0),
52  parameters_(),
53  currentNodeNumber_(-1)
54  {
55  handler_ = new CoinMessageHandler();
56  int logLevel;
57  b.options()->GetIntegerValue("oa_log_level",logLevel,b.prefix());
58  b.options()->GetNumericValue("oa_log_frequency",parameters_.logFrequency_,b.prefix());
59  b.options()->GetNumericValue("allowable_fraction_gap", parameters_.gap_tol_, b.prefix());
60  handler_ -> setLogLevel(logLevel);
61  b.options()->GetIntegerValue("solution_limit", parameters_.maxSols_,b.prefix());
62 
64  timeBegin_ = CoinCpuTime();
65  b.options()->GetIntegerValue("milp_log_level",parameters_.subMilpLogLevel_,b.prefix());
66  b.options()->GetNumericValue("cutoff_decr",parameters_.cbcCutoffIncrement_,b.prefix());
67  b.options()->GetNumericValue("integer_tolerance",parameters_.cbcIntegerTolerance_,b.prefix());
68  int ivalue;
69  b.options()->GetEnumValue("add_only_violated_oa", ivalue,b.prefix());
71  b.options()->GetEnumValue("oa_cuts_scope", ivalue,b.prefix());
72  parameters_.global_ = ivalue;
73 }
74 
76  (const OaDecompositionBase & other)
77  :
78  CglCutGenerator(other),
79  nlp_(other.nlp_),
80  s_(other.s_),
81  lp_(other.lp_),
82  objects_(other.objects_),
83  nObjects_(other.nObjects_),
84  nLocalSearch_(0),
85  messages_(other.messages_),
86  leaveSiUnchanged_(other.leaveSiUnchanged_),
87  reassignLpsolver_(other.reassignLpsolver_),
88  timeBegin_(0),
89  numSols_(other.numSols_),
90  parameters_(other.parameters_),
91  currentNodeNumber_(other.currentNodeNumber_)
92  {
93  timeBegin_ = CoinCpuTime();
94  handler_ = other.handler_->clone();
95  }
98  global_(true),
99  addOnlyViolated_(false),
100  cbcCutoffIncrement_(1e-06),
101  cbcIntegerTolerance_(1e-05),
102  gap_tol_(1e-05),
103  maxLocalSearch_(0),
104  maxLocalSearchTime_(3600),
105  subMilpLogLevel_(0),
106  maxSols_(INT_MAX),
107  logFrequency_(1000.),
108  strategy_(NULL)
109  {}
110 
113  {
114  delete handler_;
115  }
116 
117 
120  global_(other.global_),
121  addOnlyViolated_(other.addOnlyViolated_),
122  cbcCutoffIncrement_(other.cbcCutoffIncrement_),
123  cbcIntegerTolerance_(other.cbcIntegerTolerance_),
124  gap_tol_(other.gap_tol_),
125  maxLocalSearch_(other.maxLocalSearch_),
126  maxLocalSearchTime_(other.maxLocalSearchTime_),
127  subMilpLogLevel_(other.subMilpLogLevel_),
128  maxSols_(other.maxSols_),
129  logFrequency_(other.logFrequency_),
130  strategy_(NULL)
131  {
132  if (other.strategy_)
133  strategy_ = other.strategy_->clone();
134  }
135 
136 
137 
139 (OsiSolverInterface * si,
140  bool saveNumRows,
141  bool saveBasis,
142  bool saveBounds,
143  bool saveCutoff,
144  bool resolve):
145  si_(si),
146  initialNumberRows_(-1),
147  colLower_(NULL),
148  colUpper_(NULL),
149  warm_(NULL),
150  cutoff_(DBL_MAX),
151  deleteSolver_(false),
152  objects_(NULL),
153  nObjects_(0)
154 {
155  getCached();
156  if (saveNumRows)
157  initialNumberRows_ = numrows_;
158  if (saveBasis)
159  warm_ = si->getWarmStart();
160  if (saveBounds) {
161  colLower_ = new double[numcols_];
162  colUpper_ = new double[numcols_];
163  CoinCopyN(si->getColLower(), numcols_ , colLower_);
164  CoinCopyN(si->getColUpper(), numcols_ , colUpper_);
165  }
166  if (saveCutoff)
167  si->getDblParam(OsiDualObjectiveLimit, cutoff_);
168  si->messageHandler()->setLogLevel(0);
169  if (resolve) si->resolve();
170 }
171 
172 
174 (const OsiSolverInterface & si):
175  si_(NULL),
176  initialNumberRows_(-1),
177  colLower_(NULL),
178  colUpper_(NULL),
179  warm_(NULL),
180  cutoff_(DBL_MAX),
181  deleteSolver_(true),
182  objects_(NULL),
183  nObjects_(0)
184 {
185  si_ = si.clone();
186  getCached();
187 }
188 
190 {
191  if (warm_) delete warm_;
192  if (colLower_) delete [] colLower_;
193  if (colUpper_) delete [] colUpper_;
194  if (deleteSolver_) delete si_;
195 }
196 
197 void
199 {
200  if (initialNumberRows_ >= 0) {
201  int nRowsToDelete = si_->getNumRows() - initialNumberRows_;
202  int * rowsToDelete = new int[nRowsToDelete];
203  for (int i = 0 ; i < nRowsToDelete ; i++) {
204  rowsToDelete[i] = i + initialNumberRows_;
205  }
206  si_->deleteRows(nRowsToDelete, rowsToDelete);
207  delete [] rowsToDelete;
208  numrows_ = si_->getNumRows() ;
209  }
210 
211  if (colLower_) {
212  si_->setColLower(colLower_);
213  }
214 
215  if (colUpper_) {
216  si_->setColUpper(colUpper_);
217  }
218 
219  if (cutoff_<COIN_DBL_MAX) {
220  si_->setDblParam(OsiDualObjectiveLimit, cutoff_);
221  }
222 
223  if (warm_) {
224  if (si_->setWarmStart(warm_)==false) {
225  throw CoinError("Fail restoring the warm start at the end of procedure",
226  "restore","OaDecompositionBase::SaveSolverState") ;
227  }
228  }
229  getCached();
230 }
231 
232 void
233 OaDecompositionBase::passInMessageHandler(CoinMessageHandler * handler)
234 {
235  int logLevel = handler_->logLevel();
236  delete handler_;
237  handler_=handler->clone();
238  handler_->setLogLevel(logLevel);
239 }
240 
242 void
243 OaDecompositionBase::generateCuts(const OsiSolverInterface &si, OsiCuts & cs,
244  const CglTreeInfo info) {
245  if (nlp_ == NULL) {
246  throw CoinError("Error in cut generator for outer approximation no NLP ipopt assigned", "generateCuts", "OaDecompositionBase");
247  }
248 
249  // babInfo is used to communicate with the b-and-b solver (Cbc or Bcp).
250  BabInfo * babInfo = dynamic_cast<BabInfo *> (si.getAuxiliaryInfo());
251  assert(babInfo);
252  assert(babInfo->babPtr());
253  numSols_ = babInfo->babPtr()->model().getSolutionCount ();
254  CglTreeInfo info_copy = info;
255  const CbcNode * node = babInfo->babPtr()->model().currentNode();
256  info_copy.level = (node == NULL) ? 0 : babInfo->babPtr()->model().currentNode()->depth();
257  if(babInfo->hasSolution()) numSols_ ++;
258  if (babInfo)
259  if (!babInfo->mipFeasible())
260  return;
261 
262  //Get the continuous solution
263  const double *colsol = si.getColSolution();
264 
265 
266  vector<double> savedColLower(nlp_->getNumCols());
267  CoinCopyN(nlp_->getColLower(), nlp_->getNumCols(), savedColLower());
268  vector<double> savedColUpper(nlp_->getNumCols());
269  CoinCopyN(nlp_->getColUpper(), nlp_->getNumCols(), savedColUpper());
270 
271 
272  OsiBranchingInformation brInfo(nlp_, false);
273  brInfo.solution_ = colsol;
274  //Check integer infeasibility
277 
278 
279  //Check nodeNumber if it did not change scan savedCuts_ if one is violated force it and exit
280  int nodeNumber = babInfo->babPtr()->model().getNodeCount();
281  if(nodeNumber == currentNodeNumber_){
282 #ifdef OA_DEBUG
283  printf("OA decomposition recalled from the same node!\n");
284 #endif
285  int numCuts = savedCuts_.sizeRowCuts();
286  for(int i = 0 ; i < numCuts ; i++){
287  //Check if cuts off solution
288  if(savedCuts_.rowCut(i).violated(colsol) > 0.){
289 #ifdef OA_DEBUG
290  printf("A violated saved cut has been found\n");
291 #endif
292  savedCuts_.rowCut(i).setEffectiveness(9.99e99);
293  cs.insert(savedCuts_.rowCut(i));
294  savedCuts_.eraseRowCut(i);
295  return;
296  i--; numCuts--;
297  }
298  }
299  }
300  else {
301  currentNodeNumber_ = nodeNumber;
302  savedCuts_.dumpCuts();
303  }
304 
305  if (!isInteger) {
306  if (!doLocalSearch(babInfo))//create sub mip solver.
307  return;
308  }
309 
310  //get the current cutoff
311  double cutoff;
312  si.getDblParam(OsiDualObjectiveLimit, cutoff);
313 
314  // Save solvers state if needed
315 
316  solverManip * lpManip = NULL;
317  if (lp_ != NULL) {
318  assert(lp_ == &si);
319  lpManip = new solverManip(lp_, true, leaveSiUnchanged_, true, true);
320  }
321  else {
322  lpManip = new solverManip(si);
323  }
324  lpManip->setObjects(objects_, nObjects_);
325 
326  double milpBound = performOa(cs, *lpManip, babInfo, cutoff, info_copy);
327 
328  if(babInfo->hasSolution()){
329  babInfo->babPtr()->model().setSolutionCount (numSols_ - 1);
330  }
331 
332  //Transmit the bound found by the milp
333  {
334  if (milpBound>-1e100)
335  {
336  // Also store into solver
337  if (babInfo)
338  babInfo->setMipBound(milpBound);
339  }
340  } //Clean everything :
341 
342  // Reset the two solvers
343  if (leaveSiUnchanged_)
344  lpManip->restore();
345  delete lpManip;
346 
347  nlp_->setColLower(savedColLower());
348  nlp_->setColUpper(savedColUpper());
349 
350  return;
351 }
352 
353 void
355  numrows_ = si_->getNumRows();
356  numcols_ = si_->getNumCols();
357  siColLower_ = si_->getColLower();
358  siColUpper_ = si_->getColUpper();
359 }
360 
361 
363 bool
364 OaDecompositionBase::post_nlp_solve(BabInfo * babInfo, double cutoff) const{
365  nSolve_++;
366  bool return_value = false;
367  if (nlp_->isProvenOptimal()) {
368  handler_->message(FEASIBLE_NLP, messages_)
370  <<nlp_->getObjValue()<<CoinMessageEol;
371 
372 #ifdef OA_DEBUG
373  const double * colsol2 = nlp_->getColSolution();
374  debug_.checkInteger(*nlp_,std::cerr);
375 #endif
376 
377  if ((nlp_->getObjValue() < cutoff) ) {
378  handler_->message(UPDATE_UB, messages_)
379  <<nlp_->getObjValue()
380  <<CoinCpuTime()-timeBegin_
381  <<CoinMessageEol;
382 
383  return_value = true;
384  // Also pass it to solver
385  assert(babInfo);
386  if (babInfo) {
387  int numcols = nlp_->getNumCols();
388  double * lpSolution = new double[numcols + 1];
389  CoinCopyN(nlp_->getColSolution(), numcols, lpSolution);
390  lpSolution[numcols] = nlp_->getObjValue();
391  babInfo->setSolution(lpSolution,
392  numcols + 1, lpSolution[numcols]);
393  delete [] lpSolution;
394  }
395  }
396  }
397  else if (nlp_->isAbandoned() || nlp_->isIterationLimitReached()) {
398  (*handler_)<<"Unsolved NLP... exit"<<CoinMessageEol;
399  }
400  else {
403  <<CoinMessageEol;
404  }
405  return return_value;
406 }
407 
408 void
410 
411 
412 }
413 
414 #ifdef OA_DEBUG
415 bool
416 OaDecompositionBase::OaDebug::checkInteger(const OsiSolverInterface &nlp,
417  std::ostream & os) const {
418  const double * colsol = nlp.getColSolution();
419  int numcols = nlp.getNumCols();
420  for (int i = 0 ; i < numcols ; i++) {
421  if (nlp.isInteger(i)) {
422  if (fabs(colsol[i]) - floor(colsol[i] + 0.5) >
423  1e-07) {
424  std::cerr<<"Integer infeasible point (should not be), integer infeasibility for variable "<<i
425  <<" is, "<<fabs(colsol[i] - floor(colsol[i] + 0.5))<<std::endl;
426  }
427  }
428  return true;
429  }
430 
431 }
432 
433 void
434 OaDecompositionBase::OaDebug::printEndOfProcedureDebugMessage(const OsiCuts &cs,
435  bool foundSolution,
436  double solValue,
437  double milpBound,
438  bool isInteger,
439  bool feasible,
440  std::ostream & os) const{
441  std::cout<<"------------------------------------------------------------------"
442  <<std::endl;
443  std::cout<<"OA procedure finished"<<std::endl;
444  std::cout<<"Generated "<<cs.sizeRowCuts()<<std::endl;
445  if (foundSolution)
446  std::cout <<"Found NLP-integer feasible solution of value : "<<solValue<<std::endl;
447  std::cout<<"Current MILP lower bound is : "<<milpBound<<std::endl;
448  std::cout<<"-------------------------------------------------------------------"<<std::endl;
449  std::cout<<"Stopped because : isInteger "<<isInteger<<", feasible "<<feasible<<std::endl<<std::endl;
450 
451 }
452 
453 
454 
455 #endif
456 }/* End namespace Bonmin. */
457 
OaDecompositionBase(BabSetupBase &b, bool leaveSiUnchanged, bool reassignLpsolver)
New usefull constructor.
int maxSols_
maximum number of solutions
Small class to manipulatee various things in an OsiSolverInterface and restore them.
virtual bool isAbandoned() const
Are there a numerical difficulties?
OsiCuts savedCuts_
Saved cuts: in some cases when using OA to check feasible solution algorithm may loop because Cbc rem...
virtual const double * getColLower() const
Get pointer to array[getNumCols()] of column lower bounds.
void fint fint fint real fint real real real real real real real real real fint real fint fint fint real fint fint fint fint * info
void passInMessageHandler(CoinMessageHandler *handler)
bool reassignLpsolver_
Do we need to reassign the lp solver with Cbc.
bool addOnlyViolated_
Add only violated OA inequalities.
virtual void generateCuts(const OsiSolverInterface &si, OsiCuts &cs, const CglTreeInfo info=CglTreeInfo())
Standard cut generation methods.
OsiSolverInterface * lp_
A linear solver.
virtual bool doLocalSearch(BabInfo *babInfo) const =0
virutal method to decide if local search is performed
double cbcIntegerTolerance_
integer tolerance (has to be the same as Cbc&#39;s)
bool hasSolution() const
Definition: BonBabInfos.hpp:49
virtual int getNumCols() const
Get number of columns.
virtual bool isProvenOptimal() const
Is optimality proven?
virtual double getObjValue() const
Get objective function value (can&#39;t use default)
OsiObject ** objects_
Some objects the feasiblitiy of which to verify.
solverManip(OsiSolverInterface *si, bool saveNumRows=true, bool saveBasis=true, bool saveBounds=false, bool saveCutoff=false, bool resolve=true)
Constructor.
CoinMessageHandler * handler_
messages handler.
double gap_tol_
setting for gap tolerance.
int nObjects_
Number of objects.*/.
CbcModel * OAModel
Definition: BonCbc.cpp:36
virtual const double * getColSolution() const
Get pointer to array[getNumCols()] of primal solution vector.
void fint fint fint real fint real real real real real real real real real * e
virtual void setColUpper(int elementIndex, double elementValue)
Set a single column upper bound.
A class to have all elements necessary to setup a branch-and-bound.
double timeBegin_
time of construction
void setupMipSolver(BabSetupBase &b, const std::string &prefix)
virtual ~OaDecompositionBase()
Destructor.
Parameters parameters_
Parameters.
int currentNodeNumber_
Store the current node number.
int numSols_
number of solutions found by OA_decomposition.
double cbcCutoffIncrement_
cutoff min increase (has to be intialized trhough Cbc)
virtual bool isIterationLimitReached() const
Iteration limit reached?
int nSolve_
Number of nlp solved done.
int subMilpLogLevel_
sub milp log level.
Bab * babPtr()
Pointer to the branch-and-bound algorithm (to access CbcModel).
Definition: BonBabInfos.hpp:44
virtual int getIterationCount() const
Get how many iterations it took to solve the problem (whatever &quot;iteration&quot; mean to the solver...
fint lp_
bool leaveSiUnchanged_
Wether or not we should remove cuts at the end of the procedure.
double logFrequency_
Frequency of log.
CoinMessages messages_
Messages for OA.
virtual double performOa(OsiCuts &cs, solverManip &lpManip, BabInfo *babInfo, double &, const CglTreeInfo &info) const =0
virtual method which performs the OA algorithm by modifying lp and nlp.
virtual const double * getColUpper() const
Get pointer to array[getNumCols()] of column upper bounds.
BabSetupBase * s_
Pointer to setup.
Output messages for Outer approximation cutting planes.
Ipopt::SmartPtr< Ipopt::OptionsList > options()
Acces list of Options.
void setObjects(OsiObject **objects, int nObjects)
Set objects.
Base class for OA algorithms.
static char prefix[100]
Definition: BM_lp.cpp:26
virtual void setColLower(int elementIndex, double elementValue)
Set a single column lower bound.
bool integerFeasible(OsiSolverInterface &si, const OsiBranchingInformation &info, double integer_tolerance, OsiObject **objects, int nObjects)
Check for integer feasibility of a solution return 1 if it is.
OsiTMINLPInterface * nlp_
Pointer to nlp interface.
return b
Definition: OSdtoa.cpp:1719
Parameters()
Constructor with default values.
const char * prefix() const
Get prefix to use for options.
const CbcModel & model() const
Get cbc model used to solve.
Definition: BonCbc.hpp:87
Bonmin class for passing info between components of branch-and-cuts.
Definition: BonBabInfos.hpp:19
CbcStrategy * strategy_
Strategy to apply when using Cbc as MILP sub-solver.
bool post_nlp_solve(BabInfo *babInfo, double cutoff) const
Solve the nlp and do output.
bool isInteger(CouNumber x)
is this number integer?