exprPow.cpp
Go to the documentation of this file.
1 /* $Id: exprPow.cpp 1147 2015-05-04 14:01:51Z stefan $
2  *
3  * Name: exprPow.cpp
4  * Author: Pietro Belotti
5  * Purpose: definition of powers
6  *
7  * (C) Carnegie-Mellon University, 2006-11.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include <math.h>
12 #include <assert.h>
13 
14 #include "CouennePrecisions.hpp"
15 #include "CouenneExprPow.hpp"
16 #include "CouenneExprSum.hpp"
17 #include "CouenneExprMul.hpp"
18 #include "CouenneExprDiv.hpp"
19 #include "CouenneExprLog.hpp"
20 #include "CouenneExprConst.hpp"
21 #include "CouenneProblem.hpp"
22 
23 #include "CouenneConfig.h"
24 #include "CoinHelperFunctions.hpp"
25 #include "CoinFinite.hpp"
26 
27 using namespace Couenne;
28 
30 
32 
34 
35  if ((*arglist_) -> Type () == CONST) { // expr = c0 ^ g(x)
36 
37  CouNumber c0 = (*arglist_) -> Value ();
38 
39  if (arglist_ [1] -> Type () == CONST) { // expr = c0 ^ c1
40 
41  CouNumber c1 = arglist_ [1] -> Value ();
42 
43  // delete arglist_ [0];
44  // delete arglist_ [1];
45 
46  // arglist_ [0] = arglist_ [1] = NULL;
47 
48  return new exprConst
49  (issignpower_ ?
50  COUENNE_sign(c0) * pow (fabs(c0), c1) :
51  pow (c0, c1));
52  }
53  else
54  if (fabs (c0) <= COUENNE_EPS_SIMPL)
55  return new exprConst (0.);
56  }
57  else // only need to check if g(x) == 0
58 
59  if (arglist_ [1] -> Type () == CONST) {
60 
61  CouNumber expon = arglist_ [1] -> Value ();
62 
63  if (fabs (expon) <= COUENNE_EPS_SIMPL) // expr = x ^ 0 = 1
64  return new exprConst (1.);
65 
66  else if (fabs (expon - 1.) <= COUENNE_EPS_SIMPL) { // expr = x ^ 1 = x
67 
68  //delete arglist_ [1];
69  expression *ret = arglist_ [0];
70  arglist_ [0] = NULL;
71 
72  return ret;
73  }
74 
75  else if (fabs (expon + 1.) <= COUENNE_EPS_SIMPL) { // expr = x ^ -1 = 1/x
76 
77  //delete arglist_ [1];
78  expression *ret = new exprInv (arglist_ [0]);
79  arglist_ [0] = NULL;
80  return ret;
81  }
82 
83  //
84  // x^k = x for x binary. Too bad we don't know bounds yet, so the code below will give segfault
85 
86  // TODO: readnl first reads bounds. Then uncomment this.
87 
88  // // is it an integer variable with bounds [-1,0] or [0,1]
89  // else if ((arglist_ [0] -> Type () == VAR) && (arglist_ [0] -> isDefinedInteger ())) {
90 
91  // CouNumber lb, ub;
92  // arglist_ [0] -> getBounds (lb, ub);
93 
94  // if ((fabs (lb) < COUENNE_EPS) &&
95  // (fabs (ub - 1.) < COUENNE_EPS)) { // {0,1}
96 
97  // delete arglist_ [1];
98  // expression *ret = arglist_ [0];
99  // arglist_ [0] = arglist_ [1] = NULL;
100  // return ret;
101 
102  // } else if ((fabs (lb + 1.) < COUENNE_EPS) &&
103  // (fabs (ub) < COUENNE_EPS)) { // {-1,0}
104 
105  // delete arglist_ [1];
106  // expression *ret = new exprOpp (arglist_ [0]);
107  // arglist_ [0] = arglist_ [1] = NULL;
108  // return ret;
109  // }
110  // }
111 
112  }
113 
114  return NULL;
115 }
116 
117 
119 
121 
122  if (!(arglist_ [0] -> dependsOn (index)) &&
123  !(arglist_ [1] -> dependsOn (index)))
124  return new exprConst (0.);
125 
126  if (arglist_ [0] -> Type () == CONST) { // k^f(x), k constant
127 
128  CouNumber base = arglist_ [0] -> Value ();
129 
130  if (base == 0.)
131  return new exprConst (0.);
132 
133  return new exprMul (new exprConst (log (base)),
134  new exprMul (new exprPow (new exprConst (base),
135  arglist_ [1] -> clone ()),
136  arglist_ [1] -> differentiate (index)));
137 
138  } else if (arglist_ [1] -> Type () == CONST) { // f(x)^k, k constant
139 
140  CouNumber exponent = arglist_ [1] -> Value ();
141 
142  return new exprMul (new exprConst (exponent),
143  new exprMul (new exprPow (arglist_ [0] -> clone (),
144  new exprConst (exponent - 1.)),
145  arglist_ [0] -> differentiate (index)));
146  }
147 
148  // all other cases: f(x)^g(x)
149 
150  expression **alm = new expression * [2];
151  expression **alp = new expression * [2];
152  expression **als = new expression * [2];
153  expression **alm1 = new expression * [2];
154  expression **alm2 = new expression * [2];
155  expression **ald = new expression * [2];
156 
157  alp [0] = new exprClone (arglist_ [0]);
158  alp [1] = new exprClone (arglist_ [1]);
159 
160  alm [0] = new exprPow (alp, 2);
161 
162  alm1 [0] = arglist_ [1] -> differentiate (index);
163  alm1 [1] = new exprLog (new exprClone (arglist_ [0]));
164 
165  als [0] = new exprMul (alm1, 2);
166 
167  ald [0] = new exprClone (arglist_ [1]);
168  ald [1] = new exprClone (arglist_ [0]);
169 
170  alm2 [0] = new exprDiv (ald, 2);
171  alm2 [1] = arglist_ [0] -> differentiate (index);
172 
173  als [1] = new exprMul (alm2, 2);
174 
175  alm [1] = new exprSum (als, 2);
176 
177  return new exprMul (alm, 2);
178 }
179 
180 
188 
190 
191  if (arglist_ [0] -> Type () == CONST) {
192 
193  if (arglist_ [1] -> Type () == CONST) return CONSTANT;
194  else return NONLINEAR;
195  }
196  else {
197 
198  double exponent = arglist_ [1] -> Value ();
199 
200  if (fabs (exponent - COUENNE_round (exponent)) > COUENNE_EPS)
201  return NONLINEAR;
202 
203  if (arglist_ [1] -> Type () == CONST) {
204 
205  int expInt = (int) COUENNE_round (exponent);
206 
207  if (arglist_ [0] -> Linearity () == LINEAR) {
208 
209  switch (expInt) {
210 
211  case 0: return CONSTANT;
212  case 1: return LINEAR;
213  case 2: return (issignpower_ ? NONLINEAR : QUADRATIC);
214 
215  default: return NONLINEAR;
216  }
217  }
218  else
219  if (arglist_ [0] -> Linearity () == QUADRATIC)
220  switch (expInt) {
221 
222  case 0: return CONSTANT;
223  case 1: return QUADRATIC;
224 
225  default: return NONLINEAR;
226  }
227  else return NONLINEAR;
228  }
229  else return NONLINEAR;
230  }
231 }
232 
233 
236 
237  // base
238 
239  if (!(arglist_ [0] -> isInteger ())) {
240 
241  // base not integer: check if constant and integer
242  CouNumber lb, ub;
243  arglist_ [0] -> getBounds (lb, ub);
244 
245  if ((fabs (lb - ub) > COUENNE_EPS) ||
246  !::isInteger (lb))
247  return false;
248  }
249 
250  // exponent
251 
252  if (!(arglist_ [1] -> isInteger ())) {
253 
254  // exponent not defined integer: check if constant and at integer
255  // value (and positive, or base negative integer)
256 
257  CouNumber lb, ub;
258  arglist_ [1] -> getBounds (lb, ub);
259 
260  if ((fabs (lb - ub) > COUENNE_EPS) ||
261  !::isInteger (lb))
262  return false;
263 
264  if (lb < 0) { // exponent negative, check again base
265 
266  arglist_ [0] -> getBounds (lb, ub);
267 
268  if ((fabs (lb - ub) > COUENNE_EPS) ||
269  (fabs (lb) < COUENNE_EPS) ||
270  !::isInteger (1. / lb))
271  return false;
272  }
273  } else {
274 
275  // if base integer and exponent integer, must check that exponent
276  // is nonnegative
277 
278  CouNumber lb, ub;
279  arglist_ [1] -> getBounds (lb, ub);
280 
281  if (lb < .5)
282  return false;
283  }
284 
285  return true;
286 }
287 
288 
291  expression *vardep,
292  CouNumber &left,
293  CouNumber &right) const {
294  CouNumber
295  x = (*varind) (),
296  y = (*vardep) (),
297  k = arglist_ [1] -> Value (),
298  xk = safe_pow (x, k, issignpower_),
299  yk = safe_pow (y, 1./k, issignpower_);
300 
301  assert(!issignpower_ || k > 0);
302 
303  int intk = 0;
304 
305  bool isInt = fabs (k - (double) (intk = COUENNE_round (k))) < COUENNE_EPS,
306  isInvInt = !isInt && (fabs (1./k - (double) (intk = COUENNE_round (1./k))) < COUENNE_EPS);
307 
308  // three cases:
309  // 1) k or 1/k odd or signpower => have either left or right
310  // 2) k or 1/k even, => may have both
311  // 3) k and 1/k fractional => have either left or right
312 
313  if (isInt || isInvInt)
314 
315  if (intk % 2 || issignpower_) // case 1
316 
317  if (k > 0)
318  ((y < xk) ? left : right) = yk; // easy, x^k is continuous
319 
320  else
321 
322  if (y < 0.) // third, fourth orthant
323  if (y < xk) right = yk; // in convex region y < 1/x within third orthant
324  else left = yk; // remaining non-convex area
325 
326  else // first, second orthant
327  if (y > xk) left = yk; // in convex region y > 1/x within first orthant
328  else right = yk; // remaining non-convex area
329 
330  else // case 2
331 
332  if (y <= 0.) // third, fourth orthant => no solution
333  left = - (right = COIN_DBL_MAX);
334 
335  else
336 
337  if (k > 0)
338 
339  if (k < 1) // roots, have x >= 0
340 
341  if (x > yk) left = yk;
342  else right = yk;
343 
344  else
345 
346  if (x > yk) left = yk;
347  else if (x < -yk) right = -yk;
348  else left = - (right = yk);
349 
350  else // k negative
351  if (y < xk) // between asymptotes
352  left = - (right = yk);
353  else // in one of the two convex areas
354  if (x > 0) left = yk;
355  else right = -yk;
356 
357  else // case 3: assume x bounded from below by 0
358 
359  if (k > 0) ((y < xk) ? left : right) = yk;
360  else ((y > xk) ? left : right) = yk;
361 }
362 
363 
366 
367  int ind0 = arglist_ [0] -> Index ();
368  CouNumber exponent = arglist_ [1] -> Value ();
369  return (ind0 < 0) ? 0. : fabs (exponent * safe_pow (x [ind0], exponent - 1, issignpower_));
370 }
371 
372 
375 bool exprPow::isCuttable (CouenneProblem *problem, int index) const {
376 
377  CouNumber exponent = arglist_ [1] -> Value ();
378 
379  bool
380  isInt = ::isInteger (exponent),
381  isInvInt = (exponent != 0.) && ::isInteger (1. / exponent);
382 
383  int intExp = (isInt ? COUENNE_round (exponent) : (isInvInt ? COUENNE_round (1. / exponent) : 0));
384 
385  if (exponent > 0.) {
386 
387  if (isInt || isInvInt) {
388 
389  // TODO also with an odd exponent, there are convex parts where one could do separation
390  if (intExp % 2 || issignpower_) return false; // exponent odd or 1/odd
391 
392  CouNumber
393  x = problem -> X (arglist_ [0] -> Index ()),
394  y = problem -> X (index);
395 
396  if (isInt) return (y <= safe_pow (x, exponent, issignpower_)); // below convex curve ==> cuttable
397 
398  return (y >= safe_pow (x, exponent, issignpower_)); // above concave k-th root curve ==> cuttable
399  } else {
400 
401  // non-integer exponent
402  CouNumber
403  x = problem -> X (arglist_ [0] -> Index ()),
404  y = problem -> X (index);
405 
406  return (((exponent <= 1.) && (y >= safe_pow (x, exponent))) ||
407  ((exponent >= 1.) && (y <= safe_pow (x, exponent))));
408  }
409  } else {
410 
411  // non-integer exponent
412  CouNumber
413  x = problem -> X (arglist_ [0] -> Index ()),
414  y = problem -> X (index),
415  lb = problem -> Lb (index),
416  ub = problem -> Ub (index);
417 
418  if (isInt || isInvInt)
419 
420  if (!(intExp % 2 || issignpower_)) return (((lb > 0) || (ub < 0)) && (y * safe_pow (fabs (x), -exponent, issignpower_) <= 1.));
421  else return (((lb > 0) || (ub < 0)) && (y * safe_pow (x, -exponent, issignpower_) <= 1.));
422  else return (y * safe_pow (x, -exponent, issignpower_) <= 1.);
423  }
424 }
virtual bool isInteger()
is this expression integer?
Definition: exprPow.cpp:235
class inverse:
virtual CouNumber gradientNorm(const double *x)
return l-2 norm of gradient at given point
Definition: exprPow.cpp:365
virtual int dependsOn(int *ind, int n, enum dig_type type=STOP_AT_AUX)
dependence on variable set: return cardinality of subset of the set of indices in first argument whic...
Definition: expression.cpp:172
#define COUENNE_round(x)
CouExpr & log(CouExpr &e)
Power of an expression (binary operator), with constant.
expression * clone(Domain *d=NULL) const
cloning method
virtual int Linearity()
get a measure of &quot;how linear&quot; the expression is
Definition: exprPow.cpp:189
exprPow(expression **al, int n=2, bool signpower=false)
Constructor.
constant-type operator
virtual bool isCuttable(CouenneProblem *problem, int index) const
can this expression be further linearized or are we on its concave (&quot;bad&quot;) side
Definition: exprPow.cpp:375
class for divisions,
#define COUENNE_EPS_SIMPL
virtual enum nodeType Type() const
Node type.
virtual int Index() const
Return index of variable (only valid for exprVar and exprAux)
virtual void getBounds(expression *&, expression *&)
Get lower and upper bound of an expression (if any)
Class for MINLP problems with symbolic information.
void fint fint * k
expression clone (points to another expression)
void fint fint fint real fint real real real real real real real real real fint real * alp
#define COUENNE_EPS
bool issignpower_
do we mean a signed power function: sign(arg0) * |arg0|^arg1 (assumes that arg1 is constant) ...
static int
Definition: OSdtoa.cpp:2173
virtual expression * simplify()
simplification
Definition: exprOp.cpp:243
expression ** arglist_
argument list is an array of pointers to other expressions
double CouNumber
main number type in Couenne
virtual void closestFeasible(expression *varind, expression *vardep, CouNumber &left, CouNumber &right) const
compute $y^{lv}$ and $y^{uv}$ for Violation Transfer algorithm
Definition: exprPow.cpp:290
class logarithm,
#define COUENNE_sign(x)
virtual expression * simplify()
simplification
Definition: exprPow.cpp:31
CouNumber safe_pow(CouNumber base, CouNumber exponent, bool signpower=false)
compute power and check for integer-and-odd inverse exponent
Expression base class.
virtual expression * differentiate(int index)
differentiation
Definition: exprPow.cpp:120
virtual CouNumber Value() const
value (empty)
void fint fint fint real fint real * x
class for multiplications,