/home/coin/SVN-release/OS-2.4.2/Couenne/src/bound_tightening/obbt_iter.cpp

Go to the documentation of this file.
00001 /* $Id: obbt_iter.cpp 732 2011-07-03 20:06:50Z pbelotti $
00002  *
00003  * Name:    obbt.cpp
00004  * Author:  Pietro Belotti
00005  * Purpose: Optimality-Based Bound Tightening
00006  *
00007  * (C) Carnegie-Mellon University, 2006-10.
00008  * This file is licensed under the Eclipse Public License (EPL)
00009  */
00010 
00011 #include "CglCutGenerator.hpp"
00012 #include "CouenneCutGenerator.hpp"
00013 #include "CouenneProblem.hpp"
00014 #include "CouenneProblemElem.hpp"
00015 #include "CouenneExprVar.hpp"
00016 
00017 using namespace Ipopt;
00018 using namespace Couenne;
00019 
00020 #define OBBT_EPS 1e-3
00021 
00022 // TODO: seems like Clp doesn't like large bounds and crashes on
00023 // explicit bounds around 1e200 or so. For now simply use fictitious
00024 // bounds around 1e14. Fix.
00025 
00027 static bool obbt_updateBound (OsiSolverInterface *csi, 
00028                               int sense,               
00029                               CouNumber &bound,        
00030                               bool isint) {            
00031 
00032   //csi -> deleteScaleFactors ();
00033   csi -> setDblParam (OsiDualObjectiveLimit, COIN_DBL_MAX); 
00034   csi -> setDblParam (OsiPrimalObjectiveLimit, (sense==1) ? bound : -bound);
00035   //csi -> setObjSense (1); // always minimize, just change the sign of the variable // done in caller
00036 
00038 
00039   //csi -> resolve_nobt (); // this is a time-expensive part, be considerate...
00040   csi -> resolve (); // this is a time-expensive part, be considerate...
00041 
00043 
00044   if (csi -> isProvenOptimal ()) {
00045 
00046     double opt = csi -> getObjValue ();
00047 
00048     if (sense > 0) 
00049          {if (opt        > bound + OBBT_EPS) {bound = (isint ? ceil  (opt - COUENNE_EPS) : opt); return true;}}
00050     else {if ((opt=-opt) < bound - OBBT_EPS) {bound = (isint ? floor (opt + COUENNE_EPS) : opt); return true;}}
00051   }
00052 
00053   return false;
00054 }
00055 
00056 
00058 
00059 int CouenneProblem::obbt_iter (OsiSolverInterface *csi, 
00060                                t_chg_bounds *chg_bds, 
00061                                const CoinWarmStart *warmstart, 
00062                                Bonmin::BabInfo *babInfo,
00063                                double *objcoe,
00064                                int sense, 
00065                                int index) const {
00066 
00067   // TODO: do NOT apply OBBT if this is a variable of the form
00068   // w2=c*w1, as it suffices to multiply result. More in general, do
00069   // not apply if w2 is a unary monotone function of w1. Even more in
00070   // general, if w2 is a unary function of w1, apply bound propagation
00071   // from w1 to w2 and mark it as exact (depending on whether it is
00072   // non-decreasing or non-increasing
00073 
00074   //static int iter = 0;
00075 
00076   // exclude checking known optimal solution if initial bounding box
00077   // already excludes it
00078 
00079   CouNumber *knownOptimum = optimum_;
00080 
00081   if (optimum_) {
00082 
00083     for (int i=nVars(); i--; knownOptimum++)
00084 
00085       if (*knownOptimum < Lb (i) || 
00086           *knownOptimum > Ub (i)) {
00087 
00088         knownOptimum = NULL;
00089         break;
00090       }
00091 
00092     if (knownOptimum) 
00093       knownOptimum -= nVars ();
00094   }
00095 
00096   std::set <int> deplist;
00097   int deplistsize;
00098 
00099   bool issimple = false;
00100 
00101   exprVar *var = Var (index);
00102 
00103   int
00104     objind  = Obj (0) -> Body () -> Index (),
00105     ncols   = csi -> getNumCols (),
00106     nImprov = 0;
00107 
00108   if ((var -> Type  () == AUX) &&
00109       ((deplistsize = var -> Image () -> DepList (deplist, STOP_AT_AUX)) <= 1)) {
00110 
00111     if (!deplistsize) { // funny, the expression is constant...
00112 
00113       CouNumber value = (*(var -> Image ())) ();
00114 
00115       if (csi -> getColLower () [index] < value - COUENNE_EPS) {
00116         csi -> setColLower (index, value); 
00117         chg_bds    [index].setLowerBits(t_chg_bounds::CHANGED | t_chg_bounds::EXACT);
00118       }
00119       else chg_bds [index].setLowerBits(t_chg_bounds::EXACT);
00120 
00121       if (csi -> getColUpper () [index] > value + COUENNE_EPS) {
00122         csi -> setColUpper (index, value); 
00123         chg_bds    [index].setUpperBits(t_chg_bounds::CHANGED | t_chg_bounds::EXACT);
00124       }
00125       else chg_bds [index].setUpperBits(t_chg_bounds::EXACT);
00126 
00127       issimple = true;
00128 
00129     } else { // the expression only depends on one variable, meaning
00130              // that bound propagation should be sufficient
00131 
00132       int indInd = *(deplist.begin ());
00133 
00134       //      expression *image = var -> Image ();
00135       // TODO: write code for monotone functions...
00136 
00137       if // independent variable is exactly bounded in both ways
00138         ((((chg_bds [indInd].lower() & t_chg_bounds::EXACT) && 
00139            (chg_bds [indInd].upper() & t_chg_bounds::EXACT)) ||
00140           // or if this expression is of the form w=cx+d, that is, it
00141           // depends on one variable only and it is linear
00142           (var -> Image () -> Linearity () <= LINEAR)) &&
00143          (var -> sign () == expression::AUX_EQ)) {
00144 
00145         issimple = true;
00146 
00147         CouNumber lb, ub;
00148         var -> Image () -> getBounds (lb, ub);
00149 
00150         if (lb < Lb (index)) lb = Lb (index);
00151         if (ub > Ub (index)) ub = Ub (index);
00152 
00153         if (var -> isInteger ()) {
00154           lb = ceil  (lb - COUENNE_EPS);
00155           ub = floor (ub + COUENNE_EPS);
00156         }
00157 
00158         if (lb > csi -> getColLower () [index] + COUENNE_EPS) {
00159           csi -> setColLower (index, lb); 
00160           Lb (index) = lb;
00161           chg_bds      [index].setLowerBits(t_chg_bounds::CHANGED | t_chg_bounds::EXACT);
00162         } else chg_bds [index].setLowerBits(t_chg_bounds::EXACT);
00163 
00164         if (ub < csi -> getColUpper () [index] - COUENNE_EPS) {
00165           csi -> setColUpper (index, ub); 
00166           Ub (index) = ub;
00167           chg_bds      [index].setUpperBits(t_chg_bounds::CHANGED | t_chg_bounds::EXACT);
00168         } else chg_bds [index].setUpperBits(t_chg_bounds::EXACT);
00169       }
00170     }
00171   }
00172 
00173   // only improve bounds if
00174   if (!issimple &&
00175       ((Var (index) -> Type () == VAR) ||        // it is an original variable 
00176        (Var (index) -> Multiplicity () > 0)) &&  // or its multiplicity is at least 1
00177       (Lb (index) < Ub (index) - COUENNE_EPS) && // in any case, bounds are not equal
00178 
00179       ((index != objind) // this is not the objective
00180        // or it is, so we use it for re-solving // TODO: check!
00181        || ((sense ==  1) && !(chg_bds [index].lower() & t_chg_bounds::EXACT))
00182        )) {
00183        //((sense==-1) && (psense == MAXIMIZE) && !(chg_bds [index].upper() & t_chg_bounds::EXACT)))) {
00184 
00185     bool isInt = (Var (index) -> isInteger ());
00186 
00187     objcoe [index] = sense;
00188 
00189     csi -> setObjective (objcoe);
00190     csi -> setObjSense (1); // minimization
00191 
00192     // TODO: Use something else!
00193 #if 0
00194     for (int iv=0; iv<csi->getNumCols (); iv++) {
00195       if (fabs (csi -> getColLower () [iv]) > 1e7) csi -> setColLower (iv, -1e14);
00196       if (fabs (csi -> getColUpper () [iv]) > 1e7) csi -> setColUpper (iv,  1e14);
00197     }
00198 #endif
00199 
00200     CouNumber &bound = 
00201       (sense == 1) ? 
00202       (Lb (index)) : 
00203       (Ub (index)); 
00204 
00205     // m{in,ax}imize xi on csi
00206 
00207     /*if (Jnlst()->ProduceOutput(J_MOREVECTOR, J_BOUNDTIGHTENING)) {
00208       Jnlst()->Printf(J_MOREVECTOR, J_BOUNDTIGHTENING,
00209                       "m%simizing x%d [%g,%g] %c= %g\n",
00210             (sense==1) ? "in" : "ax", index, Lb (index), Ub (index),
00211             (sense==1) ? '>'  : '<',  bound); fflush (stdout);
00212       if (Jnlst()->ProduceOutput(J_MOREMATRIX, J_BOUNDTIGHTENING)) {
00213         char fname [20];
00214         sprintf (fname, "m%s_w%03d_%03d", (sense == 1) ? "in" : "ax", index, iter);
00215         printf ("saving in %s\n", fname);
00216         //Jnlst()->Printf(J_MOREVECTOR, J_BOUNDTIGHTENING,"writing %s\n", fname);
00217         csi -> writeLp (fname);
00218       }
00219       }*/
00220 
00221     csi -> setWarmStart (warmstart);
00222     //csi -> continuousModel () -> setPerturbation (50);
00223 
00224     /* From ClpSimplex.cpp:
00225        
00226        If you are re-using the same matrix again and again then the
00227        setup time to do scaling may be significant.  Also you may not
00228        want to initialize all values or return all values (especially
00229        if infeasible).  While an auxiliary model exists it will be
00230        faster.  If options -1 then model is switched off.  Otherwise
00231        switched on with following options.
00232 
00233        1 - rhs is constant
00234        2 - bounds are constant
00235        4 - objective is constant
00236        8 - solution in by basis and no djs etc in
00237        16 - no duals out (but reduced costs)
00238        32 - no output if infeasible
00239     */
00240 
00241     //csi -> continuousModel () -> auxiliaryModel (1|8|16|32);
00242 
00243     //Jnlst () -> Printf (J_MATRIX, J_BOUNDTIGHTENING,
00244     //"obbt___ index = %d [sen=%d,bd=%g,int=%d]\n", 
00245     //index, sense, bound, isInt);
00246 
00247     if (obbt_updateBound (csi, sense, bound, isInt)) {
00248 
00249       if (knownOptimum) {
00250         if (sense == 1) {
00251           if (bound       > COUENNE_EPS + knownOptimum [index])
00252             Jnlst()->Printf(J_STRONGWARNING, J_BOUNDTIGHTENING,
00253                             "#### OBBT cuts optimum at x%d: lb = %g, opt = %g, new lb = %g\n", 
00254                             index, Lb (index), knownOptimum [index], bound);
00255         } else {
00256           if (bound       < -COUENNE_EPS + knownOptimum [index])
00257             Jnlst()->Printf(J_STRONGWARNING, J_BOUNDTIGHTENING,
00258                             "#### OBBT cuts optimum at x%d: ub = %g, opt = %g, new ub = %g\n", 
00259                             index, Ub (index), knownOptimum [index], bound);
00260         }
00261       }
00262 
00263       if (sense == 1) {if (bound > Lb (index)) Lb (index) = bound;}
00264       else            {if (bound < Ub (index)) Ub (index) = bound;}
00265 
00266       // more conservative, only change (and set CHANGED) if improve
00267 
00268       if (sense==1)
00269         if (csi -> getColLower () [index] < bound - COUENNE_EPS) {
00270           Jnlst()->Printf(J_DETAILED, J_BOUNDTIGHTENING,"l_%d: %g --> %g\n", 
00271                           index, csi -> getColLower () [index], bound);
00272           csi -> setColLower (index, bound); 
00273           chg_bds      [index].setLowerBits(t_chg_bounds::CHANGED | t_chg_bounds::EXACT);
00274         } else chg_bds [index].setLowerBits(t_chg_bounds::EXACT);
00275       else
00276         if (csi -> getColUpper () [index] > bound + COUENNE_EPS) {
00277           Jnlst()->Printf(J_DETAILED, J_BOUNDTIGHTENING,"u_%d: %g --> %g\n", 
00278                           index, csi -> getColUpper () [index], bound);
00279           csi -> setColUpper (index, bound); 
00280           chg_bds      [index].setUpperBits(t_chg_bounds::CHANGED | t_chg_bounds::EXACT);
00281         } else chg_bds [index].setUpperBits(t_chg_bounds::EXACT);
00282 
00283       /*
00284       if (sense==1) {csi -> setColLower (index, bound); chg_bds [index].lower |= CHANGED | EXACT;}
00285       else          {csi -> setColUpper (index, bound); chg_bds [index].upper |= CHANGED | EXACT;}
00286       */
00287 
00288       // check value and bounds of other variables
00289 
00290       const double *sol = csi -> getColSolution ();
00291 
00292       for (int j=0; j<ncols; j++) 
00293         if ((j!=index) && (j!=objind)) {
00294 
00295           if (sol [j] <= Lb (j) + COUENNE_EPS) chg_bds [j].setLowerBits(t_chg_bounds::EXACT);
00296           if (sol [j] >= Ub (j) - COUENNE_EPS) chg_bds [j].setUpperBits(t_chg_bounds::EXACT);
00297         }
00298 
00299 #if 0
00300       // re-check considering reduced costs (more expensive)
00301 
00302       CouNumber *redcost = NULL;
00303 
00304       // first, compute reduced cost when c = c - e_i, where e_i is
00305       // a vector with all zero except a one in position i. This
00306       // serves as a base to compute modified reduced cost below.
00307 
00308       for (int j=0; j<ncols; j++) 
00309         if ((j!=index) && (j!=objind)) {
00310 
00311           // fake a change in the objective function and compute
00312           // reduced cost. If resulting vector is all positive
00313           // (negative), this solution is also optimal for the
00314           // minimization (maximization) of x_j and the corresponding
00315           // chg_bds[j].lower (.upper) can be set to EXACT.
00316 
00317           if (!(chg_bds [j].lower & EXACT)) {
00318           }
00319 
00320           if (!(chg_bds [j].upper & EXACT)) {
00321           }
00322         }
00323 #endif  
00324 
00325       // re-apply bound tightening -- here WITHOUT reduced cost
00326       // (first argument =NULL is pointer to solverInterface) as csi
00327       // is not our problem
00328 
00329       Jnlst()->Printf(J_DETAILED, J_BOUNDTIGHTENING,
00330                       "  OBBT: x_%d: [%g, %g]\n", index, 
00331                       csi -> getColLower () [index], 
00332                       csi -> getColUpper () [index]);
00333 
00334       // should be faster
00335 
00336       //if (doFBBT_ && !(boundTightening (chg_bds, babInfo))) {
00337       if (doFBBT_ && !(btCore (chg_bds))) {
00338         Jnlst () -> Printf (J_DETAILED, J_BOUNDTIGHTENING,
00339                         "node is infeasible after post-OBBT tightening\n");
00340         return -1; // tell caller this is infeasible
00341       }
00342 
00343       nImprov++;
00344     }
00345 
00346     // if we solved the problem on the objective function's
00347     // auxiliary variable (that is, we re-solved the extended
00348     // problem), it is worth updating the current point (it will be
00349     // used later to generate new cuts).
00350 
00351     // TODO: is it, really? And shouldn't we check the opt sense too?
00352     /*
00353     if ((objind == index) && (csi -> isProvenOptimal ()) && (sense == 1))
00354       update (csi -> getColSolution (), NULL, NULL);
00355     */
00356     // restore null obj fun
00357     objcoe [index] = 0;
00358   }
00359 
00360   if (nImprov && jnlst_ -> ProduceOutput (J_ITERSUMMARY, J_BOUNDTIGHTENING)) {
00361     Jnlst () -> Printf (J_ITERSUMMARY, J_BOUNDTIGHTENING, "OBBT: tightened ", nImprov);
00362     Var (index) -> print ();
00363     Jnlst () -> Printf (J_ITERSUMMARY, J_BOUNDTIGHTENING, "\n");
00364   }
00365 
00366   return nImprov;
00367 }

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