/home/coin/SVN-release/OS-2.4.2/Couenne/src/branch/operators/branchExprMul.cpp

Go to the documentation of this file.
00001 /* $Id: branchExprMul.cpp 708 2011-06-23 14:04:59Z pbelotti $
00002  *
00003  * Name:    branchExprMul.cpp
00004  * Author:  Pietro Belotti
00005  * Purpose: return branch data for multiplications
00006  *
00007  * (C) Carnegie-Mellon University, 2006-10.
00008  * This file is licensed under the Eclipse Public License (EPL)
00009  */
00010 
00011 #include "CouennePrecisions.hpp"
00012 #include "CouenneTypes.hpp"
00013 #include "CouenneObject.hpp"
00014 
00015 #include "CouenneExprMul.hpp"
00016 #include "CouenneFunTriplets.hpp"
00017 #include "CouenneProjections.hpp"
00018 
00019 using namespace Couenne;
00020 
00023 CouNumber exprMul::selectBranch (const CouenneObject *obj,
00024                                  const OsiBranchingInformation *info,
00025                                  expression *&var,
00026                                  double * &brpts, 
00027                                  double * &brDist, // distance of current LP
00028                                                    // point to new convexifications
00029                                  int &way) {
00030 
00031   if (brDist) {free (brDist); brDist = NULL;} // clear it, computeMulBrDist will fill it
00032 
00033   int xi = arglist_ [0] -> Index (),
00034       yi = arglist_ [1] -> Index (),
00035       wi = obj -> Reference () -> Index ();
00036 
00037   assert ((xi >= 0) && (yi >= 0) && (wi >= 0));
00038 
00039   CouNumber 
00040     x0 = info -> solution_  [xi], y0 = info -> solution_  [yi],
00041     xl = info -> lower_     [xi], yl = info -> lower_     [yi],
00042     xu = info -> upper_     [xi], yu = info -> upper_     [yi];
00043 
00044 #ifdef DEBUG
00045   printf ("    branch MUL: %g [%g,%g] %g [%g,%g]\n", 
00046           x0, xl, xu, y0, yl, yu);
00047 #endif
00048 
00049   brpts = (double *) realloc (brpts, sizeof (double));
00050 
00051   // Constant x and/or y //////////////////////////////////////////////////////////
00052 
00053   if (fabs (xu-xl) < COUENNE_EPS) { // x almost constant
00054 
00055     if (fabs (yu-yl) < COUENNE_EPS) { // both almost constant, return null result
00056 
00057       var = NULL;
00058       return 0.;
00059 
00060     } else { // x constant, branch on y
00061 
00062       var = arglist_ [1];
00063       *brpts = 0.5 * (yl+yu);
00064       brDist = (double *) realloc (brDist, 2 * sizeof (double));
00065 
00066       brDist [0] = projectSeg (x0, y0, yl, xl*yl, *brpts, *brpts * xl, 0);
00067       brDist [1] = projectSeg (x0, y0, *brpts, *brpts * xl, yu, xl*yu, 0);
00068 
00069       //return fabs (w0 - x0*y0);
00070       return CoinMin (brDist [0], brDist [1]);
00071     }
00072 
00073   } else if (fabs (yu-yl) < COUENNE_EPS) { // y constant, branch on x
00074 
00075     var = arglist_ [0];
00076     *brpts = 0.5 * (xl+xu);
00077     brDist = (double *) realloc (brDist, 2 * sizeof (double));
00078 
00079     brDist [0] = projectSeg (x0, y0, xl, xl*yl, *brpts, *brpts * yl, 0);
00080     brDist [1] = projectSeg (x0, y0, *brpts, *brpts * yl, xu, xu*yl, 0);
00081 
00082     //return fabs (w0 - x0*y0);
00083     return CoinMin (brDist [0], brDist [1]);
00084   }
00085 
00086   // Unbounded x and/or y /////////////////////////////////////////////////////////
00087 
00088   if ((((var = arglist_ [0]) -> Index() >= 0) && (xl < -COUENNE_INFINITY) && (xu > COUENNE_INFINITY)) ||
00089       (((var = arglist_ [1]) -> Index() >= 0) && (yl < -COUENNE_INFINITY) && (yu > COUENNE_INFINITY))) {
00090 
00091     *brpts = 0.;
00092     brDist = computeMulBrDist (info, xi, yi, wi, var -> Index (), brpts);
00093     way = (info -> solution_ [var -> Index ()] > *brpts) ? TWO_RIGHT : TWO_LEFT;
00094 
00095     return CoinMin (brDist [0], brDist [1]);
00096   }
00097 
00098   // TODO: don't privilege xi over yi
00099 
00100   // at most one bound is infinite ///////////////////////////////////////////////
00101 
00102   int ind = -1;
00103 
00104   if      (xl < -large_bound)                              // x unbounded below
00105     {ind = xi; *brpts = obj -> midInterval (((x0 < 0.) ? 2 : 0.5) * x0, xl, xu, info); way = TWO_RIGHT;}
00106 
00107   else if (xu >  large_bound)                              // x unbounded above
00108     {ind = xi; *brpts = obj -> midInterval (((x0 > 0.) ? 2 : 0.5) * x0, xl, xu, info); way = TWO_LEFT;} 
00109 
00110   else if (yl < -large_bound)                              // y unbounded below
00111     {ind = yi; *brpts = obj -> midInterval (((y0 < 0.) ? 2 : 0.5) * y0, yl, yu, info); way = TWO_RIGHT;}
00112 
00113   else if (yu >  large_bound)                              // y unbounded above
00114     {ind = yi; *brpts = obj -> midInterval (((y0 > 0.) ? 2 : 0.5) * y0, yl, yu, info); way = TWO_LEFT;} 
00115 
00116   else { // both are bounded
00117 
00118     // Check if, though bounded, they are a bit too large
00119 
00120     CouNumber delta = (yu-yl) - (xu-xl);
00121 
00122     if      (delta > +COUENNE_EPS) ind = yi;
00123     else if (delta < -COUENNE_EPS) ind = xi;
00124     else ind = (CoinDrand48 () < 0.5) ? xi : yi;
00125 
00126     CouNumber 
00127       pt = info -> solution_  [ind],
00128       lb = info -> lower_     [ind],
00129       ub = info -> upper_     [ind],
00130       margin = obj -> lp_clamp () * (ub - lb);
00131 
00132     if ((lb < -COUENNE_EPS) && 
00133         (ub >  COUENNE_EPS) && 
00134         (-lb/ub >= THRES_ZERO_SYMM) &&
00135         (-ub/lb >= THRES_ZERO_SYMM))
00136       // interval is fairly symmetric around 0, branch on it
00137       *brpts = 0.;
00138 
00139     else if ((lb < - large_bound) && 
00140              (ub >   large_bound) &&
00141              (fabs (pt) > large_bound))
00142       *brpts = 0.;
00143 
00144     else switch (obj -> Strategy ()) {
00145       case CouenneObject::LP_CENTRAL:   *brpts = pt; if ((pt < lb + margin) || 
00146                                                          (pt > ub - margin)) 
00147                                                        pt = .5 * (lb+ub);                     break;
00148       case CouenneObject::LP_CLAMPED:   *brpts = CoinMax (lb + margin, 
00149                                                  CoinMin (ub - margin, pt));                  break;
00150       case CouenneObject::MID_INTERVAL: *brpts = obj -> midInterval (pt, lb, ub, info);       break;
00151       case CouenneObject::BALANCED:     *brpts = balancedMul (info, (ind == xi) ? 0 : 1, wi); break;
00152       case CouenneObject::MIN_AREA: // in products, the minimum volume
00153                                     // subdivision is at the middle of
00154                                     // the interval
00155       default:                          *brpts = (0.5 * (lb+ub));                             break;
00156     }
00157 
00158     way = (pt > *brpts) ? TWO_RIGHT : TWO_LEFT;
00159   }
00160 
00161   assert (ind >= 0);
00162 
00163   var = arglist_ [(ind == xi) ? 0 : 1];
00164 
00165   brDist = computeMulBrDist (info, xi, yi, wi, ind, brpts);
00166 
00167 #ifdef DEBUG
00168   printf ("    MUL: br on x_%d %g [%g,%g] [%g,%g] (%g,%g)\n", 
00169           ind, *brpts, xl, xu, yl, yu, x0, y0);
00170 #endif
00171 
00172   return CoinMin (brDist [0], brDist [1]);
00173   //return fabs (w0 - x0*y0);
00174 }
00175 
00176 
00177 // branching point for multiplication according to the balanced strategy
00178 CouNumber exprMul::balancedMul (const OsiBranchingInformation *info, int index, int wind) {
00179 
00180   // first of all, make sure both arguments are variables
00181 
00182   int other;
00183 
00184   if (index==0) {
00185     index = arglist_ [0] -> Index ();
00186     other = arglist_ [1] -> Index ();
00187   } else {
00188     index = arglist_ [1] -> Index ();
00189     other = arglist_ [0] -> Index ();
00190   }
00191 
00192   assert ((index >= 0) && (other >= 0));
00193 
00194   CouNumber 
00195     xl = info -> lower_    [index],  yl = info -> lower_    [other],
00196     xu = info -> upper_    [index],  yu = info -> upper_    [other],
00197     x0 = info -> solution_ [index],  y0 = info -> solution_ [other],
00198     w0 = info -> solution_ [wind];
00199     
00200   // It is quite tricky to implement a balanced strategy for products,
00201   // because it is more difficult to measure "balancedness" for binary
00202   // operators than it is for univariate functions.
00203   //
00204   // As a rule of thumb, we therefore apply the usual balanced
00205   // strategy for the univariate function resulting from constraining
00206   // (x,y) to a segment crossing their bounding box [xl,xu] X [yl,yu].
00207   //
00208   // Said segment is the set of points between (xl,yl) and (xu,yu) if
00209   // the current point is above the curve w:=xy, otherwise it is the
00210   // other diagonal, i.e. the set of points between (xl,yu) and
00211   // (xu,yl).
00212   //
00213   // In the two cases, we have the point 
00214   //
00215   // (above) P(t) = (xp,yp) := (xl + t (xu-xl), yl + t (yu-yl))
00216   // (below) P(t) = (xp,yp) := (xu + t (xl-xu), yl + t (yu-yl))
00217   //
00218   // with t in [0,1], which forms the following second degree
00219   // polynomial when multiplying the coordinates:
00220   //
00221   // (above) f(t) = xp*yp = (yu-yl)*(xu-xl)*t^2 + [yl(xu-xl) + xl(yu-yl)]*t + xl*yl
00222   // (below) f(t) = xp*yp = (yu-yl)*(xl-xu)*t^2 + [yl(xl-xu) + xu(yu-yl)]*t + xu*yl
00223   //
00224   // which is a quadratic function that can be expressed in the form
00225   // of f'(z) = z^2 + c if we apply an affine transformation to t:
00226   //
00227   // t = mz + q
00228   //
00229   // such that the resulting coefficients of the quadratic- and the
00230   // linear terms are one and zero, respectively. Thus:
00231   // 
00232   // (above) f(z) = (yu-yl)*(xu-xl)*(mz+q)^2               + [yl(xu-xl)-xl(yu-yl)]*(mz+q) + xl*yl = 
00233   //              = (yu-yl)*(xu-xl)*(m^2 z^2 + 2qmz + q^2) + [yl(xu-xl)-xl(yu-yl)]*(mz+q) + xl*yl = 
00234   //              = z^2 + c 
00235   //
00236   // (below) f(z) = (yu-yl)*(xl-xu)*(mz+q)^2               + [yl(xl-xu)-xu(yu-yl)]*(mz+q) + xu*yl = 
00237   //              = (yu-yl)*(xl-xu)*(m^2 z^2 + 2qmz + q^2) + [yl(xl-xu)-xu(yu-yl)]*(mz+q) + xu*yl = 
00238   //              = -z^2 + c 
00239   //
00240   // if and only if
00241   //
00242   // (above) ((yu-yl)*(xu-xl)) * m^2 =  1   )
00243   //                                        } <====>  m = 1 / sqrt ((yu-yl)*(xu-xl))
00244   // (below) ((yu-yl)*(xl-xu)) * m^2 = -1   )
00245   //
00246   // (above)  2qm*(yu-yl)*(xu-xl) + m[yl(xu-xl)-xl(yu-yl)] = 0   <====>
00247   //          q = -[yl(xu-xl)-xl(yu-yl)] / (2(yu-yl)*(xu-xl))
00248   //
00249   // (below)  2qm*(yu-yl)*(xl-xu) + m[yl(xl-xu)-xu(yu-yl)] = 0   <====>
00250   //          q = -[yl(xl-xu)-xu(yu-yl)] / (2(yu-yl)*(xl-xu))
00251   //
00252   // If the point is below the curve, a very similar reasoning applies
00253   // (simply swap xl with xu).
00254   // 
00255   // Hence, we simply apply the balanced strategy to the function
00256   // f(z)=z^2 with z bounded between -q/m and (1-q)/m. The returning
00257   // value z_opt must be transformed to get
00258   //
00259   // t_opt = m z_opt + q
00260   //
00261   // and the branching point is xl + t_opt (xu-xl)
00262   //
00263 
00264   powertriplet ft (2);
00265 
00266   // A: above
00267   // B: below
00268 
00269   bool above = (w0 > x0*y0);
00270 
00271   CouNumber 
00272     dx     = xu-xl,
00273     dy     = yu-yl,
00274     area   = dx*dy,          // coefficient of t^2
00275     bA     =  yl*dx - xl*dy, // coefficient of t
00276     bB     = -yl*dx - xu*dy, // coefficient of t
00277     m      = 1. / sqrt (area),
00278     qA     = -bA / (2*area),
00279     qB     =  bB / (2*area),
00280     z_opt = above ? 
00281       minMaxDelta (&ft, -qA/m, (1-qA)/m): 
00282       minMaxDelta (&ft, -qB/m, (1-qB)/m),
00283     t_optA = m*z_opt + qA,
00284     t_optB = m*z_opt + qB;
00285 
00286   /*printf ("------------------\n(%d,%d): [%g,%g], [%g,%g]\n", index, other, xl, xu, yl, yu);
00287   printf ("dx = %g, dy = %g, area = %g, bA = %g, bB = %g, m = %g\n", dx, dy, area, bA, bB, m);
00288   printf ("qA = %g, qB = %g, z_opt = %g, tA = %g, tB = %g\n", 
00289           qA, qB, z_opt, t_optA, t_optB);
00290   printf ("w = %g %c xy = %g*%g = %g --> %g\n", w0,
00291           (w0 > x0*y0) ? '>' : '<', x0, y0, x0*y0, 
00292           (w0 > x0*y0) ? (xl + dx * t_optA) : (xu - dx * t_optB));*/
00293 
00294   return (w0 > x0*y0) ? 
00295     (xl + dx * t_optA) : 
00296     (xu - dx * t_optB);
00297 }

Generated on Wed Nov 30 03:03:58 2011 by  doxygen 1.4.7