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

Go to the documentation of this file.
00001 /* $Id: boundTightening.cpp 738 2011-07-10 17:38:58Z pbelotti $
00002  *
00003  * Name:    boundTightening.cpp
00004  * Author:  Pietro Belotti
00005  * Purpose: tighten bounds prior to convexification cuts
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 #include "CouenneProblem.hpp"
00013 #include "CouenneExprVar.hpp"
00014 #include "CouenneProblemElem.hpp"
00015 #include "BonBabInfos.hpp"
00016 #include "BonCbc.hpp"
00017 
00018 // max # bound tightening iterations
00019 #define THRES_IMPROVED 0
00020 
00021 using namespace Couenne;
00022 
00023 // core of the bound tightening procedure
00024 
00025 bool CouenneProblem::btCore (t_chg_bounds *chg_bds) const {
00026 
00027   if (!chg_bds) {
00028 
00029     chg_bds = new t_chg_bounds [nVars ()];
00030 
00031     for (int i=0; i < nVars (); i++) 
00032 
00033     if (Var (i) -> Multiplicity () > 0) {
00034 
00035       chg_bds [i].setLower (t_chg_bounds::CHANGED);
00036       chg_bds [i].setUpper (t_chg_bounds::CHANGED);
00037     }
00038   }
00039 
00040   // Bound propagation and implied bounds ////////////////////
00041 
00042   int   ntightened = 0,
00043       nbwtightened = 0,
00044       niter = 0;
00045 
00046   bool first = true;
00047 
00048   installCutOff ();
00049 
00050   // check if bt cuts the optimal solution -- now and after bound tightening
00051   bool contains_optimum = false;
00052 
00053   if (optimum_ != NULL) {
00054     contains_optimum = true;
00055     for (int i=0; i < nVars (); i++)
00056       if ((optimum_ [i] < Lb (i) * (1 - COUENNE_EPS) - COUENNE_EPS) ||
00057           (optimum_ [i] > Ub (i) * (1 + COUENNE_EPS) + COUENNE_EPS)) {
00058         /*printf ("won't check BT: %d [%g,%g] (%g) -- %g\n", 
00059                 i, Lb (i), Ub (i), optimum_ [i],
00060                 CoinMax (- optimum_ [i] + (Lb (i) * (1 - COUENNE_EPS) - COUENNE_EPS),
00061                 optimum_ [i] - (Ub (i) * (1 + COUENNE_EPS) + COUENNE_EPS)));*/
00062         contains_optimum = false;
00063         break;
00064       }
00065   }
00066 
00067   if (max_fbbt_iter_)  do {
00068 
00069     if (CoinCpuTime () > maxCpuTime_)
00070       break;
00071 
00072     // propagate bounds to auxiliary variables
00073 
00074     //    if ((nbwtightened > 0) || (ntightened > 0))
00075     ntightened = ((nbwtightened > 0) || first) ? 
00076       tightenBounds (chg_bds) : 0;
00077 
00078     // implied bounds. Call also at the beginning, as some common
00079     // expression may have non-propagated bounds
00080 
00081     // if last call didn't signal infeasibility
00082     nbwtightened = ((ntightened > 0) || ((ntightened==0) && first)) ? impliedBounds (chg_bds) : 0;
00083 
00084     if (first)
00085       first = false;
00086 
00087     if ((ntightened < 0) || (nbwtightened < 0)) {
00088       Jnlst () -> Printf (Ipopt::J_ITERSUMMARY, J_BOUNDTIGHTENING, "infeasible BT\n");
00089       return false;
00090     }
00091 
00092     // continue if EITHER procedures gave (positive) results, as
00093     // expression structure is not a tree.
00094 
00095     if (contains_optimum) {
00096       for (int i=0; i<nVars (); i++)
00097         if ((optimum_[i] < Lb(i) - COUENNE_EPS * (1. + CoinMin (fabs(optimum_ [i]), fabs (Lb(i))))) ||
00098             (optimum_[i] > Ub(i) + COUENNE_EPS * (1. + CoinMin (fabs(optimum_ [i]), fabs (Ub(i)))))) {
00099           printf ("bound tightening CUTS optimum: x%d [%e,%e] val = %e, violation = %e\n", 
00100                   i, Lb (i), Ub (i), optimum_ [i],
00101                   CoinMax (- optimum_ [i] + Lb (i),
00102                              optimum_ [i] - Ub (i)));
00103           contains_optimum = false;
00104         }
00105     }
00106 
00107     // double width = 0.;
00108 
00109     // int 
00110     //   ninf  = 0,
00111     //   ndinf = 0;
00112 
00113     // for (int i=nOrigVars (); i--;)
00114 
00115     //   if ((Lb (i) < -COUENNE_INFINITY/1e3) && 
00116     //    (Ub (i) >  COUENNE_INFINITY/1e3)) ndinf++;
00117     //   else if ((Lb (i) < -COUENNE_INFINITY/1e3) ||
00118     //         (Ub (i) >  COUENNE_INFINITY/1e3)) ninf++;
00119     //   else width += Ub (i) - Lb (i);
00120 
00121     // printf ("pass %5d: %5d fwd, %5d bwd, %5d inf, %5d double inf, width: %g\n", 
00122     //      niter, ntightened, nbwtightened, ninf, ndinf, width);
00123 
00124   } while (((ntightened > 0) || (nbwtightened > 0)) && 
00125            (ntightened + nbwtightened > THRES_IMPROVED) &&
00126            ((max_fbbt_iter_ < 0) || (niter++ < max_fbbt_iter_)));
00127 
00128   fbbtReachedIterLimit_ = ((max_fbbt_iter_ > 0) && (niter >= max_fbbt_iter_));
00129 
00130   // TODO: limit should depend on number of constraints, that is,
00131   // bound transmission should be documented and the cycle should stop
00132   // as soon as no new constraint subgraph has benefited from bound
00133   // transmission. 
00134   //
00135   // BT should be more of a graph spanning procedure that moves from
00136   // one vertex to another when either tightening procedure has given
00137   // some result. This should save some time especially
00138   // w.r.t. applying implied bounds to ALL expressions just because
00139   // one single propagation was found.
00140 
00141   for (int i = 0, j = nVars (); j--; i++) 
00142     if (Var (i) -> Multiplicity () > 0) {
00143 
00144       // final test 
00145       if ((Lb (i) > Ub (i) + COUENNE_BOUND_PREC * (1 + CoinMin (fabs (Lb (i)), fabs (Ub (i))))) || 
00146           (Ub (i) < - MAX_BOUND) ||
00147           (Lb (i) >   MAX_BOUND)) {
00148 
00149         Jnlst () -> Printf (Ipopt::J_ITERSUMMARY, J_BOUNDTIGHTENING, "final test: infeasible BT\n");
00150         return false;
00151       }
00152 
00153       // sanity check. Ipopt gives an exception when Lb (i) is above Ub (i)
00154       if (Lb (i) > Ub (i)) {
00155         CouNumber swap = Lb (i);
00156         Lb (i) = Ub (i);
00157         Ub (i) = swap;
00158       }
00159     }
00160 
00161   return true;
00162 }
00163 
00164 
00167 
00168 bool CouenneProblem::boundTightening (t_chg_bounds *chg_bds, 
00169                                       Bonmin::BabInfo * babInfo) const {
00170 
00171   //  double startTime = CoinCpuTime ();
00172   //
00173   // #define SMALL_BOUND 1e4
00174   //   for (int i=nOrigVars (); i--;) {
00175   //     if (Lb (i) < -SMALL_BOUND) Lb (i) = -SMALL_BOUND;
00176   //     if (Ub (i) >  SMALL_BOUND) Ub (i) =  SMALL_BOUND;
00177   //   } 
00178 
00179   Jnlst () -> Printf (Ipopt::J_ITERSUMMARY, J_BOUNDTIGHTENING,
00180                       "Feasibility-based Bound Tightening\n");
00181 
00182   int objInd = Obj (0) -> Body () -> Index ();
00183 
00185 
00186   if ((objInd >= 0) && babInfo && (babInfo -> babPtr ())) {
00187 
00188     CouNumber UB      = babInfo  -> babPtr () -> model (). getObjValue(),
00189               LB      = babInfo  -> babPtr () -> model (). getBestPossibleObjValue (),
00190               primal0 = Ub (objInd), 
00191               dual0   = Lb (objInd);
00192 
00193     // Bonmin assumes minimization. Hence, primal (dual) is an UPPER
00194     // (LOWER) bound.
00195     
00196     if ((UB < COUENNE_INFINITY) && 
00197         (UB < primal0 - COUENNE_EPS)) { // update primal bound (MIP)
00198 
00199       Ub (objInd) = UB;
00200       chg_bds [objInd].setUpper(t_chg_bounds::CHANGED);
00201     }
00202 
00203     if ((LB > - COUENNE_INFINITY) && 
00204         (LB > dual0 + COUENNE_EPS)) { // update dual bound
00205       Lb (objInd) = LB;
00206       chg_bds [objInd].setLower(t_chg_bounds::CHANGED);
00207     }
00208   }
00209 
00210   return btCore (chg_bds);
00211 
00212   //printf ("Total cpu time = %e\n", CoinCpuTime () - startTime);
00213   //exit (-1);
00214   //return retval;
00215 }
00216 
00217 
00219 int CouenneProblem::redCostBT (const OsiSolverInterface *psi,
00220                                t_chg_bounds *chg_bds) const {
00221   
00222   int 
00223     nchanges = 0,
00224     objind   = Obj (0) -> Body () -> Index ();
00225 
00226   assert (objind >= 0);
00227 
00228   CouNumber
00229     UB = getCutOff (), //babInfo -> babPtr () -> model (). getObjValue(),
00230     LB = Lb (objind);  //babInfo -> babPtr () -> model (). getBestPossibleObjValue ();
00231 
00233 
00234   if ((LB > -COUENNE_INFINITY) && 
00235       (UB <  COUENNE_INFINITY)) {
00236 
00237     const double 
00238       *X  = psi -> getColSolution (),
00239       *L  = psi -> getColLower    (),
00240       *U  = psi -> getColUpper    (),
00241       *RC = psi -> getReducedCost ();
00242 
00243     if (jnlst_ -> ProduceOutput (Ipopt::J_MATRIX, J_BOUNDTIGHTENING)) {
00244       printf ("REDUCED COST BT (LB=%g, UB=%g):\n", LB, UB);
00245       for (int i=0, j=0; i < nVars (); i++) {
00246         if (Var (i) -> Multiplicity () <= 0)
00247           continue;
00248         printf ("%3d %7e [%7e %7e] c %7e ", i, X [i], L [i], U [i], RC [i]);
00249         if (!(++j % 3))
00250           printf ("\n");
00251       }
00252       printf ("-----------\n");
00253     }
00254 
00255     int ncols = psi -> getNumCols ();
00256 
00257     for (int i=0; i<ncols; i++)
00258       if ((i != objind) && 
00259           (Var (i) -> Multiplicity () > 0)) {
00260 
00261         CouNumber
00262           x  = X  [i],
00263           l  = L  [i],
00264           u  = U  [i],
00265           rc = RC [i];
00266 
00267 #define CLOSE_TO_BOUNDS 1.e-15
00268 
00269         if ((fabs (rc)  < CLOSE_TO_BOUNDS) || 
00270             (fabs (l-u) < CLOSE_TO_BOUNDS)) // no need to check
00271           continue;
00272 
00273         bool isInt = Var (i) -> isInteger ();
00274 
00275         if ((rc >= 0.) && 
00276             (fabs (x-l) <= CLOSE_TO_BOUNDS)) {
00277 
00278           if (LB + (u-l)*rc > UB) {
00279 
00280             CouNumber newUb = l + (UB-LB) / rc; // which is surely < u
00281             newUb = !isInt ? newUb : floor (newUb + COUENNE_EPS);
00282 
00283             if (newUb < Ub (i)) {
00284 
00285               Ub (i) = newUb;
00286 
00287               nchanges++;
00288               chg_bds [i].setLower (t_chg_bounds::CHANGED);
00289             }
00290           }
00291 
00292         } else if ((rc <= 0.) && 
00293                    (fabs (x-u) <= CLOSE_TO_BOUNDS)) {
00294 
00295           if (LB - (u-l) * rc > UB) {
00296 
00297             CouNumber newLb = u + (UB-LB) / rc; // recall rc < 0 here
00298 
00299             newLb = !isInt ? newLb : ceil (newLb - COUENNE_EPS);
00300 
00301             if (newLb > Lb (i)) {
00302 
00303               Lb (i) = newLb;
00304 
00305               nchanges++;
00306               chg_bds [i].setUpper (t_chg_bounds::CHANGED);
00307             }
00308           }
00309         }
00310       }
00311 
00312     if (jnlst_ -> ProduceOutput (Ipopt::J_MATRIX, J_BOUNDTIGHTENING)) {
00313       printf ("AFTER reduced cost bt:\n");
00314       for (int i=0, j=0; i < nVars (); ++i) {
00315         if (Var (i) -> Multiplicity () <= 0)
00316           continue;
00317         printf ("%3d [%7e %7e] ", i, Lb (i), Ub (i));
00318         if (!(++j % 4))
00319           printf ("\n");
00320       }
00321       printf ("-----------\n");
00322     }
00323   }
00324 
00325   return nchanges;
00326 }

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