SepaHeuristicInnerApproximation.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 namespace Sepa{
38 
40  CbcHeuristic(), setup_(setup), howOften_(100), mip_(NULL),
41  nbAp_(50), time_limit_(10.) {
42  Initialize(setup);
43 }
44 
46  const HeuristicInnerApproximation &copy) :
47  CbcHeuristic(copy),
48  setup_(copy.setup_),
49  howOften_(copy.howOften_),
50  mip_(new Bonmin::SubMipSolver(*copy.mip_)),
51  nbAp_(copy.nbAp_),
52  time_limit_(copy.time_limit_)
53  {
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 Bonmin::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  roptions->AddLowerBoundedIntegerOption("number_inner_approximation_points",
81  "Set the number of points to use for linear inner approximation of nonlinear functions in heuristic",
82  1, 20);
83  roptions->setOptionExtraInfo("number_inner_approximation_points", 63);
84 
85  roptions->AddLowerBoundedNumberOption("inner_time_limit",
86  "Time limit for inner approximation",
87  0, true, 10, "");
88  roptions->setOptionExtraInfo("number_inner_approximation_points", 63);
89 }
90 
91 void
93 
94  delete mip_;
95  mip_ = new Bonmin::SubMipSolver (*b, "inner_approximation");
96  b->options()->GetIntegerValue("number_inner_approximation_points",
97  nbAp_, b->prefix());
98  b->options()->GetNumericValue("inner_time_limit",
99  time_limit_, b->prefix());
100 }
101 
103 delete mip_;
104 }
105 
109 int
110 HeuristicInnerApproximation::solution(double &solutionValue, double *betterSolution)
111 {
112 if(model_->getNodeCount() || model_->getCurrentPassNumber() > 1) return 0;
113 if ((model_->getNodeCount()%howOften_)!=0||model_->getCurrentPassNumber()>1)
114 return 0;
115 
116 int returnCode = 0; // 0 means it didn't find a feasible solution
117 
118 Bonmin::OsiTMINLPInterface * nlp = NULL;
120 nlp = dynamic_cast<Bonmin::OsiTMINLPInterface *>(model_->solver()->clone());
121 else
122 nlp = dynamic_cast<Bonmin::OsiTMINLPInterface *>(setup_->nonlinearSolver()->clone());
123 
124 Bonmin::TMINLP2TNLP* minlp = nlp->problem();
125 // set tolerances
126 
127 //double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
128 
129 int numberColumns;
130 int numberRows;
131 int nnz_jac_g;
132 int nnz_h_lag;
133 Ipopt::TNLP::IndexStyleEnum index_style;
134 minlp->get_nlp_info(numberColumns, numberRows, nnz_jac_g,
135  nnz_h_lag, index_style);
136 
137 //const Bonmin::TMINLP::VariableType* variableType = minlp->var_types();
138 
139 const double* x_sol = minlp->x_sol();
140 
141 double* newSolution = new double [numberColumns];
142 memcpy(newSolution,x_sol,numberColumns*sizeof(double));
143 double* new_g_sol = new double [numberRows];
144 
145 bool feasible = true;
146 // load the problem to OSI
147 #ifdef DEBUG_BON_HEURISTIC
148 std::cout << "Loading the problem to OSI\n";
149 #endif
150 OsiSolverInterface *si = mip_->solver(); // the MIP solver
151 
152 bool delete_si = false;
153 if(si == NULL) {
154  si = new OsiClpSolverInterface;
155  mip_->setLpSolver(si);
156  delete_si = true;
157 }
158 CoinMessageHandler * handler = model_->messageHandler()->clone();
159 si->passInMessageHandler(handler);
160 si->messageHandler()->setLogLevel(2);
161 #ifdef DEBUG_BON_HEURISTIC
162 std::cout << "Loading problem into si\n";
163 #endif
164 extractInnerApproximation(*nlp, *si, newSolution, true); // Call the function construncting the inner approximation description
165 #ifdef DEBUG_BON_HEURISTIC
166 std::cout << "problem loaded\n";
167 std::cout << "**** Running optimization ****\n";
168 #endif
169 mip_->optimize(DBL_MAX, 2, time_limit_); // Optimize the MIP
170 #ifdef DEBUG_BON_HEURISTIC
171 std::cout << "Optimization finished\n";
172 #endif
173 if(mip_->getLastSolution()) { // if the MIP solver returns a feasible solution
174  const double* solution = mip_->getLastSolution();
175  std::copy(solution, solution + numberColumns, newSolution);
176  }
177  else
178  feasible = false;
179 
180 if(delete_si) {
181  delete si;
182 }
183 delete handler;
184 
185 
186 #if 0 // Set to 1 if you need to test the feasibility of the returned solution
187 const double* x_l = minlp->x_l();
188 const double* x_u = minlp->x_u();
189 const double* g_l = minlp->g_l();
190 const double* g_u = minlp->g_u();
191 double primalTolerance = 1.0e-6;
192 
193 Bonmin::vector<Ipopt::TNLP::LinearityType> constTypes(numberRows);
194 minlp->get_constraints_linearity(numberRows, constTypes());
195 feasible = true;
196 for (int iColumn=0;iColumn<numberColumns;iColumn++) {
197  double value=newSolution[iColumn];
198  if(value - x_l[iColumn] < -1e-8|| value - x_u[iColumn] > 1e-8) {
199  std::cout<<"Solution found infeasible because: "<<std::endl;
200  std::cout<<"x_l["<<iColumn<<"]= "<<x_l[iColumn]<<" "
201  <<"x_sol["<<iColumn<<"]= "<<value<<" "
202  <<"x_u["<<iColumn<<"]= "<<x_u[iColumn]<<std::endl;
203  feasible = false;
204  break;
205  }
206 }
207 minlp->eval_g(numberColumns, newSolution, true,
208  numberRows, new_g_sol);
209 for(int iRow=0; iRow<numberRows; iRow++) {
210  if(new_g_sol[iRow]<g_l[iRow]-primalTolerance ||
211  new_g_sol[iRow]>g_u[iRow]+primalTolerance) {
212  std::cout<<"It should be infeasible because: "<<std::endl;
213  std::cout<<"g_l["<<iRow<<"]= "<<g_l[iRow]<<" "
214  <<"g_sol["<<iRow<<"]= "<<new_g_sol[iRow]<<" "
215  <<"g_u["<<iRow<<"]= "<<g_u[iRow]<<std::endl;
216  std::cout<<"primalTolerance= "<<primalTolerance<<std::endl;
217  if(constTypes[iRow] == Ipopt::TNLP::NON_LINEAR)
218  std::cout<<"nonLinear constraint number "<<iRow<<std::endl;
219  feasible = false;
220  }
221 }
222 std::cout<<"Every thing is feasible"<<std::endl;
223 #endif
224 
225 if(feasible) {
226  double newSolutionValue;
227  minlp->eval_f(numberColumns, newSolution, true, newSolutionValue);
228  if(newSolutionValue < solutionValue) {
229  memcpy(betterSolution,newSolution,numberColumns*sizeof(double));
230  solutionValue = newSolutionValue;
231  returnCode = 1;
232  }
233 }
234 
235 delete [] newSolution;
236 delete [] new_g_sol;
237 
238 delete nlp;
239 
240 #ifdef DEBUG_BON_HEURISTIC
241 std::cout<<"Inner approximation returnCode = "<<returnCode<<std::endl;
242 #endif
243 return returnCode;
244 }
245 
248 bool
250  const double * x, const double * x2) {
251 
252  int n, m, nnz_jac_g, nnz_h_lag;
253  Ipopt::TNLP::IndexStyleEnum index_style;
254  Bonmin::TMINLP2TNLP * problem = si.problem();
255  problem->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style);
256  double infty = si.getInfinity();
257 
258 
259  CoinPackedVector cut;
260  double lb = -infty;
261  double ub = 0;
262 
263 
264  double g = 0;
265  double g2 = 0;
266  double diff = 0;
267  double a = 0;
268  problem->eval_gi(n, x, 1, ind, g);
269  problem->eval_gi(n, x2, 1, ind, g2);
270  Bonmin::vector<int> jCol(n);
271  int nnz;
272  problem->eval_grad_gi(n, x2, 0, ind, nnz, jCol(), NULL);
273  Bonmin::vector<double> jValues(nnz);
274  problem->eval_grad_gi(n, x2, 0, ind, nnz, NULL, jValues());
275  bool add = false;
276  //printf("const %i nnz %i\n", ind, nnz);
277  for (int i = 0; i < nnz; i++) {
278  const int &colIdx = jCol[i];
279  if(index_style == Ipopt::TNLP::FORTRAN_STYLE) jCol[i]--;
280  diff = x[colIdx] - x2[colIdx];
281 
282  if (fabs(diff) >= 1e-8) {
283  a = (g - g2) / diff;
284  cut.insert(colIdx, a);
285  ub = (a * x[colIdx] - g) - fabs(a * x[colIdx] - g)*1e-6;
286  //printf("const %i col %i p[col] %g pp[col] %g g %g g2 %g diff %g\n",ind, colIdx, x[colIdx], x2[colIdx], g, g2, diff);
287  add = true;
288  } else {
289  cut.insert(colIdx, jValues[i]);
290  //printf("const %i col %i val %g\n",ind, colIdx, jValues[i]);
291  }
292  }
293 
294  if (add) {
295 
296  OsiRowCut newCut;
297  newCut.setGloballyValidAsInteger(1);
298  newCut.setLb(lb);
299 
300  //********* Perspective Extension ********//
301  int binary_id = 0; // index corresponding to the binary variable activating the corresponding constraint
302  const int* ids = problem->get_const_xtra_id(); // vector of indices corresponding to the binary variable activating the corresponding constraint
303  // Get the index of the corresponding indicator binary variable
304  binary_id = (ids == NULL) ? -1 : ids[ind];
305  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
306  cut.insert(binary_id, -ub); // ∂x ≤ ub => ∂x - ub*z ≤ 0
307  newCut.setUb(0);
308  }
309  else
310  newCut.setUb(ub);
311  //********* Perspective Extension ********//
312 
313  newCut.setRow(cut);
314  cs.insert(newCut);
315  //newCut.print();
316  return true;
317  }
318  return false;
319 }
320 
321 void
323  const double * x, bool getObj) {
324  printf("************ Start extracting inner approx");
325  int n;
326  int m;
327  int nnz_jac_g;
328  int nnz_h_lag;
329  Ipopt::TNLP::IndexStyleEnum index_style;
330  Bonmin::TMINLP2TNLP * problem = nlp.problem();
331  //Get problem information
332  problem->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style);
333 
334  Bonmin::vector<int> jRow(nnz_jac_g);
335  Bonmin::vector<int> jCol(nnz_jac_g);
336  Bonmin::vector<double> jValues(nnz_jac_g);
337  problem->eval_jac_g(n, NULL, 0, m, nnz_jac_g, jRow(), jCol(), NULL);
338  if(index_style == Ipopt::TNLP::FORTRAN_STYLE)//put C-style
339  {
340  for(int i = 0 ; i < nnz_jac_g ; i++){
341  jRow[i]--;
342  jCol[i]--;
343  }
344  }
345 
346  //get Jacobian
347  problem->eval_jac_g(n, x, 1, m, nnz_jac_g, NULL, NULL,
348  jValues());
349 
351  problem->eval_g(n, x, 1, m, g());
352 
353  Bonmin::vector<int> nonLinear(m);
354  //store non linear constraints (which are to be removed from IA)
355  int numNonLinear = 0;
356  const double * rowLower = nlp.getRowLower();
357  const double * rowUpper = nlp.getRowUpper();
358  const double * colLower = nlp.getColLower();
359  const double * colUpper = nlp.getColUpper();
360  assert(m == nlp.getNumRows());
361  double infty = si.getInfinity();
362  double nlp_infty = nlp.getInfinity();
365  problem->get_constraints_linearity(m, constTypes());
366  problem->get_variables_linearity(n, varTypes());
367  for (int i = 0; i < m; i++) {
368  if (constTypes[i] == Ipopt::TNLP::NON_LINEAR) {
369  nonLinear[numNonLinear++] = i;
370  }
371  }
372  Bonmin::vector<double> rowLow(m - numNonLinear);
373  Bonmin::vector<double> rowUp(m - numNonLinear);
374  int ind = 0;
375  for (int i = 0; i < m; i++) {
376  if (constTypes[i] != Ipopt::TNLP::NON_LINEAR) {
377  if (rowLower[i] > -nlp_infty) {
378  // printf("Lower %g ", rowLower[i]);
379  rowLow[ind] = (rowLower[i]);
380  } else
381  rowLow[ind] = -infty;
382  if (rowUpper[i] < nlp_infty) {
383  // printf("Upper %g ", rowUpper[i]);
384  rowUp[ind] = (rowUpper[i]);
385  } else
386  rowUp[ind] = infty;
387  ind++;
388  }
389 
390  }
391 
392  CoinPackedMatrix mat(true, jRow(), jCol(), jValues(), nnz_jac_g);
393  mat.setDimensions(m, n); // In case matrix was empty, this should be enough
394 
395  //remove non-linear constraints
396  mat.deleteRows(numNonLinear, nonLinear());
397 
398  int numcols = nlp.getNumCols();
399  Bonmin::vector<double> obj(numcols);
400  for (int i = 0; i < numcols; i++)
401  obj[i] = 0.;
402 
403  si.loadProblem(mat, nlp.getColLower(), nlp.getColUpper(),
404  obj(), rowLow(), rowUp());
405  const Bonmin::TMINLP::VariableType* variableType = problem->var_types();
406  for (int i = 0; i < n; i++) {
407  if ((variableType[i] == Bonmin::TMINLP::BINARY) || (variableType[i] == Bonmin::TMINLP::INTEGER))
408  si.setInteger(i);
409  }
410  if (getObj) {
411  bool addObjVar = false;
412  if (problem->hasLinearObjective()) {
413  double zero;
414  Bonmin::vector<double> x0(n, 0.);
415  problem->eval_f(n, x0(), 1, zero);
416  si.setDblParam(OsiObjOffset, -zero);
417  //Copy the linear objective and don't create a dummy variable.
418  problem->eval_grad_f(n, x, 1, obj());
419  si.setObjective(obj());
420  } else {
421  addObjVar = true;
422  }
423 
424  if (addObjVar) {
425  nlp.addObjectiveFunction(si, x);
426  }
427  }
428 
429  // Hassan IA initial description
430  int InnerDesc = 1;
431  if (InnerDesc == 1) {
432  OsiCuts cs;
433 
434  double * p = CoinCopyOfArray(colLower, n);
435  double * pp = CoinCopyOfArray(colLower, n);
436  double * up = CoinCopyOfArray(colUpper, n);
437 
438  for (int i = 0; i < n; i++) {
439  if (p[i] < -1e3){
440  p[i] = pp[i] = -1e3;
441  }
442  if (up[i] > 1e2){
443  up[i] = 1e2;
444  }
445  }
446 
447  const int& nbAp = nbAp_;
448  printf("Generating approximation with %i points.\n", nbAp);
449 
450  std::vector<double> step(n);
451  int n_lin = 0;
452 
453  for (int i = 0; i < n; i++) {
454  //if ((variableType[i] == Bonmin::TMINLP::BINARY) || (variableType[i] == Bonmin::TMINLP::INTEGER)) {
455  if (varTypes[i] == Ipopt::TNLP::LINEAR) {
456  n_lin ++;
457  step[i] = 0;
458  p[i] = pp[i] = up[i] = 0;
459  }
460  else {
461  step[i] = (up[i] - p[i]) / (nbAp);
462  }
463  }
464  printf("Number of linears %i\n", n_lin);
465 
466  for (int j = 1; j < nbAp; j++) {
467 
468  for (int i = 0; i < n; i++) {
469  pp[i] += step[i];
470  }
471 
472  for (int i = 0; (i < m ); i++) {
473  if (constTypes[i] == Ipopt::TNLP::LINEAR) continue;
474  bool status = getMyInnerApproximation(nlp, cs, i, p, pp);// Generate a chord connecting the two points
475  if(status == false){
476  printf("Error in generating inner approximation\n");
477  exit(1);
478  }
479  }
480  std::copy(pp, pp+n, p);
481 
482  }
483 
484  for(int i = 0; (i< m); i++) {
485  if (constTypes[i] == Ipopt::TNLP::LINEAR) continue;
486  getMyInnerApproximation(nlp, cs, i, p, up);// Generate a chord connecting the two points
487  }
488 
489  delete [] p;
490  delete [] pp;
491  delete [] up;
492  si.applyCuts(cs);
493  }
494  printf("************ Done extracting inner approx ********");
495  }
496 
497 }
498 
virtual double getInfinity() const
Get solver&#39;s value for infinity.
static Bigint * diff(Bigint *a, Bigint *b)
Definition: OSdtoa.cpp:1120
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
This is class provides an Osi interface for a Mixed Integer Linear Program expressed as a TMINLP (so ...
int howOften_
How often to do (code can change)
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
int nbAp_
Number of Approximation points.
OsiSolverInterface * clone(bool copyData=true) const
Virtual copy constructor.
void Initialize(Bonmin::BonminSetup *setup)
Initialize method.
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
virtual int getNumRows() const
Get number of rows.
virtual int getNumCols() const
Get number of columns.
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register the options common to all local search based heuristics.
static char * j
Definition: OSdtoa.cpp:3622
HeuristicInnerApproximation(Bonmin::BonminSetup *setup)
Constructor with setup.
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.
virtual bool get_variables_linearity(Ipopt::Index n, LinearityType *var_types)
Returns the variables 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.
const Ipopt::Number * x_u()
Get the current values for the upper bounds.
bool getMyInnerApproximation(Bonmin::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 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.
Bonmin::BonminSetup * setup_
Setup to use for local searches (will make copies).
virtual int solution(double &solutionValue, double *betterSolution)
Performs heuristic.
Bonmin::SubMipSolver * mip_
A subsolver for MIP.
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 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.
HeuristicInnerApproximation & operator=(const HeuristicInnerApproximation &rhs)
Assignment operator.
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.
void extractInnerApproximation(Bonmin::OsiTMINLPInterface &nlp, OsiSolverInterface &si, const double *x, bool getObj)
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.