branchExprMul.cpp
Go to the documentation of this file.
1 /* $Id: branchExprMul.cpp 708 2011-06-23 14:04:59Z pbelotti $
2  *
3  * Name: branchExprMul.cpp
4  * Author: Pietro Belotti
5  * Purpose: return branch data for multiplications
6  *
7  * (C) Carnegie-Mellon University, 2006-10.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CouennePrecisions.hpp"
12 #include "CouenneTypes.hpp"
13 #include "CouenneObject.hpp"
14 
15 #include "CouenneExprMul.hpp"
16 #include "CouenneFunTriplets.hpp"
17 #include "CouenneProjections.hpp"
18 
19 using namespace Couenne;
20 
24  const OsiBranchingInformation *info,
25  expression *&var,
26  double * &brpts,
27  double * &brDist, // distance of current LP
28  // point to new convexifications
29  int &way) {
30 
31  if (brDist) {free (brDist); brDist = NULL;} // clear it, computeMulBrDist will fill it
32 
33  int xi = arglist_ [0] -> Index (),
34  yi = arglist_ [1] -> Index (),
35  wi = obj -> Reference () -> Index ();
36 
37  assert ((xi >= 0) && (yi >= 0) && (wi >= 0));
38 
39  CouNumber
40  x0 = info -> solution_ [xi], y0 = info -> solution_ [yi],
41  xl = info -> lower_ [xi], yl = info -> lower_ [yi],
42  xu = info -> upper_ [xi], yu = info -> upper_ [yi];
43 
44 #ifdef DEBUG
45  printf (" branch MUL: %g [%g,%g] %g [%g,%g]\n",
46  x0, xl, xu, y0, yl, yu);
47 #endif
48 
49  brpts = (double *) realloc (brpts, sizeof (double));
50 
51  // Constant x and/or y //////////////////////////////////////////////////////////
52 
53  if (fabs (xu-xl) < COUENNE_EPS) { // x almost constant
54 
55  if (fabs (yu-yl) < COUENNE_EPS) { // both almost constant, return null result
56 
57  var = NULL;
58  return 0.;
59 
60  } else { // x constant, branch on y
61 
62  var = arglist_ [1];
63  *brpts = 0.5 * (yl+yu);
64  brDist = (double *) realloc (brDist, 2 * sizeof (double));
65 
66  brDist [0] = projectSeg (x0, y0, yl, xl*yl, *brpts, *brpts * xl, 0);
67  brDist [1] = projectSeg (x0, y0, *brpts, *brpts * xl, yu, xl*yu, 0);
68 
69  //return fabs (w0 - x0*y0);
70  return CoinMin (brDist [0], brDist [1]);
71  }
72 
73  } else if (fabs (yu-yl) < COUENNE_EPS) { // y constant, branch on x
74 
75  var = arglist_ [0];
76  *brpts = 0.5 * (xl+xu);
77  brDist = (double *) realloc (brDist, 2 * sizeof (double));
78 
79  brDist [0] = projectSeg (x0, y0, xl, xl*yl, *brpts, *brpts * yl, 0);
80  brDist [1] = projectSeg (x0, y0, *brpts, *brpts * yl, xu, xu*yl, 0);
81 
82  //return fabs (w0 - x0*y0);
83  return CoinMin (brDist [0], brDist [1]);
84  }
85 
86  // Unbounded x and/or y /////////////////////////////////////////////////////////
87 
88  if ((((var = arglist_ [0]) -> Index() >= 0) && (xl < -COUENNE_INFINITY) && (xu > COUENNE_INFINITY)) ||
89  (((var = arglist_ [1]) -> Index() >= 0) && (yl < -COUENNE_INFINITY) && (yu > COUENNE_INFINITY))) {
90 
91  *brpts = 0.;
92  brDist = computeMulBrDist (info, xi, yi, wi, var -> Index (), brpts);
93  way = (info -> solution_ [var -> Index ()] > *brpts) ? TWO_RIGHT : TWO_LEFT;
94 
95  return CoinMin (brDist [0], brDist [1]);
96  }
97 
98  // TODO: don't privilege xi over yi
99 
100  // at most one bound is infinite ///////////////////////////////////////////////
101 
102  int ind = -1;
103 
104  if (xl < -large_bound) // x unbounded below
105  {ind = xi; *brpts = obj -> midInterval (((x0 < 0.) ? 2 : 0.5) * x0, xl, xu, info); way = TWO_RIGHT;}
106 
107  else if (xu > large_bound) // x unbounded above
108  {ind = xi; *brpts = obj -> midInterval (((x0 > 0.) ? 2 : 0.5) * x0, xl, xu, info); way = TWO_LEFT;}
109 
110  else if (yl < -large_bound) // y unbounded below
111  {ind = yi; *brpts = obj -> midInterval (((y0 < 0.) ? 2 : 0.5) * y0, yl, yu, info); way = TWO_RIGHT;}
112 
113  else if (yu > large_bound) // y unbounded above
114  {ind = yi; *brpts = obj -> midInterval (((y0 > 0.) ? 2 : 0.5) * y0, yl, yu, info); way = TWO_LEFT;}
115 
116  else { // both are bounded
117 
118  // Check if, though bounded, they are a bit too large
119 
120  CouNumber delta = (yu-yl) - (xu-xl);
121 
122  if (delta > +COUENNE_EPS) ind = yi;
123  else if (delta < -COUENNE_EPS) ind = xi;
124  else ind = (CoinDrand48 () < 0.5) ? xi : yi;
125 
126  CouNumber
127  pt = info -> solution_ [ind],
128  lb = info -> lower_ [ind],
129  ub = info -> upper_ [ind],
130  margin = obj -> lp_clamp () * (ub - lb);
131 
132  if ((lb < -COUENNE_EPS) &&
133  (ub > COUENNE_EPS) &&
134  (-lb/ub >= THRES_ZERO_SYMM) &&
135  (-ub/lb >= THRES_ZERO_SYMM))
136  // interval is fairly symmetric around 0, branch on it
137  *brpts = 0.;
138 
139  else if ((lb < - large_bound) &&
140  (ub > large_bound) &&
141  (fabs (pt) > large_bound))
142  *brpts = 0.;
143 
144  else switch (obj -> Strategy ()) {
145  case CouenneObject::LP_CENTRAL: *brpts = pt; if ((pt < lb + margin) ||
146  (pt > ub - margin))
147  pt = .5 * (lb+ub); break;
148  case CouenneObject::LP_CLAMPED: *brpts = CoinMax (lb + margin,
149  CoinMin (ub - margin, pt)); break;
150  case CouenneObject::MID_INTERVAL: *brpts = obj -> midInterval (pt, lb, ub, info); break;
151  case CouenneObject::BALANCED: *brpts = balancedMul (info, (ind == xi) ? 0 : 1, wi); break;
152  case CouenneObject::MIN_AREA: // in products, the minimum volume
153  // subdivision is at the middle of
154  // the interval
155  default: *brpts = (0.5 * (lb+ub)); break;
156  }
157 
158  way = (pt > *brpts) ? TWO_RIGHT : TWO_LEFT;
159  }
160 
161  assert (ind >= 0);
162 
163  var = arglist_ [(ind == xi) ? 0 : 1];
164 
165  brDist = computeMulBrDist (info, xi, yi, wi, ind, brpts);
166 
167 #ifdef DEBUG
168  printf (" MUL: br on x_%d %g [%g,%g] [%g,%g] (%g,%g)\n",
169  ind, *brpts, xl, xu, yl, yu, x0, y0);
170 #endif
171 
172  return CoinMin (brDist [0], brDist [1]);
173  //return fabs (w0 - x0*y0);
174 }
175 
176 
177 // branching point for multiplication according to the balanced strategy
178 CouNumber exprMul::balancedMul (const OsiBranchingInformation *info, int index, int wind) {
179 
180  // first of all, make sure both arguments are variables
181 
182  int other;
183 
184  if (index==0) {
185  index = arglist_ [0] -> Index ();
186  other = arglist_ [1] -> Index ();
187  } else {
188  index = arglist_ [1] -> Index ();
189  other = arglist_ [0] -> Index ();
190  }
191 
192  assert ((index >= 0) && (other >= 0));
193 
194  CouNumber
195  xl = info -> lower_ [index], yl = info -> lower_ [other],
196  xu = info -> upper_ [index], yu = info -> upper_ [other],
197  x0 = info -> solution_ [index], y0 = info -> solution_ [other],
198  w0 = info -> solution_ [wind];
199 
200  // It is quite tricky to implement a balanced strategy for products,
201  // because it is more difficult to measure "balancedness" for binary
202  // operators than it is for univariate functions.
203  //
204  // As a rule of thumb, we therefore apply the usual balanced
205  // strategy for the univariate function resulting from constraining
206  // (x,y) to a segment crossing their bounding box [xl,xu] X [yl,yu].
207  //
208  // Said segment is the set of points between (xl,yl) and (xu,yu) if
209  // the current point is above the curve w:=xy, otherwise it is the
210  // other diagonal, i.e. the set of points between (xl,yu) and
211  // (xu,yl).
212  //
213  // In the two cases, we have the point
214  //
215  // (above) P(t) = (xp,yp) := (xl + t (xu-xl), yl + t (yu-yl))
216  // (below) P(t) = (xp,yp) := (xu + t (xl-xu), yl + t (yu-yl))
217  //
218  // with t in [0,1], which forms the following second degree
219  // polynomial when multiplying the coordinates:
220  //
221  // (above) f(t) = xp*yp = (yu-yl)*(xu-xl)*t^2 + [yl(xu-xl) + xl(yu-yl)]*t + xl*yl
222  // (below) f(t) = xp*yp = (yu-yl)*(xl-xu)*t^2 + [yl(xl-xu) + xu(yu-yl)]*t + xu*yl
223  //
224  // which is a quadratic function that can be expressed in the form
225  // of f'(z) = z^2 + c if we apply an affine transformation to t:
226  //
227  // t = mz + q
228  //
229  // such that the resulting coefficients of the quadratic- and the
230  // linear terms are one and zero, respectively. Thus:
231  //
232  // (above) f(z) = (yu-yl)*(xu-xl)*(mz+q)^2 + [yl(xu-xl)-xl(yu-yl)]*(mz+q) + xl*yl =
233  // = (yu-yl)*(xu-xl)*(m^2 z^2 + 2qmz + q^2) + [yl(xu-xl)-xl(yu-yl)]*(mz+q) + xl*yl =
234  // = z^2 + c
235  //
236  // (below) f(z) = (yu-yl)*(xl-xu)*(mz+q)^2 + [yl(xl-xu)-xu(yu-yl)]*(mz+q) + xu*yl =
237  // = (yu-yl)*(xl-xu)*(m^2 z^2 + 2qmz + q^2) + [yl(xl-xu)-xu(yu-yl)]*(mz+q) + xu*yl =
238  // = -z^2 + c
239  //
240  // if and only if
241  //
242  // (above) ((yu-yl)*(xu-xl)) * m^2 = 1 )
243  // } <====> m = 1 / sqrt ((yu-yl)*(xu-xl))
244  // (below) ((yu-yl)*(xl-xu)) * m^2 = -1 )
245  //
246  // (above) 2qm*(yu-yl)*(xu-xl) + m[yl(xu-xl)-xl(yu-yl)] = 0 <====>
247  // q = -[yl(xu-xl)-xl(yu-yl)] / (2(yu-yl)*(xu-xl))
248  //
249  // (below) 2qm*(yu-yl)*(xl-xu) + m[yl(xl-xu)-xu(yu-yl)] = 0 <====>
250  // q = -[yl(xl-xu)-xu(yu-yl)] / (2(yu-yl)*(xl-xu))
251  //
252  // If the point is below the curve, a very similar reasoning applies
253  // (simply swap xl with xu).
254  //
255  // Hence, we simply apply the balanced strategy to the function
256  // f(z)=z^2 with z bounded between -q/m and (1-q)/m. The returning
257  // value z_opt must be transformed to get
258  //
259  // t_opt = m z_opt + q
260  //
261  // and the branching point is xl + t_opt (xu-xl)
262  //
263 
264  powertriplet ft (2);
265 
266  // A: above
267  // B: below
268 
269  bool above = (w0 > x0*y0);
270 
271  CouNumber
272  dx = xu-xl,
273  dy = yu-yl,
274  area = dx*dy, // coefficient of t^2
275  bA = yl*dx - xl*dy, // coefficient of t
276  bB = -yl*dx - xu*dy, // coefficient of t
277  m = 1. / sqrt (area),
278  qA = -bA / (2*area),
279  qB = bB / (2*area),
280  z_opt = above ?
281  minMaxDelta (&ft, -qA/m, (1-qA)/m):
282  minMaxDelta (&ft, -qB/m, (1-qB)/m),
283  t_optA = m*z_opt + qA,
284  t_optB = m*z_opt + qB;
285 
286  /*printf ("------------------\n(%d,%d): [%g,%g], [%g,%g]\n", index, other, xl, xu, yl, yu);
287  printf ("dx = %g, dy = %g, area = %g, bA = %g, bB = %g, m = %g\n", dx, dy, area, bA, bB, m);
288  printf ("qA = %g, qB = %g, z_opt = %g, tA = %g, tB = %g\n",
289  qA, qB, z_opt, t_optA, t_optB);
290  printf ("w = %g %c xy = %g*%g = %g --> %g\n", w0,
291  (w0 > x0*y0) ? '>' : '<', x0, y0, x0*y0,
292  (w0 > x0*y0) ? (xl + dx * t_optA) : (xu - dx * t_optB));*/
293 
294  return (w0 > x0*y0) ?
295  (xl + dx * t_optA) :
296  (xu - dx * t_optB);
297 }
#define THRES_ZERO_SYMM
const double large_bound
if |branching point| &gt; this, change it
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
OsiObject for auxiliary variables $w=f(x)$.
CouNumber minMaxDelta(funtriplet *ft, CouNumber lb, CouNumber ub)
Definition: minMaxDelta.cpp:49
ULong * x0
Definition: OSdtoa.cpp:1776
virtual int Index() const
Return index of variable (only valid for exprVar and exprAux)
double * computeMulBrDist(const OsiBranchingInformation *info, int xi, int yi, int wi, int brind, double *brpt, int nPts)
compute distance from future convexifications in set with x,y,w bounded.
#define COUENNE_EPS
CouNumber balancedMul(const OsiBranchingInformation *info, int index, int wind)
balanced strategy for branching point selection in products
virtual CouNumber selectBranch(const CouenneObject *obj, const OsiBranchingInformation *info, expression *&var, double *&brpts, double *&brDist, int &way)
set up branching object by evaluating many branching points for each expression&#39;s arguments ...
CouNumber projectSeg(CouNumber x0, CouNumber y0, CouNumber x1, CouNumber y1, CouNumber x2, CouNumber y2, int sign, CouNumber *xp=NULL, CouNumber *yp=NULL)
Compute projection of point (x0, y0) on the segment defined by two points (x1,y1), (x2, y2) – sign provided by parameter sign.
Definition: projections.cpp:78
expression ** arglist_
argument list is an array of pointers to other expressions
double CouNumber
main number type in Couenne
#define COUENNE_INFINITY
Expression base class.
void fint * m