unifiedProdCuts.cpp
Go to the documentation of this file.
1 /* $Id: unifiedProdCuts.cpp 811 2012-02-01 19:21:41Z pbelotti $
2  *
3  * Name: unifiedProdCuts.cpp
4  * Author: Pietro Belotti
5  * Purpose: unified convexification of products and divisions
6  *
7  * (C) Carnegie-Mellon University, 2006-10.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CouenneCutGenerator.hpp"
12 
13 #include "CouenneTypes.hpp"
14 #include "CouennePrecisions.hpp"
15 #include "CouenneProblem.hpp"
16 #include "CouenneExprDiv.hpp"
17 #include "CouenneExprMul.hpp"
18 #include "CouenneExprPow.hpp"
19 #include "CouenneFunTriplets.hpp"
20 
21 using namespace Couenne;
22 
24 
26  OsiCuts &cs,
27  CouNumber xp, CouNumber yp, // current point
28  CouNumber wb, // bound on w
29  int sign, // is wb lower or upper?
30  CouNumber x0, CouNumber y0, // (allegedly) outside point
31  CouNumber x1, CouNumber y1, // inside
32  int xi, int yi, int wi) { // indices of the variables
33 
34  // Upper right corner of the bounding box of (x,y) is feasible,
35  // the opposite corner is not, hence there is a cut violated by
36  // (x0,y0).
37 
38  // If (x0,y0) is not in the same orthant as the contour in
39  // question, move it in so that we can apply a Newton step to
40  // find closest point on contour.
41 
42  int xsign = (x1 >= 0) ? 1 : -1, // define orthant where the "inside
43  ysign = (y1 >= 0) ? 1 : -1; // point" lies
44 
45  if (((xsign > 0) ? xp : -xp) <= COUENNE_EPS)
46  if (((ysign > 0) ? yp : -yp) <= COUENNE_EPS) {
47 
48  // opposite orthant, put in the right one where constraint is violated
49  xp = yp = sqrt (fabs (wb))/2;
50  if (xsign<0) xp = -xp;
51  if (ysign<0) yp = -yp;
52  } // otherwise, must cross one axis only:
53  else {xp = sqrt (fabs(wb/yp)); if (xsign<0) xp=-xp;}//y
54  else if (((ysign > 0) ? yp : -yp) <= COUENNE_EPS) {yp = sqrt (fabs(wb/xp)); if (ysign<0) yp=-yp;}//x
55 
56  // pt here describes a function of the form wb*x^(-1)
57  kpowertriplet pt (-1, wb);
58 
59  CouNumber
60  // tangent point closest to current point
61  xt = powNewton (xp, yp, &pt),
62  *lb = cg -> Problem () -> Lb (),
63  *ub = cg -> Problem () -> Ub (),
64  xL = lb [xi], xU = ub [xi],
65  yL = lb [yi], yU = ub [yi];
66 
67  if (xt == 0.) // no tangents are possible
68  return;
69 
70  // check if (xt,wb/xt) is outside of bounds. If so, project it back
71  // into the bounding box
72  if ((xt < xL) && (xL != 0.)) xt = xL;
73  if ((xt > xU) && (xU != 0.)) xt = xU;
74 
75  if ((wb / xt < yL) && (yL != 0.)) xt = wb / yL;
76  if ((wb / xt > yU) && (yU != 0.)) xt = wb / yU;
77 
78  // coefficient of w in the lifted cut
79  CouNumber
80  alpha = ((fabs (x1) < COUENNE_INFINITY) &&
81  (fabs (y1) < COUENNE_INFINITY) &&
82  (fabs (x1*y1 - wb) > 0.)) ?
83  ((2*wb/xt - y1 - wb*x1 / (xt*xt)) / (x1*y1 - wb)) : 0;
84 
85  //printf ("+++++ %d %d %d. [%c] xp (%g,%g) wb %g out(%g,%g) in(%g,%g) --> [%g,%g] alpha %g\n",
86  //xi, yi, wi, (sign<0) ? '-' : '+', xp, yp, wb, x0, y0, x1, y1, xt, wb/xt, alpha);
87 
88  if (alpha != 0)
89  cg -> createCut (cs, alpha*wb + 2*wb/xt, sign, wi, alpha, yi, 1., xi, wb/(xt*xt));
90  else cg -> createCut (cs, 2*wb/xt, sign, yi, 1., xi, wb/(xt*xt));
91 }
92 
93 
94 
95 // Unified procedure to create convexification cuts for an expression of the form w = x*y
96 void Couenne::unifiedProdCuts (const CouenneCutGenerator *cg, OsiCuts &cs,
97  int xi, CouNumber x0, CouNumber xl, CouNumber xu,
98  int yi, CouNumber y0, CouNumber yl, CouNumber yu,
99  int wi, CouNumber w0, CouNumber wl, CouNumber wu,
100  t_chg_bounds *chg, enum expression::auxSign sign) {
101 
102  bool cLX, cRX, cLY, cRY, cLW, cRW =
103  cLX = cRX = cLY = cRY = cLW = true;
104 
105  if (!(cg -> isFirst ()) && chg) {
106  cLX= chg[xi].lower() != t_chg_bounds::UNCHANGED; cRX= chg[xi].upper() != t_chg_bounds::UNCHANGED;
107  cLY= chg[yi].lower() != t_chg_bounds::UNCHANGED; cRY= chg[yi].upper() != t_chg_bounds::UNCHANGED;
108  cLW= chg[wi].lower() != t_chg_bounds::UNCHANGED; cRW= chg[wi].upper() != t_chg_bounds::UNCHANGED;
109  }
110 
111  // Add McCormick convexification cuts:
112  //
113  // 1) w >= yl x + xl y - yl xl
114  // 2) w >= yu x + xu y - yu xu
115  //
116  // 3) w <= yl x + xu y - yl xu
117  // 4) w <= yu x + xl y - yu xl
118  //
119  // These cuts are added if the corresponding bounds are finite
120 
121  if (sign != expression::AUX_LEQ) {
122  if ((cLX || cLY) && is_boundbox_regular (yl, xl)) cg -> createCut (cs,yl*xl,-1,wi,-1.,xi,yl,yi,xl);
123  if ((cRX || cRY) && is_boundbox_regular (yu, xu)) cg -> createCut (cs,yu*xu,-1,wi,-1.,xi,yu,yi,xu);
124  }
125 
126  if (sign != expression::AUX_GEQ) {
127  if ((cRX || cLY) && is_boundbox_regular (yl, xu)) cg -> createCut (cs,yl*xu,+1,wi,-1.,xi,yl,yi,xu);
128  if ((cLX || cRY) && is_boundbox_regular (yu, xl)) cg -> createCut (cs,yu*xl,+1,wi,-1.,xi,yu,yi,xl);
129  }
130 
131  // If w=xy and w >= l > 0 (resp. w <= u < 0) are "tight" bounds
132  // (i.e. they are tighter than those obtained through propagation of
133  // x and y's bounds), McCormick's convexification is not tight as
134  // the surface has a curve contour at w=l (resp. w=u).
135  //
136  // McCormick rules induce a tangent to this contour at the bounds of
137  // both variables, but it may be useful to add further cuts along
138  // the contour to eliminate infeasible point (x0,y0,w0), which may
139  // be in the convexification but out of the contour (on its "convex"
140  // side, or "out of the belly").
141  //
142  // Suppose P (xt,l/xt) (resp. (xt,u/xt) is the point on the contour
143  // closest to (x0,y0), found through a Newton method. The cut is
144  // tangent to the contour in P and has the form
145  //
146  // y - l/xt >= -l/(xt^2) (x-xt) if xl*yl < l and xu*yu > l
147  // y - l/xt <= -l/(xt^2) (x-xt) if xl*yl > l and xu*yu < l
148  //
149  // (resp. y - u/xt <= -u/(xt^2) (x-xt) if xl*yu > u and xu*yl < u
150  // y - u/xt >= -u/(xt^2) (x-xt) if xl*yu < u and xu*yl > u)
151  //
152  // These can be lifted to satisfy, at equality, the point
153  // (xu,yu,wu=xu*yu) (resp. (xl,yl,wl=xl*yl)), where xl and xu are
154  // lower and upper bound of x, etc.
155  //
156  // alpha (w - l) + y - l/xt >= -l/(xt^2) (x-xt) ...
157  //
158  // where alpha is such that the relation holds at equality at the
159  // point (xu,yu,xu*yu):
160  //
161  // alpha = [-yu + l/xt - l/(xt^2)(xu-xt)] / (xu*yu - l)
162 
163  if (cg -> Problem () -> MultilinSep () == CouenneProblem::MulSepSimple ||
164  fabs (wu - wl) < COUENNE_EPS) {
165 
166  if ((x0 > xl + COUENNE_EPS) && (y0 > yl + COUENNE_EPS) &&
167  (x0 < xu + COUENNE_EPS) && (y0 < yu + COUENNE_EPS)) {
168 
169  if (cLW && (wl > 0) && (x0*y0 < wl) && (sign != expression::AUX_GEQ)) { // that is, if (x0,y0) is out of the contour
170 
171  CouNumber xyl = xl * yl;
172 
173  // first and third orthant
174  if ((xyl < wl) && (xu*yu >= wl)) contourCut (cg,cs, x0,y0, wl, +1, xl,yl, xu,yu, xi,yi,wi);
175  else if ((xyl >= wl) && (xu*yu < wl)) contourCut (cg,cs, x0,y0, wl, -1, xu,yu, xl,yl, xi,yi,wi);
176  }
177 
178  // Similarly for w <= u < 0
179 
180  if (cRW && (wu < 0) && (x0*y0 > wu) && (sign != expression::AUX_LEQ)) { // that is, if (x0,y0) is out of the contour
181 
182  CouNumber xuyl = xl * yu;
183 
184  // second and fourth orthant
185  if ((xuyl > wu) && (xl*yu <= wu)) contourCut (cg,cs, x0,y0, wu, +1, xu,yl, xl,yu, xi,yi,wi);
186  else if ((xuyl <=wu) && (xl*yu > wu)) contourCut (cg,cs, x0,y0, wu, -1, xl,yu, xu,yl, xi,yi,wi);
187  }
188  }
189  } else
190  if (cg -> Problem () -> MultilinSep () == CouenneProblem::MulSepTight)
191  upperEnvHull (cg, cs,
192  xi, x0, xl, xu,
193  yi, y0, yl, yu,
194  wi, w0, wl, wu);
195 }
Cut Generator for linear convexifications.
void unifiedProdCuts(const CouenneCutGenerator *, OsiCuts &, int, CouNumber, CouNumber, CouNumber, int, CouNumber, CouNumber, CouNumber, int, CouNumber, CouNumber, CouNumber, t_chg_bounds *, enum expression::auxSign)
unified convexification of products and divisions
CouNumber powNewton(CouNumber xc, CouNumber yc, unary_function f, unary_function fp, unary_function fpp)
find proper tangent point to add deepest tangent cut
Definition: powNewton.cpp:29
status of lower/upper bound of a variable, to be checked/modified in bound tightening ...
const char & lower() const
const char & upper() const
bool is_boundbox_regular(register CouNumber b1, register CouNumber b2)
check if bounding box is suitable for a multiplication/division convexification constraint ...
real alpha
ULong * x0
Definition: OSdtoa.cpp:1776
ULong x1
Definition: OSdtoa.cpp:1776
auxSign
&quot;sign&quot; of the constraint defining an auxiliary.
void contourCut(const CouenneCutGenerator *cg, OsiCuts &cs, CouNumber xp, CouNumber yp, CouNumber wb, int sign, CouNumber x0, CouNumber y0, CouNumber x1, CouNumber y1, int xi, int yi, int wi)
Add cut around curve x*y=k.
void upperEnvHull(const CouenneCutGenerator *cg, OsiCuts &cs, int xi, CouNumber x0, CouNumber xl, CouNumber xu, int yi, CouNumber y0, CouNumber yl, CouNumber yu, int wi, CouNumber w0, CouNumber wl, CouNumber wu)
better cuts than those from unifiedProdCuts
#define COUENNE_EPS
double CouNumber
main number type in Couenne
#define COUENNE_INFINITY