/home/coin/SVN-release/OS-2.4.1/Couenne/src/convex/operators/unifiedProdCuts.cpp

Go to the documentation of this file.
00001 /* $Id: unifiedProdCuts.cpp 490 2011-01-14 16:07:12Z pbelotti $
00002  *
00003  * Name:    unifiedProdCuts.cpp
00004  * Author:  Pietro Belotti
00005  * Purpose: unified convexification of products and divisions
00006  *
00007  * (C) Carnegie-Mellon University, 2006-10.
00008  * This file is licensed under the Eclipse Public License (EPL)
00009  */
00010 
00011 #include "CouenneCutGenerator.hpp"
00012 
00013 #include "CouenneTypes.hpp"
00014 #include "CouennePrecisions.hpp"
00015 #include "CouenneProblem.hpp"
00016 #include "CouenneExprDiv.hpp"
00017 #include "CouenneExprMul.hpp"
00018 #include "CouenneExprPow.hpp"
00019 #include "CouenneFunTriplets.hpp"
00020 
00021 namespace Couenne {
00022 
00024 
00025 void contourCut (const CouenneCutGenerator *cg,
00026                  OsiCuts &cs, 
00027                  CouNumber xp, CouNumber yp, // current point
00028                  CouNumber wb,               // bound on w
00029                  int sign,                   // is wb lower or upper?
00030                  CouNumber x0, CouNumber y0, // (allegedly) outside point
00031                  CouNumber x1, CouNumber y1, //              inside
00032                  int xi, int yi, int wi) {   // indices of the variables
00033 
00034   // Upper right corner of the bounding box of (x,y) is feasible,
00035   // the opposite corner is not, hence there is a cut violated by
00036   // (x0,y0).
00037 
00038   // If (x0,y0) is not in the same orthant as the contour in
00039   // question, move it in so that we can apply a Newton step to
00040   // find closest point on contour.
00041 
00042   int xsign = (x1 >= 0) ? 1 : -1, // define orthant where the "inside
00043       ysign = (y1 >= 0) ? 1 : -1; // point" lies
00044 
00045   if      (((xsign > 0) ? xp : -xp) <= COUENNE_EPS)
00046     if    (((ysign > 0) ? yp : -yp) <= COUENNE_EPS) { 
00047 
00048       // opposite orthant, put in the right one where constraint is violated
00049       xp = yp = sqrt (fabs (wb))/2; 
00050       if (xsign<0) xp = -xp;
00051       if (ysign<0) yp = -yp;
00052     }                                                // otherwise, must cross one axis only:
00053     else                                            {xp = sqrt (fabs(wb/yp)); if (xsign<0) xp=-xp;}//y
00054   else if (((ysign > 0) ? yp : -yp) <= COUENNE_EPS) {yp = sqrt (fabs(wb/xp)); if (ysign<0) yp=-yp;}//x
00055 
00056   // pt here describes a function of the form wb*x^(-1)
00057   kpowertriplet pt (-1, wb);
00058 
00059   CouNumber 
00060     // tangent point closest to current point
00061     xt = powNewton (xp, yp, &pt),
00062     *lb = cg -> Problem () -> Lb (),
00063     *ub = cg -> Problem () -> Ub (),
00064     xL = lb [xi], xU = ub [xi],
00065     yL = lb [yi], yU = ub [yi];  
00066 
00067   if (xt == 0.) // no tangents are possible
00068     return;
00069 
00070   // check if (xt,wb/xt) is outside of bounds. If so, project it back
00071   // into the bounding box
00072   if ((xt < xL) && (xL != 0.)) xt = xL;
00073   if ((xt > xU) && (xU != 0.)) xt = xU;
00074 
00075   if ((wb / xt < yL) && (yL != 0.)) xt = wb / yL;
00076   if ((wb / xt > yU) && (yU != 0.)) xt = wb / yU;
00077 
00078   // coefficient of w in the lifted cut
00079   CouNumber
00080     alpha = ((fabs (x1) < COUENNE_INFINITY) && 
00081              (fabs (y1) < COUENNE_INFINITY) &&
00082              (fabs (x1*y1 - wb) > 0.)) ? 
00083     ((2*wb/xt - y1 - wb*x1 / (xt*xt)) / (x1*y1 - wb)) : 0;
00084 
00085   //printf ("+++++ %d %d %d. [%c] xp (%g,%g) wb %g out(%g,%g) in(%g,%g) --> [%g,%g] alpha %g\n",
00086   //xi, yi, wi, (sign<0) ? '-' : '+', xp, yp, wb, x0, y0, x1, y1, xt, wb/xt, alpha);
00087 
00088   if (alpha != 0)
00089     cg     -> createCut (cs, alpha*wb + 2*wb/xt, sign, wi, alpha, yi, 1., xi, wb/(xt*xt));
00090   else  cg -> createCut (cs,            2*wb/xt, sign,            yi, 1., xi, wb/(xt*xt));
00091 }
00092 
00093 
00094 
00095 // Unified procedure to create convexification cuts for an expression of the form w = x*y
00096 void unifiedProdCuts (const CouenneCutGenerator *cg, OsiCuts &cs, 
00097                       int xi, CouNumber x0, CouNumber xl, CouNumber xu,
00098                       int yi, CouNumber y0, CouNumber yl, CouNumber yu,
00099                       int wi, CouNumber w0, CouNumber wl, CouNumber wu,
00100                       t_chg_bounds *chg, enum expression::auxSign sign) {
00101 
00102   bool cLX,  cRX,  cLY,  cRY,  cLW,  cRW = 
00103        cLX = cRX = cLY = cRY = cLW = true;
00104 
00105   if (!(cg -> isFirst ()) && chg) {
00106     cLX= chg[xi].lower() != t_chg_bounds::UNCHANGED; cRX= chg[xi].upper() != t_chg_bounds::UNCHANGED;
00107     cLY= chg[yi].lower() != t_chg_bounds::UNCHANGED; cRY= chg[yi].upper() != t_chg_bounds::UNCHANGED;
00108     cLW= chg[wi].lower() != t_chg_bounds::UNCHANGED; cRW= chg[wi].upper() != t_chg_bounds::UNCHANGED;
00109   }
00110 
00111   // Add McCormick convexification cuts:
00112   //
00113   // 1) w >= yl x + xl y - yl xl
00114   // 2) w >= yu x + xu y - yu xu
00115   //
00116   // 3) w <= yl x + xu y - yl xu
00117   // 4) w <= yu x + xl y - yu xl
00118   //
00119   // These cuts are added if the corresponding bounds are finite
00120 
00121   if (sign != expression::AUX_LEQ) {
00122     if ((cLX || cLY) && is_boundbox_regular (yl, xl)) cg -> createCut (cs,yl*xl,-1,wi,-1.,xi,yl,yi,xl);
00123     if ((cRX || cRY) && is_boundbox_regular (yu, xu)) cg -> createCut (cs,yu*xu,-1,wi,-1.,xi,yu,yi,xu);
00124   }
00125 
00126   if (sign != expression::AUX_GEQ) {
00127     if ((cRX || cLY) && is_boundbox_regular (yl, xu)) cg -> createCut (cs,yl*xu,+1,wi,-1.,xi,yl,yi,xu);
00128     if ((cLX || cRY) && is_boundbox_regular (yu, xl)) cg -> createCut (cs,yu*xl,+1,wi,-1.,xi,yu,yi,xl);
00129   }
00130 
00131   // If w=xy and w >= l > 0 (resp. w <= u < 0) are "tight" bounds
00132   // (i.e. they are tighter than those obtained through propagation of
00133   // x and y's bounds), McCormick's convexification is not tight as
00134   // the surface has a curve contour at w=l (resp. w=u).
00135   //
00136   // McCormick rules induce a tangent to this contour at the bounds of
00137   // both variables, but it may be useful to add further cuts along
00138   // the contour to eliminate infeasible point (x0,y0,w0), which may
00139   // be in the convexification but out of the contour (on its "convex"
00140   // side, or "out of the belly").
00141   //
00142   // Suppose P (xt,l/xt) (resp. (xt,u/xt) is the point on the contour
00143   // closest to (x0,y0), found through a Newton method. The cut is
00144   // tangent to the contour in P and has the form
00145   //
00146   //        y - l/xt >= -l/(xt^2) (x-xt)   if xl*yl < l and xu*yu > l
00147   //        y - l/xt <= -l/(xt^2) (x-xt)   if xl*yl > l and xu*yu < l
00148   //
00149   // (resp. y - u/xt <= -u/(xt^2) (x-xt)   if xl*yu > u and xu*yl < u
00150   //        y - u/xt >= -u/(xt^2) (x-xt)   if xl*yu < u and xu*yl > u)
00151   //
00152   // These can be lifted to satisfy, at equality, the point
00153   // (xu,yu,wu=xu*yu) (resp. (xl,yl,wl=xl*yl)), where xl and xu are
00154   // lower and upper bound of x, etc.
00155   //
00156   //        alpha (w - l) + y - l/xt >= -l/(xt^2) (x-xt) ...
00157   //
00158   // where alpha is such that the relation holds at equality at the
00159   // point (xu,yu,xu*yu):
00160   //
00161   //    alpha = [-yu + l/xt - l/(xt^2)(xu-xt)] / (xu*yu - l)
00162 
00163   if (cg -> Problem () -> MultilinSep () == CouenneProblem::MulSepSimple || 
00164       fabs (wu - wl) < COUENNE_EPS) {
00165 
00166     if ((x0 > xl + COUENNE_EPS) && (y0 > yl + COUENNE_EPS) &&
00167         (x0 < xu + COUENNE_EPS) && (y0 < yu + COUENNE_EPS)) {
00168 
00169       if (cLW && (wl > 0) && (x0*y0 < wl) && (sign != expression::AUX_GEQ)) { // that is, if (x0,y0) is out of the contour
00170 
00171         CouNumber xyl = xl * yl;
00172 
00173         // first and third orthant
00174         if      ((xyl <  wl) && (xu*yu >= wl)) contourCut (cg,cs, x0,y0, wl, +1, xl,yl, xu,yu, xi,yi,wi);
00175         else if ((xyl >= wl) && (xu*yu <  wl)) contourCut (cg,cs, x0,y0, wl, -1, xu,yu, xl,yl, xi,yi,wi);
00176       }
00177 
00178       // Similarly for w <= u < 0 
00179 
00180       if (cRW && (wu < 0) && (x0*y0 > wu) && (sign != expression::AUX_LEQ)) { // that is, if (x0,y0) is out of the contour
00181 
00182         CouNumber xuyl = xl * yu;
00183 
00184         // second and fourth orthant
00185         if      ((xuyl > wu) && (xl*yu <= wu)) contourCut (cg,cs, x0,y0, wu, +1, xu,yl, xl,yu, xi,yi,wi);
00186         else if ((xuyl <=wu) && (xl*yu >  wu)) contourCut (cg,cs, x0,y0, wu, -1, xl,yu, xu,yl, xi,yi,wi);
00187       }
00188     }
00189   } else
00190     if (cg -> Problem () -> MultilinSep () == CouenneProblem::MulSepTight)
00191       upperEnvHull (cg, cs, 
00192                     xi, x0, xl, xu, 
00193                     yi, y0, yl, yu,
00194                     wi, w0, wl, wu);
00195 }
00196 
00197 }

Generated on Thu Nov 10 03:05:43 2011 by  doxygen 1.4.7