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

Go to the documentation of this file.
00001 /* $Id: aggressiveBT.cpp 752 2011-08-08 03:45:07Z pbelotti $
00002  *
00003  * Name:    aggressiveBT.cpp
00004  * Author:  Pietro Belotti
00005  * Purpose: probing -- fake bounds in variables to exclude parts of
00006  *          the solution space through fathoming on
00007  *          bounds/infeasibility
00008  *
00009  * (C) Carnegie-Mellon University, 2007-11.
00010  * This file is licensed under the Eclipse Public License (EPL)
00011  */
00012 
00013 #include "CouenneCutGenerator.hpp"
00014 
00015 #include "BonTNLPSolver.hpp"
00016 #include "BonNlpHeuristic.hpp"
00017 #include "CoinHelperFunctions.hpp"
00018 #include "BonCouenneInfo.hpp"
00019 
00020 #include "CouenneProblem.hpp"
00021 #include "CouenneExprVar.hpp"
00022 #include "CouenneProblemElem.hpp"
00023 
00024 using namespace Ipopt;
00025 using namespace Couenne;
00026 
00027 namespace Bonmin {
00028   class OsiTMINLPInterface;
00029   class BabInfo;
00030   class TNLPSolver;
00031 }
00032 
00033 #define MAX_ABT_ITER           4  // max # aggressive BT iterations
00034 #define THRES_ABT_IMPROVED     0  // only continue ABT if at least these bounds have improved
00035 #define THRES_ABT_ORIG       100  // only do ABT on auxiliaries if they are less originals than this 
00036 
00037 static double distanceToBound (register int n, 
00038                                register const double* xOrig,
00039                                register const double* lower, 
00040                                register const double* upper,
00041                                register double cutoff_distance) { // stop if distance is above this
00042 
00043   register double Xdist = 0.;
00044 
00045   for (; n--; ++upper, ++xOrig) {
00046 
00047     register CouNumber diff = *lower++ - *xOrig;
00048 
00049     if      ( diff                    > 0.) {if ((Xdist += diff) > cutoff_distance) break;}
00050     else if ((diff = *xOrig - *upper) > 0.) {if ((Xdist += diff) > cutoff_distance) break;}
00051   }
00052 
00053   return Xdist;
00054 }
00055 
00056 
00057 // Probing: for each variable, fake new bounds [l,b] or [b,u], with
00058 // given b, and apply bound tightening. If the interval is fathomed on
00059 // bounds or on infeasibility, the complementary bound interval is a
00060 // valid tightening.
00061 
00062 bool CouenneProblem::aggressiveBT (Bonmin::OsiTMINLPInterface *nlp,
00063                                    t_chg_bounds *chg_bds, 
00064                                    const CglTreeInfo &info,
00065                                    Bonmin::BabInfo * babInfo) const {
00066 
00067   if (info.level <= 0 && !(info.inTree))  {
00068     jnlst_ -> Printf (J_ERROR, J_COUENNE, "Probing: ");
00069     fflush (stdout);
00070   }
00071 
00072   CouenneInfo* couInfo =
00073     dynamic_cast <CouenneInfo *> (babInfo);
00074 
00075   int  ncols  = nVars ();
00076   bool retval = false;
00077 
00078   CouNumber
00079     *olb = CoinCopyOfArray (Lb (), ncols),
00080     *oub = CoinCopyOfArray (Ub (), ncols);
00081 
00082   // Find the solution that is closest to the current bounds
00083   // TODO: Also check obj value
00084   SmartPtr<const CouenneInfo::NlpSolution> closestSol;
00085   double dist = 1.e50;
00086 
00087   if (couInfo) {
00088 
00089     const std::list<SmartPtr<const CouenneInfo::NlpSolution> >& solList =
00090       couInfo->NlpSolutions();
00091 
00092     for (std::list<SmartPtr<const CouenneInfo::NlpSolution> >::const_iterator 
00093            i = solList.begin();
00094          i  != solList.end(); ++i) {
00095 
00096       assert (nOrigVars_ - ndefined_ == (*i)->nVars());
00097 
00098       const double thisDist = distanceToBound (nOrigVars_ - ndefined_, (*i)->solution(), olb, oub, dist);
00099 
00100       if (thisDist < dist) {
00101         closestSol = *i;
00102         dist = thisDist;
00103       }
00104     }
00105   }
00106 
00107   jnlst_ -> Printf (J_VECTOR, J_BOUNDTIGHTENING, "best dist = %e\n", dist);
00108 
00109   bool haveNLPsol = false;
00110 
00111   // If this solution is not sufficiently inside the bounds, we solve the NLP now
00112   if (dist > 0.1) { // TODO: Find tolerance
00113 
00114     // find integer initial point /////////////////////////
00115 
00116     int nvars = nVars ();
00117 
00118     double *lower = new double [nvars];
00119     double *upper = new double [nvars];
00120 
00121     CoinFillN (lower, nvars, -COUENNE_INFINITY);
00122     CoinFillN (upper, nvars,  COUENNE_INFINITY);
00123 
00124     CoinCopyN (nlp -> getColLower (), nOrigVars_ - ndefined_, lower);
00125     CoinCopyN (nlp -> getColUpper (), nOrigVars_ - ndefined_, upper);
00126 
00127     double *Y = new double [nvars];
00128 
00129     CoinZeroN (Y,    nvars);
00130     CoinCopyN (X (), nOrigVars_ - ndefined_, Y);
00131 
00132     if (getIntegerCandidate (nlp -> getColSolution (), Y, lower, upper) < 0) {
00133 
00134       jnlst_ -> Printf (J_ITERSUMMARY, J_BOUNDTIGHTENING, "TODO: find NLP point in ABT failed\n");
00135       retval = true;
00136 
00137     } else {
00138 
00140 
00141       nlp -> setColLower    (lower);
00142       nlp -> setColUpper    (upper);
00143       nlp -> setColSolution (Y);
00144 
00145       try {
00146 
00147         nlp -> options () -> SetNumericValue ("max_cpu_time", CoinMax (0., getMaxCpuTime () - CoinCpuTime ()));
00148         nlp -> initialSolve ();
00149       }
00150 
00151       catch (Bonmin::TNLPSolver::UnsolvedError *E) {}
00152     
00153       delete [] Y;
00154       delete [] lower;
00155       delete [] upper;
00156 
00157       if (nlp -> isProvenOptimal ()) {
00158 
00159         if (couInfo) {
00160           closestSol = new CouenneInfo::NlpSolution 
00161             (nOrigVars_ - ndefined_, nlp->getColSolution(), nlp->getObjValue());
00162           couInfo->addSolution(closestSol);
00163           dist = 0.;
00164           haveNLPsol = true;      
00165         }
00166       }
00167       else {
00168         jnlst_ -> Printf(J_ITERSUMMARY, J_BOUNDTIGHTENING, "TODO: NLP solve in ABT failed\n");
00169         retval = true;
00170       }
00171     }
00172   }
00173 
00174   int nTotImproved = 0;
00175 
00176   // Probing can also run on an LP point.
00177 
00178   //if (true || (retval && (dist < 1e10))) {
00179 
00180   {
00181     retval = true;
00182 
00183     // if the NLP solver succeeded, X is now the NLP solution, but in
00184     // a low-dimensional space. We have to get the corresponding point
00185     // in higher dimensional space through getAuxs()
00186 
00187     double *X = NULL;
00188 
00189     if (haveNLPsol) {
00190 
00191       X = new double [ncols];
00192       CoinZeroN (X, nVars ());
00193       CoinCopyN (closestSol -> solution(), nOrigVars_ - ndefined_, X);
00194       getAuxs (X);
00195     } else X = domain () -> x ();
00196 
00197     // create a new, fictitious, bound bookkeeping structure
00198     t_chg_bounds *f_chg = new t_chg_bounds [ncols];
00199 
00200     if (Jnlst()->ProduceOutput(J_ITERSUMMARY, J_BOUNDTIGHTENING)) {
00201       //    CouNumber cutoff = getCutOff ();
00202       int       objind = Obj (0) -> Body  () -> Index ();
00203       for (int i=0; i<nOrigVars_ - ndefined_; i++)
00204         Jnlst()->Printf(J_MOREVECTOR, J_BOUNDTIGHTENING,
00205                         "   %2d %+20g [%+20g %+20g]\n",
00206                         i, X [i], Lb (i), Ub (i));
00207       Jnlst()->Printf(J_ITERSUMMARY, J_BOUNDTIGHTENING,
00208                       "-------------\nAggressive BT. Current bound = %g, cutoff = %g, %d vars\n", 
00209                       Lb (objind), getCutOff (), ncols);
00210     }
00211 
00212     int improved, second, iter = 0;
00213 
00214     // Repeatedly fake tightening bounds on both sides of every variable
00215     // to concentrate around current NLP point.
00216     //
00217     // MAX_ABT_ITER is the maximum # of outer cycles. Each call to
00218     // fake_tighten in turn has an iterative algorithm for a
00219     // derivative-free, uni-dimensional optimization problem on a
00220     // monotone function.
00221 
00222     bool maxTimeReached = false;
00223 
00224     do {
00225 
00226       improved = 0;
00227 
00228       // scan all variables
00229       for (int i=0; i<ncols; i++) {
00230 
00231         if (CoinCpuTime () > maxCpuTime_) {
00232           maxTimeReached = true; // avoids getrusage after loop...
00233           break;
00234         }
00235 
00236         int index = evalOrder (i);
00237 
00238         if ((Var (index) -> Multiplicity () <= 0) ||
00239             (fabs (Lb (index) - Ub (index)) < COUENNE_EPS) ||
00240             ((nOrigVars_ >= THRES_ABT_ORIG) &&
00241              (index >= nOrigVars_)))
00242           continue;
00243 
00244         // AW: We only want to do the loop that temporarily changes
00245         // bounds around the NLP solution only for those points from the
00246         // NLP solution (no auxiliary vars)?
00247 
00248         // PBe: if we do want that, index should be initialized as i, as
00249         // evalOrder gives a variable index out of an array index.
00250 
00251         // PBe: That makes a lot of sense when problems are really
00252         // big. Instances arki000[24].nl spend a lot of time here
00253 
00254         { //if ((nOrigVars_ < THRES_ABT_ORIG) || (index < nOrigVars_)) {
00255 
00256           // if (index == objind) continue; // don't do it on objective function
00257 
00258           improved = 0;
00259 
00260           if ((variables_ [index] -> sign () != expression::AUX_GEQ) &&
00261               (X [index] >= Lb (index) + COUENNE_EPS)) {
00262 
00263             Jnlst()->Printf(J_DETAILED, J_BOUNDTIGHTENING,
00264                             "------------- tighten left %d-th = x%d @%g [%g,%g]\n", 
00265                             i, index, X [index], olb [index], oub [index]);
00266 
00267             // tighten on left
00268             if ((improved = fake_tighten (0, index, X, olb, oub, chg_bds, f_chg)) < 0) {
00269 
00270               retval = false;
00271               break;
00272             }
00273           }
00274 
00275           second = 0;
00276 
00277           if (retval && (variables_ [index] -> sign () != expression::AUX_LEQ) &&
00278               (X [index] <= Ub (index) - COUENNE_EPS)) {
00279 
00280             Jnlst()->Printf(J_DETAILED, J_BOUNDTIGHTENING,
00281                             "------------- tighten right %d-th = x%d @%g [%g,%g]\n", 
00282                             i, index, X [index], olb [index], oub [index]);
00283 
00284             // tighten on right
00285             if ((second = fake_tighten (1, index, X, olb, oub, chg_bds, f_chg) < 0)) {
00286               retval = false;
00287               break;
00288             }
00289           }
00290 
00291           improved += second;
00292           nTotImproved += improved;
00293         }
00294       }
00295 
00296     } while (!maxTimeReached && retval && (improved > THRES_ABT_IMPROVED) && (iter++ < MAX_ABT_ITER));
00297 
00298     // store new valid bounds, or restore old ones if none changed
00299     CoinCopyN (olb, ncols, Lb ());
00300     CoinCopyN (oub, ncols, Ub ());
00301 
00302     if (Jnlst()->ProduceOutput(J_ITERSUMMARY, J_BOUNDTIGHTENING)) {
00303 
00304       Jnlst()->Printf(J_ITERSUMMARY, J_BOUNDTIGHTENING,"------------------\n");
00305 
00306       if (!retval) Jnlst()->Printf(J_ITERSUMMARY, J_BOUNDTIGHTENING,
00307                                    "Couenne infeasible node from aggressive BT\n");
00308 
00309       int objind = Obj (0) -> Body  () -> Index ();
00310 
00311       Jnlst()->Printf(J_ITERSUMMARY, J_BOUNDTIGHTENING,
00312                       "-------------\ndone Aggressive BT. Current bound = %g, cutoff = %g, %d vars\n", 
00313                       Lb (objind), getCutOff (), ncols);
00314 
00315       if (Jnlst()->ProduceOutput(J_DETAILED, J_BOUNDTIGHTENING))
00316         for (int i=0; i<nOrigVars_; i++)
00317           printf("   x%02d [%+20g %+20g]  | %+20g\n",
00318                  i, Lb (i), Ub (i), X [i]);
00319 
00320       if (Jnlst()->ProduceOutput(J_MOREDETAILED, J_BOUNDTIGHTENING))
00321         for (int i=nOrigVars_; i<ncols; i++)
00322           printf ("   w%02d [%+20g %+20g]  | %+20g\n", i, Lb (i), Ub (i), X [i]);
00323     }
00324 
00325     if (haveNLPsol)
00326       delete [] X;
00327     delete [] f_chg;    
00328   }
00329   // else
00330   // if ((dist > 1e10) && !retval)
00331   //   jnlst_ -> Printf(J_ITERSUMMARY, J_BOUNDTIGHTENING, "TODO: Don't have point for ABT\n");
00332 
00333   delete [] olb;
00334   delete [] oub;
00335 
00336   if (info.level <= 0 && !(info.inTree))  {
00337     if (!retval) jnlst_ -> Printf (J_ERROR, J_COUENNE, "infeasible\n");
00338     else         jnlst_ -> Printf (J_ERROR, J_COUENNE, "%d improved bounds\n", nTotImproved);
00339   }
00340 
00341   return retval; // && btCore (psi, cs, chg_bds, babInfo, true); // !!!
00342   //return retval && btCore (psi, cs, chg_bds, babInfo, true);
00343 }

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