BonCouenneInterface.cpp
Go to the documentation of this file.
1 /* $Id: BonCouenneInterface.cpp 997 2013-08-11 23:21:38Z pbelotti $ */
2 // (C) Copyright International Business Machines Corporation (IBM) 2006, 2007
3 // All Rights Reserved.
4 // This code is published under the Eclipse Public License (EPL).
5 //
6 // Authors :
7 // Pietro Belotti, Carnegie Mellon University
8 // Pierre Bonami, International Business Machines Corporation
9 //
10 // Date : 12/19/2006
11 
12 
13 #include "BonCouenneInterface.hpp"
14 #include "CoinHelperFunctions.hpp"
15 
16 #include "CouenneProblem.hpp"
17 #include "CouenneProblemElem.hpp"
18 #include "CouenneExprVar.hpp"
19 #include "CouenneRecordBestSol.hpp"
20 
21 using namespace Couenne;
22 
25  AmplInterface(),
26  have_nlp_solution_ (false)
27 {}
28 
31  AmplInterface(other),
32  have_nlp_solution_ (false)
33 {}
34 
37  return new CouenneInterface(*this);
38 }
39 
42 }
43 
44 #ifdef COUENNEINTERFACE_FROM_ASL
45 void
49  // if (!IsValid (app_))
50  //createApplication (roptions, options, journalist, "couenne.");
51  AmplInterface::readAmplNlFile(argv, roptions, options, journalist);
52 }
53 #endif
54 
67 void
69 (OsiSolverInterface &si, CouenneCutGenerator & couenneCg, bool getObj, bool solveNlp) {
70 
71  {
72  int nlpLogLevel;
73  options () -> GetIntegerValue ("nlp_log_level", nlpLogLevel, "couenne.");
74  messageHandler () -> setLogLevel (nlpLogLevel);
75  }
76 
77  CouenneProblem *p = couenneCg.Problem ();
78  bool is_feasible = true;
79 
80  if (solveNlp) {
81 
82  int nvars = p -> nVars();
83 
84  if (p -> doFBBT ()) {
85 
86  // include the rhs of auxiliary-based constraints into the FBBT
87  // (should be useful with Vielma's problems, for example)
88 
89  for (int i=0; i < p -> nCons (); i++) {
90 
91  // for each constraint
92  CouenneConstraint *con = p -> Con (i);
93 
94  // (which has an aux as its body)
95  int index = con -> Body () -> Index ();
96 
97  if ((index >= 0) && (con -> Body () -> Type () == AUX)) {
98 
99  // if there exists violation, add constraint
100  CouNumber
101  l = con -> Lb () -> Value (),
102  u = con -> Ub () -> Value ();
103 
104  // tighten bounds in Couenne's problem representation
105  p -> Lb (index) = CoinMax (l, p -> Lb (index));
106  p -> Ub (index) = CoinMin (u, p -> Ub (index));
107  }
108  }
109 
110  t_chg_bounds *chg_bds = new t_chg_bounds [nvars];
111 
112  for (int i=0; i<nvars; i++) {
113  chg_bds [i].setLower(t_chg_bounds::CHANGED);
114  chg_bds [i].setUpper(t_chg_bounds::CHANGED);
115  }
116 
117  if (!(p -> boundTightening (chg_bds, CglTreeInfo (), NULL))) {
118  is_feasible = false;
119  //*messageHandler() << "Couenne: Warning, tightened NLP is infeasible" << CoinMessageEol;
120  }
121 
122  delete [] chg_bds;
123 
124  const double
125  *nlb = getColLower (),
126  *nub = getColUpper ();
127 
128  for (int i=0; i < p -> nOrigVars () - p -> nDefVars (); i++)
129  if (p -> Var (i) -> Multiplicity () > 0) {
130  /*printf ("---- %4d [%g,%g] [%g,%g]\n", i,
131  nlb [i], nub [i],
132  p -> Lb (i), p -> Ub (i));*/
133 
134  double
135  lower = nlb [i],
136  upper = nub [i];
137 
138  if (lower > upper) CoinSwap (lower, upper);
139  if (p -> Lb (i) > p -> Ub (i)) CoinSwap (p -> Lb (i), p -> Ub (i));
140 
141  if (lower < p -> Lb (i) - COUENNE_EPS) setColLower (i, CoinMin (nub[i], p -> Lb (i)));
142  if (upper > p -> Ub (i) + COUENNE_EPS) setColUpper (i, CoinMax (nlb[i], p -> Ub (i)));
143 
144  } else {
145  // if not enabled, fix them in the NLP solver
146  setColLower (i, -COIN_DBL_MAX);
147  setColUpper (i, COIN_DBL_MAX);
148  }
149  } // ends FBBT part
150 
151  if (is_feasible) {
152  try {
153  options () -> SetNumericValue ("max_cpu_time", CoinMax (0.1, (p -> getMaxCpuTime () - CoinCpuTime ()) / 2));
154 
155  initialSolve ();
156 
157  if (isDualObjectiveLimitReached() &&
158  (getNumIntegers () == 0))
159  *messageHandler () << "Couenne: Warning, NLP is unbounded" << CoinMessageEol;
160  }
162  // wrong, if NLP has problems this is not necessarily true...
163  //is_feasible = false;
164  }
165  }
166 
167  if (!is_feasible) {
168  OsiAuxInfo * auxInfo = si.getAuxiliaryInfo ();
169  Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (auxInfo);
170 
171  if (babInfo)
172  babInfo -> setInfeasibleNode ();
173  }
174 
175  if (is_feasible && isProvenOptimal ()) {
176 
177  CouNumber obj = getObjValue ();
178  const CouNumber *solution = getColSolution ();
179 
180  if (getNumIntegers () > 0) {
181 
182  int
183  norig = p -> nOrigVars () - p -> nDefVars (),
184  nvars = p -> nVars ();
185 
186  bool fractional = false;
187 
188  // if problem is integer, check if any integral variable is
189  // fractional. If so, round them and re-optimize
190 
191  for (int i=0; i<norig; i++)
192  if ((p -> Var (i) -> Multiplicity () > 0) &&
193  p -> Var (i) -> isDefinedInteger () &&
194  (!::isInteger (solution [i]))) {
195  fractional = true;
196  break;
197  }
198 
199  if (fractional) { // try again if solution found by Ipopt is fractional
200 
201  double
202  *lbSave = new double [norig],
203  *ubSave = new double [norig],
204 
205  *lbCur = new double [nvars],
206  *ubCur = new double [nvars],
207 
208  *Y = new double [nvars];
209 
210  CoinCopyN (getColLower (), norig, lbSave);
211  CoinCopyN (getColUpper (), norig, ubSave);
212 
213  CoinFillN (Y, nvars, 0.);
214  CoinFillN (lbCur, nvars, -COUENNE_INFINITY);
215  CoinFillN (ubCur, nvars, COUENNE_INFINITY);
216 
217  CoinCopyN (getColLower (), norig, lbCur);
218  CoinCopyN (getColUpper (), norig, ubCur);
219 
220  if (p -> getIntegerCandidate (solution, Y, lbCur, ubCur) >= 0) {
221 
222  for (int i = getNumCols (); i--;) {
223 
224  if (lbCur [i] > ubCur [i])
225  CoinSwap (lbCur [i], ubCur [i]);
226 
227  if (Y [i] < lbCur [i]) Y [i] = lbCur [i];
228  else if (Y [i] > ubCur [i]) Y [i] = ubCur [i];
229  }
230 
231  for (int i=0; i<norig; i++)
232  if ((p -> Var (i) -> Multiplicity () > 0) &&
233  p -> Var (i) -> isDefinedInteger ()) {
234 
235  setColLower (i, lbCur [i]);
236  setColUpper (i, ubCur [i]);
237  }
238 
239  setColSolution (Y); // use initial solution given
240 
241  try {
242  options () -> SetNumericValue ("max_cpu_time", CoinMax (0.1, p -> getMaxCpuTime () - CoinCpuTime ()));
243 
244  resolve (); // solve with integer variables fixed
245 
246  if (isDualObjectiveLimitReached() &&
247  (getNumIntegers () == 0))
248  *messageHandler () << "Couenne: Warning, NLP is is unbounded" << CoinMessageEol;
249  }
251  }
252 
253  //resolve ();
254 
255  obj = getObjValue ();
256  solution = getColSolution ();
257 
258  // restore previous bounds on integer variables
259  for (int i=0; i<norig; i++)
260  if ((p -> Var (i) -> Multiplicity () > 0) &&
261  p -> Var (i) -> isDefinedInteger ()) {
262 
263  if (lbSave [i] > ubSave [i])
264  CoinSwap (lbSave [i], ubSave [i]);
265 
266  setColLower (i, lbSave [i]);
267  setColUpper (i, ubSave [i]);
268  }
269  }
270 
271  delete [] Y;
272  delete [] lbSave;
273  delete [] ubSave;
274  delete [] lbCur;
275  delete [] ubCur;
276  }
277  }
278 
279  // re-check optimality in case resolve () was called
280  if (isProvenOptimal () &&
281  // (obj < p -> getCutOff ()) && // check #1 (before re-computing) -- BUG. What if real object is actually better?
282 
283 #ifdef FM_CHECKNLP2
284  (p->checkNLP2(solution, 0, false, true, false, p->getFeasTol())) &&
285  (p->getRecordBestSol()->getModSolVal() < p->getCutOff())
286 #else
287  p -> checkNLP (solution, obj, true) && // true for recomputing obj
288  (obj < p -> getCutOff ())
289 #endif
290  ) { // check #2 (real object might be different)
291 
292  // tell caller there is an initial solution to be fed to the initHeuristic
293  have_nlp_solution_ = true;
294 
295  // set cutoff to take advantage of bound tightening
296 
297 #ifdef FM_CHECKNLP2
298  obj = p->getRecordBestSol()->getModSolVal();
299 #endif
300 
301  p -> setCutOff (obj, solution);
302 
303  OsiAuxInfo * auxInfo = si.getAuxiliaryInfo ();
304  Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (auxInfo);
305 
306  if (babInfo) {
307 
308 #ifdef FM_CHECKNLP2
309  babInfo -> setNlpSolution (p->getRecordBestSol()->modSol,
310  getNumCols(), obj);
311 #else
312  babInfo -> setNlpSolution (solution, getNumCols (), obj);
313 #endif
314  babInfo -> setHasNlpSolution (true);
315  }
316 
317 #ifdef FM_TRACE_OPTSOL
318 #ifdef FM_CHECKNLP2
319  p->getRecordBestSol()->update();
320 #else
321  p->getRecordBestSol()->update(solution, getNumCols(),
322  obj, p->getFeasTol());
323 #endif
324 #endif
325 
326  }
327  } else {
328 
329 
330  }
331  }
332 
333  if (!is_feasible) // nothing else to do, problem infeasible
334  return;
335 
336  int
337  numcols = p -> nOrigVars (), // # original variables
338  numcolsconv = p -> nVars (); // # original + # auxiliary variables
339 
340  const double
341  *lb = p -> Lb (), //getColLower (),
342  *ub = p -> Ub (); //getColUpper ();
343 
344  // add original and auxiliary variables to the new problem
345  for (int i=0; i<numcols; i++)
346  if (p -> Var (i) -> Multiplicity () > 0) si.addCol (0, NULL,NULL, lb [i], ub [i], 0);
347  else si.addCol (0, NULL,NULL, -COIN_DBL_MAX,COIN_DBL_MAX,0);
348  for (int i=numcols; i<numcolsconv; i++) si.addCol (0, NULL,NULL, -COIN_DBL_MAX,COIN_DBL_MAX,0);
349 
350  // get initial relaxation
351  OsiCuts cs;
352  couenneCg.generateCuts (si, cs);
353 
354  // store all (original + auxiliary) bounds in the relaxation
355  CouNumber * colLower = new CouNumber [numcolsconv];
356  CouNumber * colUpper = new CouNumber [numcolsconv];
357 
358  CouNumber *ll = p -> Lb ();
359  CouNumber *uu = p -> Ub ();
360 
361  // overwrite original bounds, could have improved within generateCuts
362  for (int i = numcolsconv; i--;)
363  if (p -> Var (i) -> Multiplicity () > 0) {
364  colLower [i] = (ll [i] > - COUENNE_INFINITY) ? ll [i] : -COIN_DBL_MAX;
365  colUpper [i] = (uu [i] < COUENNE_INFINITY) ? uu [i] : COIN_DBL_MAX;
366  } else {
367  colLower [i] = -COIN_DBL_MAX;
368  colUpper [i] = COIN_DBL_MAX;
369  }
370 
371  int numrowsconv = cs.sizeRowCuts ();
372 
373  // create matrix and other stuff
374  CoinBigIndex * start = new CoinBigIndex [numrowsconv + 1];
375 
376  int * length = new int [numrowsconv];
377  double * rowLower = new double [numrowsconv];
378  double * rowUpper = new double [numrowsconv];
379 
380  start[0] = 0;
381  int nnz = 0;
382  /* fill the four arrays. */
383  for(int i = 0 ; i < numrowsconv ; i++)
384  {
385  OsiRowCut * cut = cs.rowCutPtr (i);
386 
387  const CoinPackedVector &v = cut->row();
388  start[i+1] = start[i] + v.getNumElements();
389  nnz += v.getNumElements();
390  length[i] = v.getNumElements();
391 
392  rowLower[i] = cut->lb();
393  rowUpper[i] = cut->ub();
394  }
395 
396  assert (nnz == start [numrowsconv]);
397  /* Now fill the elements arrays. */
398  int * ind = new int[start[numrowsconv]];
399  double * elem = new double[start[numrowsconv]];
400  for(int i = 0 ; i < numrowsconv ; i++) {
401 
402  OsiRowCut * cut = cs.rowCutPtr (i);
403 
404  const CoinPackedVector &v = cut->row();
405 
406  if(v.getNumElements() != length[i])
407  std::cout<<"Empty row"<<std::endl;
408  // cut->print();
409  CoinCopyN (v.getIndices(), length[i], ind + start[i]);
410  CoinCopyN (v.getElements(), length[i], elem + start[i]);
411  }
412 
413  // Ok everything done now create interface
414  CoinPackedMatrix A;
415  A.assignMatrix(false, numcolsconv, numrowsconv,
416  start[numrowsconv], elem, ind,
417  start, length);
418  if(A.getNumCols() != numcolsconv || A.getNumRows() != numrowsconv){
419  std::cout<<"Error in row number"<<std::endl;
420  }
421  assert(A.getNumElements() == nnz);
422  // Objective function
423  double * obj = new double[numcolsconv];
424  CoinFillN(obj,numcolsconv,0.);
425 
426  // some instances have no (or null) objective function, check it here
427  if (p -> nObjs () > 0)
428  p -> fillObjCoeff (obj);
429 
430  // Finally, load interface si with the initial LP relaxation
431  si.loadProblem (A, colLower, colUpper, obj, rowLower, rowUpper);
432 
433  delete [] rowLower;
434  delete [] rowUpper;
435  delete [] colLower;
436  delete [] colUpper;
437  delete [] obj;
438 
439  for (int i=0; i<numcolsconv; i++)
440  if ((p -> Var (i) -> Multiplicity () > 0) &&
441  (p -> Var (i) -> isDefinedInteger ()))
442  si.setInteger (i);
443 
444  //si.writeMpsNative("toto",NULL,NULL,1);
445  //si.writeLp ("toto");
446  app_ -> enableWarmStart();
447 
448  // restored check. With "TOO FEW DEGREES OF FREEDOM" exception, x_sol() is null
449  if (problem () -> x_sol ()) {
450  setColSolution (problem () -> x_sol ());
451  setRowPrice (problem () -> duals_sol ());
452  }
453 }
454 
455 
458  Options->SetStringValue("bonmin.algorithm", "B-Couenne", true, true);
459  Options->SetIntegerValue("bonmin.filmint_ecp_cuts", 1, true, true);
460 }
461 
Cut Generator for linear convexifications.
void update(const double *givenSol, const int givenCard, const double givenVal, const double givenMaxViol)
virtual CouenneInterface * clone(bool CopyData)
virutal copy constructor.
status of lower/upper bound of a variable, to be checked/modified in bound tightening ...
void setLower(ChangeStatus lower)
CouenneInterface()
Default constructor.
bool checkNLP2(const double *solution, const double obj, const bool careAboutObj, const bool stopAtFirstViol, const bool checkAll, const double precision) const
Return true if either solution or recomputed_solution obtained using getAuxs() from the original vari...
Definition: checkNLP.cpp:571
CouenneProblem * Problem() const
return pointer to symbolic problem
CouNumber getCutOff() const
Get cutoff.
void setUpper(ChangeStatus upper)
Class to represent nonlinear constraints.
CouenneRecordBestSol * getRecordBestSol() const
returns recorded best solution
virtual void setAppDefaultOptions(Ipopt::SmartPtr< Ipopt::OptionsList > Options)
To set some application specific defaults.
virtual void readAmplNlFile(char **&argv, Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions, Ipopt::SmartPtr< Ipopt::OptionsList > options, Ipopt::SmartPtr< Ipopt::Journalist > journalist, std::string *nl_file_content=NULL)
#define AmplInterface
Class for MINLP problems with symbolic information.
#define COUENNE_EPS
virtual ~CouenneInterface()
Destructor.
#define FM_CHECKNLP2
double CouNumber
main number type in Couenne
fint ll
virtual void extractLinearRelaxation(OsiSolverInterface &si, CouenneCutGenerator &couenneCg, bool getObj=1, bool solveNlp=1)
Extract a linear relaxation of the MINLP.
#define COUENNE_INFINITY
We will throw this error when a problem is not solved.
double getFeasTol()
returns feasibility tolerance
int nnz
ATTENTION: Filter expect the jacobian to be ordered by row.
void generateCuts(const OsiSolverInterface &, OsiCuts &, const CglTreeInfo=CglTreeInfo()) const
the main CglCutGenerator
Bonmin class for passing info between components of branch-and-cuts.
Definition: BonBabInfos.hpp:19
bool isInteger(CouNumber x)
is this number integer?