impliedBounds-exprQuad.cpp
Go to the documentation of this file.
1 /* $Id: impliedBounds-exprQuad.cpp 560 2011-04-17 10:01:15Z stefan $
2  *
3  * Name: impliedBounds-exprQuad.cpp
4  * Author: Pietro Belotti
5  * Purpose: inferring bounds on independent variables of an exprQuad
6  * given bounds on the auxiliary variable
7  *
8  * (C) Carnegie-Mellon University, 2006-10.
9  * This file is licensed under the Eclipse Public License (EPL)
10  */
11 
12 #include <set>
13 
14 #include "CouenneExprQuad.hpp"
15 #include "CouenneConfig.h"
16 #include "CoinFinite.hpp"
17 #include "CoinHelperFunctions.hpp"
18 
19 using namespace Couenne;
20 
21 // struct compExpr;
22 
28 struct compVar {
29  inline bool operator () (exprVar* e0, exprVar* e1) const
30  {return (e0 -> Index () < e1 -> Index ());}
31 };
32 
33 
36 
37 bool exprQuad::impliedBound (int wind, CouNumber *l, CouNumber *u, t_chg_bounds *chg, enum auxSign sign) {
38 
39  //return false; // !!!
40 
41  // three implied bound computations, of increasing complexity. The
42  // first reduces this sum to a sum of aux and tries, after
43  // tightening bounds of each aux, to infer new bounds
44 
45  CouNumber
46  wl = sign == expression::AUX_GEQ ? -COIN_DBL_MAX : l [wind],
47  wu = sign == expression::AUX_LEQ ? COIN_DBL_MAX : u [wind];
48 
49 #ifdef DEBUG
50  printf ("################ implied bounds: [%g,%g], ", wl, wu);
51  print (); printf ("\n");
52 #endif
53 
54  // Nevermind about the nonlinear part stored in arglist_...
55 
56  //std::set <int> indexSet;
57  std::set <exprVar *, compVar> indexSet;
58 
59  // insert indices of linear part
60  for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el)
61  indexSet.insert (el -> first);
62 
63  // insert indices of quadratic part
64  for (sparseQ::iterator row = matrix_.begin (); row != matrix_.end (); ++row) {
65 
66  indexSet.insert (row -> first);
67 
68  for (sparseQcol::iterator col = row -> second.begin (); col != row -> second.end (); ++col)
69  indexSet.insert (col -> first);
70  }
71 
72  // CAUTION: this relies on the first version of bound expressions
73  // for quadratic form, i.e. the sum of bounds of independent terms
74 
75  CouNumber qMin, qMax;
76 
77  int indInfLo = -1, indInfUp = -1;
78 
79  // get bounds for nonlinear part of the sum
80  expression *qlb, *qub;
81  exprSum::getBounds (qlb, qub);
82  qMin = (*qlb) (); delete qlb;
83  qMax = (*qub) (); delete qub;
84  //exprSum::getBounds (qMin, qMax);
85 
86  if (qMin < -COUENNE_INFINITY) indInfLo = -2;
87  if (qMax > COUENNE_INFINITY) indInfUp = -2;
88 
89  if ((indInfLo == -2) &&
90  (indInfUp == -2))
91  return false;
92 
93 #ifdef DEBUG
94  printf ("1st phase... inf=(%d,%d) q=[%g,%g].\n", indInfLo, indInfUp, qMin, qMax);
95  for (std::set <int>:: iterator iter = indexSet.begin ();
96  iter != indexSet.end (); ++iter)
97  printf ("%4d [%+6g %+6g]\n", *iter, l [iter -> Index ()], u [iter -> Index ()]);
98 #endif
99 
100  // compute bound on expression using only finite variable bounds
101 
102  computeQuadFiniteBound (qMin, qMax, l, u, indInfLo, indInfUp);
103 
104  // similar to impliedBounds-exprGroup. indInf* are -1 if no
105  // variables are unbounded, i>0 if variable x_i is unbounded and -2
106  // if at least two are, thus making implied bounds useless.
107 
108  qMin += c0_;
109  qMax += c0_;
110 
111  if (((indInfLo == -2) && (indInfUp == -2)) || // at least two variables are unbounded
112  ((indInfLo == -1) && (indInfUp == -1) && // or, none is (and qMin, qMax are exact)
113  (qMin > wl) && (qMax < wu))) // but explicit bounds are loose
114  return false;
115 
116 #ifdef DEBUG
117  printf ("2nd phase... inf=(%d,%d) q=[%g,%g].\n", indInfLo, indInfUp, qMin, qMax);
118 #endif
119 
121  //
122  // now fill in b_i (constant term in both linear coefficient vectors)
123 
124  // prepare data structure for scanning all variables
125  int
126  minindex = (*(indexSet.begin ())) -> Index (), // minimum index
127  maxindex = (*(indexSet.rbegin ())) -> Index (), // maximum index
128  nvars = maxindex - minindex + 1; // upper bound on # variables involved
129 
130  CouNumber
131  *linCoeMin = new CouNumber [nvars], // min coeff of var x_i
132  *linCoeMax = new CouNumber [nvars], // max coeff of var x_i
133  *qii = new CouNumber [nvars], // quadratic coeff
134  *bCutLb = new CouNumber [nvars], // amount to be drawn from the overall lower bound
135  *bCutUb = new CouNumber [nvars]; // amount to be drawn from the overall upper bound
136 
137  // fill all with 0
138  CoinFillN (linCoeMin, nvars, 0.);
139  CoinFillN (linCoeMax, nvars, 0.);
140  CoinFillN (qii, nvars, 0.);
141  CoinFillN (bCutLb, nvars, 0.);
142  CoinFillN (bCutUb, nvars, 0.);
143 
144  // assume all coefficients are finite
145  for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) {
146  // for (int i=0; i<nlterms_; i++) {
147 
148  int ind = el -> first -> Index ();//index_ [i];
149 
150  CouNumber
151  coe = el -> second, //coeff_ [i],
152  li = l [ind],
153  ui = u [ind];
154 
155  ind -= minindex;
156 
157  linCoeMin [ind] += coe;
158  linCoeMax [ind] += coe;
159 
160  if (coe > 0) { // contribution of linear term to bound depends on its coefficient
161  if (li > -COUENNE_INFINITY) bCutLb [ind] += coe * li;
162  if (ui < COUENNE_INFINITY) bCutUb [ind] += coe * ui;
163  } else {
164  if (ui < COUENNE_INFINITY) bCutLb [ind] += coe * ui;
165  if (li > -COUENNE_INFINITY) bCutUb [ind] += coe * li;
166  }
167  }
168 
169 #ifdef DEBUG
170  printf ("linear filling (%d,%d): -----------------------\n", minindex, maxindex);
171  for (std::set <int>:: iterator iter = indexSet.begin ();
172  iter != indexSet.end (); ++iter)
173  printf ("%4d [%+6g %+6g] [%+6g %+6g]\n", iter -> Index (),
174  linCoeMin [iter -> Index () - minindex], linCoeMax [iter -> Index () - minindex],
175  bCutLb [iter -> Index () - minindex], bCutUb [iter -> Index () - minindex]);
176 #endif
177 
178  // fill in remaining linear coefficients and quadratic ones
179  for (sparseQ::iterator row = matrix_.begin (); row != matrix_.end (); ++row) {
180 
181  for (sparseQcol::iterator col = row -> second.begin (); col != row -> second.end (); ++col) {
182 
183  int
184  qi = row -> first -> Index (),
185  qj = col -> first -> Index (); //qindexJ_ [i];
186 
187  CouNumber coe = col -> second, //qcoeff_ [i],
188  li = l [qi], lj = l [qj],
189  ui = u [qi], uj = u [qj];
190 
191  if (qi == qj) { // quadratic term
192 
193  qi -= minindex;
194 
195  qii [qi] = coe; // quadratic term
196 
197  CouNumber
198  maxbUb = CoinMax (fabs (li), fabs (ui)),
199  maxbLb = (li >= 0) ? (li) : (ui <= 0) ? (ui) : 0;
200 
201  if (maxbUb > COUENNE_INFINITY) maxbUb = 0;
202 
203  maxbUb *= maxbUb * coe;
204  maxbLb *= maxbLb * coe;
205 
206  if (coe > 0) {
207  bCutUb [qi] += maxbUb;
208  bCutLb [qi] += maxbLb;
209  } else {
210  bCutUb [qi] += maxbLb;
211  bCutLb [qi] += maxbUb;
212  }
213  } else { // product term
214 
215  coe *= 2;
216 
217  CouNumber *b1, *b2;
218 
219  if (coe > 0) {b1 = l; b2 = u;}
220  else {b1 = u; b2 = l;}
221 
222  b1 += minindex;
223  b2 += minindex;
224 
225  qi -= minindex;
226  qj -= minindex;
227 
228  linCoeMin [qi] += coe * b1 [qj];
229  linCoeMin [qj] += coe * b1 [qi];
230 
231  linCoeMax [qi] += coe * b2 [qj];
232  linCoeMax [qj] += coe * b2 [qi];
233 
234  CouNumber
235  addLo = CoinMin (CoinMin (li*lj, ui*uj),
236  CoinMin (ui*lj, li*uj)),
237  addUp = CoinMax (CoinMax (li*lj, ui*uj),
238  CoinMax (ui*lj, li*uj));
239 
240  if (addLo < -COUENNE_INFINITY) addLo = 0;
241  if (addUp > COUENNE_INFINITY) addUp = 0;
242 
243  addLo *= coe;
244  addUp *= coe;
245 
246  if (coe > 0) {
247  bCutLb [qi] += addLo; bCutUb [qi] += addUp;
248  bCutLb [qj] += addLo; bCutUb [qj] += addUp;
249  } else {
250  bCutLb [qi] += addUp; bCutUb [qi] += addLo;
251  bCutLb [qj] += addUp; bCutUb [qj] += addLo;
252  }
253  }
254  }
255  }
256 
257 #ifdef DEBUG
258  printf ("quad filling: -----------------------\n");
259  for (std::set <int>:: iterator iter = indexSet.begin ();
260  iter != indexSet.end (); ++iter)
261  printf ("%4d [%+6g %+6g] [%+6g %+6g]\n", *iter,
262  linCoeMin [iter -> Index () - minindex], linCoeMax [iter -> Index () - minindex],
263  bCutLb [iter -> Index () - minindex], bCutUb [iter -> Index () - minindex]);
264 #endif
265 
266  // Done filling vectors /////////////////////////////////////////////////////////////
267  // Now improve each independent variable in the set indexSet
268 
269  bool one_updated = false;
270 
271  for (std::set <exprVar *, compVar>:: iterator iter = indexSet.begin ();
272  iter != indexSet.end (); ++iter) {
273 
274  bool
275  updatedL = false,
276  updatedU = false;
277 
278  int ind = (*iter) -> Index (),
279  indn = ind - minindex;
280 
281  CouNumber
282  al = linCoeMin [indn],
283  au = linCoeMax [indn],
284  q = qii [indn];
285 
286 #ifdef DEBUG
287  CouNumber
288  ol = l [ind],
289  ou = u [ind];
290 #endif
291 
292  if (fabs (q) < COUENNE_EPS) { // case 1: qii is zero, term is "linear"
293 
294  if ((al > 0) || (au < 0)) { // otherwise, min and max lin coe
295  // contain zero, not much to do...
296 
297  // l <= b_i x_i + c <= u
298  // <===> l - c_MAX <= b_i x_i <= u - c_MIN
299  //
300  // c_MAX = qMax - bCutUb [indn]
301  // c_MIN = qMin - bCutLb [indn]
302 
303  CouNumber
304  l_b = wl - qMax + bCutUb [indn],
305  u_b = wu - qMin + bCutLb [indn];
306 
307  if (al > 0) { // care about min -- see outer if, it means 0 < al < au
308 
309  if ((indInfUp == -1) || (indInfUp == ind))
310  updatedL = updateBound (-1, l + ind, (l_b) / ((l_b < 0) ? al : au)) || updatedL;
311  if ((indInfLo == -1) || (indInfLo == ind))
312  updatedU = updateBound (+1, u + ind, (u_b) / ((u_b < 0) ? au : al)) || updatedU;
313 
314 #ifdef DEBUG
315  if (l [ind] > ol) printf ("0. l%d: %g --> %g\n", ind, ol, l [ind]);
316  if (u [ind] < ou) printf ("0. u%d: %g --> %g\n", ind, ou, u [ind]);
317 #endif
318  } else { // only look at max, as al < au < 0
319 
320  if ((indInfLo == -1) || (indInfLo == ind))
321  updatedL = updateBound (-1, l + ind, (u_b) / ((u_b < 0) ? al : au)) || updatedL;
322  if ((indInfUp == -1) || (indInfUp == ind))
323  updatedU = updateBound (+1, u + ind, (l_b) / ((l_b < 0) ? au : al)) || updatedU;
324 
325 #ifdef DEBUG
326  if (l [ind] > ol) printf ("1. l%d: %g --> %g\n", ind, ol, l [ind]);
327  if (u [ind] < ou) printf ("1. u%d: %g --> %g\n", ind, ou, u [ind]);
328 #endif
329  }
330  }
331 
332  } else if (q > 0) {
333 
334  // skip if constant term is unbounded from below
335 
336  if ((indInfLo != -1) &&
337  (indInfLo != ind))
338  continue;
339 
340  // case 2: qii is positive, the parabola is facing upwards and
341  // we only need to look at w_U = wu
342 
343  // there are two parabolas, with linear coefficient linCoeMin
344  // and linCoeMax, respectively. If both cut the line $w=w_U$
345  // then take the minimum of the cut points as new lower bound
346  // and similarly for the new upper bound.
347 
348  // Fortunately there are just two values of linCoe which we have
349  // to look at, as the parabola is of the form $q_{ii} x_i^2 +
350  // \hat b_i x_i + c \le w_u$ and the solution contains $\sqrt
351  // {b_i^2 - 4q_{ii}(c-u)}$, whose maximum is attained with b_i
352  // maximum or minimum, that is, at linCoeMax and linCoeMin.
353 
354  CouNumber
355  deltaSecond = 4 * q * (qMin - bCutLb [indn] - wu),
356  deltaUp = au*au - deltaSecond,
357  deltaLo = al*al - deltaSecond;
358 
359  // First case, both parabolas cut the line
360 
361  if ((deltaUp >= 0) &&
362  (deltaLo >= 0)) {
363 
364  updatedL = updateBound (-1, l + ind, (- au - sqrt (deltaUp)) / (2*q)) || updatedL;
365  updatedU = updateBound (+1, u + ind, (- al + sqrt (deltaLo)) / (2*q)) || updatedU;
366 
367 #ifdef DEBUG
368  if (l [ind] > ol) printf ("2. l%d: %g --> %g\n", ind, ol, l [ind]);
369  if (u [ind] < ou) printf ("2. u%d: %g --> %g\n", ind, ou, u [ind]);
370 #endif
371 
372  } else if (deltaUp >= 0) { // only left-leaning parabola does
373 
374  updatedL = updateBound (-1, l + ind, (- au - sqrt (deltaUp)) / (2*q)) || updatedL;
375  updatedU = updateBound (+1, u + ind, (- au + sqrt (deltaUp)) / (2*q)) || updatedU;
376  // addCoeffCut ();
377 
378 #ifdef DEBUG
379  if (l [ind] > ol) printf ("3. l%d: %g --> %g\n", ind, ol, l [ind]);
380  if (u [ind] < ou) printf ("3. u%d: %g --> %g\n", ind, ou, u [ind]);
381 #endif
382 
383  } else if (deltaLo >= 0) { // only right-leaning parabola does
384 
385  updatedL = updateBound (-1, l + ind, (- al - sqrt (deltaLo)) / (2*q)) || updatedL;
386  updatedU = updateBound (+1, u + ind, (- al + sqrt (deltaLo)) / (2*q)) || updatedU;
387  // addCoeffCut ();
388 
389 #ifdef DEBUG
390  if (l [ind] > ol) printf ("4. l%d: %g --> %g\n", ind, ol, l [ind]);
391  if (u [ind] < ou) printf ("4. u%d: %g --> %g\n", ind, ou, u [ind]);
392 #endif
393 
394  } else { // none of them does, the problem is infeasible
395 
396  updatedL = updateBound (-1, l+ind, +1) || updatedL;
397  updatedU = updateBound (+1, u+ind, -1) || updatedU;
398 
399 #ifdef DEBUG
400  printf ("5. infeasible!\n");
401 #endif
402  }
403 
404  // if only one parabola cuts the line, take its lower and upper
405  // bounds as the new bounds
406 
407  // TODO: in the 2nd and 3rd cases, add constraint $\hat b \ge
408  // \sqrt {4q_{ii}(c-u)}$ or the opposite, to ensure that
409  // parabola is at least tangent to line w=w_U
410 
411  // Also, lower bound can be of help if x_i has a bound between
412  // the two intersections of the parabola with line w=w_L
413 
414  } else {
415 
416  // case 3: qii is negative, the parabola is facing downwards and
417  // we only need to look at wl
418 
419  // skip if constant term is unbounded from above
420  if ((indInfUp != -1) &&
421  (indInfUp != ind))
422  continue;
423 
424  CouNumber
425  deltaSecond = 4 * q * (qMax - bCutUb [indn] - wl),
426  deltaUp = au*au - deltaSecond,
427  deltaLo = al*al - deltaSecond;
428 
429  // First case, both parabolas cut the line
430 
431  if ((deltaUp >= 0) &&
432  (deltaLo >= 0)) {
433 
434  updatedL = updateBound (-1, l + ind, (al - sqrt (deltaLo)) / (-2*q)) || updatedL;
435  updatedU = updateBound (+1, u + ind, (au + sqrt (deltaUp)) / (-2*q)) || updatedU;
436 
437 #ifdef DEBUG
438  if (l [ind] > ol) printf ("6. l%d: %g --> %g\n", ind, ol, l [ind]);
439  if (u [ind] < ou) printf ("6. u%d: %g --> %g\n", ind, ou, u [ind]);
440 #endif
441  } else if (deltaUp >= 0) { // only left-leaning parabola does
442 
443  updatedL = updateBound (-1, l + ind, (au - sqrt (deltaUp)) / (-2*q)) || updatedU;
444  updatedU = updateBound (+1, u + ind, (au + sqrt (deltaUp)) / (-2*q)) || updatedL;
445  // addCoeffCut ();
446 
447 #ifdef DEBUG
448  if (l [ind] > ol) printf ("7. l%d: %g --> %g\n", ind, ol, l [ind]);
449  if (u [ind] < ou) printf ("7. u%d: %g --> %g\n", ind, ou, u [ind]);
450 #endif
451 
452  } else if (deltaLo >= 0) { // only right-leaning parabola does
453 
454  updatedL = updateBound (-1, l + ind, (al - sqrt (deltaLo)) / (-2*q)) || updatedL;
455  updatedU = updateBound (+1, u + ind, (al + sqrt (deltaLo)) / (-2*q)) || updatedU;
456  // addCoeffCut ();
457 #ifdef DEBUG
458  if (l [ind] > ol) printf ("8. l%d: %g --> %g\n", ind, ol, l [ind]);
459  if (u [ind] < ou) printf ("8. u%d: %g --> %g\n", ind, ou, u [ind]);
460 #endif
461 
462  } else { // none of them does, the problem is infeasible
463 
464  updatedL = updateBound (-1, l+ind, +1) || updatedL;
465  updatedU = updateBound (+1, u+ind, -1) || updatedU;
466 
467 #ifdef DEBUG
468  printf ("9. infeasible\n");
469 #endif
470  }
471  }
472 
473  //
474 
475  if (updatedL) {
476  one_updated = true;
477  chg [ind].setLower(t_chg_bounds::CHANGED);
478  if ((*iter) -> isInteger ())
479  l [ind] = ceil (l [ind] - COUENNE_EPS);
480  }
481 
482  if (updatedU) {
483  one_updated = true;
484  chg [ind].setUpper(t_chg_bounds::CHANGED);
485  if ((*iter) -> isInteger ())
486  u [ind] = floor (u [ind] + COUENNE_EPS);
487  }
488  }
489 
490  delete [] linCoeMin;
491  delete [] linCoeMax;
492  delete [] qii;
493  delete [] bCutLb;
494  delete [] bCutUb;
495 
496  return one_updated;
497 }
bool updateBound(register int sign, register CouNumber *dst, register CouNumber src)
updates maximum violation.
status of lower/upper bound of a variable, to be checked/modified in bound tightening ...
void setLower(ChangeStatus lower)
Structure for comparing variables.
CouNumber c0_
constant term
virtual bool isInteger()
is this expression integer?
Definition: exprQuad.cpp:403
Long e1
Definition: OSdtoa.cpp:1815
void setUpper(ChangeStatus upper)
virtual int Index() const
Return index of variable (only valid for exprVar and exprAux)
auxSign
&quot;sign&quot; of the constraint defining an auxiliary.
Bigint * b1
Definition: OSdtoa.cpp:1708
lincoeff lcoeff_
coefficients and indices of the linear term
virtual void getBounds(expression *&, expression *&)
Get lower and upper bound of an expression (if any)
Definition: exprSum.cpp:118
#define COUENNE_EPS
fint li
double CouNumber
main number type in Couenne
#define COUENNE_INFINITY
variable-type operator
virtual bool impliedBound(int, CouNumber *, CouNumber *, t_chg_bounds *, enum auxSign=expression::AUX_EQ)
implied bound processing
Expression base class.
void computeQuadFiniteBound(CouNumber &qMin, CouNumber &qMax, CouNumber *l, CouNumber *u, int &indInfLo, int &indInfUp)
return lower and upper bound of quadratic expression
virtual void print(std::ostream &=std::cout, bool=false) const
Print expression to an iostream.
Definition: exprQuad.cpp:178