/home/coin/SVN-release/OS-2.4.1/Couenne/src/bound_tightening/fake_tightening.cpp

Go to the documentation of this file.
00001 /* $Id: fake_tightening.cpp 749 2011-07-31 11:54:55Z pbelotti $
00002  *
00003  * Name:    fake_tightening.cpp
00004  * Author:  Pietro Belotti
00005  * Purpose: fake single bounds in variables to exclude parts of the solution space 
00006  *
00007  * (C) Carnegie-Mellon University, 2007-10.
00008  * This file is licensed under the Eclipse Public License (EPL)
00009  */
00010 
00011 #include "CoinHelperFunctions.hpp"
00012 
00013 #include "CouenneProblem.hpp"
00014 #include "CouenneProblemElem.hpp"
00015 #include "CouenneExprVar.hpp"
00016 
00017 #include "BonBabInfos.hpp"
00018 
00019 using namespace Couenne;
00020 
00021 #define MAX_ITER  3 // max # fake tightening (inner) iterations 
00022 #define AGGR_MUL  2 // the larger,  the more conservative. Must be > 0
00023 #define AGGR_DIV  2 // the smaller, the more conservative. Must be > 1
00024 
00025 // golden ratio, used to find the ideal bound
00026 const CouNumber phi = 0.5 * (1. + sqrt (5.));
00027 
00028 // create fictitious bounds to tighten current interval
00029 CouNumber fictBounds (char direction,
00030                       CouNumber  x,
00031                       CouNumber  lb,   
00032                       CouNumber  ub) {
00033 
00034 #define LARGE_BOUND 1e10
00035 
00036   if   (lb < -LARGE_BOUND) {
00037     if (ub >  LARGE_BOUND) { // ]-inf,+inf[
00038 
00039       return (!direction ? -sqrt (-lb) : sqrt (ub));
00040 
00041       //if (fabs (x) < COUENNE_EPS) return (direction ? AGGR_MUL : - AGGR_MUL);
00042       //else                        return (direction ? AGGR_MUL : - AGGR_MUL) * fabs (x);
00043 
00044     } else { // ]-inf,u]
00045 
00046       if (!direction)
00047         return -sqrt (-lb); // try to tighten interval from a very large value
00048 
00049       if      (x < -COUENNE_EPS) return (CoinMin (0., (x+ub)/2));
00050       else if (x >  COUENNE_EPS) return ((x + (ub-x)/AGGR_DIV));
00051       else                       return ((ub/AGGR_DIV));
00052 
00053       // if      (x < -COUENNE_EPS) return (direction ? CoinMin (0., (x+ub)/2) : AGGR_MUL * x);
00054       // else if (x >  COUENNE_EPS) return (direction ? (x + (ub-x)/AGGR_DIV) : 0);
00055       // else                       return (direction ? (ub/AGGR_DIV) : -AGGR_MUL);
00056     }
00057   }
00058   else {
00059     if (ub >  LARGE_BOUND) { // [l,+inf[
00060 
00061       if (direction)
00062         return sqrt (ub);
00063 
00064       if      (x < -COUENNE_EPS) return ((x - (x-lb) / AGGR_DIV));
00065       else if (x >  COUENNE_EPS) return (CoinMax (0.,(x+lb)/2));
00066       else                       return (lb/AGGR_DIV);
00067 
00068       // if      (x < -COUENNE_EPS) return (direction ? 0 : (x - (x-lb) / AGGR_DIV));
00069       // else if (x >  COUENNE_EPS) return (direction ? (AGGR_MUL * x) : CoinMax (0.,(x+lb)/2));
00070       // else                       return (direction ? AGGR_MUL : lb/AGGR_DIV);
00071 
00072     } else // [l,u]
00073       return (direction ? 
00074               (x + (ub-x) / AGGR_DIV) : 
00075               (x - (x-lb) / AGGR_DIV));
00076   }
00077 }
00078 
00079 
00080 // Single fake tightening. Return
00081 //
00082 // -1   if infeasible
00083 //  0   if no improvement
00084 // +1   if improved
00085 int CouenneProblem::
00086 fake_tighten (char direction,  // 0: left, 1: right
00087               int index,       // index of the variable tested
00088               const double *X, // point round which tightening is done
00089               CouNumber *olb,  // cur. lower bound
00090               CouNumber *oub,  //      upper
00091               t_chg_bounds *chg_bds,
00092               t_chg_bounds *f_chg) const {
00093   int
00094     ncols    = nVars (),
00095     objind   = Obj (0) -> Body  () -> Index ();
00096 
00097   assert (objind >= 0);
00098 
00099   bool 
00100     tightened = false,
00101     intvar    = variables_ [index] -> isInteger ();
00102 
00103   CouNumber 
00104     xcur      = X [index],
00105     inner     = xcur,                                                 // point closest to current x
00106     outer     = (direction ? oub : olb) [index],                      // point closest to bound
00107     fb        = fictBounds (direction, xcur, Lb (index), Ub (index)); // starting point
00108 
00109   // This is a one-dimensional optimization problem between inner and
00110   // outer, on a monotone function of which we can compute the value
00111   // (with relative expense) but not the derivative.
00112 
00113   jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING, 
00114                     "  x_%d.  x = %10g, lb = %g, cutoff = %g-----------------\n", 
00115                     index,xcur,Lb (objind),getCutOff());
00116 
00117   /*if (index == objind)
00118     printf ("  x_%d [%g,%g].  x = %10g, break at %g, cutoff = %g-----------------\n", 
00119     index, Lb (index), Ub (index), xcur, fb, getCutOff());*/
00120 
00121   for (int iter = 0; iter < MAX_ITER; iter++) {
00122 
00123     if (intvar) {
00124 
00125       if (!direction) {inner = floor (inner + COUENNE_EPS); outer = ceil  (outer - COUENNE_EPS);}
00126       else            {inner = ceil  (inner - COUENNE_EPS); outer = floor (outer + COUENNE_EPS);}
00127 
00128       if ( (direction && (inner > outer + .5)) || // more robust check on integer-valued doubles
00129           (!direction && (inner < outer - .5))) {
00130 
00131         // fictitious interval is empty, hence useless to check. 
00132 
00133         // apply new (valid, tightened) bound
00134         if (direction) {oub[index] = Ub (index) = fb; chg_bds[index].setUpper(t_chg_bounds::CHANGED);}
00135         else           {olb[index] = Lb (index) = fb; chg_bds[index].setLower(t_chg_bounds::CHANGED);}
00136 
00137         tightened = true;
00138 
00139         if (!(btCore (f_chg))) 
00140           return -1;
00141 
00142         CoinCopyN (Lb (), ncols, olb);
00143         CoinCopyN (Ub (), ncols, oub);
00144 
00145         // restore initial bound. 
00146         CoinCopyN (chg_bds, ncols, f_chg);
00147         //CoinCopyN (olb, ncols, Lb ());
00148         //CoinCopyN (oub, ncols, Ub ());
00149 
00150         break;
00151       }
00152 
00153       if ( (direction && ((fb < inner) || (fb > outer))) ||
00154           (!direction && ((fb > inner) || (fb < outer))))
00155         fb = 0.5 * (inner + outer);
00156     }
00157 
00158     if (direction) {
00159       Lb (index) = intvar ? ceil (fb - COUENNE_EPS)  : fb; 
00160       f_chg [index].setLower (t_chg_bounds::CHANGED);
00161     } else {
00162       Ub (index) = intvar ? floor (fb + COUENNE_EPS) : fb; 
00163       f_chg [index].setUpper (t_chg_bounds::CHANGED);
00164     }
00165 
00166     //    (direction ? lb_ : ub_) [index] = fb; 
00167 
00168     if (jnlst_ -> ProduceOutput (Ipopt::J_ERROR, J_BOUNDTIGHTENING)) {
00169       char c1 = direction ? '-' : '>', c2 = direction ? '<' : '-';
00170       printf ("    # x%d = %g iter %3d: [%+10g -%c %+10g %c- %+10g] /\\/\\ ",index,xcur,iter,olb[index],c1,fb,c2, oub [index]);
00171       printf (" [%10g,%10g]<%g,%g>=> ",Lb (index),Ub (index),CoinMin(inner,outer),CoinMax(inner,outer));
00172     }
00173 
00174     bool
00175       feasible  = btCore (f_chg),                           // true if feasible with fake bound
00176       betterbds = Lb (objind) > getCutOff () + COUENNE_EPS; // true if over cutoff
00177 
00178     jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING,
00179                       " [%10g,%10g] lb = %g {fea=%d,btr=%d} ",
00180                       Lb (index), Ub (index), Lb (objind),feasible,betterbds);
00181 
00182     if (feasible && !betterbds) {
00183 
00184       // case 1: too tight, move inner out
00185       inner = fb;
00186 
00187       // restore initial bound
00188       CoinCopyN (chg_bds, ncols, f_chg);
00189       CoinCopyN (olb, ncols, Lb ());
00190       CoinCopyN (oub, ncols, Ub ());
00191 
00192     } else {
00193 
00194       // Here, !feasible || betterbds
00195       //
00196       // If !feasible OR
00197       //    (betterbds and the new lb is above the cutoff)
00198       //
00199       // then there is a tightening
00200 
00201       // case 2: tightening valid, apply and move outer in
00202 
00203       //printf (" --> %cbound [x_%d]: %g --> %g",direction?'U':'L',index,(direction?oub:olb)[index],fb);
00204 
00205       if (optimum_ && 
00206           ((!direction &&
00207             (optimum_ [index] >= olb [index]) && 
00208             (optimum_ [index] <= Lb (index) - COUENNE_EPS)) ||
00209            (direction &&
00210             (optimum_ [index] <= oub [index]) && 
00211             (optimum_ [index] >= Ub (index) + COUENNE_EPS)))) {
00212 
00213         jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING, 
00214                           "fake tightening CUTS optimum: x%d=%g in [%g,%g] but not in [%g,%g]\n",
00215                           index, olb [index], oub [index], Lb (index), Ub (index));
00216       }
00217 
00218       /*bool do_not_tighten = false;
00219 
00220       // check if cut best known solution
00221       if (optimum_) {
00222         if (direction) {
00223           if ((oub [index] > optimum_ [index]) && 
00224               (fb          < optimum_ [index])) {
00225             printf ("aggressive bt cuts optimum ub %d: %g < %g < %g\n", 
00226                     index, fb, optimum_ [index], oub [index]);
00227             do_not_tighten = true;
00228           }
00229         } else {
00230           if ((olb [index] < optimum_ [index]) && 
00231               (fb          > optimum_ [index])) {
00232             printf ("aggressive bt cuts optimum lb %d: %g < %g < %g\n", 
00233                     index, olb [index], optimum_ [index], fb);
00234             do_not_tighten = true;
00235           }
00236         }
00237         }*/
00238 
00239       //if (!do_not_tighten) {
00240 
00241       // apply bound
00242       if (direction) {
00243 
00244         oub [index] = Ub (index) = intvar ? floor (fb + COUENNE_EPS) : fb; 
00245         chg_bds [index]. setUpper (t_chg_bounds::CHANGED);
00246 
00247       } else {
00248 
00249         olb [index] = Lb (index) = intvar ? ceil  (fb - COUENNE_EPS) : fb; 
00250         chg_bds [index]. setLower (t_chg_bounds::CHANGED);
00251       }
00252 
00253       outer = fb; // we have at least a tightened bound, save it 
00254 
00255       tightened = true;
00256       //}
00257 
00258       // restore initial bound
00259       CoinCopyN (chg_bds, ncols, f_chg);
00260       CoinCopyN (olb, ncols, Lb ());
00261       CoinCopyN (oub, ncols, Ub ());
00262 
00263       //#if BR_TEST_LOG < 0 // for fair testing
00264       // check tightened problem for feasibility
00265       if (!(btCore (chg_bds))) {
00266 
00267         jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING, 
00268                           "\n    pruned by Probing\n");
00269         return -1;
00270 
00271       } else {
00272 
00273         // bounds further tightened should be saved
00274         
00275         CoinCopyN (Lb (), ncols, olb);
00276         CoinCopyN (Ub (), ncols, oub);
00277       }
00278       //#endif
00279     }
00280 
00281     // TODO: compute golden section
00282     //fb = (inner + outer) / 2;
00283 
00284     //fb = fictBounds (direction, fb, CoinMin (inner, outer), CoinMax (inner, outer));
00285 
00286     // inner and outer might have to change. Update 
00287 
00288     CouNumber 
00289       lb = Lb (index),
00290       ub = Ub (index);
00291 
00292     if ((!direction && ((inner > ub) || (outer < lb))) ||
00293         ( direction && ((inner < lb) || (outer > ub)))) {
00294 
00295       // keep it simple
00296 
00297       inner = direction ? lb : ub;
00298       outer = direction ? ub : lb;
00299     }
00300 
00301     CouNumber diff = fabs (inner - outer);
00302 
00303     if (diff <= COUENNE_EPS) break;
00304 
00305     if (diff > 1.) {
00306 
00307       CouNumber L = log (diff) / log (10.);
00308 
00309       if (direction) fb = inner + exp (log (10.) * L/2);
00310       else           fb = inner - exp (log (10.) * L/2);
00311 
00312     } else fb = (inner + outer)/2;
00313 
00314     //    if () fb = (          inner + (phi-1) * outer) / phi;
00315     //    else  fb = ((phi-1) * inner +           outer) / phi;
00316 
00317     //  if (!feasible)       
00318     //    fb = fictBounds (direction, xcur, 
00319     //       direction ? lb [index] : outer,
00320     //       direction ? outer      : ub [index]);
00321 
00322     jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING, "\n");
00323   }
00324 
00325   Jnlst()->Printf(Ipopt::J_MOREVECTOR, J_BOUNDTIGHTENING, "\n");
00326   if (tightened) 
00327     Jnlst()->Printf(Ipopt::J_MOREVECTOR, J_BOUNDTIGHTENING, 
00328                     "  [x%2d] pruned %s [%g, %g] -- lb = %g cutoff = %g\n", 
00329                     index,direction?"right":"left",
00330                     olb[index],oub[index], Lb (objind), getCutOff ());
00331 
00332   return tightened ? 1 : 0;
00333 }

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