/home/coin/SVN-release/OS-2.1.0/Couenne/src/convex/generateCuts.cpp

Go to the documentation of this file.
00001 /* $Id: generateCuts.cpp 289 2010-02-05 09:25:30Z stefan $
00002  *
00003  * Name:    generateCuts.cpp
00004  * Author:  Pietro Belotti
00005  * Purpose: the generateCuts() method of the convexification class CouenneCutGenerator
00006  *
00007  * (C) Carnegie-Mellon University, 2006-08.
00008  * This file is licensed under the Common Public License (CPL)
00009  */
00010 
00011 #include "BonAuxInfos.hpp"
00012 #include "CglCutGenerator.hpp"
00013 
00014 #include "CouenneCutGenerator.hpp"
00015 #include "CouenneProblem.hpp"
00016 
00017 #define Couenne_large_bound2 9.99e12
00018 
00019 // checks bad cuts against known optimum
00020 bool isOptimumCut (const CouNumber *opt, OsiCuts &cs, CouenneProblem *p);
00021 
00022 // set and lift bound for auxiliary variable associated with objective
00023 // function
00024 void fictitiousBound (OsiCuts &cs,
00025                       CouenneProblem *p, 
00026                       bool action) {     // true before convexifying, false afterwards
00027 
00028   // fictitious bound for initial unbounded lp relaxations
00029   const CouNumber large_tol = (Couenne_large_bound2 / 1e6);
00030 
00031   // set trivial dual bound to objective function, if there is none
00032 
00033   int ind_obj = p -> Obj (0) -> Body () -> Index ();
00034 
00035   if (ind_obj < 0) return;
00036 
00037   // we have a single variable objective function
00038 
00039   //int sense = -1; //(p -> Obj (0) -> Sense () == MINIMIZE) ? -1 : 1;
00040 
00041   if (action)
00042     //if (sense<0) 
00043       {if (p -> Lb (ind_obj) < - Couenne_large_bound2) p -> Lb (ind_obj) = - Couenne_large_bound2;}
00044   //else         {if (p -> Ub (ind_obj) >   large_bound2) p -> Ub (ind_obj) =   large_bound2;}
00045   else
00046     //if (sense>0) {if (fabs (p->Ub(ind_obj)-large_bound2)<large_tol) p->Ub(ind_obj)=COUENNE_INFINITY;}
00047     //else         
00048       {if (fabs (p->Lb(ind_obj)+Couenne_large_bound2)<large_tol) p->Lb(ind_obj) =-COUENNE_INFINITY;}
00049 }
00050 
00051 
00052 // translate changed bound sparse array into a dense one
00053 void sparse2dense (int ncols, t_chg_bounds *chg_bds, int *&changed, int &nchanged) {
00054 
00055   // convert sparse chg_bds in something handier
00056 
00057   changed  = (int *) realloc (changed, ncols * sizeof (int));
00058   nchanged = 0;
00059 
00060   for (register int i=ncols, j=0; i--; j++, chg_bds++)
00061     if (chg_bds -> lower() != t_chg_bounds::UNCHANGED ||
00062         chg_bds -> upper() != t_chg_bounds::UNCHANGED ) {
00063       *changed++ = j;
00064       nchanged++;
00065     }
00066 
00067   changed -= nchanged;
00068   //changed = (int *) realloc (changed, nchanged * sizeof (int));
00069 }
00070 
00071 
00073 void updateBranchInfo (const OsiSolverInterface &si, CouenneProblem *p, 
00074                        t_chg_bounds *chg, const CglTreeInfo &info);
00075 
00077 
00078 void CouenneCutGenerator::generateCuts (const OsiSolverInterface &si,
00079                                         OsiCuts &cs, 
00080                                         const CglTreeInfo info) const {
00081   const int infeasible = 1;
00082 
00083   int nInitCuts = cs.sizeRowCuts ();
00084 
00085   CouNumber
00086     *&realOpt = problem_ -> bestSol (),
00087     *saveOptimum = realOpt;
00088 
00089   if (!firstcall_ && realOpt) { 
00090 
00091     // have a debug optimal solution. Check if current bounds
00092     // contain it, otherwise pretend it does not exist
00093 
00094     CouNumber *opt = realOpt;
00095 
00096     const CouNumber 
00097       *sol = si.getColSolution (),
00098       *lb  = si.getColLower (),
00099       *ub  = si.getColUpper ();
00100 
00101     int objind = problem_ -> Obj (0) -> Body () -> Index ();
00102 
00103     for (int j=0, i=problem_ -> nVars (); i--; j++, opt++, lb++, ub++)
00104       if ((j != objind) && 
00105           ((*opt < *lb - COUENNE_EPS * (1 + CoinMin (fabs (*opt), fabs (*lb)))) || 
00106            (*opt > *ub + COUENNE_EPS * (1 + CoinMin (fabs (*opt), fabs (*ub)))))) {
00107         
00108         jnlst_ -> Printf (J_VECTOR, J_CONVEXIFYING, 
00109                           "out of bounds, ignore x%d = %g [%g,%g] opt = %g\n", 
00110                           problem_ -> nVars () - i - 1, *sol, *lb, *ub, *opt);
00111 
00112         // optimal point is not in current bounding box,
00113         // pretend realOpt is NULL until we return from this procedure
00114         realOpt = NULL;
00115         break;
00116       }
00117   }
00118 
00119   /*static int count = 0;
00120   char fname [20];
00121   sprintf (fname, "relax_%d", count++);
00122   si.writeLp (fname);
00123   printf ("writing %s\n", fname);*/
00124 
00125   jnlst_ -> Printf (J_DETAILED, J_CONVEXIFYING,
00126                     "generateCuts: level = %d, pass = %d, intree = %d\n",
00127                     info.level, info.pass, info.inTree);
00128 
00129   Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (si.getAuxiliaryInfo ());
00130 
00131   if (babInfo)
00132     babInfo -> setFeasibleNode ();
00133 
00134   double now   = CoinCpuTime ();
00135   int    ncols = problem_ -> nVars ();
00136 
00137   // This vector contains variables whose bounds have changed due to
00138   // branching, reduced cost fixing, or bound tightening below. To be
00139   // used with malloc/realloc/free
00140 
00141   t_chg_bounds *chg_bds = new t_chg_bounds [ncols];
00142 
00143   /*for (int i=0; i < ncols; i++) 
00144     if (problem_ -> Var (i) -> Multiplicity () <= 0) {
00145       chg_bds [i].setLower (t_chg_bounds::UNCHANGED);
00146       chg_bds [i].setUpper (t_chg_bounds::UNCHANGED);
00147       }*/
00148 
00149   problem_ -> installCutOff (); // install upper bound
00150 
00151   if (firstcall_) {
00152 
00153     // First convexification //////////////////////////////////////
00154 
00155     // OsiSolverInterface is empty yet, no information can be obtained
00156     // on variables or bounds -- and none is needed since our
00157     // constructor populated *problem_ with variables and bounds. We
00158     // only need to update the auxiliary variables and bounds with
00159     // their current value.
00160 
00161     for (int i=0; i < ncols; i++) 
00162       if (problem_ -> Var (i) -> Multiplicity () > 0) {
00163         chg_bds [i].setLower (t_chg_bounds::CHANGED);
00164         chg_bds [i].setUpper (t_chg_bounds::CHANGED);
00165       }
00166 
00167     // start with FBBT, should take advantage of cutoff found by NLP
00168     // run AFTER initial FBBT...
00169     if (problem_ -> doFBBT () &&
00170         (! (problem_ -> boundTightening (chg_bds, babInfo))))
00171           jnlst_ -> Printf (J_STRONGWARNING, J_CONVEXIFYING,
00172             "Couenne: WARNING, first convexification is infeasible\n");
00173 
00174     // For each auxiliary variable replacing the original (nonlinear)
00175     // constraints, check if corresponding bounds are violated, and
00176     // add cut to cs
00177 
00178     int nnlc = problem_ -> nCons ();
00179 
00180     for (int i=0; i<nnlc; i++) {
00181 
00182       // for each constraint
00183       CouenneConstraint *con = problem_ -> Con (i);
00184 
00185       // (which has an aux as its body)
00186       int index = con -> Body () -> Index ();
00187 
00188       if ((index >= 0) && 
00189           ((con -> Body () -> Type () == AUX) ||
00190            (con -> Body () -> Type () == VAR))) {
00191 
00192         // get the auxiliary that is at the lhs
00193         exprVar *conaux = problem_ -> Var (index);
00194 
00195         if (conaux &&
00196             (conaux -> Type () == AUX) &&
00197             (conaux -> Image ()) && 
00198             (conaux -> Image () -> Linearity () <= LINEAR)) {
00199 
00200           // reduce density of problem by adding w >= l rather than
00201           // ax + b >= l for any linear auxiliary defined as w := ax+b
00202 
00203           double 
00204             lb = (*(con -> Lb ())) (), 
00205             ub = (*(con -> Ub ())) ();
00206 
00207           OsiColCut newBound;
00208           if (lb > -COUENNE_INFINITY) newBound.setLbs (1, &index, &lb);
00209           if (ub <  COUENNE_INFINITY) newBound.setUbs (1, &index, &ub);
00210 
00211           cs.insert (newBound);
00212 
00213           // the auxiliary w of constraint w <= b is associated with a
00214           // linear expression w = ax: add constraint ax <= b
00215           /*conaux -> Image () -> generateCuts (conaux, si, cs, this, chg_bds, 
00216                                               conaux -> Index (), 
00217                                               (*(con -> Lb ())) (), 
00218                                               (*(con -> Ub ())) ());*/
00219 
00220           // take it from the list of the variables to be linearized
00221           // 
00222           // DO NOT decrease multiplicity. Even if it is a linear
00223           // term, its bounds can still be used in implied bounds
00224           //
00225           // Are we sure? That will happen only if its multiplicity is
00226           // nonzero, for otherwise this aux is only used here, and is
00227           // useless elsewhere
00228           //
00229           //conaux -> decreaseMult (); // !!!
00230         }
00231 
00232         // also, add constraint w <= b
00233 
00234         // not now, do it later
00235 
00236 //      // if there exists violation, add constraint
00237 //      CouNumber l = con -> Lb () -> Value (), 
00238 //                u = con -> Ub () -> Value ();
00239 
00240 //      // tighten bounds in Couenne's problem representation
00241 //      problem_ -> Lb (index) = CoinMax (l, problem_ -> Lb (index));
00242 //      problem_ -> Ub (index) = CoinMin (u, problem_ -> Ub (index));
00243 
00244       } else { // body is more than just a variable, but it should be
00245                // linear. If so, generate equivalent linear cut
00246 
00247         assert (false); // TODO
00248       }
00249     }
00250 
00251     if (jnlst_ -> ProduceOutput (J_ITERSUMMARY, J_CONVEXIFYING)) {
00252       if (cs.sizeRowCuts ()) {
00253         jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne: %d constraint row cuts\n",
00254                           cs.sizeRowCuts ());
00255         for (int i=0; i<cs.sizeRowCuts (); i++) 
00256           cs.rowCutPtr (i) -> print ();
00257       }
00258       if (cs.sizeColCuts ()) {
00259         jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne: %d constraint col cuts\n",
00260                           cs.sizeColCuts ());
00261         for (int i=0; i<cs.sizeColCuts (); i++) 
00262           cs.colCutPtr (i) -> print ();
00263       }
00264     }
00265   } else {
00266 
00267     // use new optimum as lower bound for variable associated w/objective
00268     int indobj = problem_ -> Obj (0) -> Body () -> Index ();
00269 
00270     assert (indobj >= 0);
00271 
00272     // transmit solution from OsiSolverInterface to problem
00273     problem_ -> domain () -> push 
00274       (problem_ -> nVars (),
00275        si. getColSolution (), 
00276        si. getColLower    (),
00277        si. getColUpper    ());
00278 
00279     if (indobj >= 0) {
00280 
00281       // Use current value of objvalue's x as a lower bound for bound
00282       // tightening
00283       double lp_bound = problem_ -> domain () -> x (indobj);
00284 
00285       //if (problem_ -> Obj (0) -> Sense () == MINIMIZE) 
00286       {if (lp_bound > problem_ -> Lb (indobj)) problem_ -> Lb (indobj) = lp_bound;}
00287            //else {if (lp_bound < problem_ -> Ub (indobj)) problem_ -> Ub (indobj) = lp_bound;}
00288     }
00289 
00290     updateBranchInfo (si, problem_, chg_bds, info); // info.depth >= 0 || info.pass >= 0
00291   }
00292 
00293   // restore constraint bounds before tightening and cut generation
00294   for (int i = problem_ -> nCons (); i--;) {
00295 
00296     // for each constraint
00297     CouenneConstraint *con = problem_ -> Con (i);
00298 
00299     // (which has an aux as its body)
00300     int index = con -> Body () -> Index ();
00301 
00302     if ((index >= 0) && 
00303         ((con -> Body () -> Type () == AUX) ||
00304          (con -> Body () -> Type () == VAR))) {
00305 
00306       // if there exists violation, add constraint
00307       CouNumber l = con -> Lb () -> Value (),   
00308         u = con -> Ub () -> Value ();
00309 
00310       // tighten bounds in Couenne's problem representation
00311       problem_ -> Lb (index) = CoinMax (l, problem_ -> Lb (index));
00312       problem_ -> Ub (index) = CoinMin (u, problem_ -> Ub (index));
00313     }
00314   }
00315 
00316   problem_ -> installCutOff (); // install upper bound
00317 
00318   fictitiousBound (cs, problem_, false); // install finite lower bound, if currently -inf
00319 
00320   int *changed = NULL, nchanged;
00321 
00322   // Bound tightening ///////////////////////////////////////////
00323 
00324   // do bound tightening only at first pass of cutting plane in a node
00325   // of BB tree (info.pass == 0) or if first call (creation of RLT,
00326   // info.pass == -1)
00327 
00328   try {
00329 
00330     // Bound tightening ////////////////////////////////////
00331 
00332     /*printf ("== BT ================\n");
00333     for (int i = 0; i < problem_ -> nVars (); i++)
00334       if (problem_ -> Var (i) -> Multiplicity () > 0)
00335         printf ("%4d %+20.8g [%+20.8g,%+20.8g]\n", i,
00336                 problem_ -> X  (i), problem_ -> Lb (i), problem_ -> Ub (i));
00337                 printf("=============================\n");*/
00338 
00339     // Reduced Cost BT -- to be done first to use rcost correctly
00340     if (!firstcall_  &&                         // have a linearization already
00341         problem_ -> doRCBT () &&                // authorized to do reduced cost tightening
00342         problem_ -> redCostBT (&si, chg_bds) && // some variables were tightened with reduced cost
00343         !(problem_ -> btCore (chg_bds)))        // in this case, do another round of FBBT
00344       throw infeasible;
00345 
00346     // FBBT
00347     if (problem_ -> doFBBT () && 
00348         //(info.pass <= 0) && // do it in subsequent rounds too
00349         (! (problem_ -> boundTightening (chg_bds, babInfo))))
00350       throw infeasible;
00351 
00352     // OBBT
00353     if (!firstcall_ && // no obbt if first call (there is no LP to work with)
00354         problem_ -> obbt (this, si, cs, info, babInfo, chg_bds) < 0)
00355       throw infeasible;
00356 
00357     // Bound tightening done /////////////////////////////
00358 
00359     if ((problem_ -> doFBBT () ||
00360          problem_ -> doOBBT () ||
00361          problem_ -> doABT  ()) &&
00362         (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING))) {
00363 
00364       jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== after bt =============\n");
00365       for (int i = 0; i < problem_ -> nVars (); i++)
00366         if (problem_ -> Var (i) -> Multiplicity () > 0)
00367           jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i,
00368                          problem_ -> X  (i), problem_ -> Lb (i), problem_ -> Ub (i));
00369       jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n");
00370     }
00371 
00372     // Generate convexification cuts //////////////////////////////
00373 
00374     sparse2dense (ncols, chg_bds, changed, nchanged);
00375 
00376     double *nlpSol;
00377 
00378     //--------------------------------------------
00379 
00380     if (babInfo && ((nlpSol = const_cast <double *> (babInfo -> nlpSolution ())))) {
00381 
00382       // Aggressive Bound Tightening ////////////////////////////////
00383 
00384       int logAbtLev = problem_ -> logAbtLev ();
00385 
00386       if (problem_ -> doABT () &&           // flag is checked, AND
00387           ((logAbtLev != 0) ||                // (parameter is nonzero OR
00388            (info.level == 0)) &&              //  we are at root node), AND
00389           (info.pass == 0) &&               // at first round of cuts, AND 
00390           ((logAbtLev < 0) ||                 // (logAbtLev = -1, OR
00391            (info.level <= logAbtLev) ||       //  depth is lower than COU_OBBT_CUTOFF_LEVEL, OR
00392            (CoinDrand48 () <                  //  probability inversely proportional to the level)
00393             pow (2., (double) logAbtLev - (info.level + 1))))) {
00394 
00395         jnlst_ -> Printf(J_ITERSUMMARY, J_CONVEXIFYING,"  performing ABT\n");
00396         if (! (problem_ -> aggressiveBT (nlp_, chg_bds, babInfo)))
00397           throw infeasible;
00398 
00399         sparse2dense (ncols, chg_bds, changed, nchanged);
00400       }
00401 
00402       // obtain solution just found by nlp solver
00403 
00404       // Auxiliaries should be correct. solution should be the one found
00405       // at the node even if not as good as the best known.
00406 
00407       // save violation flag and disregard it while adding cut at NLP
00408       // point (which are not violated by the current, NLP, solution)
00409       bool save_av = addviolated_;
00410       addviolated_ = false;
00411 
00412       // save values
00413       problem_ -> domain () -> push 
00414         (problem_ -> nVars (), 
00415          problem_ -> domain () -> x  (), 
00416          problem_ -> domain () -> lb (), 
00417          problem_ -> domain () -> ub (), false);
00418 
00419       // fill originals with nlp values
00420       CoinCopyN (nlpSol, problem_ -> nOrigVars (), problem_ -> domain () -> x ());
00421       //problem_ -> initAuxs ();
00422 
00423       problem_ -> getAuxs (problem_ -> domain () -> x ());
00424 
00425       if (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING)) {
00426         jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== genrowcuts on NLP =============\n");
00427         for (int i = 0; i < problem_ -> nVars (); i++)
00428           if (problem_ -> Var (i) -> Multiplicity () > 0)
00429             jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i,
00430                            problem_ -> X  (i),
00431                            problem_ -> Lb (i),
00432                            problem_ -> Ub (i));
00433         jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n");
00434       }
00435 
00436       problem_ -> domain () -> current () -> isNlp () = true;
00437       genRowCuts (si, cs, nchanged, changed, chg_bds);  // add cuts
00438 
00439       problem_ -> domain () -> pop (); // restore point
00440 
00441       addviolated_ = save_av;     // restore previous value
00442 
00443       //    if (!firstcall_) // keep solution if called from extractLinearRelaxation()
00444       babInfo -> setHasNlpSolution (false); // reset it after use //AW HERE
00445     } else {
00446 
00447       if (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING)) {
00448         jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== genrowcuts on LP =============\n");
00449         for (int i = 0; i < problem_ -> nVars (); i++)
00450           if (problem_ -> Var (i) -> Multiplicity () > 0)
00451             jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i,
00452                            problem_ -> X  (i),
00453                            problem_ -> Lb (i),
00454                            problem_ -> Ub (i));
00455         jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n");
00456       }
00457 
00458       genRowCuts (si, cs, nchanged, changed, chg_bds);
00459     }
00460 
00461     // change tightened bounds through OsiCuts
00462     if (nchanged)
00463       genColCuts (si, cs, nchanged, changed);
00464 
00465     if (firstcall_ && (cs.sizeRowCuts () >= 1))
00466       jnlst_->Printf(J_ITERSUMMARY, J_CONVEXIFYING,
00467                      "Couenne: %d initial row cuts\n", cs.sizeRowCuts ());
00468 
00469     if (realOpt && // this is a good time to check if we have messed up with the optimal solution
00470         isOptimumCut (realOpt, cs, problem_))
00471       jnlst_->Printf(J_ITERSUMMARY, J_CONVEXIFYING,
00472                      "\n\n CUT OPTIMUM\n\n");
00473   }
00474 
00475   catch (int exception) {
00476 
00477     if ((exception == infeasible) && (!firstcall_)) {
00478 
00479       jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,
00480                         "Couenne: Infeasible node\n");
00481 
00482       OsiColCut *infeascut = new OsiColCut;
00483 
00484       if (infeascut) {
00485         int i=0;
00486         double upper = -1., lower = +1.;
00487         infeascut -> setLbs (1, &i, &lower);
00488         infeascut -> setUbs (1, &i, &upper);
00489         cs.insert (infeascut);
00490         delete infeascut;
00491       }
00492     }
00493 
00494     if (babInfo) // set infeasibility to true in order to skip NLP heuristic
00495       babInfo -> setInfeasibleNode ();
00496   }
00497 
00498   delete [] chg_bds;
00499 
00500   if (changed) 
00501     free (changed);
00502 
00503   if (firstcall_) {
00504 
00505     jnlst_ -> Printf (J_SUMMARY, J_CONVEXIFYING, 
00506                       "Couenne: %d cuts (%d row, %d col) for linearization\n", 
00507                       cs.sizeRowCuts () + cs.sizeColCuts (),
00508                       cs.sizeRowCuts (),  cs.sizeColCuts ());
00509 
00510     fictitiousBound (cs, problem_, true);
00511     firstcall_  = false;
00512     ntotalcuts_ = nrootcuts_ = cs.sizeRowCuts ();
00513   } else { 
00514     problem_ -> domain () -> pop ();
00515 
00516     ntotalcuts_ += (cs.sizeRowCuts () - nInitCuts);
00517 
00518     if (saveOptimum)
00519       realOpt = saveOptimum; // restore debug optimum
00520   }
00521 
00522   septime_ += CoinCpuTime () - now;
00523 
00524   if (jnlst_ -> ProduceOutput (J_ITERSUMMARY, J_CONVEXIFYING)) {
00525 
00526     if (cs.sizeColCuts ()) {
00527       jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne col cuts:\n");
00528       for (int i=0; i<cs.sizeColCuts (); i++) 
00529         cs.colCutPtr (i) -> print ();
00530     }
00531   }
00532 
00533   if (!(info.inTree)) 
00534     rootTime_ = CoinCpuTime ();
00535 }

Generated on Tue Mar 30 03:04:36 2010 by  doxygen 1.4.7