SepaTMINLP2OsiLP.cpp
Go to the documentation of this file.
1 // (C) Copyright International Business Machines Corporation 2007
2 // All Rights Reserved.
3 // This code is published under the Eclipse Public License.
4 //
5 // Authors :
6 // Pierre Bonami, International Business Machines Corporation
7 //
8 // Date : 10/16/2007
9 #include "SepaTMINLP2OsiLP.hpp"
10 #include "BonTypes.hpp"
11 #include "OsiSolverInterface.hpp"
12 #include "BonTMINLP2TNLP.hpp"
13 #include "CoinPackedMatrix.hpp"
14 
15 #include <vector>
16 #include <sstream>
17 #include <climits>
18 
19 using namespace Ipopt;
20 
21 namespace Sepa {
22 
23 void
24 SepaTMINLP2OsiLP::extract(OsiSolverInterface *si,
25  const double * x, bool getObj)
26 {
27  assert(IsValid(model_));
28  int n;
29  int m;
30  int nnz_jac_g;
31  int nnz_h_lag;
32  TNLP::IndexStyleEnum index_style;
33  //Get problem information
34  model_->get_nlp_info( n, m, nnz_jac_g, nnz_h_lag, index_style);
35 
36  //get Jacobian
37  model_->eval_jac_g(n, x, 1, m, nnz_jac_g, NULL, NULL, value_());
38 
39 
41  model_->eval_g(n, x, 1, m, g());
42 
43  Bonmin::vector<double> rowLow(m);
44  Bonmin::vector<double> rowUp(m);
45 
46 
47 
48  const double * rowLower = model_->g_l();
49  const double * rowUpper = model_->g_u();
50  const double * colLower = model_->x_l();
51  const double * colUpper = model_->x_u();
52 
53  double nlp_infty = si->getInfinity();
54  double infty = DBL_MAX;
55 
56  for(int i = 0 ; i < m ; i++) {
57  if(const_types_[i] == Ipopt::TNLP::NON_LINEAR) {
58  if(rowLower[i] > - nlp_infty){
59  rowLow[i] = (rowLower[i] - g[i]) - 1e-07;
60  }
61  else
62  rowLow[i] = - infty;
63  if(rowUpper[i] < nlp_infty)
64  rowUp[i] = (rowUpper[i] - g[i]) + 1e-07;
65  else
66  rowUp[i] = infty;
67  }
68  else {
69  if(rowLower[i] > -nlp_infty){
70  rowLow[i] = (rowLower[i]);
71  }
72  else
73  rowLow[i] = - infty;
74  if(rowUpper[i] < nlp_infty){
75  rowUp[i] = (rowUpper[i]);
76  }
77  else
78  rowUp[i] = infty;
79  }
80  }
81 
82 
83 
84  //Then convert everything to a CoinPackedMatrix
85  //Go through values, clean coefficients and fix bounds
86  for(int i = 0 ; i < nnz_jac_g ; i++) {
87  if(const_types_[iRow_[i]] != TNLP::LINEAR){//For linear just copy is fine.
88  if(//For other clean tinys
89  cleanNnz(value_[i],colLower[jCol_[i]], colUpper[jCol_[i]],
90  rowLower[iRow_[i]], rowUpper[iRow_[i]],
91  x[jCol_[i]],
92  rowLow[iRow_[i]],
93  rowUp[iRow_[i]], tiny_, very_tiny_)) {
94  if(rowLow[iRow_[i]] > -infty)
95  rowLow[iRow_[i]] += value_[i] * x[jCol_[i]];
96  if(rowUp[iRow_[i]] < infty)
97  rowUp[iRow_[i]] += value_[i] *x[jCol_[i]];
98  }
99  }
100  }
101  CoinPackedMatrix mat(true, iRow_(), jCol_(), value_(), nnz_jac_g);
102  mat.setDimensions(m,n); // In case matrix was empty, this should be enough
103 
104 #if 0
105  vector<double> act(m);
106  mat.times(x, act());
107  for(int j = 0 ; j < m ; j++){
108  if(j==10 && fabs(x[0] - 4.73032) < 1e-4)
109  assert(act[j] + 1e-5 > rowLow[j] && act[j] - 1e-5 < rowUp[j] + g[j]);
110  }
111 #endif
112 
113  Bonmin::vector<double> obj(n);
114  for(int i = 0 ; i < n; i++)
115  obj[i] = 0.;
116 
117 
118  si->loadProblem(mat, colLower, colUpper, obj(), rowLow(), rowUp());
119  for(int i = 0 ; i < n ; i++) {
120  if(model_->var_types()[i] == Bonmin::TMINLP::BINARY || model_->var_types()[i] == Bonmin::TMINLP::INTEGER )
121  si->setInteger(i);
122  }
123  if(getObj) {
124  if(model_->hasLinearObjective()){
125  double zero;
127  model_->eval_f(n, x0(), 1, zero);
128  si->setDblParam(OsiObjOffset, -zero);
129  //Copy the linear objective and don't create a dummy variable.
130  model_->eval_grad_f(n, x, 1,obj());
131  si->setObjective(obj());
132  }
133  else {
134  throw -1;
135  }
136 
137  }
138 
139  OsiCuts cs;
140  get_oas(cs, x, 0, 1);
141  si->applyCuts(cs);
142 
143 
144 }
145 
146 void
147 SepaTMINLP2OsiLP::get_oas(OsiCuts &cs, const double *x, bool getObj, bool global) const {
148 
149  int n,m, nnz_jac_g, nnz_h_lag;
150  TNLP::IndexStyleEnum index_style;
151  model_->get_nlp_info( n, m, nnz_jac_g, nnz_h_lag, index_style);
152 
154 
155  model_->eval_jac_g(n, x, 1, m, nnz_jac_g, NULL, NULL, value_());
156  model_->eval_g(n,x,0,m,g());
157 
158  //As jacobian is stored by cols fill OsiCuts with cuts
159  Bonmin::vector<double> lb(m + 1);
160  Bonmin::vector<double> ub(m + 1);
161 
162  Bonmin::vector<int> row2cutIdx(m,-1);//store correspondance between index of row and index of cut (some cuts are not generated for rows because linear, or not binding). -1 if constraint does not generate a cut, otherwise index in cuts.
163 
164  std::vector<int> cut2rowIdx;
165 
166  int numCuts = 0;
167 
168  const double * rowLower = model_->g_l();
169  const double * rowUpper = model_->g_u();
170  const double * colLower = model_->x_l();
171  const double * colUpper = model_->x_u();
172  double nlp_infty = infty_;
173  double infty = DBL_MAX;
174 
175  for(int rowIdx = 0; rowIdx < m ; rowIdx++) {
176  if(const_types_[rowIdx] == TNLP::NON_LINEAR) {
177  row2cutIdx[rowIdx] = numCuts;
178  cut2rowIdx.push_back(rowIdx);
179  if(rowLower[rowIdx] > - nlp_infty)
180  lb[numCuts] = rowLower[rowIdx] - g[rowIdx];
181  else
182  lb[numCuts] = - infty;
183  if(rowUpper[rowIdx] < nlp_infty)
184  ub[numCuts] = rowUpper[rowIdx] - g[rowIdx];
185  else
186  ub[numCuts] = infty;
187  numCuts++;
188  }
189  }
190 
191  lb.resize(numCuts);
192  ub.resize(numCuts);
193  Bonmin::vector<CoinPackedVector> cuts(numCuts);
194 
195 
196  for(int i = 0 ; i < nnz_jac_g ; i++) {
197  const int &rowIdx = iRow_[i];
198  const int & cutIdx = row2cutIdx[ rowIdx ];
199  if(cutIdx != -1) {
200  const int &colIdx = jCol_[i];
201  //"clean" coefficient
202  if(cleanNnz(value_[i],colLower[colIdx], colUpper[colIdx],
203  rowLower[rowIdx], rowUpper[rowIdx],
204  x[colIdx],
205  lb[cutIdx],
206  ub[cutIdx], tiny_, very_tiny_)) {
207  if(fabs(value_[i]) > 1e15) {
208  printf("Not generating cut because of big coefficient %g col %i x[%i] = %g\n", value_[i], colIdx, colIdx, x[colIdx]);
209  return;
210  }
211  cuts[cutIdx].insert(colIdx,value_[i]);
212  if(lb[cutIdx] > - infty)
213  lb[cutIdx] += value_[i] * x[colIdx];
214  if(ub[cutIdx] < infty)
215  ub[cutIdx] += value_[i] * x[colIdx];
216  }
217  }
218  }
219 
220  for(int cutIdx = 0; cutIdx < numCuts; cutIdx++) {
221  OsiRowCut newCut;
222  if(global)
223  newCut.setGloballyValidAsInteger(1);
224  //********* Perspective Extension ********//
225  const int* ids = model_->get_const_xtra_id(); // vector of indices corresponding to the binary variable activating the corresponding constraint
226  // Get the index of the corresponding indicator binary variable
227  int binary_id = (ids == NULL) ? -1 : ids[cut2rowIdx[cutIdx]];// index corresponding to the binary variable activating the corresponding constraint
228  if(binary_id>0) {// If this hyperplane is a linearization of a disjunctive constraint, we link its righthand (or lefthand) side to the corresponding indicator binary variable
229  //printf("Using perspectives\n");
230  if (lb[cutIdx] > -infty) { // ∂x ≥ lb => ∂x - lb*z ≥ 0
231  cuts[cutIdx].insert(binary_id, -lb[cutIdx]);
232  newCut.setLb(0);
233  newCut.setUb(ub[cutIdx]);
234 
235  }
236  if (ub[cutIdx] < infty) { // ∂x ≤ ub => ∂x - ub*z ≤ 0
237  cuts[cutIdx].insert(binary_id, -ub[cutIdx]);
238  newCut.setLb(lb[cutIdx]);
239  newCut.setUb(0);
240 
241  }
242  }
243  else {
244  newCut.setLb(lb[cutIdx]);
245  newCut.setUb(ub[cutIdx]);
246  }
247  //********* Perspective Extension ********//
248  newCut.setRow(cuts[cutIdx]);
249  cs.insert(newCut);
250  }
251  printf("++++++++ I have generated %i cuts +++++++++\n", numCuts);
252 
253  return;
254 
255 
256 }
257 
258 void
259 SepaTMINLP2OsiLP::get_oa(int rowIdx, OsiCuts &cs, const double *x, bool getObj, bool global) const {
260 
261  int n,m, nnz_jac_g, nnz_h_lag;
262  TNLP::IndexStyleEnum index_style;
263  model_->get_nlp_info( n, m, nnz_jac_g, nnz_h_lag, index_style);
264 
265  double gi;
266  model_->eval_gi(n,x,1, rowIdx,gi);
267  Bonmin::vector<int> jCol(n);
268  int nnz;
269  model_->eval_grad_gi(n, x, 0, rowIdx, nnz, jCol(), NULL);
270  model_->eval_grad_gi(n, x, 0, rowIdx, nnz, NULL, value_());
271 
272 
273  //As jacobian is stored by cols fill OsiCuts with cuts
274  double lb;
275  double ub;
276 
277  const double * rowLower = model_->g_l();
278  const double * rowUpper = model_->g_u();
279  const double * colLower = model_->x_l();
280  const double * colUpper = model_->x_u();
281  double nlp_infty = infty_;
282  double infty = DBL_MAX;
283 
284  if (rowLower[rowIdx] > -nlp_infty)
285  lb = rowLower[rowIdx] - gi;
286  else
287  lb = -infty;
288  if (rowUpper[rowIdx] < nlp_infty)
289  ub = rowUpper[rowIdx] - gi;
290  else
291  ub = infty;
292 
293  CoinPackedVector cut;
294 
295 
296  for(int i = 0 ; i < nnz ; i++) {
297  if(index_style == Ipopt::TNLP::FORTRAN_STYLE) jCol[i]--;
298  const int &colIdx = jCol[i];
299  //"clean" coefficient
300  if(cleanNnz(value_[i],colLower[colIdx], colUpper[colIdx],
301  rowLower[rowIdx], rowUpper[rowIdx],
302  x[colIdx],
303  lb,
304  ub, tiny_, very_tiny_)) {
305  if(fabs(value_[i]) > 1e15) {
306  printf("Not generating cut because of big coefficient %g col %i x[%i] = %g\n", value_[i], colIdx, colIdx, x[colIdx]);
307  return;
308  }
309  cut.insert(colIdx,value_[i]);
310  if(lb > - infty)
311  lb += value_[i] * x[colIdx];
312  if(ub < infty)
313  ub += value_[i] * x[colIdx];
314  }
315  }
316 
317  OsiRowCut newCut;
318  if(global)
319  newCut.setGloballyValidAsInteger(1);
320  //********* Perspective Extension ********//
321  const int* ids = model_->get_const_xtra_id(); // vector of indices corresponding to the binary variable activating the corresponding constraint
322  // Get the index of the corresponding indicator binary variable
323  int binary_id = (ids == NULL) ? -1 : ids[rowIdx];// index corresponding to the binary variable activating the corresponding constraint
324  if(binary_id>0) {// If this hyperplane is a linearization of a disjunctive constraint, we link its righthand (or lefthand) side to the corresponding indicator binary variable
325  //printf("Using perspectives\n");
326  if (lb > -infty) { // ∂x ≥ lb => ∂x - lb*z ≥ 0
327  cut.insert(binary_id, -lb);
328  newCut.setLb(0);
329  newCut.setUb(ub);
330 
331  }
332  if (ub < infty) { // ∂x ≤ ub => ∂x - ub*z ≤ 0
333  cut.insert(binary_id, -ub);
334  newCut.setLb(lb);
335  newCut.setUb(0);
336  }
337  }
338  else {
339  newCut.setLb(lb);
340  newCut.setUb(ub);
341  }
342  //********* Perspective Extension ********//
343  newCut.setRow(cut);
344  cs.insert(newCut);
345  return;
346 }
347 
348 void
349 SepaTMINLP2OsiLP::get_refined_oa(OsiCuts & cs) const{
350  if(num_approx_ <= 0)
351  return;
352  int n;
353  int m;
354  int nnz_jac_g;
355  int nnz_h_lag;
356  Ipopt::TNLP::IndexStyleEnum index_style;
357  //Get problem information
358  model_->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style);
359 
360  //const double * rowLower = model_->g_l();
361  //const double * rowUpper = model_->g_u();
362  const double * colLower = model_->x_l();
363  const double * colUpper = model_->x_u();
365 
366  model_->get_variables_linearity(n, varTypes());
367  //const Bonmin::TMINLP::VariableType* variableType = model_->var_types();
368  // Hassan OA initial description
369 
370  double * p = CoinCopyOfArray(colLower, n);
371  double * pp = CoinCopyOfArray(colLower, n);
372  double * up = CoinCopyOfArray(colUpper, n);
373 
374  std::vector<double> step(n);
375 
376 
377  for (int i = 0; i < n; i++) {
378  if (p[i] < -1e4){
379  p[i] = pp[i] = -1e4;
380  }
381  if (up[i] > 1e4){
382  up[i] = 1e4;
383  }
384  }
385 
386 
387  //Step step
388  for (int i = 0; i < n; i++) {
389 
390  if (varTypes[i] == Ipopt::TNLP::LINEAR) {
391  step[i] = 0;
392  p[i] = pp[i] = up[i] = 0;
393  }
394  else
395  step[i] = (up[i] - p[i]) / (num_approx_);
396 
397  }
398  get_oas(cs, p, 0, true);// Generate Tangents at current point
399  for (int j = 1; j <= num_approx_; j++) {
400 
401  for (int i = 0; i < n; i++) {
402  pp[i] += step[i];
403  }
404 
405  get_oas(cs, pp, 0, true);// Generate Tangents at current point
406 
407  }
408 
409  get_oas(cs, up, 0, true);// Generate Tangents at current point
410 
411  delete [] p;
412  delete [] pp;
413  delete [] up;
414  }
415 
416 void
417 SepaTMINLP2OsiLP::add_outer_description_function_values(OsiSolverInterface &si) {
418  int n;
419  int m;
420  int nnz_jac_g;
421  int nnz_h_lag;
422  Ipopt::TNLP::IndexStyleEnum index_style;
423  //Get problem information
424  model_->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style);
425 
426  //const double * rowLower = model_->g_l();
427  //const double * rowUpper = model_->g_u();
428  const double * colLower = model_->x_l();
429  const double * colUpper = model_->x_u();
431 
432  model_->get_variables_linearity(n, varTypes());
433  const Bonmin::TMINLP::VariableType* variableType = model_->var_types();
434  // Hassan OA initial description
435  OsiCuts cs;
436 
437  double * p = CoinCopyOfArray(colLower, n);
438  double * pp = CoinCopyOfArray(colLower, n);
439  double * up = CoinCopyOfArray(colUpper, n);
440  double * low = CoinCopyOfArray(colLower, n);
441 
442  Bonmin::vector<double> step(n);
443  Bonmin::vector<int> nbG(m,2);
444 
445 
446  for (int i = 0; i < n; i++) {
447  if (low[i] < -1e4){
448  low[i] = -1e4;
449  }
450  if (up[i] > 1e4){
451  up[i] = 1e4;
452  }
453  }
454 
455 
456  for (int i = 0; i < n; i++) {
457 
458  if (varTypes[i] == Ipopt::TNLP::LINEAR) {
459  step[i] = 0;
460  low[i] = p[i] = pp[i] = up[i] = 0;
461  }
462  else
463  step[i] = (up[i] - low[i]) / (num_approx_*20);
464 
465  }
466  get_oas(cs, low, 0, true);// Generate Tangents at start point
467  get_oas(cs, up, 0, true);// Generate Tangents at end point
468  Bonmin::vector<double> g_p(m);
469  Bonmin::vector<double> g_pp(m);
470  model_->eval_g(n, low, 1, m, g_p()); // Evaluate function g at lowerbounds
471  model_->eval_g(n, up, 1, m, g_pp()); // Evaluate function g at upperbounds
472 
473  for (int i = 0; (i < m); i++) { // Generate Outer-Approximation initial cuts for all nonlinear constraints
474  if(const_types_[i] != Ipopt::TNLP::NON_LINEAR) continue;
475  double thresh = std::abs(g_pp[i] - g_p[i])/(num_approx_-1);
476 
477  printf("Constraint %i threshold is %g lower val %g upper %g\n",i, thresh,
478  g_p[i], g_pp[i]);
479  std::copy(low, low + n, p);
480  std::copy(low, low + n, pp);
481  double g_p_i, g_pp_i;
482  g_p_i = g_p[i];
483  int n_steps = 0;
484  while (nbG[i] < num_approx_) { // Iterate untill increase is sufficient
485  n_steps++;
486  // Curvature sampling
487  for (int j = 0; j < n; j++) {
488  pp[j] += step[j];
489  }
490  model_->eval_gi(n, pp, 1, i, g_pp_i);
491  // printf("Difference in function value: %g\n", std::abs(g_p_i - g_pp_i));
492  if (std::abs(g_p_i - g_pp_i)>=thresh ) {
493  printf("Function value after %i steps %g\n", n_steps, g_pp_i);
494  get_oa(i, cs, pp, 0, true);// Generate Tangents at current point
495  for (int j = 0; j < n; j++) {
496  p[j] = pp[j]; // Move all previous points to the current one
497  }
498  g_p_i = g_pp_i;
499  nbG[i]++;
500  }
501  }
502 
503  }
504 
505 
506 
507  si.applyCuts(cs);
508  delete [] p;
509  delete [] pp;
510  delete [] up;
511  }
512 }
bool IsValid(const OSSmartPtr< U > &smart_ptr)
Definition: OSSmartPtr.hpp:465
static char * j
Definition: OSdtoa.cpp:3622
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
static bool cleanNnz(double &value, double colLower, double colUpper, double rowLower, double rowUpper, double colsol, double &lb, double &ub, double tiny, double veryTiny)
void fint fint fint real fint real real real real real real * g
void fint * m
int nnz
ATTENTION: Filter expect the jacobian to be ordered by row.
void fint * n
VariableType
Type of the variables.
Definition: BonTMINLP.hpp:192
real infty
void fint fint fint real fint real * x