disjCut.cpp
Go to the documentation of this file.
1 /* $Id: disjCut.cpp 694 2011-06-18 20:13:17Z stefan $
2  *
3  * Name: disjCut.cpp
4  * Author: Pietro Belotti
5  * Purpose: generate one disjunctive cut based on a single disjunction
6  *
7  * (C) Carnegie-Mellon University, 2008.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CoinTime.hpp"
12 #include "OsiClpSolverInterface.hpp"
13 #include "CouennePrecisions.hpp"
14 #include "CouenneDisjCuts.hpp"
15 //#include "CouenneCutGenerator.hpp"
16 //#include "CouenneProblem.hpp"
17 #include "CouenneInfeasCut.hpp"
18 
19 using namespace Ipopt;
20 using namespace Couenne;
21 
22 #define COEFF_BOUNDS 1.e10
23 
24 #define MIN_NUM_COEFF 1.e-9
25 #define MAX_NUM_COEFF 1.e+9
26 #define MAX_NUM_RATIO 1.e+6
27 
28 
29 // print content of sparse matrix
30 void printMatrix (int nrows, int ncols, int nel,
31  const int *start, const int *len,
32  const int *ind, const double *el);
33 
34 // same with CoinPackedMatrix
35 void printMatrix (const CoinPackedMatrix *A);
36 
37 // same with si.GetMatrixByRow()
38 void printLPMatrix (const OsiSolverInterface &si);
39 
40 // add columns specified by start/len/ind/el to matrix Astd
41 void addSubMatr (int *start, int *len, int *ind, double *el,
42  CoinPackedMatrix &Astd, CoinPackedVector &rstd,
43  int &cur, int &curCol, int dispM, int dispVec, int nrows);
44 
45 
47 int CouenneDisjCuts::generateDisjCuts (std::vector <std::pair <OsiCuts *, OsiCuts *> > &disjunctions,
48  OsiSolverInterface &si,
49  OsiCuts &cs,
50  const CglTreeInfo &info) const {
51 
52  // create CGLP with si+left and si+right, for each (left,right) in
53  // the vector of disjunctions
54  //
55  // Here's the CGLP (row and column order as shown)
56  //
57  // {n} {1} {m} {m} {mL} {mR}
58  //
59  // max alpha xbar - beta --- maximize so can copy xbar
60  // s.t. -alpha + u A + u'C = 0 --- n rows
61  // -alpha + v A + v'D = 0 --- n
62  // -beta + u b + u'c <= 0 --- 1
63  // -beta + v b + v'd <= 0 --- 1
64  // |(u, v, u', v')|_1 = 1 --- normalized multipliers
65  //
66  // u, v, u', v' >= 0 --- non-negativity
67  //
68  //
69  // And here are the submatrices (M' is M transposed)
70  //
71  // First Second Third Fourth Fifth Sixth --- Columns
72  //
73  // xbar -1 0 0 0 0
74  // ---------------------------------------------
75  // -I_n . A' . C' . = 0
76  // -I_n . . A' . D' = 0
77  // . -1 b' . c' . <= 0
78  // . -1 . b' . d' <= 0
79  // . . e e e e = 1
80  //
81  //
82  // build a different A such that
83  //
84  // - only active rows (resp. columns) of A are included if active_rows_
85  // (resp. active_columns_) are set
86  // - equality constraints are duplicated in a <= and a >= constraint
87  // - >= constraints are inverted
88  //
89  // Also, add disjunctive cut to CGLP for use with next disjunction
90 
91  // put matrix from base problem in canonical form //////////////////////////////
92  CoinPackedMatrix Astd;
93  CoinPackedVector rstd;
94  OsiSI2MatrVec (Astd, rstd, si);
95 
96  int
97  n = si. getNumCols (), //mC = 2*n + 3,
98  m = Astd. getMajorDim (), nC = 1 + n + 2 * m,
99  nnz = Astd. getNumElements (), nnzC = 2 * (n + 1 + nnz + 2*m);
100 
101  if (jnlst_ -> ProduceOutput (J_DETAILED, J_DISJCUTS))
102  printf ("canonical form has %d cols, %d rows, %d nonzeros --> cglp has %d,%d,%d\n",
103  n, m, nnz, nC, 2*n + 3, nnzC);
104 
105  double
106  *elements = new double [nnzC];
107 
108  int
109  *indices = new int [nnzC],
110  *start = new int [nC + 1],
111  *length = new int [nC],
112  cur = 0,
113  curCol = 0;
114 
115  // first column: two identity matrices
116  for (int i=0, i2 = n; i<n;) {
117  start [curCol] = cur;
118  length [curCol++] = 2;
119  indices [cur] = i++; elements [cur++] = -1.;
120  indices [cur] = i2++; elements [cur++] = -1.;
121  }
122 
123  // second column: two "-1" at position 2n and 2n+1
124  start [curCol] = cur;
125  length [curCol++] = 2;
126  indices [cur] = 2*n; elements [cur++] = -1.;
127  indices [cur] = 2*n+1; elements [cur++] = -1.;
128 
129  // third...
130  addSubMatr (start + curCol, length + curCol,
131  indices + cur, elements + cur,
132  Astd, rstd,
133  cur, curCol,
134  0, 2*n, 2*n+2);
135 
136  if (jnlst_ -> ProduceOutput (J_MATRIX, J_DISJCUTS)) {
137  printf ("with third column\n");
138  printMatrix (curCol, 2*n+3, cur, start, length, indices, elements);
139  }
140 
141  // ... and fourth column: get single rows from Astd
142  addSubMatr (start + curCol, length + curCol,
143  indices + cur, elements + cur,
144  Astd, rstd,
145  cur, curCol,
146  n, 2*n+1, 2*n+2);
147 
148  if (jnlst_ -> ProduceOutput (J_MATRIX, J_DISJCUTS)) {
149  printf ("with 4th column\n");
150  printMatrix (curCol, 2*n+3, cur, start, length, indices, elements);
151  }
152 
153  CoinPackedMatrix *baseA = new CoinPackedMatrix;
154 
155  baseA -> assignMatrix (true, // column ordered
156  2*n+3, // minor dimension
157  curCol, // major dimension
158  cur, // number of elements
159  elements, // elements
160  indices, // indices
161  start, // starting positions
162  length); // length
163 
164  //printf ("should be copy of above\n");
165  //printMatrix (baseA);
166 
167  OsiClpSolverInterface cglp;
168 
169  cglp. messageHandler () -> setLogLevel (0);
170 
171  int
172  N = baseA -> getMajorDim (), // # cols in base problem
173  M = baseA -> getMinorDim (); // # rows in base problem
174 
175  assert (M == 2 * n + 3);
176 
177  // vectors of the problem
178  double
179  *collb = new double [N], // variable lower bounds
180  *colub = new double [N], // variable upper bounds
181  *obj = new double [N], // objective coefficients
182  *rowrhs = new double [M], // right hand sides (all zero except the last, 1)
183  *rowrng = new double [M]; // row range (empty)
184 
185  // bounds
186  CoinFillN (collb, n+1, -COEFF_BOUNDS);
187  CoinFillN (collb + n+1, N - (n+1), 0.);
188  CoinFillN (colub, n+1, COEFF_BOUNDS);
189  CoinFillN (colub + n+1, N - (n+1), 1.);
190 
191  // objective coefficients
192  CoinCopyN (si.getColSolution (), n, obj);
193  obj [n] = -1.;
194  CoinFillN (obj + (n+1), N-(n+1), 0.);
195 
196  // rhs
197  CoinFillN (rowrhs, M-1, 0.);
198  rowrhs [M-1] = 1.;
199 
200  // rhs range
201  CoinFillN (rowrng, M, COIN_DBL_MAX);
202 
203  // signs of the inequalities
204  char *rowsen = new char [M];
205  CoinFillN (rowsen, M, 'E');
206  rowsen [M-3] = rowsen [M-2] = 'L';
207 
208  cglp.assignProblem (baseA, // matrix
209  collb, // lower bounds
210  colub, // upper bounds
211  obj, // obj coefficients
212  rowsen, // row sense
213  rowrhs, // right hand sides
214  rowrng); // no row range
215 
216  // this is a maximization problem
217  cglp. setObjSense (-1);
218 
220 
221  // generate and solve one CGLP for each disjunction
222 
223  bool first = true;
224 
225  for (std::vector <std::pair <OsiCuts *, OsiCuts *> >::iterator disjI = disjunctions.begin ();
226  (disjI != disjunctions.end ()) && (CoinCpuTime () < cpuTime_); ++disjI) {
227 
228  OsiCuts
229  *left = disjI -> first,
230  *right = disjI -> second;
231 
232  int
233  ncolLeft = OsiCuts2MatrVec (&cglp, left, 0, 2*n),
234  ncolRight = OsiCuts2MatrVec (&cglp, right, n, 2*n+1);
235 
236  /*char filename [30];
237  static int iter = 0;
238  sprintf (filename, "cglp-%04d-%04d-%04d", info.level, iter++, info.pass);
239  cglp.writeLp (filename);*/
240 
241  if (jnlst_ -> ProduceOutput (J_MOREMATRIX, J_DISJCUTS)) {
242  printf ("current CGLP:\n");
243  printLPMatrix (cglp);
244  }
245 
246  //cglp.options () -> SetNumericValue ("max_cpu_time", couenneCG_ -> Problem () -> getMaxCpuTime () - CoinCpuTime ());
247  if (first) {cglp.initialSolve (); first = false;}
248  else cglp.resolve (); // segfault in ex1244
249 
250  if (cglp. isProvenOptimal () && (cglp.getObjValue () > COUENNE_EPS)) {
251 
252  const double *AlphaBeta = cglp. getColSolution ();
253 
254  int *colInd = NULL, nnzCut = 0;
255  double *colCoe = NULL;
256 
257  // count nonzero entries, compute ratio max/min coefficient
258  double mincoeff = COIN_DBL_MAX, maxcoeff = 0.;
259 
260  for (register int i=n+1; i--;) {
261  double value = fabs (AlphaBeta [i]);
262  if (value == 0.) continue;
263  if (value > maxcoeff) maxcoeff = value;
264  if (value < mincoeff) mincoeff = value;
265  if ((maxcoeff > MAX_NUM_COEFF) ||
266  (maxcoeff < MIN_NUM_COEFF) ||
267  (maxcoeff / mincoeff > MAX_NUM_RATIO))
268  break;
269  nnzCut++;
270  }
271 
272  if (nnzCut &&
273  (maxcoeff < MAX_NUM_COEFF) &&
274  (maxcoeff > MIN_NUM_COEFF) &&
275  (maxcoeff / mincoeff < MAX_NUM_RATIO)) {
276 
277  // cut data
278  double *nzcoeff = new double [nnzCut];
279  int *indices = new int [nnzCut];
280 
281  // fill in indices and coefficient
282  for (int i = nnzCut = 0; i<n; i++)
283  if (fabs (AlphaBeta [i]) > MIN_NUM_COEFF) {
284  indices [nnzCut] = i;
285  nzcoeff [nnzCut++] = AlphaBeta [i];
286  }
287 
288  OsiRowCut *cut = new OsiRowCut;
289  cut -> setRow (nnzCut, indices, nzcoeff);
290  cut -> setUb (AlphaBeta [n]);
291 
292  /*if (1) {
293 
294  printf ("---- RESOLVING\n");
295  si.applyRowCuts (1, cut);
296  si.writeLp ("added");
297  si.resolve ();
298  printf ("---- RESOLVED\n");
299 
300  double *obj = new double [N]; // objective coefficients
301 
302  // objective coefficients
303  CoinCopyN (si.getColSolution (), n, obj);
304  obj [n] = -1.;
305  CoinFillN (obj + (n+1), N-(n+1), 0.);
306 
307  cglp.setObjective (obj);
308  }*/
309 
310  // add it to CGLP
311  if (addPreviousCut_) {
312 
313  colInd = new int [2 * (nnzCut + 2)];
314  colCoe = new double [2 * (nnzCut + 2)];
315 
316  // first column
317  CoinCopyN (nzcoeff, nnzCut, colCoe);
318  CoinCopyN (indices, nnzCut, colInd);
319  colInd [nnzCut] = 2*n; colCoe [nnzCut] = AlphaBeta [n];
320  colInd [nnzCut+1] = 2*n+2; colCoe [nnzCut+1] = 1; // entry in norm constraint
321 
322  // second column
323  CoinCopyN (nzcoeff, nnzCut, colCoe + nnzCut + 2);
324  CoinCopyDisp (indices, nnzCut, colInd + nnzCut + 2, n);
325  colInd [2*nnzCut + 2] = 2*n+1; colCoe [2*nnzCut+2] = AlphaBeta [n];
326  colInd [2*nnzCut + 3] = 2*n+2; colCoe [2*nnzCut+3] = 1.; // entry in norm constraint
327 
328  // extra vectors
329  double lb [2] = {0., 0.};
330  double ub [2] = {1., 1.};
331  double obj [2] = {0., 0.};
332 
333  int start [3];
334  *start = 0;
335  start [2] = 2 * (start [1] = nnzCut + 2);
336 
337  cglp. addCols (2, // const int numcols,
338  start, // const int* columnStarts,
339  colInd, // const int* rows,
340  colCoe, // const double* elements,
341  lb, // const double* collb,
342  ub, // const double* colub,
343  obj); // const double* obj
344 
345  delete [] colCoe;
346  delete [] colInd;
347  }
348 
349  delete [] nzcoeff;
350  delete [] indices;
351 
352  if (jnlst_ -> ProduceOutput (J_DETAILED, J_DISJCUTS)) {
353  printf ("====== disjunctive cut: ");
354  cut -> print ();
355  }
356 
357  // add cut to cs
358  cs. insert (cut);
359  }
360  }
361 
362  // remove last ncolLeft + ncolRight columns from cglp
363  int *delIndices = new int [ncolLeft + ncolRight];
364  for (register int nc = ncolLeft + ncolRight, j = N + nc; nc--;)
365  *delIndices++ = --j;
366  delIndices -= (ncolLeft + ncolRight);
367  cglp.deleteCols (ncolLeft + ncolRight, delIndices);
368  delete [] delIndices;
369  }
370 
371  return COUENNE_FEASIBLE;
372 }
#define MAX_NUM_COEFF
Definition: disjCut.cpp:25
void printLPMatrix(const OsiSolverInterface &si)
void fint fint fint real fint real real real real real real real real real fint real fint fint fint real fint fint fint fint * info
const Ipopt::EJournalCategory J_DISJCUTS(Ipopt::J_USER6)
#define COEFF_BOUNDS
Definition: disjCut.cpp:22
void printMatrix(int nrows, int ncols, int nel, const int *start, const int *len, const int *ind, const double *el)
static char * j
Definition: OSdtoa.cpp:3622
void CoinCopyDisp(register const int *src, register int num, register int *dst, register int displacement)
a CoinCopyN with a += on each element
#define COUENNE_EPS
void addSubMatr(int *start, int *len, int *ind, double *el, CoinPackedMatrix &Astd, CoinPackedVector &rstd, int &cur, int &curCol, int dispM, int dispVec, int nrows)
#define MIN_NUM_COEFF
Definition: disjCut.cpp:24
#define MAX_NUM_RATIO
Definition: disjCut.cpp:26
void fint * m
int nnz
ATTENTION: Filter expect the jacobian to be ordered by row.
void fint * n