branchExprPow.cpp
Go to the documentation of this file.
1 /* $Id: branchExprPow.cpp 940 2013-01-13 19:49:02Z pbelotti $
2  *
3  * Name: branchExprPow.cpp
4  * Author: Pietro Belotti
5  * Purpose: return branch gain and branch object for powers
6  *
7  * (C) Carnegie-Mellon University, 2006-11.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CoinHelperFunctions.hpp"
12 
13 #include "CouenneExprPow.hpp"
14 #include "CouenneObject.hpp"
16 #include "CouenneProjections.hpp"
17 #include "CouenneFunTriplets.hpp"
18 
19 using namespace Couenne;
20 
23  const OsiBranchingInformation *info,
24  double * &brpts,
25  double * &brDist, // distance of current LP
26  // point to new convexifications
27  int &way,
28  CouNumber k,
29  CouNumber x0, CouNumber y0,
30  CouNumber l, CouNumber u);
31 
32 
36  const OsiBranchingInformation *info,
37  expression *&var,
38  double * &brpts,
39  double * &brDist, // distance of current LP
40  // point to new convexifications
41  int &way) {
42 
43  // return branching point and branching policies for an expression
44  // of the form x^k
45 
46  var = arglist_ [0];
47 
48  int
49  ind = arglist_ [0] -> Index (),
50  wi = obj -> Reference () -> Index ();
51 
52  assert ((ind >= 0) && (wi >= 0) && (arglist_ [1] -> Type () == CONST));
53 
54  double k = arglist_ [1] -> Value ();
55 
56  CouNumber y0 = info -> solution_ [wi],
57  x0 = info -> solution_ [ind],
58  l = info -> lower_ [ind],
59  u = info -> upper_ [ind];
60 
61  /*printf ("selbra for "); print ();
62  printf ("%g [%g,%g] -> %g [%g,%g]\n",
63  x0, l, u, y0,
64  info -> lower_ [wi],
65  info -> upper_ [wi]);*/
66 
67  if (x0 < l) x0 = l;
68  else if (x0 > u) x0 = u;
69 
70  // bounds coincide (happens within setupList)
71  if (fabs (u-l) < COUENNE_EPS) {
72  brpts = (CouNumber *) realloc (brpts, sizeof (CouNumber));
73  *brpts = 0.5*(l+u);
74  way = TWO_RAND;
75  brDist = (double *) realloc (brDist, 2 * sizeof (double));
76  return (brDist [0] = brDist [1] = fabs (y0 - (issignpower_ ? COUENNE_sign(x0) * pow(fabs(x0), k) : pow (x0, k))));
77  }
78 
79  assert (!issignpower_ || k > 0);
80 
81  // case 1: k negative, resort to method similar to exprInv:: ///////////////////////////////
82  if (k<0) return negPowSelectBranch (obj, info, brpts, brDist, way, k, x0, y0, l, u);
83 
84  brDist = (double *) realloc (brDist, 2 * sizeof (double));
85 
86  int intk = 0;
87 
88  bool isInt = fabs (k - (double) (intk = COUENNE_round (k))) < COUENNE_EPS,
89  isInvInt = !isInt && (k != 0.) && fabs (1./k - (double) (intk = COUENNE_round (1./k))) < COUENNE_EPS;
90 
91  // case 2: k is positive and even /////////////////////////////////////////////////////////
92 
93  if (isInt && !((1 == intk % 2) || issignpower_)) {
94 
95  if ((l < - COUENNE_INFINITY) &&
96  (u > COUENNE_INFINITY)) { // infinite bounds
97 
98  if (y0 < pow (x0, k)) { // good side
99 
100  brpts = (double *) realloc (brpts, sizeof (double));
101  powertriplet pt (k);
102  *brpts = powNewton (x0, y0, &pt);
103 
104  way = (x0 > 0) ? TWO_RIGHT : TWO_LEFT; // priority to same side as x0
105 
106  x0 -= *brpts;
107  y0 -= pow (*brpts, k);
108 
109  return (brDist [0] = brDist [1] = sqrt (x0*x0 + y0*y0)); // exact distance
110  }
111 
112  // on the bad side /////////////////////
113 
114  // TODO: restore when we can do three-way branching
115 
116  /*double xp = pow (y0, 1./k);
117 
118  brpts = (double *) realloc (brpts, 2 * sizeof (double));
119  brpts [0] = 0.5 * (x0 - xp);
120  brpts [1] = 0.5 * (x0 + xp);
121 
122  way = THREE_CENTER;
123 
124  return CoinMin (x0 - brpts [0],
125  CoinMin (brpts [1] - x0,
126  projectSeg (x0, y0,
127  brpts [0], pow (brpts [0], k),
128  brpts [1], pow (brpts [1], k), -1)));*/
129 
130  // in the meantime, branch on current point (next branch won't
131  // have unbounded x)
132 
133  brpts = (double *) realloc (brpts, sizeof (double));
134  *brpts = x0;
135  way = TWO_RAND;
136 
137  return (brDist [0] = brDist [1] = fabs (y0 - pow (x0,k)));
138 
139  // no bounds on x
140  /* double alpha = pow ((y0 + pow (x0, k))/2, 1./k),
141  yroot = pow (y0, 1./k);
142  brpts = (double *) realloc (brpts, 2 * sizeof (double));
143  double lambdaL = (-x0 / yroot), lambdaR = 0;
144  if (lambdaL < 0) {
145  lambdaR = -lambdaL;
146  lambdaL = 0;
147  }
148  CouNumber // approx distance
149  b0 = brpts [0] = -alpha + lambdaL * (alpha - yroot),
150  b1 = brpts [1] = alpha + lambdaR * (yroot - alpha);
151  way = THREE_CENTER;
152  return CoinMin (projectSeg (x0, y0, b0, pow (b0, k), b1, pow (b1, k), -1),
153  CoinMin (x0 - b0, b1 - x0)); */
154  }
155 
156  // at least one bound is finite //////////////////////////////////////////////
157 
158  brpts = (double *) realloc (brpts, sizeof (double));
159 
160  if (l < -COUENNE_INFINITY) {
161 
162  // if y0 is huge, try to make it close to 0
163  *brpts = obj -> midInterval (-safe_pow (y0, 1. / k, issignpower_), l, u, info);
164  way = TWO_RIGHT;
165 
166  //printf (" ----> brptPow %g\n", *brpts);
167 
168  return CoinMin (brDist [0] = x0 - *brpts,
169  brDist [1] = projectSeg
170  (x0, y0,
171  *brpts, safe_pow (*brpts, k, issignpower_),
172  u, safe_pow (u, k, issignpower_), -1));
173  }
174 
175  if (u > COUENNE_INFINITY) {
176 
177  // if y0 is huge, try to make it close to 0
178  //*brpts = CoinMin (safe_pow (y0, 1. / k), COU_MAX_COEFF / k);
179  *brpts = obj -> midInterval (safe_pow (y0, 1. / k, issignpower_), l, u, info);
180  way = TWO_LEFT;
181 
182  //printf (" ----> brptPow %g\n", *brpts);
183 
184  return CoinMin (brDist [1] = *brpts - x0,
185  brDist [0] = projectSeg
186  (x0, y0,
187  l, safe_pow (l, k, issignpower_),
188  *brpts, safe_pow (*brpts, k, issignpower_), -1));
189  }
190 
191  // both bounds are finite ///////////////////////////////////////////////
192 
193  powertriplet ft (k);
194  //*brpts = maxHeight (&ft, x0, y0, l, u);
195  *brpts = obj -> getBrPoint (&ft, x0, l, u, info);
196 
197  way = (x0 < *brpts) ? TWO_LEFT : TWO_RIGHT;
198 
199  // w -> print (); printf (" := "); dynamic_cast <exprAux *> (w) -> Image () -> print ();
200  /*print ();
201  printf (" (%g,%g) [%g,%g] --> %g, distances = %g,%g\n",
202  x0, y0, l, u, *brpts,
203  projectSeg (x0, y0, l, safe_pow (l,k), *brpts, safe_pow (*brpts,k), 0),
204  projectSeg (x0, y0, *brpts, safe_pow (*brpts,k), u, safe_pow (u,k), 0));*/
205 
206  // Min area -- exact distance
207  CouNumber retval =
208  CoinMin (brDist [0] = projectSeg (x0, y0, l, safe_pow (l, k, issignpower_), *brpts, safe_pow (*brpts, k, issignpower_), 0),
209  brDist [1] = projectSeg (x0, y0, *brpts, safe_pow (*brpts, k, issignpower_), u, safe_pow (u, k, issignpower_), 0));
210 
211  //printf ("returning %.10e\n", retval);
212 
213  return retval;
214 
215  /* brpts = (double *) realloc (brpts, sizeof (double));
216  *brpts = midInterval (x0, l, u, info);
217  way =
218  (l < - COUENNE_INFINITY) ? TWO_RIGHT :
219  (u > COUENNE_INFINITY) ? TWO_LEFT : TWO_RAND;
220 
221  return fabs (y0 - pow (x0, k)); // not an exact measure
222  */
223  }
224 
225  // from here on, we use two-way branch
226 
227  brpts = (double *) realloc (brpts, sizeof (double));
228  *brpts = x0; // just in case none of the ifs below is satisfied...
229  CouNumber pow0 = issignpower_ ? COUENNE_sign(x0) * pow(fabs(x0), k) : pow (x0, k);
230 
231  // case 3: k>1 and odd or signpower ////////////////////////////////////////////////////////////
232 
233  if ((isInt && (1 == intk % 2)) || issignpower_) {
234 
235  way = (x0 > 0.) ? TWO_RIGHT : TWO_LEFT;
236 
237  if (((l < - COUENNE_INFINITY) && (u > COUENNE_INFINITY)) || // [-inf,+inf[
238  ((l < - COUENNE_INFINITY) && (y0 < pow0)) ||
239  ((u > COUENNE_INFINITY) && (y0 > pow0))) {
240 
241  if (((y0 > 0) && (y0 < pow0)) ||
242  ((y0 < 0) && (y0 > pow0))) {
243 
244  *brpts = 0;
245  return (brDist [0] = brDist [1] = fabs (pow0 - y0));
246 
247  } else {
248 
249  *brpts = COUENNE_sign(y0) * pow(fabs(y0), 1./k);
250 
251  return (brDist [0] = brDist [1] = (y0 > 0) ? // approx distance
252  projectSeg (x0, y0, x0, CoinMax (pow0, 0.), *brpts, y0, 0) :
253  projectSeg (x0, y0, x0, CoinMin (pow0, 0.), *brpts, y0, 0));
254  }
255  }
256 
257  // otherwise, on the side of the current point the convexification
258  // is bounded.
259 
260  powertriplet pt (k, issignpower_);
261  *brpts = obj -> getBrPoint (&pt, x0, l, u, info);
262 
263  // in min-area and balanced strategy, point returned is
264  // positive. Put the right sign
265 
266  if (y0 < pow0)
267  *brpts = -*brpts;
268 
269  if (*brpts > x0) {
270 
271  brDist [0] = y0 - safe_pow (*brpts, k, issignpower_);
272  brDist [1] = sqrt (brDist [0] * brDist [0] + (x0 - *brpts) * (x0 - *brpts));
273 
274  } else {
275 
276  brDist [1] = y0 - safe_pow (*brpts, k, issignpower_);
277  brDist [0] = sqrt (brDist [1] * brDist [1] + (x0 - *brpts) * (x0 - *brpts));
278  }
279 
280  // otherwise, the convexification is surely bounded.
281  //
282  // apply minarea
283 
284  /*if (u > l + COUENNE_EPS) {
285  *brpts = safe_pow ((safe_pow (u, k) - safe_pow (l,k)) / (k* (u-l)), 1./(k-1.));
286  if (u<0)
287  *brpts = -*brpts;
288  }*/
289  }
290 
291  // case 4: k positive, in ]0,1[ and 1/k is integer and odd ////////////////////////
292 
293  if (isInvInt && (intk % 2) && !issignpower_) {
294 
295  way = (x0 > 0.) ? TWO_RIGHT : TWO_LEFT;
296 
297  if (((l < - COUENNE_INFINITY) && (u > COUENNE_INFINITY)) || // ]-inf,+inf[
298  ((l < - COUENNE_INFINITY) && (y0 < pow0)) ||
299  ((u > COUENNE_INFINITY) && (y0 > pow0))) {
300 
301  if (((x0 > 0.) && (y0 > pow0)) ||
302  ((x0 < 0.) && (y0 < pow0))) { // in the same orthant as the
303  // curve (i.e. first or third
304  // orthant)
305 
306  *brpts = 0.;
307  return (brDist [0] = brDist [1] = fabs (pow0 - y0));
308 
309  } else {
310 
311  *brpts = x0; // safe for any x0 as (l != x0 != u)
312 
313  //*brpts = obj -> midInterval (x0, l, u, info);
314 
315  return (brDist [0] = brDist [1] = (x0 > 0) ? // approx distance
316  projectSeg (x0,y0,x0, pow0, CoinMax (0., pow (y0, 1./k)), y0, 0) :
317  projectSeg (x0,y0,x0, pow0, CoinMin (0., pow (y0, 1./k)), y0, 0));
318  }
319  }
320 
321  // otherwise, on the side of the current point the convexification
322  // is bounded.
323 
324  powertriplet pt (k);
325  *brpts = obj -> getBrPoint (&pt, x0, l, u, info);
326 
327  // in min-area and balanced strategy, point returned is
328  // positive. Put the right sign
329 
330  if (y0 > pow0) *brpts = -*brpts;
331  else if (y0 < pow0) *brpts = -*brpts;
332 
333  if (*brpts > x0) {
334 
335  brDist [0] = y0 - safe_pow (*brpts, k);
336  brDist [1] = sqrt (brDist [0] * brDist [0] + (x0 - *brpts) * (x0 - *brpts));
337 
338  } else {
339 
340  brDist [1] = y0 - safe_pow (*brpts, k);
341  brDist [0] = sqrt (brDist [1] * brDist [1] + (x0 - *brpts) * (x0 - *brpts));
342  }
343 
344  return CoinMax (brDist [0], brDist [1]);
345 
346  /*if (u > l + COUENNE_EPS) {
347  *brpts = safe_pow ((safe_pow (u, k) - safe_pow (l,k)) / (k* (u-l)), 1./(k-1.));
348  if (u<0)
349  *brpts = -*brpts;
350  } else *brpts = 0.5*(l+u);*/
351  }
352 
353  if (k>1) { // case 5: k>1, but not integer //////////////////////////////////////
354 
355  if (y0 < pow0) { // on the good side, i.e. out of the convex
356  // side. We don't care if u is infinity
357 
358  powertriplet pt (k, issignpower_);
359  *brpts = powNewton (x0, y0, &pt);
360 
361  way = TWO_LEFT;
362 
363  x0 -= *brpts;
364  y0 -= pow (*brpts, k);
365 
366  return (brDist [0] = brDist [1] = sqrt (x0*x0 + y0*y0));
367 
368  } else { // on the bad (concave) side, above curve
369 
370  // as a rule of thumb, take the x coordinate of the midpoint of
371  // horizontal segment between current point and curve
372 
373  if (obj -> Strategy () == CouenneObject::MID_INTERVAL) {
374  assert (!issignpower_);
375  *brpts = 0.5 * (x0 + pow (y0, 1. / k));
376  } else {
377  powertriplet pt (k, issignpower_);
378  *brpts = obj -> getBrPoint (&pt, x0, l, u, info);
379  }
380 
381  way = TWO_LEFT;
382 
383  if (l < 0. && !issignpower_) l = 0.;
384 
385  CouNumber
386  powbpt = issignpower_ ? COUENNE_sign(*brpts) * pow (fabs (*brpts), k) : pow (*brpts, k),
387  projL = projectSeg (x0, y0, l, issignpower_ ? COUENNE_sign(u) * pow(fabs(u),k) : pow (l, k), *brpts, powbpt, -1);
388 
389  return (brDist[0] = brDist[1] = (u > COUENNE_INFINITY) ?
390  CoinMin (projL, *brpts - x0) :
391  CoinMin (projL, projectSeg (x0,y0, *brpts, powbpt, u, pow(u,k), -1)));
392  }
393 
394  } else { // case 6: 0<k<1 //////////////////////////////////////////////////////////////////
395 
396  if (y0 < pow0) { // on the bad side, below
397 
398  // same rule of thumb as above, take the x coordinate of the
399  // midpoint of horizontal segment between current point and
400  // curve
401 
402  if (obj -> Strategy () == CouenneObject::MID_INTERVAL)
403  *brpts = 0.5 * (x0 + pow (y0, 1. / k));
404  else {
405  powertriplet pt (k);
406  *brpts = obj -> getBrPoint (&pt, x0, l, u, info);
407  }
408 
409  //*brpts = 0.5 * (x0 + pow (x0, 1. / k));
410  way = TWO_LEFT;
411 
412  if (l < 0 && !issignpower_) l = 0.;
413 
414  CouNumber
415  powbpt = pow (*brpts, k),
416  projL = projectSeg (x0, y0, l, pow (l, k), *brpts, powbpt, +1);
417 
418  return (brDist[0] = brDist[1] = (u > COUENNE_INFINITY) ?
419  CoinMin (projL, powbpt - y0) :
420  CoinMin (projL, projectSeg (x0, y0, *brpts, powbpt, u, pow (u,k), +1)));
421 
422  } else { // on the convex side. We don't care if u is infinite
423 
424  powertriplet pt (k);
425  *brpts = powNewton (x0, y0, &pt);
426 
427  way = TWO_LEFT;
428 
429  x0 -= *brpts;
430  y0 -= pow (*brpts, k);
431 
432  return (brDist [0] = brDist [1] = sqrt (x0*x0 + y0*y0));
433  }
434  }
435 
436  // failsafe: return null, so that CouenneObject picks the default
437  // variable/branchingpoint for the expression
438 
439  assert (false);
440 
441  var = NULL;
442  return 0.;
443 }
#define COUENNE_round(x)
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 ...
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 negPowSelectBranch(const CouenneObject *obj, const OsiBranchingInformation *info, double *&brpts, double *&brDist, int &way, CouNumber k, CouNumber x0, CouNumber y0, CouNumber l, CouNumber u)
generic approach for negative powers (commom with exprInv::selectBranch())
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
ULong * x0
Definition: OSdtoa.cpp:1776
virtual enum nodeType Type() const
Node type.
virtual int Index() const
Return index of variable (only valid for exprVar and exprAux)
void fint fint * k
#define COUENNE_EPS
bool issignpower_
do we mean a signed power function: sign(arg0) * |arg0|^arg1 (assumes that arg1 is constant) ...
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
#define COUENNE_sign(x)
CouNumber safe_pow(CouNumber base, CouNumber exponent, bool signpower=false)
compute power and check for integer-and-odd inverse exponent
Expression base class.
virtual CouNumber Value() const
value (empty)