00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <math.h>
00012 #include <assert.h>
00013
00014 #include "CouennePrecisions.hpp"
00015 #include "CouenneExprPow.hpp"
00016 #include "CouenneExprSum.hpp"
00017 #include "CouenneExprMul.hpp"
00018 #include "CouenneExprDiv.hpp"
00019 #include "CouenneExprLog.hpp"
00020 #include "CouenneExprConst.hpp"
00021 #include "CouenneProblem.hpp"
00022
00023 #include "CouenneConfig.h"
00024 #include "CoinHelperFunctions.hpp"
00025 #include "CoinFinite.hpp"
00026
00027 using namespace Couenne;
00028
00030
00031 expression *exprPow::simplify () {
00032
00033 exprOp:: simplify ();
00034
00035 if ((*arglist_) -> Type () == CONST) {
00036
00037 CouNumber c0 = (*arglist_) -> Value ();
00038
00039 if (arglist_ [1] -> Type () == CONST) {
00040
00041 CouNumber c1 = arglist_ [1] -> Value ();
00042
00043
00044
00045
00046
00047
00048 return new exprConst
00049 (issignpower_ ?
00050 COUENNE_sign(c0) * pow (fabs(c0), c1) :
00051 pow (c0, c1));
00052 }
00053 else
00054 if (fabs (c0) <= COUENNE_EPS_SIMPL)
00055 return new exprConst (0.);
00056 }
00057 else
00058
00059 if (arglist_ [1] -> Type () == CONST) {
00060
00061 CouNumber expon = arglist_ [1] -> Value ();
00062
00063 if (fabs (expon) <= COUENNE_EPS_SIMPL)
00064 return new exprConst (1.);
00065
00066 else if (fabs (expon - 1.) <= COUENNE_EPS_SIMPL) {
00067
00068
00069 expression *ret = arglist_ [0];
00070 arglist_ [0] = NULL;
00071
00072 return ret;
00073 }
00074
00075 else if (fabs (expon + 1.) <= COUENNE_EPS_SIMPL) {
00076
00077
00078 expression *ret = new exprInv (arglist_ [0]);
00079 arglist_ [0] = NULL;
00080 return ret;
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 }
00113
00114 return NULL;
00115 }
00116
00117
00119
00120 expression *exprPow::differentiate (int index) {
00121
00122 if (!(arglist_ [0] -> dependsOn (index)) &&
00123 !(arglist_ [1] -> dependsOn (index)))
00124 return new exprConst (0.);
00125
00126 if (arglist_ [0] -> Type () == CONST) {
00127
00128 CouNumber base = arglist_ [0] -> Value ();
00129
00130 if (base == 0.)
00131 return new exprConst (0.);
00132
00133 return new exprMul (new exprConst (log (base)),
00134 new exprMul (new exprPow (new exprConst (base),
00135 arglist_ [1] -> clone ()),
00136 arglist_ [1] -> differentiate (index)));
00137
00138 } else if (arglist_ [1] -> Type () == CONST) {
00139
00140 CouNumber exponent = arglist_ [1] -> Value ();
00141
00142 return new exprMul (new exprConst (exponent),
00143 new exprMul (new exprPow (arglist_ [0] -> clone (),
00144 new exprConst (exponent - 1.)),
00145 arglist_ [0] -> differentiate (index)));
00146 }
00147
00148
00149
00150 expression **alm = new expression * [2];
00151 expression **alp = new expression * [2];
00152 expression **als = new expression * [2];
00153 expression **alm1 = new expression * [2];
00154 expression **alm2 = new expression * [2];
00155 expression **ald = new expression * [2];
00156
00157 alp [0] = new exprClone (arglist_ [0]);
00158 alp [1] = new exprClone (arglist_ [1]);
00159
00160 alm [0] = new exprPow (alp, 2);
00161
00162 alm1 [0] = arglist_ [1] -> differentiate (index);
00163 alm1 [1] = new exprLog (new exprClone (arglist_ [0]));
00164
00165 als [0] = new exprMul (alm1, 2);
00166
00167 ald [0] = new exprClone (arglist_ [1]);
00168 ald [1] = new exprClone (arglist_ [0]);
00169
00170 alm2 [0] = new exprDiv (ald, 2);
00171 alm2 [1] = arglist_ [0] -> differentiate (index);
00172
00173 als [1] = new exprMul (alm2, 2);
00174
00175 alm [1] = new exprSum (als, 2);
00176
00177 return new exprMul (alm, 2);
00178 }
00179
00180
00188
00189 int exprPow::Linearity () {
00190
00191 if (arglist_ [0] -> Type () == CONST) {
00192
00193 if (arglist_ [1] -> Type () == CONST) return CONSTANT;
00194 else return NONLINEAR;
00195 }
00196 else {
00197
00198 double exponent = arglist_ [1] -> Value ();
00199
00200 if (fabs (exponent - COUENNE_round (exponent)) > COUENNE_EPS)
00201 return NONLINEAR;
00202
00203 if (arglist_ [1] -> Type () == CONST) {
00204
00205 int expInt = (int) COUENNE_round (exponent);
00206
00207 if (arglist_ [0] -> Linearity () == LINEAR) {
00208
00209 switch (expInt) {
00210
00211 case 0: return CONSTANT;
00212 case 1: return LINEAR;
00213 case 2: return (issignpower_ ? NONLINEAR : QUADRATIC);
00214
00215 default: return NONLINEAR;
00216 }
00217 }
00218 else
00219 if (arglist_ [0] -> Linearity () == QUADRATIC)
00220 switch (expInt) {
00221
00222 case 0: return CONSTANT;
00223 case 1: return QUADRATIC;
00224
00225 default: return NONLINEAR;
00226 }
00227 else return NONLINEAR;
00228 }
00229 else return NONLINEAR;
00230 }
00231 }
00232
00233
00235 bool exprPow::isInteger () {
00236
00237
00238
00239 if (!(arglist_ [0] -> isInteger ())) {
00240
00241
00242 CouNumber lb, ub;
00243 arglist_ [0] -> getBounds (lb, ub);
00244
00245 if ((fabs (lb - ub) > COUENNE_EPS) ||
00246 !::isInteger (lb))
00247 return false;
00248 }
00249
00250
00251
00252 if (!(arglist_ [1] -> isInteger ())) {
00253
00254
00255
00256
00257 CouNumber lb, ub;
00258 arglist_ [1] -> getBounds (lb, ub);
00259
00260 if ((fabs (lb - ub) > COUENNE_EPS) ||
00261 !::isInteger (lb))
00262 return false;
00263
00264 if (lb < 0) {
00265
00266 arglist_ [0] -> getBounds (lb, ub);
00267
00268 if ((fabs (lb - ub) > COUENNE_EPS) ||
00269 (fabs (lb) < COUENNE_EPS) ||
00270 !::isInteger (1. / lb))
00271 return false;
00272 }
00273 } else {
00274
00275
00276
00277
00278 CouNumber lb, ub;
00279 arglist_ [1] -> getBounds (lb, ub);
00280
00281 if (lb < .5)
00282 return false;
00283 }
00284
00285 return true;
00286 }
00287
00288
00290 void exprPow::closestFeasible (expression *varind,
00291 expression *vardep,
00292 CouNumber &left,
00293 CouNumber &right) const {
00294 CouNumber
00295 x = (*varind) (),
00296 y = (*vardep) (),
00297 k = arglist_ [1] -> Value (),
00298 xk = safe_pow (x, k, issignpower_),
00299 yk = safe_pow (y, 1./k, issignpower_);
00300
00301 assert(!issignpower_ || k > 0);
00302
00303 int intk = 0;
00304
00305 bool isInt = fabs (k - (double) (intk = COUENNE_round (k))) < COUENNE_EPS,
00306 isInvInt = !isInt && (fabs (1./k - (double) (intk = COUENNE_round (1./k))) < COUENNE_EPS);
00307
00308
00309
00310
00311
00312
00313 if (isInt || isInvInt)
00314
00315 if (intk % 2 || issignpower_)
00316
00317 if (k > 0)
00318 ((y < xk) ? left : right) = yk;
00319
00320 else
00321
00322 if (y < 0.)
00323 if (y < xk) right = yk;
00324 else left = yk;
00325
00326 else
00327 if (y > xk) left = yk;
00328 else right = yk;
00329
00330 else
00331
00332 if (y <= 0.)
00333 left = - (right = COIN_DBL_MAX);
00334
00335 else
00336
00337 if (k > 0)
00338
00339 if (k < 1)
00340
00341 if (x > yk) left = yk;
00342 else right = yk;
00343
00344 else
00345
00346 if (x > yk) left = yk;
00347 else if (x < -yk) right = -yk;
00348 else left = - (right = yk);
00349
00350 else
00351 if (y < xk)
00352 left = - (right = yk);
00353 else
00354 if (x > 0) left = yk;
00355 else right = -yk;
00356
00357 else
00358
00359 if (k > 0) ((y < xk) ? left : right) = yk;
00360 else ((y > xk) ? left : right) = yk;
00361 }
00362
00363
00365 CouNumber exprPow::gradientNorm (const double *x) {
00366
00367 int ind0 = arglist_ [0] -> Index ();
00368 CouNumber exponent = arglist_ [1] -> Value ();
00369 return (ind0 < 0) ? 0. : fabs (exponent * safe_pow (x [ind0], exponent - 1, issignpower_));
00370 }
00371
00372
00375 bool exprPow::isCuttable (CouenneProblem *problem, int index) const {
00376
00377 CouNumber exponent = arglist_ [1] -> Value ();
00378
00379 bool
00380 isInt = ::isInteger (exponent),
00381 isInvInt = (exponent != 0.) && ::isInteger (1. / exponent);
00382
00383 int intExp = (isInt ? COUENNE_round (exponent) : (isInvInt ? COUENNE_round (1. / exponent) : 0));
00384
00385 if (exponent > 0.) {
00386
00387 if (isInt || isInvInt) {
00388
00389
00390 if (intExp % 2 || issignpower_) return false;
00391
00392 CouNumber
00393 x = problem -> X (arglist_ [0] -> Index ()),
00394 y = problem -> X (index);
00395
00396 if (isInt) return (y <= safe_pow (x, exponent, issignpower_));
00397
00398 return (y >= safe_pow (x, exponent, issignpower_));
00399 } else {
00400
00401
00402 CouNumber
00403 x = problem -> X (arglist_ [0] -> Index ()),
00404 y = problem -> X (index);
00405
00406 return (((exponent <= 1.) && (y >= safe_pow (x, exponent))) ||
00407 ((exponent >= 1.) && (y <= safe_pow (x, exponent))));
00408 }
00409 } else {
00410
00411
00412 CouNumber
00413 x = problem -> X (arglist_ [0] -> Index ()),
00414 y = problem -> X (index),
00415 lb = problem -> Lb (index),
00416 ub = problem -> Ub (index);
00417
00418 if (isInt || isInvInt)
00419
00420 if (!(intExp % 2 || issignpower_)) return (((lb > 0) || (ub < 0)) && (y * safe_pow (fabs (x), -exponent, issignpower_) <= 1.));
00421 else return (((lb > 0) || (ub < 0)) && (y * safe_pow (x, -exponent, issignpower_) <= 1.));
00422 else return (y * safe_pow (x, -exponent, issignpower_) <= 1.);
00423 }
00424 }