/home/coin/SVN-release/OS-2.1.0/Couenne/src/expression/operators/exprPow.cpp

Go to the documentation of this file.
00001 /* $Id: exprPow.cpp 217 2009-07-08 17:02:07Z pbelotti $
00002  *
00003  * Name:    exprPow.cpp
00004  * Author:  Pietro Belotti
00005  * Purpose: definition of powers
00006  *
00007  * (C) Carnegie-Mellon University, 2006-08. 
00008  * This file is licensed under the Common Public License (CPL)
00009  */
00010 
00011 #include <math.h>
00012 #include <assert.h>
00013 
00014 #include "CoinHelperFunctions.hpp"
00015 
00016 #include "CouennePrecisions.hpp"
00017 #include "exprPow.hpp"
00018 #include "exprSum.hpp"
00019 #include "exprMul.hpp"
00020 #include "exprDiv.hpp"
00021 #include "exprLog.hpp"
00022 #include "exprConst.hpp"
00023 #include "CouenneProblem.hpp"
00024 
00025 
00027 
00028 expression *exprPow::simplify () {
00029 
00030   exprOp:: simplify ();
00031 
00032   if ((*arglist_) -> Type () == CONST) { // expr = c1 ^ g(x)
00033 
00034     CouNumber c0 = (*arglist_) -> Value ();
00035 
00036     if (arglist_ [1] -> Type () == CONST) { // expr = c1 ^ c2
00037 
00038       CouNumber c1 = arglist_ [1] -> Value ();
00039 
00040       delete arglist_ [0]; 
00041       delete arglist_ [1];
00042 
00043       arglist_ [0] = arglist_ [1] = NULL;
00044 
00045       return new exprConst (pow (c0, c1));
00046     }
00047     else 
00048       if (fabs (c0) < COUENNE_EPS_SIMPL) 
00049         return new exprConst (0.);
00050   }
00051   else // only need to check if g(x) == 0
00052 
00053     if (arglist_ [1] -> Type () == CONST) {
00054 
00055       CouNumber expon = arglist_ [1] -> Value ();
00056 
00057       if (fabs (expon) < COUENNE_EPS_SIMPL) // expr = x ^ 0 = 1
00058         return new exprConst (1.);
00059 
00060       else if (fabs (expon - 1) < COUENNE_EPS_SIMPL) { // expr = x ^ 1 = x
00061 
00062         delete arglist_ [1];
00063         expression *ret = arglist_ [0];
00064         arglist_ [0] = arglist_ [1] = NULL;
00065         return ret;
00066       }
00067 
00068       else if (fabs (expon + 1) < COUENNE_EPS_SIMPL) { // expr = x ^ -1 = 1/x
00069 
00070         delete arglist_ [1];
00071         expression *ret = new exprInv (arglist_ [0]);
00072         arglist_ [0] = arglist_ [1] = NULL;
00073         return ret;
00074       }
00075     }
00076 
00077   return NULL;
00078 }
00079 
00080 
00082 
00083 expression *exprPow::differentiate (int index) {
00084 
00085   if (!(arglist_ [0] -> dependsOn (&index, 1))  &&
00086       !(arglist_ [1] -> dependsOn (&index, 1)))
00087     return new exprConst (0.);
00088 
00089   // TODO: two cases
00090 
00091   expression **alm  = new expression * [2];
00092   expression **alp  = new expression * [2];
00093   expression **als  = new expression * [2];
00094   expression **alm1 = new expression * [2];
00095   expression **alm2 = new expression * [2];
00096   expression **ald  = new expression * [2];
00097 
00098   alp [0] = new exprClone (arglist_ [0]);
00099   alp [1] = new exprClone (arglist_ [1]);
00100 
00101   alm [0] = new exprPow (alp, 2);
00102 
00103   alm1 [0] = arglist_ [1] -> differentiate (index);
00104   alm1 [1] = new exprLog (new exprClone (arglist_ [0]));
00105 
00106   als [0] = new exprMul (alm1, 2);
00107 
00108   ald [0] = new exprClone (arglist_ [1]);
00109   ald [1] = new exprClone (arglist_ [0]);
00110 
00111   alm2 [0] = new exprDiv (ald, 2);
00112   alm2 [1] = arglist_ [0] -> differentiate (index);
00113 
00114   als [1] = new exprMul (alm2, 2);
00115 
00116   alm [1] = new exprSum (als, 2);
00117 
00118   return new exprMul (alm, 2);
00119 }
00120 
00121 
00129 
00130 int exprPow::Linearity () {
00131 
00132   if (arglist_ [0] -> Type () == CONST) {
00133 
00134     if (arglist_ [1] -> Type () == CONST) return CONSTANT;
00135     else                                  return NONLINEAR;
00136   }
00137   else {
00138 
00139     double exponent = arglist_ [1] -> Value ();
00140 
00141     if (fabs (exponent - COUENNE_round (exponent)) > COUENNE_EPS)
00142       return NONLINEAR;
00143 
00144     if (arglist_ [1] -> Type () == CONST) { 
00145 
00146       int expInt = (int) COUENNE_round (exponent);
00147 
00148       if (arglist_ [0] -> Linearity () == LINEAR) {
00149 
00150         switch (expInt) {
00151 
00152         case 0:  return CONSTANT;
00153         case 1:  return LINEAR;
00154         case 2:  return QUADRATIC;
00155 
00156         default: return NONLINEAR;
00157         }
00158       }
00159       else 
00160         if (arglist_ [0] -> Linearity () == QUADRATIC) 
00161           switch (expInt) {
00162 
00163           case 0:  return CONSTANT;
00164           case 1:  return QUADRATIC;
00165 
00166           default: return NONLINEAR;
00167           }
00168         else return NONLINEAR;
00169     }
00170     else return NONLINEAR;
00171   }
00172 }
00173 
00174 
00176 bool exprPow::isInteger () {
00177 
00178   // base
00179 
00180   if (!(arglist_ [0] -> isInteger ())) { 
00181 
00182     // base not integer: check if constant and integer
00183     CouNumber lb, ub;
00184     arglist_ [0] -> getBounds (lb, ub);
00185 
00186     if ((fabs (lb - ub) > COUENNE_EPS) ||
00187         !::isInteger (lb))
00188       return false;
00189   }
00190 
00191   // exponent
00192 
00193   if (!(arglist_ [1] -> isInteger ())) { 
00194     // exponent not integer: check if constant and integer (and
00195     // positive, or base negative integer)
00196     CouNumber lb, ub;
00197     arglist_ [1] -> getBounds (lb, ub);
00198 
00199     if ((fabs (lb - ub) > COUENNE_EPS) ||
00200         !::isInteger (lb))
00201       return false;
00202 
00203     if (lb < 0) { // exponent negative, check again base
00204 
00205       arglist_ [0] -> getBounds (lb, ub);
00206 
00207       if ((fabs (lb - ub) > COUENNE_EPS) ||
00208           (fabs (lb) < COUENNE_EPS) ||
00209           !::isInteger (1. / lb))
00210         return false;
00211     }
00212   }
00213 
00214   return true;
00215 }
00216 
00217 
00219 void exprPow::closestFeasible (expression *varind,
00220                                expression *vardep, 
00221                                CouNumber &left,
00222                                CouNumber &right) const {
00223   CouNumber
00224     x  = (*varind) (),
00225     y  = (*vardep) (),
00226     k  = arglist_ [1] -> Value (),
00227     xk = safe_pow (x, k),
00228     yk = safe_pow (y, 1./k);
00229 
00230   int intk = 0;
00231 
00232   bool isInt    =            fabs (k    - (double) (intk = COUENNE_round (k)))    < COUENNE_EPS,
00233        isInvInt = !isInt && (fabs (1./k - (double) (intk = COUENNE_round (1./k))) < COUENNE_EPS);
00234 
00235   // three cases: 
00236   // 1) k or  1/k odd,        => have either left or right
00237   // 2) k or  1/k even,       => may have both
00238   // 3) k and 1/k fractional  => have either left or right
00239 
00240   if (isInt || isInvInt)
00241 
00242     if (intk % 2) // case 1
00243 
00244       if (k > 0) 
00245         ((y < xk) ? left : right) = yk; // easy, x^k is continuous
00246 
00247       else
00248 
00249         if      (y < 0.)          // third, fourth orthant
00250           if (y < xk) right = yk; // in convex region y < 1/x within third orthant
00251           else        left  = yk; // remaining non-convex area
00252 
00253         else                      // first, second orthant
00254           if (y > xk) left  = yk; // in convex region y > 1/x within first orthant
00255           else        right = yk; // remaining non-convex area
00256 
00257     else // case 2
00258 
00259       if (y <= 0.) // third, fourth orthant => no solution
00260         left = - (right = COIN_DBL_MAX);
00261 
00262       else
00263 
00264         if (k > 0) 
00265 
00266           if (k < 1) // roots, have x >= 0
00267 
00268             if (x > yk) left  = yk;
00269             else        right = yk;
00270 
00271           else
00272 
00273             if (x > yk)       left  =  yk;
00274             else if (x < -yk) right = -yk;
00275             else              left  = - (right = yk);
00276 
00277         else // k negative
00278           if (y < xk) // between asymptotes
00279             left = - (right = yk);
00280           else  // in one of the two convex areas
00281             if (x > 0) left  =  yk;
00282             else       right = -yk;
00283 
00284   else // case 3: assume x bounded from below by 0
00285 
00286     if (k > 0) ((y < xk) ? left : right) = yk;
00287     else       ((y > xk) ? left : right) = yk;
00288 }
00289 
00290 
00292 CouNumber exprPow::gradientNorm (const double *x) {
00293 
00294   int ind0 = arglist_ [0] -> Index ();
00295   CouNumber exponent = arglist_ [1] -> Value ();
00296   return (ind0 < 0) ? 0. : fabs (exponent * safe_pow (x [ind0], exponent - 1));
00297 }
00298 
00299 
00302 bool exprPow::isCuttable (CouenneProblem *problem, int index) const {
00303 
00304   CouNumber exponent = arglist_ [1] -> Value ();
00305 
00306   bool
00307     isInt    = ::isInteger (exponent),
00308     isInvInt = (exponent != 0.) && ::isInteger (1. / exponent);
00309 
00310   int intExp = (isInt ? COUENNE_round (exponent) : (isInvInt ? COUENNE_round (1. / exponent) : 0));
00311 
00312   if (exponent > 0.) {
00313 
00314     if (isInt || isInvInt) {
00315 
00316       if (intExp % 2) return false; // exponent odd or 1/odd
00317 
00318       CouNumber 
00319         x = problem -> X (arglist_ [0] -> Index ()),
00320         y = problem -> X (index);
00321 
00322       if (isInt) return (y <= safe_pow (x, exponent)); // below convex curve ==> cuttable
00323 
00324       return (y >= safe_pow (x, exponent)); // above concave k-th root curve ==> cuttable
00325     } else {
00326 
00327       // non-integer exponent
00328       CouNumber 
00329         x = problem -> X (arglist_ [0] -> Index ()),
00330         y = problem -> X (index);
00331 
00332       return ((exponent <= 1.) && (y >= safe_pow (x, exponent)) ||
00333               (exponent >= 1.) && (y <= safe_pow (x, exponent)));
00334     }      
00335   } else {
00336 
00337     // non-integer exponent
00338     CouNumber 
00339       x  = problem -> X (arglist_ [0] -> Index ()),
00340       y  = problem -> X (index),
00341       lb = problem -> Lb (index),
00342       ub = problem -> Ub (index);
00343 
00344     if (isInt || isInvInt)
00345 
00346       if (!(intExp % 2)) return (((lb > 0) || (ub < 0)) && (y * safe_pow (fabs (x), -exponent) <= 1.));
00347       else               return (((lb > 0) || (ub < 0)) && (y * safe_pow (x,        -exponent) <= 1.));
00348     else                 return                            (y * safe_pow (x,        -exponent) <= 1.);
00349   }
00350 }

Generated on Tue Mar 30 03:04:37 2010 by  doxygen 1.4.7