CouenneIterativeRounding.cpp
Go to the documentation of this file.
1 // (C) Copyright International Business Machines Corporation 2010
2 // and others.
3 // All Rights Reserved.
4 // This code is published under the Eclipse Public License (EPL).
5 //
6 // Authors :
7 // Giacomo Nannicini, Tepper School of Business, Carnegie Mellon University
8 //
9 // Date : 07/25/2010
10 
12 #include "BonTMINLP2Quad.hpp"
13 #include "BonTMINLPLinObj.hpp"
14 #ifdef COIN_HAS_CPX
15 #include "OsiCpxSolverInterface.hpp"
16 #include "cplex.h"
17 #endif
18 
19 #include "CouenneRecordBestSol.hpp"
20 
21 #define MILPTIME 5
22 #define CBCMILPTIME 20
23 
24 namespace Couenne{
25 
27  CbcHeuristic(),
28  nlp_(NULL), cinlp_(NULL), milp_(NULL),
29  maxRoundingIter_(10),
30  maxFirPoints_(5), maxTime_(60), maxTimeFirstCall_(60), numInitialRows_(0),
31  numSol_(-1), colLower_(NULL), colUpper_(NULL),
32  colLowerNlp_(NULL), colUpperNlp_(NULL),
33  omega_(0.2), baseLbRhs_(15),
34  couenne_(NULL)
35  {
36  setHeuristicName("CouenneIterativeRounding");
37  }
38 
40  OsiSolverInterface* cinlp,
41  CouenneProblem* couenne,
43  CbcHeuristic(), nlp_(NULL),
44  cinlp_(NULL), milp_(NULL),
45  numSol_(-1), colLower_(NULL), colUpper_(NULL),
46  colLowerNlp_(NULL), colUpperNlp_(NULL),
47  couenne_(couenne)
48  {
49  // Initialize Dynamic NLP
50  setNlp(nlp, cinlp);
51 
52  // Read options
53  int irAggressiveness;
54  options->GetIntegerValue("iterative_rounding_aggressiveness",
55  irAggressiveness, "couenne.");
56  setAggressiveness(irAggressiveness);
57  double maxTime, maxTimeInit;
58  options->GetNumericValue("iterative_rounding_time", maxTime,
59  "couenne.");
60  options->GetNumericValue("iterative_rounding_time_firstcall",
61  maxTimeInit, "couenne.");
62  if (maxTime >= 0){
63  setMaxTime(maxTime);
64  }
65  if (maxTimeInit >= 0){
66  setMaxTimeFirstCall(maxTimeInit);
67  }
68  int irLbrhs;
69  options->GetIntegerValue("iterative_rounding_base_lbrhs",
70  irLbrhs, "couenne.");
71  setBaseLbRhs(irLbrhs);
72  int numFirPoints;
73  options->GetIntegerValue("iterative_rounding_num_fir_points",
74  numFirPoints, "couenne.");
75  setMaxFirPoints(numFirPoints);
76  double omega;
77  options->GetNumericValue("iterative_rounding_omega",
78  omega, "couenne.");
79  setOmega(omega);
80  }
81 
83  CbcHeuristic(other), nlp_(other.nlp_),
84  cinlp_(other.cinlp_), milp_(other.milp_),
85  maxRoundingIter_(other.maxRoundingIter_),
86  maxFirPoints_(other.maxFirPoints_),
87  maxTime_(other.maxTime_),
88  maxTimeFirstCall_(other.maxTimeFirstCall_),
89  numInitialRows_(other.numInitialRows_),
90  numSol_(other.numSol_),
91  omega_(other.omega_), baseLbRhs_(other.baseLbRhs_),
92  couenne_(other.couenne_)
93  {
94  if(nlp_ != NULL){
95  nlp_ = dynamic_cast<Bonmin::OsiTMINLPInterface*>(other.nlp_->clone());
96  }
97  if(milp_ != NULL)
98 #ifdef COIN_HAS_CPX
99  milp_ = dynamic_cast<OsiCpxSolverInterface*>(other.milp_->clone());
100 #else
101  milp_ = dynamic_cast<OsiClpSolverInterface*>(other.milp_->clone());
102 #endif
103  if (other.colLower_ != NULL){
104  if (colLower_ != NULL)
105  delete colLower_;
106  colLower_ = new double[milp_->getNumCols()];
107  CoinCopyN (other.colLower_, milp_->getNumCols(), colLower_);
108  }
109  if (other.colUpper_ != NULL){
110  if (colUpper_ != NULL)
111  delete colUpper_;
112  colUpper_ = new double[milp_->getNumCols()];
113  CoinCopyN (other.colUpper_, milp_->getNumCols(), colUpper_);
114  }
115  if (other.colLowerNlp_ != NULL){
116  if (colLowerNlp_ != NULL)
117  delete colLowerNlp_;
118  colLowerNlp_ = new double[nlp_->getNumCols()];
119  CoinCopyN (other.colLowerNlp_, nlp_->getNumCols(), colLowerNlp_);
120  }
121  if (other.colUpperNlp_ != NULL){
122  if (colUpperNlp_ != NULL)
123  delete colUpperNlp_;
124  colUpperNlp_ = new double[nlp_->getNumCols()];
125  CoinCopyN (other.colUpperNlp_, nlp_->getNumCols(), colLowerNlp_);
126  }
127  }
128 
129  CbcHeuristic *
131  return new CouenneIterativeRounding(*this);
132  }
133 
136  if(this != &rhs){
137  CbcHeuristic::operator=(rhs);
138  if(nlp_)
139  delete nlp_;
140 
141  if(rhs.nlp_ != NULL){
142  nlp_ = dynamic_cast<Bonmin::OsiTMINLPInterface*>(rhs.nlp_->clone());
143  }
144  cinlp_ = rhs.cinlp_;
147  maxTime_ = rhs.maxTime_;
149  numSol_ = rhs.numSol_;
151  omega_ = rhs.omega_;
152  baseLbRhs_ = rhs.baseLbRhs_;
153  couenne_ = rhs.couenne_;
154  if (rhs.colLower_ != NULL){
155  if (colLower_ != NULL)
156  delete colLower_;
157  colLower_ = new double[milp_->getNumCols()];
158  CoinCopyN (rhs.colLower_, milp_->getNumCols(), colLower_);
159  }
160  if (rhs.colUpper_ != NULL){
161  if (colUpper_ != NULL)
162  delete colUpper_;
163  colUpper_ = new double[milp_->getNumCols()];
164  CoinCopyN (rhs.colUpper_, milp_->getNumCols(), colLower_);
165  }
166  if (rhs.colLowerNlp_ != NULL){
167  if (colLowerNlp_ != NULL)
168  delete colLowerNlp_;
169  colLowerNlp_ = new double[nlp_->getNumCols()];
170  CoinCopyN (rhs.colLowerNlp_, nlp_->getNumCols(), colLowerNlp_);
171  }
172  if (rhs.colUpperNlp_ != NULL){
173  if (colUpperNlp_ != NULL)
174  delete colUpperNlp_;
175  colUpperNlp_ = new double[nlp_->getNumCols()];
176  CoinCopyN (rhs.colUpperNlp_, nlp_->getNumCols(), colLowerNlp_);
177  }
178  }
179  return *this;
180  }
181 
183  delete nlp_;
184  nlp_ = NULL;
185  if (colLower_)
186  delete[] colLower_;
187  if (colUpper_)
188  delete[] colUpper_;
189  if (colLowerNlp_)
190  delete[] colLowerNlp_;
191  if (colUpperNlp_)
192  delete[] colUpperNlp_;
193  if (milp_)
194  delete milp_;
195  milp_ = NULL;
196  }
197 
198  void
200  OsiSolverInterface * cinlp){
201  // Create a dynamic NLP (i.e. one that can be used to add/remove
202  // linear inequalities) from the initial one
203  if(nlp_ != NULL)
204  delete nlp_;
206  Ipopt::SmartPtr<Bonmin::TMINLP> tminlp = nlp->model();
207  if (tminlp->hasLinearObjective()){
210  linObj->setTminlp(GetRawPtr(tminlp));
211  tminlp = GetRawPtr(linObj);
212  }
213  nlp_->initialize(nlp->regOptions(), nlp->options(), nlp->solver()->journalist(), "bonmin.", tminlp);
214  nlp_->use(new Bonmin::TMINLP2TNLPQuadCuts(tminlp));
215  cinlp_ = cinlp;
216  }
217 
218  void
220  if(milp_ != NULL)
221  delete milp_;
222 
223  // Save the LP relaxation of the root node
224 
225  OsiSolverInterface * milp = model_->solver();
226  int n = milp->getNumCols();
227 
228 #ifdef COIN_HAS_CPX
229  milp_ = new OsiCpxSolverInterface();
230  milp_->loadProblem(*(milp->getMatrixByRow()), milp->getColLower(),
231  milp->getColUpper(), milp->getObjCoefficients(),
232  milp->getRowLower(), milp->getRowUpper());
233  for (int i = 0; i < n; ++i){
234  if (milp->isInteger(i))
235  milp_->setInteger(i);
236  }
237 #else
238  milp_ = dynamic_cast<OsiClpSolverInterface*>(milp->clone());
239 #endif
240 
241  colLower_ = new double[n];
242  colUpper_ = new double[n];
243  memcpy(colLower_, milp->getColLower(), n*sizeof(double));
244  memcpy(colUpper_, milp->getColUpper(), n*sizeof(double));
245 
246  int nNlp = cinlp_->getNumCols();
247 
248  colLowerNlp_ = new double[nNlp];
249  colUpperNlp_ = new double[nNlp];
250  memcpy(colLowerNlp_, cinlp_->getColLower(), nNlp*sizeof(double));
251  memcpy(colUpperNlp_, cinlp_->getColUpper(), nNlp*sizeof(double));
252 
253  numIntegers_ = 0;
254  for (int i = 0; i < nNlp; ++i){
255  if (cinlp_->isInteger(i)){
256  numIntegers_++;
257  }
258  }
259 
260  // workaround for inconsistent bounds:
261  // sometimes using getColLower and getColUpper we get *slightly*
262  // inconsistent bounds, which make everything crash afterwards
263  double swap;
264  for (int i = 0; i < n; ++i){
265  if (colUpper_[i] < colLower_[i]){
266  swap = colUpper_[i];
267  colUpper_[i] = colLower_[i];
268  colLower_[i] = swap;
269  }
270  }
271 
272  numInitialRows_ = milp_->getNumRows();
273 
274  // this array contains zeroes; we use it to set empty elements
275  double * tmpArray = new double[n];
276  CoinFillN(tmpArray, n, 0.0);
277  milp_->setObjective(tmpArray);
278  milp_->setObjSense(1);
279 
280  // now there is no objective function
281  // create new variables with objective coefficient 1
282  for (int i = 0; i < n; ++i){
283  milp_->addCol(0, NULL, NULL, 0.0, COIN_DBL_MAX, 1.0);
284  }
285 
286  milp_->setHintParam(OsiDoDualInResolve,true,OsiHintDo);
287  milp_->setHintParam(OsiDoPresolveInResolve,true,OsiHintDo);
288  milp_->setHintParam(OsiDoReducePrint,true,OsiHintDo);
289  milp_->setDblParam(OsiPrimalTolerance, COUENNE_EPS_INT);
290  milp_->messageHandler()->setLogLevel(0);
291  milp_->setDblParam(OsiDualTolerance, COUENNE_EPS_INT);
292 
293 #ifdef COIN_HAS_CPX
294  // Set options if we have Cplex
295  CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_MIPEMPHASIS, CPX_MIPEMPHASIS_HIDDENFEAS);
296  CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_FPHEUR, 2);
297  CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_NODESEL, 0);
298  CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_LBHEUR, 1);
299  CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_RINSHEUR, 99);
300  CPXsetintparam(milp_->getEnvironmentPtr(), CPX_PARAM_NODELIM, 50);
301  CPXsetdblparam(milp_->getEnvironmentPtr(), CPX_PARAM_CUTSFACTOR, 1.0);
302  CPXsetdblparam(milp_->getEnvironmentPtr(), CPX_PARAM_TILIM, MILPTIME);
303 #else
304  // Set up heuristics if we use Cbc (not recommended)
305  heuristics_ = new CbcHeuristic*[1];
306  numHeuristics_ = 1;
307  CbcHeuristicFPump * feaspump = new CbcHeuristicFPump();
308  feaspump->setMaximumRetries(2);
309  feaspump->setMaximumPasses(100);
310  feaspump->setAccumulate(3);
311  heuristics_[0] = feaspump;
312 #endif
313 
314  delete[] tmpArray;
315 
316 
317  }
318 
320  switch (value){
321  case 0:
323  setMaxTimeFirstCall(300);
324  setMaxFirPoints(5);
325  setMaxTime(60);
326  break;
327  case 1:
328  setMaxRoundingIter(10);
329  setMaxTimeFirstCall(300);
330  setMaxFirPoints(5);
331  setMaxTime(120);
332  break;
333  case 2:
334  setMaxRoundingIter(20);
335  setMaxTimeFirstCall(1000);
336  setMaxFirPoints(5);
337  setMaxTime(300);
338  break;
339  default:
340  std::cerr << "CouenneIterativeRounding::setAggressiveness() : unknown value!\n" << std::endl;
341  }
342  }
343 
344  int
345  CouenneIterativeRounding::solution(double & objectiveValue, double* newSolution){
346  if (milp_ == NULL){
347  // On the very first call, we set the MILP
348  setMilp();
349  return 0;
350  }
351 
352  if ((model_->numberIntegers() == 0) ||
353  (numSol_ == model_->getSolutionCount())){
354  // There are no integers, or we already tried to improve current
355  // solution. Exit immediately.
356  return 0;
357  }
358 
359  numSol_ = model_->getSolutionCount();
360 
361  std::cout << "Launching IterativeRounding with parameters:" << std::endl;
362  std::cout << "Max rounding iter: " << maxRoundingIter_ << std::endl;
363  std::cout << "Max feas point: " << maxFirPoints_ << std::endl;
364  std::cout << "Base lbrhs: " << baseLbRhs_ << std::endl;
365  std::cout << "Omega: " << omega_ << std::endl;
366  std::cout << "Max time firstcall: " << maxTimeFirstCall_ << std::endl;
367 
368  // write down starting time and apply heuristics
369  startTime_ = CoinCpuTime();
371 
372  const double* bestKnownSolution = model_->bestSolution();
373  bool found = false;
374  bool hasSolution = true;
375  bool improved = true;
376  if (numSol_ == 0){
377  // No solution available; start with our feasibility heuristic
378  hasSolution = feasibilityIR(objectiveValue, newSolution);
379  if (hasSolution){
380  bestKnownSolution = newSolution;
381  found = hasSolution;
382  }
383  }
384  if (!hasSolution){
385  // Still do not have a starting solution, we cannot run improvementIR
386  return found;
387  }
388  while (improved && (CoinCpuTime()-startTime_) < (endTime_ - MILPTIME)){
389  // Keep improving current solution as long as it works
390  improved = false;
391  improved = improvementIR(objectiveValue, newSolution, bestKnownSolution);
392  if (improved){
393  bestKnownSolution = newSolution;
394  }
395  found = (found || improved);
396  }
397  if (found){
398  // make sure we do not run improvementIR again on the same solution
399  numSol_++;
400  }
401 
402  return found;
403  }
404 
405  int
407  double* newSolution){
408 
409  std::cout << "starting feasibility IR" << std::endl;
410 
411  OsiSolverInterface * solver = model_->solver();
412 
413  OsiAuxInfo * auxInfo = solver->getAuxiliaryInfo();
414  Bonmin::BabInfo * babInfo = dynamic_cast<Bonmin::BabInfo *> (auxInfo);
415 
416  if(babInfo){
417  babInfo->setHasNlpSolution(false);
418  if(babInfo->infeasibleNode()){
419  return 0;
420  }
421  }
422 
423  int n = couenne_->nVars();
424  int nNlp = cinlp_->getNumCols();
425 
426  // get best solution and count the number of binary variables
427  int numIntAtBound = 0;
428 
429  OsiRowCut cut;
430  OsiRowCut lbcut1;
431  OsiRowCut lbcut2;
432  OsiCuts lbcuts;
433  double obj;
434 
435  bool boundsChanged = false;
436  std::vector<int> previousBranches;
437 
438  // Try to find a feasible solution
439 
440  // apply NLP solver to obtain point xprime
441  nlp_->resolve();
443  nlp_->isAbandoned()){
445  }
446 
448  nlp_->isAbandoned()){
449  obj = COIN_DBL_MAX;
450  }
451  else{
452  obj = nlp_->getObjValue();
453  }
454 
455  if (obj == COIN_DBL_MAX){std::cout << " IR: no feasible solution found " << std::endl;
456  std::cout << " IR: elapsed time " << CoinCpuTime()-startTime_ << std::endl;
457  return 0;
458  }
459 
460  double* xprime = new double [n];
461  CoinCopyN (nlp_->getColSolution(), nlp_->getNumCols(), xprime);
462  couenne_ -> getAuxs (xprime);
463 
464  // now prepare the MILP that we will solve
465 
466  // the objective is : minimize sum_{j = 1}^n w_j
467  int constrInd[2];
468  double constrElem[2];
469 
470  // main loop: solve a sequence of MILPs and NLPs
471  bool foundSolution = false;
472  double* tmpSolution = new double[n];
473  OsiCuts revlb_all;
474  OsiSolverInterface* curr_milp = milp_;
475 
476  int outerLoop = maxFirPoints_;
477  for (int h = 0; h < outerLoop &&
478  ((CoinCpuTime()-startTime_) < (endTime_ - MILPTIME)); ++h){
479 
480  OsiCuts cs;
481  cs.insert(lbcut1);
482  cs.insert(lbcut2);
483  // write constraints:
484  // xbar[j] - x[j] <= w_j
485  // x[j] - xbar[j] <= w_j
486  for (int i = 0; i < n; i++){
487  constrInd[0] = i;
488  constrInd[1] = i+n;
489  constrElem[0] = -1;
490  constrElem[1] = -1;
491  cut.mutableRow().setVector(2, constrInd, constrElem);
492  cut.setLb(-COIN_DBL_MAX);
493  cut.setUb(-xprime[i]);
494  cs.insert(cut);
495  constrElem[0] = +1;
496  constrElem[1] = -1;
497  cut.mutableRow().setVector(2, constrInd, constrElem);
498  cut.setLb(-COIN_DBL_MAX);
499  cut.setUb(xprime[i]);
500  cs.insert(cut);
501  }
502  curr_milp->applyCuts(cs);
503 
504  for (int k = 0; k < maxRoundingIter_ &&
505  ((CoinCpuTime()-startTime_) < (endTime_ - MILPTIME)); ++k){
506  // Solve MILP to obtain an integral feasible point near xprime
507  curr_milp->restoreBaseModel(numInitialRows_+cs.sizeRowCuts());
508  curr_milp->applyCuts(revlb_all);
509  bool solFound = solveMilp(curr_milp,
510  endTime_-(CoinCpuTime()-startTime_)-2);
511  if (!solFound && !boundsChanged){
512  std::cout << " MILP cannot be solved, terminating LB " << std::endl;
513  // we cannot solve the MILP and bounds were not changed; exit
514  curr_milp->restoreBaseModel(numInitialRows_);
515  delete[] xprime;
516  delete[] tmpSolution;
517  if (boundsChanged){
518  curr_milp->setColLower(colLower_);
519  curr_milp->setColUpper(colUpper_);
520  }
521  std::cout << " IR: elapsed time " << CoinCpuTime()-startTime_ << std::endl;
522  return foundSolution;
523  }
524  else if (!solFound && boundsChanged){
525  // the MILP is infeasible but bounds were changed;
526  // restore original bounds and branch on a random variable
527  // of the solution at the previous iteration (so we do not cycle)
528  curr_milp->setColLower(colLower_);
529  curr_milp->setColUpper(colUpper_);
530  branchToCut(tmpSolution, curr_milp, previousBranches);
531  continue;
532  }
533 
534  const double * xtilde = curr_milp->getColSolution();
535 
536  // now fix integer variables and solve NLP
537  // xtilde has more columns than the NLP, so this should be ok
538  CoinCopyN (xtilde, n, tmpSolution);
539  for (int i = 0; i < nNlp; ++i){
540  if (model_->isInteger(i)){
541  tmpSolution[i] = floor(tmpSolution[i]+0.5);
542  cinlp_->setColLower(i, tmpSolution[i]);
543  cinlp_->setColUpper(i, tmpSolution[i]);
544  }
545  }
546  cinlp_->setColSolution(tmpSolution);
547 
548  cinlp_->messageHandler()->setLogLevel(1);
549  cinlp_->resolve();
550  obj = ((cinlp_->isProvenOptimal()) ?
551  cinlp_->getObjValue():COIN_DBL_MAX);
552  memcpy(tmpSolution, cinlp_->getColSolution(),
553  nNlp*sizeof(double));
554  // check solution of the NLP;
555  // if we have a new incumbent we are done, otherwise we iterate
556 
557  bool isChecked = false;
558 
559  isChecked = couenne_ -> checkNLP0 (tmpSolution, obj, true,
560  false,
561  true,
562  false);
563 
564 // #ifdef FM_CHECKNLP2
565 // isChecked = couenne_->checkNLP2(tmpSolution, 0, false, // do not care about obj
566 // true, // stopAtFirstViol
567 // false, // checkALL
568 // couenne_->getFeasTol());
569 // if(isChecked) {
570 // obj = couenne_->getRecordBestSol()->getModSolVal();
571 // }
572 // #else /* not FM_CHECKNLP2 */
573 // isChecked = couenne_->checkNLP(tmpSolution, obj, true);
574 // #endif /* not FM_CHECKNLP2 */
575 
576  if (cinlp_->isProvenOptimal () &&
577  isChecked &&
578  (obj < couenne_->getCutOff())) {
579 
580 #ifdef FM_CHECKNLP2
581 #ifdef FM_TRACE_OPTSOL
583  CoinCopyN (couenne_->getRecordBestSol()->getSol(), n, tmpSolution);
584  obj = couenne_->getRecordBestSol()->getVal();
585 #else /* not FM_TRACE_OPTSOL */
586  CoinCopyN (couenne_->getRecordBestSol()->getModSol(n), n, tmpSolution);
587 #endif /* not FM_TRACE_OPTSOL */
588 #else /* not FM_CHECKNLP2 */
589 
590  //Get correct values for all auxiliary variables
591  couenne_ -> getAuxs (tmpSolution);
592 
593 #ifdef FM_TRACE_OPTSOL
594  couenne_->getRecordBestSol()->update(tmpSolution, n,
595  obj, couenne_->getFeasTol());
596  CoinCopyN (couenne_->getRecordBestSol()->getSol(), n, tmpSolution);
597  obj = couenne_->getRecordBestSol()->getVal();
598 #endif /* FM_TRACE_OPTSOL */
599 #endif /* not FM_CHECKNLP2 */
600 
601  if (babInfo){
602  babInfo->setNlpSolution (tmpSolution, n, obj);
603  babInfo->setHasNlpSolution (true);
604  }
605 
606  std::cout << "Final Nlp solution with objective " << obj << " :" << std::endl;
607 
608  if (obj < objectiveValue - COUENNE_EPS) { // found better solution?
609  std::cout << "New incumbent found" << std::endl;
610  const CouNumber
611  *lb = solver -> getColLower (),
612  *ub = solver -> getColUpper ();
613 
614  // check bounds once more after getAux. This avoids false
615  // asserts in CbcModel.cpp:8305 on integerTolerance violated
616  for (int i=0; i < n; ++i, ++lb, ++ub) {
617  CouNumber &t = tmpSolution [i];
618  if (t < *lb) t = *lb;
619  else if (t > *ub) t = *ub;
620  }
621 
622  couenne_ -> setCutOff (obj);
623  foundSolution = true;
624  objectiveValue = obj;
625  CoinCopyN (tmpSolution, n, newSolution);
626  cinlp_->setColLower(colLowerNlp_);
627  cinlp_->setColUpper(colUpperNlp_);
628 
629  curr_milp->restoreBaseModel(numInitialRows_);
630  delete[] xprime;
631  delete[] tmpSolution;
632  if (boundsChanged){
633  curr_milp->setColLower(colLower_);
634  curr_milp->setColUpper(colUpper_);
635  }
636  //delete curr_milp;
637  double elapsed = CoinCpuTime()-startTime_;
638  std::cout << "IR: Heuristic: " << objectiveValue << std::endl;
639  std::cout << "IR: Heuristic time: " << elapsed << std::endl;
640  return foundSolution;
641  }
642  }
643  cinlp_->setColLower(colLowerNlp_);
644  cinlp_->setColUpper(colUpperNlp_);
645  double avgBound;
646  numIntAtBound = computeIntAtBound(xtilde, avgBound);
647 
648  if (numIntAtBound >= 50 ||
649  numIntAtBound >= ((numIntegers_*0.1 > 5) ? numIntegers_*0.1 : 5)){
650  // write reverse local branching constraint
651  // this avoids finding the same xtilde again
652  avgBound = floor(avgBound + 0.5);
653  std::cout << "Using reverse LB with rhs " << avgBound << std::endl;
654  writeLB(cut, xtilde, 'G', avgBound);
655  revlb_all.insert(cut);
656  }
657  else{
658  // Branch on a random variable to obtain a different integer point
659  branchToCut(xtilde, curr_milp, previousBranches);
660  boundsChanged = true;
661  }
662  }
663  if (h <= outerLoop -2){
664  // Compute a NLP-feasible point by solving a log-barrier problem
665  // with a given minimum value for the log-barrier parameter mu
668  nlp->messageHandler()->setLogLevel(10);
669  double mu_target;
670  double kappa_d;
671  opt->GetNumericValue("mu_target", mu_target, "ipopt.");
672  opt->SetNumericValue("mu_target", omega_*(h+1), "ipopt.");
673  opt->GetNumericValue("kappa_d", kappa_d, "ipopt.");
674  opt->SetNumericValue("kappa_d", 0.0, "ipopt.");
675  nlp_->resolve();
676  if (nlp_->isProvenPrimalInfeasible() ||
678  nlp_->isAbandoned()){
680  }
681  opt->SetNumericValue("mu_target", mu_target, "ipopt.");
682  opt->SetNumericValue("kappa_d", kappa_d, "ipopt.");
683 
684  if (!nlp->isProvenPrimalInfeasible() &&
685  !nlp->isProvenDualInfeasible() &&
686  !nlp->isAbandoned()){
687  CoinCopyN (nlp_->getColSolution(), nlp_->getNumCols(), xprime);
688  couenne_ -> getAuxs (xprime);
689  curr_milp->restoreBaseModel(numInitialRows_);
690  if (boundsChanged){
691  curr_milp->setColLower(colLower_);
692  curr_milp->setColUpper(colUpper_);
693  }
694  }
695  }
696  }
697 
698  curr_milp->restoreBaseModel(numInitialRows_);
699  delete[] xprime;
700  delete[] tmpSolution;
701  if (boundsChanged){
702  curr_milp->setColLower(colLower_);
703  curr_milp->setColUpper(colUpper_);
704  }
705  double elapsed = CoinCpuTime()-startTime_;
706  std::cout << "IR: Heuristic: " << COUENNE_INFINITY << std::endl;
707  std::cout << "IR: Heuristic time: " << elapsed << std::endl;
708  return foundSolution;
709  }
710 
711  int
713  double* newSolution,
714  const double* solution){
715  std::cout << "starting Improvement IR" << std::endl;
716 
717  OsiSolverInterface * solver = model_->solver();
718 
719  OsiAuxInfo * auxInfo = solver->getAuxiliaryInfo();
720  Bonmin::BabInfo * babInfo = dynamic_cast<Bonmin::BabInfo *> (auxInfo);
721 
722  if(babInfo){
723  babInfo->setHasNlpSolution(false);
724  if(babInfo->infeasibleNode()){
725  return 0;
726  }
727  }
728 
729 
730  int n = couenne_->nVars();
731  int nNlp = cinlp_->getNumCols();
732 
733  // count the number of binary variables
734  int numIntAtBound = 0;
735 
736  double lbrhs = CoinMin(baseLbRhs_, CoinMax(1,numIntegers_/2) );
737  OsiRowCut cut;
738  OsiRowCut lbcut1;
739  OsiRowCut lbcut2;
740  OsiCuts lbcuts;
741  int currentIndex = 0;
742  double obj;
743 
744  bool boundsChanged = false;
745  std::vector<int> previousBranches;
746 
747  double avgBound = 0.0;
748  numIntAtBound = computeIntAtBound(solution, avgBound);
749 
750  if (numIntAtBound >= 50 ||
751  numIntAtBound >= ((numIntegers_*0.1 > 5) ? numIntegers_*0.1 : 5)){
752  // write local branching constraint
753  writeLB(lbcut1, solution, 'L', lbrhs + floor(avgBound - 0.5));
754  lbcuts.insert(lbcut1);
755  writeLB(lbcut2, solution, 'G', 1);
756  lbcuts.insert(lbcut2);
757 
758  // We cannot add a row because OsiTMINLP will not let us do that!
759  // Therefore we add a cut -- does the same thing.
760  // We must delete the cut afterwards!
761  nlp_->applyCuts(lbcuts);
762  }
763  else{
764  // we cannot use a local branching constraint, so we simply
765  // reduce the size of the box bounds, to have a smaller NLP and
766  // stay somehow "close" to the current point
767  for (int i = 0; i < nlp_->getNumCols(); ++i){
768  if (nlp_->isInteger(i)){
769  nlp_->setColLower(i, colLowerNlp_[i]+(solution[i]-colLower_[i])*0.5);
770  nlp_->setColUpper(i, colUpperNlp_[i]+(solution[i]-colUpper_[i])*0.5);
771  }
772  }
773  }
774  // apply NLP solver to obtain point xprime
775  nlp_->setColSolution(solution);
776  nlp_->resolve();
778  nlp_->isAbandoned()){
780  }
781 
783  nlp_->isAbandoned()){
784  obj = COIN_DBL_MAX;
785  }
786  else{
787  obj = nlp_->getObjValue();
788  }
789 
790  // Restore NLP
791  if (numIntAtBound > 0){
792  currentIndex = nlp_->getNumRows()-1;
793  nlp_->deleteRows(1, &currentIndex);
794  currentIndex = nlp_->getNumRows()-1;
795  nlp_->deleteRows(1, &currentIndex);
796  }
797  else{
800  }
801 
802  if (obj == COIN_DBL_MAX || obj >= objectiveValue - COUENNE_EPS){
803  std::cout << " IR: no improvement possible " << std::endl;
804  std::cout << " IR: elapsed time " << CoinCpuTime()-startTime_ << std::endl;
805  return 0;
806  }
807 
808  double* xprime = new double [n];
809  CoinCopyN (nlp_->getColSolution(), nlp_->getNumCols(), xprime);
810  couenne_ -> getAuxs (xprime);
811 
812  // now prepare the MILP that we will solve
813 
814  // the objective is : minimize sum_{j = 1}^n w_j
815  int constrInd[2];
816  double constrElem[2];
817 
818  // main loop: solve a sequence of MILPs and NLPs
819  bool foundSolution = false;
820  double* tmpSolution = new double[n];
821  OsiCuts revlb_all;
822  OsiSolverInterface* curr_milp = milp_;
823 
824  OsiCuts cs;
825  cs.insert(lbcut1);
826  cs.insert(lbcut2);
827  // write constraints:
828  // xbar[j] - x[j] <= w_j
829  // x[j] - xbar[j] <= w_j
830  for (int i = 0; i < n; i++){
831  constrInd[0] = i;
832  constrInd[1] = i+n;
833  constrElem[0] = -1;
834  constrElem[1] = -1;
835  cut.mutableRow().setVector(2, constrInd, constrElem);
836  cut.setLb(-COIN_DBL_MAX);
837  cut.setUb(-xprime[i]);
838  cs.insert(cut);
839  constrElem[0] = +1;
840  constrElem[1] = -1;
841  cut.mutableRow().setVector(2, constrInd, constrElem);
842  cut.setLb(-COIN_DBL_MAX);
843  cut.setUb(xprime[i]);
844  cs.insert(cut);
845  }
846  curr_milp->applyCuts(cs);
847 
848  for (int k = 0; k < maxRoundingIter_ &&
849  ((CoinCpuTime()-startTime_) < (endTime_ - MILPTIME)); ++k){
850  // Solve MILP to obtain an integral feasible point near xprime
851  curr_milp->restoreBaseModel(numInitialRows_+cs.sizeRowCuts());
852  curr_milp->applyCuts(revlb_all);
853  bool solFound = solveMilp(curr_milp,
854  endTime_-(CoinCpuTime()-startTime_)-2);
855  if (!solFound && !boundsChanged){
856  std::cout << " MILP cannot be solved, terminating LB " << std::endl;
857  // we cannot solve the MILP and bounds were not changed; exit
858  curr_milp->restoreBaseModel(numInitialRows_);
859  delete[] xprime;
860  delete[] tmpSolution;
861  if (boundsChanged){
862  curr_milp->setColLower(colLower_);
863  curr_milp->setColUpper(colUpper_);
864  }
865  std::cout << " IR: elapsed time " << CoinCpuTime()-startTime_ << std::endl;
866  return foundSolution;
867  }
868  else if (!solFound && boundsChanged){
869  // the MILP is infeasible but bounds were changed;
870  // restore original bounds and branch on a random variable
871  // of the solution at the previous iteration (so we do not cycle)
872  curr_milp->setColLower(colLower_);
873  curr_milp->setColUpper(colUpper_);
874  branchToCut(tmpSolution, curr_milp, previousBranches);
875  continue;
876  }
877  const double * xtilde = curr_milp->getColSolution();
878 
879  // now fix integer variables and solve NLP
880  // xtilde has more columns than the NLP, so this should be ok
881  CoinCopyN (xtilde, n, tmpSolution);
882  for (int i = 0; i < nNlp; ++i){
883  if (model_->isInteger(i)){
884  tmpSolution[i] = floor(tmpSolution[i]+0.5);
885  cinlp_->setColLower(i, tmpSolution[i]);
886  cinlp_->setColUpper(i, tmpSolution[i]);
887  }
888  }
889  cinlp_->setColSolution(tmpSolution);
890 
891  cinlp_->messageHandler()->setLogLevel(1);
892  cinlp_->resolve();
893  obj = ((cinlp_->isProvenOptimal()) ? cinlp_->getObjValue():COIN_DBL_MAX);
894  memcpy(tmpSolution, cinlp_->getColSolution(),
895  nNlp*sizeof(double));
896  // check solution of the NLP;
897  // if we have a new incumbent we are done, otherwise we iterate
898 
899  bool isChecked = false;
900 
901  isChecked = couenne_ -> checkNLP0 (tmpSolution, obj, true,
902  false,
903  true,
904  false);
905 
906 // #ifdef FM_CHECKNLP2
907 // isChecked = couenne_->checkNLP2(tmpSolution, 0, false, // do not care about obj
908 // true, // stopAtFirstViol
909 // false, // checkALL
910 // couenne_->getFeasTol());
911 // if(isChecked) {
912 // obj = couenne_->getRecordBestSol()->getModSolVal();
913 // }
914 // #else /* not FM_CHECKNLP2 */
915 // isChecked = couenne_->checkNLP(tmpSolution, obj, true);
916 // #endif /* not FM_CHECKNLP2 */
917 
918  if (cinlp_->isProvenOptimal () &&
919  isChecked &&
920  (obj < couenne_->getCutOff())) {
921 
922 #ifdef FM_CHECKNLP2
923 #ifdef FM_TRACE_OPTSOL
925  CoinCopyN (couenne_->getRecordBestSol()->getSol(), n, tmpSolution);
926  obj = couenne_->getRecordBestSol()->getVal();
927 #else /* not FM_TRACE_OPTSOL */
928  CoinCopyN (couenne_->getRecordBestSol()->getModSol(n), n, tmpSolution);
929 #endif /* not FM_TRACE_OPTSOL */
930 #else /* not FM_CHECKNLP2 */
931 
932  //Get correct values for all auxiliary variables
933  couenne_ -> getAuxs (tmpSolution);
934 
935 #ifdef FM_TRACE_OPTSOL
936  couenne_->getRecordBestSol()->update(tmpSolution, n,
937  obj, couenne_->getFeasTol());
938  CoinCopyN (couenne_->getRecordBestSol()->getSol(), n, tmpSolution);
939  obj = couenne_->getRecordBestSol()->getVal();
940 #endif /* FM_TRACE_OPTSOL */
941 #endif /* not FM_CHECKNLP2 */
942 
943  if (babInfo){
944  babInfo->setNlpSolution (tmpSolution, n, obj);
945  babInfo->setHasNlpSolution (true);
946  }
947 
948  std::cout << "Final Nlp solution with objective " << obj << " :" << std::endl;
949 
950  if (obj < objectiveValue - COUENNE_EPS) { // found better solution?
951  std::cout << "New incumbent found" << std::endl;
952  const CouNumber
953  *lb = solver -> getColLower (),
954  *ub = solver -> getColUpper ();
955 
956  // check bounds once more after getAux. This avoids false
957  // asserts in CbcModel.cpp:8305 on integerTolerance violated
958  for (int i=0; i < n; ++i, ++lb, ++ub) {
959  CouNumber &t = tmpSolution [i];
960  if (t < *lb) t = *lb;
961  else if (t > *ub) t = *ub;
962  }
963 
964  couenne_ -> setCutOff (obj);
965  foundSolution = true;
966  objectiveValue = obj;
967  CoinCopyN (tmpSolution, n, newSolution);
968  cinlp_->setColLower(colLowerNlp_);
969  cinlp_->setColUpper(colUpperNlp_);
970 
971  curr_milp->restoreBaseModel(numInitialRows_);
972  delete[] xprime;
973  delete[] tmpSolution;
974  if (boundsChanged){
975  curr_milp->setColLower(colLower_);
976  curr_milp->setColUpper(colUpper_);
977  }
978  //delete curr_milp;
979  double elapsed = CoinCpuTime()-startTime_;
980  std::cout << "IR: Heuristic: " << objectiveValue << std::endl;
981  std::cout << "IR: Heuristic time: " << elapsed << std::endl;
982  return foundSolution;
983  }
984  }
985  cinlp_->setColLower(colLowerNlp_);
986  cinlp_->setColUpper(colUpperNlp_);
987  numIntAtBound = computeIntAtBound(xtilde, avgBound);
988 
989  if (numIntAtBound >= 50 ||
990  numIntAtBound >= ((numIntegers_*0.1 > 5) ? numIntegers_*0.1 : 5)){
991  // write reverse local branching constraint
992  // this avoids finding the same xtilde again
993  avgBound = floor(avgBound + 0.5);
994  std::cout << "Using reverse LB with rhs " << avgBound << std::endl;
995  writeLB(cut, xtilde, 'G', avgBound);
996  revlb_all.insert(cut);
997  }
998  else{
999  // Branch (randomly) so that we can obtain a new integer point
1000  branchToCut(xtilde, curr_milp, previousBranches);
1001  boundsChanged = true;
1002  }
1003  }
1004 
1005  curr_milp->restoreBaseModel(numInitialRows_);
1006  delete[] xprime;
1007  delete[] tmpSolution;
1008  if (boundsChanged){
1009  curr_milp->setColLower(colLower_);
1010  curr_milp->setColUpper(colUpper_);
1011  }
1012  double elapsed = CoinCpuTime()-startTime_;
1013  std::cout << "IR: Heuristic: " << COUENNE_INFINITY << std::endl;
1014  std::cout << "IR: Heuristic time: " << elapsed << std::endl;
1015  return foundSolution;
1016  }
1017 
1018  int
1020  int numIntAtBound = 0;
1021  for (int i = 0; i < nlp_->getNumCols(); ++i){
1022  if (nlp_->isInteger(i) && (areEqual(x[i], colLower_[i]) ||
1023  areEqual(x[i], colUpper_[i]))){
1024  numIntAtBound++;
1025  }
1026  }
1027  return numIntAtBound;
1028  }
1029 
1030  int
1032  double& avgBoundSize){
1033  int numIntAtBound = 0;
1034  avgBoundSize = 0;
1035  for (int i = 0; i < nlp_->getNumCols(); ++i){
1036  if (nlp_->isInteger(i) && (areEqual(x[i], colLower_[i]) ||
1037  areEqual(x[i], colUpper_[i]))){
1038  numIntAtBound++;
1039  avgBoundSize += colUpper_[i] - colLower_[i];
1040  }
1041  }
1042  avgBoundSize /= numIntAtBound;
1043  return numIntAtBound;
1044  }
1045 
1046  void
1047  CouenneIterativeRounding::writeLB(OsiRowCut& cut, const double* x,
1048  char sense, double rhs){
1049  cut.mutableRow().clear();
1050  for (int i = 0; i < nlp_->getNumCols(); ++i){
1051  if (nlp_->isInteger(i)){
1052  if (areEqual(x[i], colUpper_[i])){
1053  cut.mutableRow().insert(i, -1);
1054  rhs -= x[i];
1055  }
1056  else if (areEqual(x[i], colLower_[i])){
1057  cut.mutableRow().insert(i, 1);
1058  rhs += x[i];
1059  }
1060  }
1061  }
1062  if (sense == 'L'){
1063  cut.setLb(-COIN_DBL_MAX);
1064  cut.setUb(rhs);
1065  }
1066  else if (sense == 'G'){
1067  cut.setLb(rhs);
1068  cut.setUb(COIN_DBL_MAX);
1069  }
1070  else{
1071  std::cerr << "### ERROR: wrong sense of LB constraint" << std::endl;
1072  exit(1);
1073  }
1074  }
1075 
1076  bool
1077  CouenneIterativeRounding::solveMilp(OsiSolverInterface* milp,
1078  double maxTime){
1079  double start = CoinCpuTime();
1080 #ifdef COIN_HAS_CPX
1081  OsiCpxSolverInterface * solver = dynamic_cast<OsiCpxSolverInterface*>(milp);
1082  CPXENVptr env = solver->getEnvironmentPtr();
1083  CPXLPptr cpxlp = solver->getLpPtr(OsiCpxSolverInterface::KEEPCACHED_ALL);
1084  int status = 0;
1085  bool solFound = false;
1086  bool infeasible = false;
1087  while (!solFound && !infeasible && ((CoinCpuTime() - start) < maxTime)){
1088  solver->branchAndBound();
1089  status = CPXgetstat(env, cpxlp);
1090  solFound = ((status == CPXMIP_NODE_LIM_FEAS) ||
1091  (status == CPXMIP_TIME_LIM_FEAS) ||
1092  (status == CPXMIP_MEM_LIM_FEAS) ||
1093  (status == CPXMIP_ABORT_FEAS) ||
1094  (status == CPXMIP_OPTIMAL) ||
1095  (status == CPXMIP_OPTIMAL_TOL) ||
1096  (status == CPXMIP_ABORT_FEAS) ||
1097  (status == CPXMIP_FAIL_FEAS) ||
1098  (status == CPXMIP_FAIL_FEAS_NO_TREE) ||
1099  (status == CPXMIP_FEASIBLE));
1100  infeasible = ((status == CPXMIP_INForUNBD) ||
1101  (status == CPXMIP_OPTIMAL_INFEAS) ||
1102  (status == CPXMIP_INFEASIBLE));
1103  }
1104  if (solFound){
1105  return true;
1106  }
1107  return false;
1108 #else
1109  CbcModel cbcModel(*milp);
1110  for (int i = 0; i < numHeuristics_; ++i){
1111  cbcModel.addHeuristic(heuristics_[i]);
1112  }
1113  cbcModel.setMaximumSeconds(CBCMILPTIME);
1114  //CglPreProcess * prep = cbcModel.preProcess(0,2,5);
1115  while ((cbcModel.getSolutionCount() == 0) &&
1116  (!cbcModel.isProvenInfeasible()) &&
1117  (!cbcModel.isProvenDualInfeasible()) &&
1118  (!cbcModel.isAbandoned()) &&
1119  ((CoinCpuTime() - start) < maxTime)){
1120  cbcModel.branchAndBound();
1121  }
1122  //cbcModel.postProcess(prep);
1123  milp = cbcModel.solver();
1124  if (cbcModel.getSolutionCount() > 0){
1125  return true;
1126  }
1127  return false;
1128 #endif
1129  }
1130 
1131  int
1133  OsiSolverInterface* solver,
1134  std::vector<int>& previousBranches){
1135  int branch;
1136  bool found = false;
1137  while (!found){
1138  branch = rand()%numIntegers_;
1139  found = true;
1140  for (unsigned int i = 0; i < previousBranches.size(); ++i){
1141  if (branch == previousBranches[i]){
1142  found = false;
1143  break;
1144  }
1145  }
1146  if (found){
1147  previousBranches.push_back(branch);
1148  }
1149  else{
1150  continue;
1151  }
1152  for (int i = 0; i < nlp_->getNumCols(); ++i){
1153  if (model_->isInteger(i)){
1154  if (branch == 0){
1155  branch = i;
1156  break;
1157  }
1158  else{
1159  branch--;
1160  }
1161  }
1162  }
1163  }
1164  double sample = rand();
1165  if (sample <= ((x[branch]-colLower_[branch])/(colUpper_[branch]-colLower_[branch]))){
1166  solver->setColUpper(branch, x[branch]-1);
1167  }
1168  else{
1169  solver->setColLower(branch, x[branch]+1);
1170  }
1171  return branch;
1172  }
1173 
1174  void
1176  roptions -> AddStringOption2
1177  ("iterative_rounding_heuristic",
1178  "Do we use the Iterative Rounding heuristic",
1179  "no",
1180  "no","",
1181  "yes","",
1182  "If enabled, a heuristic based on Iterative Rounding is used "
1183  "to find feasible solutions for the problem. "
1184  "The heuristic may take some time, but usually finds good solutions. "
1185  "Recommended if you want good upper bounds and have Cplex. "
1186  "Not recommended if you do not have Cplex");
1187 
1188  roptions -> AddNumberOption
1189  ("iterative_rounding_time",
1190  "Specify the maximum time allowed for the Iterative Rounding heuristic",
1191  -1, "Maximum CPU time employed by the Iterative Rounding heuristic; "
1192  "if no solution found in this time, failure is reported. "
1193  "This overrides the CPU time set by Aggressiveness if positive.");
1194 
1195  roptions -> AddNumberOption
1196  ("iterative_rounding_time_firstcall",
1197  "Specify the maximum time allowed for the Iterative Rounding heuristic "
1198  "when no feasible solution is known",
1199  -1, "Maximum CPU time employed by the Iterative Rounding heuristic "
1200  "when no solution is known; if no solution found in this time, "
1201  "failure is reported."
1202  "This overrides the CPU time set by Aggressiveness if posive.");
1203 
1204  roptions -> AddBoundedIntegerOption
1205  ("iterative_rounding_aggressiveness",
1206  "Aggressiveness of the Iterative Rounding heuristic",
1207  0, 2, 1,
1208  "Set the aggressiveness of the heuristic; i.e., how many iterations "
1209  "should be run, and with which parameters. The maximum time can be "
1210  "overridden by setting the _time and _time_firstcall options. "
1211  "0 = non aggressive, 1 = standard (default), 2 = aggressive.");
1212 
1213  roptions -> AddLowerBoundedIntegerOption
1214  ("iterative_rounding_num_fir_points",
1215  "Max number of points rounded at the beginning of Iterative Rounding",
1216  1, 5,
1217  "Number of different points (obtained solving a log-barrier problem) "
1218  "that the heuristic will try to round at most, during its execution "
1219  "at the root node (i.e. the F-IR heuristic). Default 5.");
1220 
1221  roptions -> AddBoundedNumberOption
1222  ("iterative_rounding_omega",
1223  "Omega parameter of the Iterative Rounding heuristic",
1224  0, true, 1, true, 0.2,
1225  "Set the omega parameter of the heuristic, which represents a "
1226  "multiplicative factor for the minimum log-barrier parameter "
1227  "of the NLP which is solved to obtain feasible points. This "
1228  "corresponds to $\\omega'$ in the paper. Default 0.2.");
1229 
1230  roptions -> AddLowerBoundedIntegerOption
1231  ("iterative_rounding_base_lbrhs",
1232  "Base rhs of the local branching constraint for Iterative Rounding",
1233  0, 15,
1234  "Base rhs for the local branching constraint that defines a "
1235  "neighbourhood of the local incumbent. The base rhs is modified by "
1236  "the algorithm according to variable bounds. This corresponds to "
1237  "k' in the paper. Default 15.");
1238 
1239  }
1240 
1241 }
CouenneIterativeRounding & operator=(const CouenneIterativeRounding &rhs)
Assignment operator.
#define COUENNE_EPS_INT
int nVars() const
Total number of variables.
virtual bool isAbandoned() const
Are there a numerical difficulties?
An iterative rounding heuristic, tailored for nonconvex MINLPs.
Ipopt::SmartPtr< Ipopt::Journalist > journalist()
Get a pointer to a journalist.
void update(const double *givenSol, const int givenCard, const double givenVal, const double givenMaxViol)
double maxTime_
Max CPU time to run the heuristic.
const Ipopt::SmartPtr< Ipopt::OptionsList > options() const
Retrieve OsiTMINLPApplication option list.
This is class provides an Osi interface for a Mixed Integer Linear Program expressed as a TMINLP (so ...
double endTime_
Maximum allowed time for current run.
int numIntegers_
Number of integer variables in the original model.
virtual bool isInteger(int columnNumber) const
Return true if column is integer.
OsiSolverInterface * clone(bool copyData=true) const
Virtual copy constructor.
void setMaxRoundingIter(int value)
Set maximum number of iterations for each rounding phase.
virtual void deleteRows(const int num, const int *rowIndices)
We have to keep this but it will throw an error.
virtual int getNumRows() const
Get number of rows.
OsiSolverInterface * cinlp_
Pointer to the original NLP solver interface.
void use(Ipopt::SmartPtr< TMINLP2TNLP > tminlp2tnlp)
Sets the TMINLP2TNLP to be used by the interface.
int branchToCut(const double *x, OsiSolverInterface *solver, std::vector< int > &previousBranches)
Branch on a random variable to cut given solution; returns var index.
void setMaxTimeFirstCall(double value)
Set maximum CPU time for the heuristic at the root node only.
virtual int getNumCols() const
Get number of columns.
virtual double getObjValue() const
Get objective function value (can&#39;t use default)
double startTime_
Starting time for the heuristics.
CouNumber getCutOff() const
Get cutoff.
void setMaxTime(double value)
Set maximum CPU time for the heuristic at each node.
From a TMINLP, this class adapts to another TMINLP where the original objective is transformed into a...
const Bonmin::TNLPSolver * solver() const
#define MILPTIME
void setMaxFirPoints(int value)
Set maximum number of points that we try to round in F-IR.
virtual bool isProvenPrimalInfeasible() const
Is primal infeasiblity proven?
virtual const double * getColSolution() const
Get pointer to array[getNumCols()] of primal solution vector.
virtual void setColUpper(int elementIndex, double elementValue)
Set a single column upper bound.
double maxTimeFirstCall_
Max CPU time to run the heuristic when no other solution is known.
bool solveMilp(OsiSolverInterface *milp, double maxTime)
Solve the MILP contained in milp to feasibility, or report failure.
void setMilp()
Set the milp solver at the root.
double omega_
Multiplication factor for log barrier parameter in F-IR; see in the paper.
CouenneRecordBestSol * getRecordBestSol() const
returns recorded best solution
double * colLower_
Pointer to original column lower and upper bounds of the reformulated problem, i.e.
virtual void resolve()
Resolve the continuous relaxation after problem modification.
int baseLbRhs_
Base value for the rhs of the local branching constraint it I-IR.
int maxFirPoints_
Maximum number of iterations in the outer loop for feasibility.
void setOmega(double value)
Set the value for omega, the multiplicative factor for the minimum log-barrier parameter mu used by F...
void setNlp(Bonmin::OsiTMINLPInterface *nlp, OsiSolverInterface *cinlp)
Set the minlp solver.
virtual void setColSolution(const double *colsol)
Set the primal solution variable values Set the values for the starting point.
Class for MINLP problems with symbolic information.
bool areEqual(double a, double b)
Check if two double precision numbers are equal, up to some tolerance.
void fint fint * k
#define COUENNE_EPS
virtual CbcHeuristic * clone() const
Clone.
int feasibilityIR(double &objectiveValue, double *newSolution)
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions >)
initialize options to be read later
virtual bool isProvenDualInfeasible() const
Is dual infeasiblity proven?
void setBaseLbRhs(int value)
Set the base value for the rhs of the local branching constraint in the I-IR heuristic.
CouenneProblem * couenne_
Pointer to a couenne representation of the problem.
U * GetRawPtr(const OSSmartPtr< U > &smart_ptr)
Definition: OSSmartPtr.hpp:452
static const int infeasible
Definition: Couenne.cpp:68
This is a derived class fro TMINLP2TNLP to handle adding quadratic cuts.
double CouNumber
main number type in Couenne
double * colLowerNlp_
Pointer to column lower and upper bounds of the original problem, i.e.
Ipopt::SmartPtr< const Ipopt::OptionsList > options() const
Get the options (for getting their values).
CbcHeuristic ** heuristics_
Heuristics for the MILP.
bool infeasibleNode()
Say if current node is found feasible by cut generators.
Definition: BonAuxInfos.hpp:49
#define COUENNE_INFINITY
int solution(double &objectiveValue, double *newSolution)
Run heuristic, return 1 if a better solution than the one passed is found and 0 otherwise.
int computeIntAtBound(const double *x)
Compute number of integer variables at one of their bounds at a given point x.
double getFeasTol()
returns feasibility tolerance
virtual void resolveForRobustness(int numretry)
Method to be called when a problem has failed to be solved.
int numInitialRows_
Number of rows in the original convexification.
void setNlpSolution(const double *sol, int numcols, double objValue)
Pass a solution found by an nlp solver.
Definition: BonAuxInfos.cpp:78
int numSol_
Number of solutions last time the heuristic was called.
int improvementIR(double &objectiveValue, double *newSolution, const double *startingSolution)
void setAggressiveness(int value)
Set aggressiveness of heuristic.
OsiClpSolverInterface * milp_
Pointer to a milp solver interface.
void writeLB(OsiRowCut &cut, const double *x, char sense, double rhs)
Write down a local branching constraint, as an OsiRowCut.
double * getModSol(const int expectedCard)
void setHasNlpSolution(bool b)
Say if has an nlp solution.
Definition: BonAuxInfos.hpp:68
void initialize(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions, Ipopt::SmartPtr< Ipopt::OptionsList > options, Ipopt::SmartPtr< Ipopt::Journalist > journalist, const std::string &prefix, Ipopt::SmartPtr< TMINLP > tminlp)
Facilitator to initialize interface.
virtual void setColLower(int elementIndex, double elementValue)
Set a single column lower bound.
#define CBCMILPTIME
int maxRoundingIter_
Maximum number of iterations in the main loop.
static char * t
Definition: OSdtoa.cpp:3645
void fint * n
Bonmin class for passing info between components of branch-and-cuts.
Definition: BonBabInfos.hpp:19
Bonmin::OsiTMINLPInterface * nlp_
Pointer to a dynamic nlp solver interface.
void fint fint fint real fint real * x