BonHeuristicInnerApproximation.cpp
Go to the documentation of this file.
1 
2 // (C) Copyright CNRS and others 2010
3 // All Rights Reserved.
4 // This code is published under the Eclipse Public License.
5 //
6 // Authors :
7 // Pierre Bonami, Université de la Méditérannée
8 // Hassan Hijazi, Orange Labs
9 //
10 // Date : 05/22/2010
11 
12 //Test MySVN
14 #include "CoinHelperFunctions.hpp"
15 #include "CbcModel.hpp"
16 #include "BonSubMipSolver.hpp"
17 #include "BonCbcLpStrategy.hpp"
18 
19 #ifdef COIN_HAS_CPX
20 #include "OsiCpxSolverInterface.hpp"
21 #endif
22 
23 #include "OsiClpSolverInterface.hpp"
24 
25 #include "OsiAuxInfo.hpp"
26 
27 #include "CoinTime.hpp"
28 
29 #include <fstream>
30 
31 #include <iomanip>
32 
33 #include "CoinHelperFunctions.hpp"
34 
35 #define DEBUG_BON_HEURISTIC
36 
37 using namespace std;
38 
39 namespace Bonmin {
40 
41 HeuristicInnerApproximation::HeuristicInnerApproximation(BonminSetup * setup) :
42  CbcHeuristic(), setup_(setup), howOften_(100), mip_(NULL),
43  nbAp_(50) {
44  Initialize(setup);
45 }
46 
48  const HeuristicInnerApproximation &copy) :
49  CbcHeuristic(copy),
50  setup_(copy.setup_),
51  howOften_(copy.howOften_),
52  mip_(new SubMipSolver(*copy.mip_)),
53  nbAp_(copy.nbAp_) {
54 }
55 
58  if (this != &rhs) {
59  CbcHeuristic::operator=(rhs);
60  setup_ = rhs.setup_;
61  howOften_ = rhs.howOften_;
62  nbAp_ = rhs.nbAp_;
63  delete mip_;
64  if (rhs.mip_)
65  mip_ = new SubMipSolver(*rhs.mip_);
66  }
67  return *this;
68 }
69 
71  Bonmin::RegisteredOptions> roptions) {
72  roptions->SetRegisteringCategory("Initial Approximations descriptions",
74  roptions->AddStringOption2("heuristic_inner_approximation",
75  "if yes runs the InnerApproximation heuristic", "yes", "no",
76  "don't run it", "yes", "runs the heuristic", "");
77 
78  roptions->setOptionExtraInfo("heuristic_inner_approximation", 63);
79 }
80 
81 void
83 
84  delete mip_;
85  mip_ = new SubMipSolver (*b, "inner_approximation");
86  b->options()->GetIntegerValue("number_approximations_initial_outer",
87  nbAp_, b->prefix());
88 }
89 
91 delete mip_;
92 }
93 
97 int
98 HeuristicInnerApproximation::solution(double &solutionValue, double *betterSolution)
99 {
100 if(model_->getNodeCount() || model_->getCurrentPassNumber() > 1) return 0;
101 if ((model_->getNodeCount()%howOften_)!=0||model_->getCurrentPassNumber()>1)
102 return 0;
103 
104 int returnCode = 0; // 0 means it didn't find a feasible solution
105 
106 OsiTMINLPInterface * nlp = NULL;
107 if(setup_->getAlgorithm() == B_BB)
108 nlp = dynamic_cast<OsiTMINLPInterface *>(model_->solver()->clone());
109 else
110 nlp = dynamic_cast<OsiTMINLPInterface *>(setup_->nonlinearSolver()->clone());
111 
112 TMINLP2TNLP* minlp = nlp->problem();
113 // set tolerances
114 double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
115 
116 int numberColumns;
117 int numberRows;
118 int nnz_jac_g;
119 int nnz_h_lag;
120 Ipopt::TNLP::IndexStyleEnum index_style;
121 minlp->get_nlp_info(numberColumns, numberRows, nnz_jac_g,
122  nnz_h_lag, index_style);
123 
124 const Bonmin::TMINLP::VariableType* variableType = minlp->var_types();
125 
126 const double* x_sol = minlp->x_sol();
127 
128 double* newSolution = new double [numberColumns];
129 memcpy(newSolution,x_sol,numberColumns*sizeof(double));
130 double* new_g_sol = new double [numberRows];
131 
132 bool feasible = true;
133 // load the problem to OSI
134 #ifdef DEBUG_BON_HEURISTIC
135 cout << "Loading the problem to OSI\n";
136 #endif
137 OsiSolverInterface *si = mip_->solver(); // the MIP solver
138 
139 bool delete_si = false;
140 if(si == NULL) {
141  si = new OsiClpSolverInterface;
142  mip_->setLpSolver(si);
143  delete_si = true;
144 }
145 CoinMessageHandler * handler = model_->messageHandler()->clone();
146 si->passInMessageHandler(handler);
147 si->messageHandler()->setLogLevel(2);
148 #ifdef DEBUG_BON_HEURISTIC
149 cout << "Loading problem into si\n";
150 #endif
151 extractInnerApproximation(*nlp, *si, newSolution, true); // Call the function construncting the inner approximation description
152 #ifdef DEBUG_BON_HEURISTIC
153 cout << "problem loaded\n";
154 cout << "**** Running optimization ****\n";
155 #endif
156 mip_->optimize(DBL_MAX, 2, 180); // Optimize the MIP
157 #ifdef DEBUG_BON_HEURISTIC
158 cout << "Optimization finished\n";
159 #endif
160 if(mip_->getLastSolution()) { // if the MIP solver returns a feasible solution
161  const double* solution = mip_->getLastSolution();
162  for (size_t iLCol=0;iLCol<numberColumns;iLCol++) {
163  newSolution[iLCol] = solution[iLCol];
164  }
165 }
166 else
167 feasible = false;
168 
169 if(delete_si) {
170  delete si;
171 }
172 delete handler;
173 
174 const double* x_l = minlp->x_l();
175 const double* x_u = minlp->x_u();
176 const double* g_l = minlp->g_l();
177 const double* g_u = minlp->g_u();
178 double primalTolerance = 1.0e-6;
179 #if 1
180 if(feasible ) {
181 
182  std::vector<double> memLow(numberColumns);
183  std::vector<double> memUpp(numberColumns);
184  std::copy(minlp->x_l(), minlp->x_l() + numberColumns, memLow.begin());
185  std::copy(minlp->x_u(), minlp->x_u() + numberColumns, memUpp.begin());
186  // fix the integer variables and solve the NLP
187  for (int iColumn=0;iColumn<numberColumns;iColumn++) {
188  if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) {
189  double value=floor(newSolution[iColumn]+0.5);
190  minlp->SetVariableUpperBound(iColumn, value);
191  minlp->SetVariableLowerBound(iColumn, value);
192  }
193  }
194  if(feasible) {
195  nlp->initialSolve();
196  if(minlp->optimization_status() != Ipopt::SUCCESS) {
197  feasible = false;
198  }
199  memcpy(newSolution,minlp->x_sol(),numberColumns*sizeof(double));
200  }
201 
202 
203  for (int iColumn=0;iColumn<numberColumns;iColumn++) {
204  if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) {
205  minlp->SetVariableUpperBound(iColumn, memUpp[iColumn]);
206  minlp->SetVariableLowerBound(iColumn, memLow[iColumn]);
207  }
208  }
209 }
210 #endif
211 #endif
212 
213 if(feasible) {
214  double newSolutionValue;
215  minlp->eval_f(numberColumns, newSolution, true, newSolutionValue);
216  if(newSolutionValue < solutionValue) {
217  memcpy(betterSolution,newSolution,numberColumns*sizeof(double));
218  solutionValue = newSolutionValue;
219  returnCode = 1;
220  }
221 }
222 
223 delete [] newSolution;
224 delete [] new_g_sol;
225 
226 delete nlp;
227 
228 #ifdef DEBUG_BON_HEURISTIC
229 std::cout<<"Inner approximation returnCode = "<<returnCode<<std::endl;
230 #endif
231 return returnCode;
232 }
233 
236 bool
238  const double * x, const double * x2) {
239 
240  int n, m, nnz_jac_g, nnz_h_lag;
241  Ipopt::TNLP::IndexStyleEnum index_style;
242  TMINLP2TNLP * problem = si.problem();
243  problem->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style);
244 
245 
246  CoinPackedVector cut;
247  double lb = 0;
248  double ub = 0;
249 
250  double infty = si.getInfinity();
251 
252  lb = -infty; // we only compute <= constraints
253 
254  double g = 0;
255  double g2 = 0;
256  double diff = 0;
257  double a = 0;
258  problem->eval_gi(n, x, 1, ind, g);
259  problem->eval_gi(n, x2, 1, ind, g2);
260  vector<int> jCol(n);
261  int nnz;
262  problem->eval_grad_gi(n, x2, 0, ind, nnz, jCol(), NULL);
263  vector<double> jValues(nnz);
264  problem->eval_grad_gi(n, x2, 0, ind, nnz, NULL, jValues());
265  bool add = false;
266  for (int i = 0; i < nnz; i++) {
267  const int &colIdx = jCol[i];
268  if(index_style == Ipopt::TNLP::FORTRAN_STYLE) jCol[i]--;
269  diff = x[colIdx] - x2[colIdx];
270 
271  if (fabs(diff) >= 1e-8) {
272  a = (g - g2) / diff;
273  cut.insert(colIdx, a);
274  ub = a * x[colIdx] - g;
275  add = true;
276  } else
277  cut.insert(colIdx, jValues[i]);
278  }
279 
280  if (add) {
281 
282  OsiRowCut newCut;
283  newCut.setGloballyValidAsInteger(1);
284  newCut.setLb(lb);
285 
286  //********* Perspective Extension ********//
287  int* ids = problem->get_const_xtra_id(); // vector of indices corresponding to the binary variable activating the corresponding constraint
288  int binary_id = (ids == NULL) ? -1 : ids[ind]; // Get the index of the corresponding indicator binary variable
289  if(binary_id>0) {// If this hyperplane is a linearization of a disjunctive constraint, we link its righthand side to the corresponding indicator binary variable
290  cut.insert(binary_id, -ub); // ∂x ≤ ub => ∂x - ub*z ≤ 0
291  newCut.setUb(0);
292  }
293  else
294  newCut.setUb(ub);
295  //********* Perspective Extension ********//
296 
297  newCut.setRow(cut);
298  cs.insert(newCut);
299  return true;
300  }
301  return false;
302 }
303 void
305  const double * x, bool getObj) {
306  int n;
307  int m;
308  int nnz_jac_g;
309  int nnz_h_lag;
310  Ipopt::TNLP::IndexStyleEnum index_style;
311  TMINLP2TNLP * problem = nlp.problem();
312  //Get problem information
313  problem->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style);
314 
315  vector<int> jRow(nnz_jac_g);
316  vector<int> jCol(nnz_jac_g);
317  vector<double> jValues(nnz_jac_g);
318  problem->eval_jac_g(n, NULL, 0, m, nnz_jac_g, jRow(), jCol(), NULL);
319  if(index_style == Ipopt::TNLP::FORTRAN_STYLE)//put C-style
320  {
321  for(int i = 0 ; i < nnz_jac_g ; i++){
322  jRow[i]--;
323  jCol[i]--;
324  }
325  }
326 
327  //get Jacobian
328  problem->eval_jac_g(n, x, 1, m, nnz_jac_g, NULL, NULL,
329  jValues());
330 
331  vector<double> g(m);
332  problem->eval_g(n, x, 1, m, g());
333 
334  vector<int> nonLinear(m);
335  //store non linear constraints (which are to be removed from IA)
336  int numNonLinear = 0;
337  const double * rowLower = nlp.getRowLower();
338  const double * rowUpper = nlp.getRowUpper();
339  const double * colLower = nlp.getColLower();
340  const double * colUpper = nlp.getColUpper();
341  assert(m == nlp.getNumRows());
342  double infty = si.getInfinity();
343  double nlp_infty = nlp.getInfinity();
345  problem->get_constraints_linearity(m, constTypes());
346  for (int i = 0; i < m; i++) {
347  if (constTypes[i] == Ipopt::TNLP::NON_LINEAR) {
348  nonLinear[numNonLinear++] = i;
349  }
350  }
351  vector<double> rowLow(m - numNonLinear);
352  vector<double> rowUp(m - numNonLinear);
353  int ind = 0;
354  for (int i = 0; i < m; i++) {
355  if (constTypes[i] != Ipopt::TNLP::NON_LINEAR) {
356  if (rowLower[i] > -nlp_infty) {
357  // printf("Lower %g ", rowLower[i]);
358  rowLow[ind] = (rowLower[i]);
359  } else
360  rowLow[ind] = -infty;
361  if (rowUpper[i] < nlp_infty) {
362  // printf("Upper %g ", rowUpper[i]);
363  rowUp[ind] = (rowUpper[i]);
364  } else
365  rowUp[ind] = infty;
366  ind++;
367  }
368 
369  }
370 
371  CoinPackedMatrix mat(true, jRow(), jCol(), jValues(), nnz_jac_g);
372  mat.setDimensions(m, n); // In case matrix was empty, this should be enough
373 
374  //remove non-linear constraints
375  mat.deleteRows(numNonLinear, nonLinear());
376 
377  int numcols = nlp.getNumCols();
378  vector<double> obj(numcols);
379  for (int i = 0; i < numcols; i++)
380  obj[i] = 0.;
381 
382  si.loadProblem(mat, nlp.getColLower(), nlp.getColUpper(),
383  obj(), rowLow(), rowUp());
384  const Bonmin::TMINLP::VariableType* variableType = problem->var_types();
385  for (int i = 0; i < n; i++) {
386  if ((variableType[i] == TMINLP::BINARY) || (variableType[i]
387  == TMINLP::INTEGER))
388  si.setInteger(i);
389  }
390  if (getObj) {
391  bool addObjVar = false;
392  if (problem->hasLinearObjective()) {
393  double zero;
394  vector<double> x0(n, 0.);
395  problem->eval_f(n, x0(), 1, zero);
396  si.setDblParam(OsiObjOffset, -zero);
397  //Copy the linear objective and don't create a dummy variable.
398  problem->eval_grad_f(n, x, 1, obj());
399  si.setObjective(obj());
400  } else {
401  addObjVar = true;
402  }
403 
404  if (addObjVar) {
405  nlp.addObjectiveFunction(si, x);
406  }
407  }
408 
409  // Hassan IA initial description
410  int InnerDesc = 1;
411  if (InnerDesc == 1) {
412  OsiCuts cs;
413 
414  double * p = CoinCopyOfArray(colLower, n);
415  double * pp = CoinCopyOfArray(colLower, n);
416  double * up = CoinCopyOfArray(colUpper, n);
417 
418  const int& nbAp = nbAp_;
419  std::vector<int> nbG(m, 0);// Number of generated points for each nonlinear constraint
420 
421  std::vector<double> step(n);
422 
423  for (int i = 0; i < n; i++) {
424 
425  if (colUpper[i] > 1e08) {
426  up[i] = 0;
427  }
428 
429  if (colUpper[i] > 1e08 || colLower[i] < -1e08 || (variableType[i]
430  == TMINLP::BINARY) || (variableType[i] == TMINLP::INTEGER)) {
431  step[i] = 0;
432  } else
433  step[i] = (up[i] - colLower[i]) / (nbAp);
434 
435  if (colLower[i] < -1e08) {
436  p[i] = 0;
437  pp[i] = 0;
438  }
439 
440  }
441  vector<double> g_p(m);
442  vector<double> g_pp(m);
443 
444  for (int j = 1; j <= nbAp; j++) {
445 
446  for (int i = 0; i < n; i++) {
447  pp[i] += step[i];
448  }
449 
450  problem->eval_g(n, p, 1, m, g_p());
451  problem->eval_g(n, pp, 1, m, g_pp());
452  double diff = 0;
453  int varInd = 0;
454  for (int i = 0; (i < m && constTypes[i] == Ipopt::TNLP::NON_LINEAR); i++) {
455  if (varInd == n - 1)
456  varInd = 0;
457  diff = std::abs(g_p[i] - g_pp[i]);
458  if (nbG[i] < nbAp - 1) {
459  getMyInnerApproximation(nlp, cs, i, p, pp);// Generate a chord connecting the two points
460  p[varInd] = pp[varInd];
461  nbG[i]++;
462  }
463  varInd++;
464  }
465  }
466 
467  for(int i = 0; (i< m && constTypes[i] == Ipopt::TNLP::NON_LINEAR); i++) {
468  // getConstraintOuterApproximation(cs, i, colUpper, NULL, true);// Generate Tangents at current point
469  getMyInnerApproximation(nlp, cs, i, p, up);// Generate a chord connecting the two points
470  }
471 
472  delete [] p;
473  delete [] pp;
474  delete [] up;
475  si.applyCuts(cs);
476  }
477  }
478 
479 }
480 
bool getMyInnerApproximation(OsiTMINLPInterface &si, OsiCuts &cs, int ind, const double *x, const double *x2)
Get an inner-approximation constraint obtained by drawing a chord linking the two given points x and ...
virtual double getInfinity() const
Get solver&#39;s value for infinity.
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
static Bigint * diff(Bigint *a, Bigint *b)
Definition: OSdtoa.cpp:1120
BonminSetup * setup_
Setup to use for local searches (will make copies).
virtual const double * getColLower() const
Get pointer to array[getNumCols()] of column lower bounds.
ULong x2
Definition: OSdtoa.cpp:1776
const TMINLP2TNLP * problem() const
get pointer to the TMINLP2TNLP adapter
int nbAp_
Number of Approximation points.
This is class provides an Osi interface for a Mixed Integer Linear Program expressed as a TMINLP (so ...
void extractInnerApproximation(OsiTMINLPInterface &nlp, OsiSolverInterface &si, const double *x, bool getObj)
virtual bool eval_grad_gi(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index i, Ipopt::Index &nele_grad_gi, Ipopt::Index *jCol, Ipopt::Number *values)
compute the structure or values of the gradient for one constraint
void fint fint fint real * a
OsiSolverInterface * clone(bool copyData=true) const
Virtual copy constructor.
virtual bool eval_gi(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index i, Ipopt::Number &gi)
compute the value of a single constraint
void SetVariableLowerBound(Ipopt::Index var_no, Ipopt::Number x_l)
Change the lower bound on the variable.
SubMipSolver * mip_
A subsolver for MIP.
virtual int getNumRows() const
Get number of rows.
Ipopt::SolverReturn optimization_status() const
Get Optimization status.
virtual int getNumCols() const
Get number of columns.
void SetVariableUpperBound(Ipopt::Index var_no, Ipopt::Number x_u)
Change the upper bound on the variable.
virtual void initialSolve()
Solve initial continuous relaxation.
static char * j
Definition: OSdtoa.cpp:3622
const double * getLastSolution()
get the solution found in last local search (return NULL if no solution).
int up
Definition: OSdtoa.cpp:1817
void fint fint fint real fint real real real real real real real real real * e
ULong * x0
Definition: OSdtoa.cpp:1776
virtual bool get_constraints_linearity(Ipopt::Index m, LinearityType *const_types)
Returns the constraint linearity.
A very simple class to provide a common interface for solving MIPs with Cplex and Cbc...
Bonmin::Algorithm getAlgorithm()
Get the algorithm used.
const Ipopt::Number * x_l()
Get the current values for the lower bounds.
virtual bool eval_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Number *g)
Returns the vector of constraint values in x.
HeuristicInnerApproximation & operator=(const HeuristicInnerApproximation &rhs)
Assignment operator.
const Ipopt::Number * x_u()
Get the current values for the upper bounds.
virtual int solution(double &solutionValue, double *betterSolution)
Performs heuristic.
virtual bool eval_grad_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number *grad_f)
Returns the vector of the gradient of the objective w.r.t.
virtual const double * getRowUpper() const
Get pointer to array[getNumRows()] of row upper bounds.
OsiSolverInterface * solver()
const Ipopt::Number * g_l()
Get the current values for constraints lower bounds.
void Initialize(BonminSetup *setup)
Initialize method.
HeuristicInnerApproximation(BonminSetup *setup)
Constructor with setup.
const Ipopt::Number * x_sol() const
get the solution values
virtual const double * getColUpper() const
Get pointer to array[getNumCols()] of column upper bounds.
OsiTMINLPInterface * nonlinearSolver()
Pointer to the non-linear solver used.
virtual void addObjectiveFunction(OsiSolverInterface &si, const double *x)
Add constraint corresponding to objective function.
Ipopt::SmartPtr< Ipopt::OptionsList > options()
Acces list of Options.
void fint fint fint real fint real real real real real real * g
virtual const double * getRowLower() const
Get pointer to array[getNumRows()] of row lower bounds.
virtual bool eval_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number &obj_value)
Returns the value of the objective function in x.
void fint * m
int howOften_
How often to do (code can change)
int nnz
ATTENTION: Filter expect the jacobian to be ordered by row.
This is an adapter class that converts a TMINLP to a TNLP to be solved by Ipopt.
virtual bool get_nlp_info(Ipopt::Index &n, Ipopt::Index &m, Ipopt::Index &nnz_jac_g, Ipopt::Index &nnz_h_lag, TNLP::IndexStyleEnum &index_style)
This call is just passed onto the TMINLP object.
virtual const int * get_const_xtra_id() const
Access array describing constraint to which perspectives should be applied.
virtual bool hasLinearObjective()
returns true if objective is linear.
void optimize(double cutoff, int loglevel, double maxTime)
update cutoff and optimize MIP.
void fint * n
return b
Definition: OSdtoa.cpp:1719
const Ipopt::Number * g_u()
Get the current values for constraints upper bounds.
const char * prefix() const
Get prefix to use for options.
VariableType
Type of the variables.
Definition: BonTMINLP.hpp:192
void setLpSolver(OsiSolverInterface *lp)
Assign lp solver.
const TMINLP::VariableType * var_types()
Get the variable types.
virtual bool eval_jac_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index *iRow, Ipopt::Index *jCol, Ipopt::Number *values)
Returns the jacobian of the constraints.
real infty
void fint fint fint real fint real * x
Class to add a few more information to Ipopt::RegisteredOptions.