/home/coin/SVN-release/OS-2.0.1/Couenne/src/bound_tightening/operators/impliedBounds-exprQuad.cpp

Go to the documentation of this file.
00001 /* $Id: impliedBounds-exprQuad.cpp 141 2009-06-03 04:19:19Z pbelotti $ */
00002 /*
00003  * Name:    impliedBounds-exprQuad.cpp
00004  * Author:  Pietro Belotti
00005  * Purpose: inferring bounds on independent variables of an exprQuad
00006  *          given bounds on the auxiliary variable
00007  *
00008  * (C) Carnegie-Mellon University, 2006. 
00009  * This file is licensed under the Common Public License (CPL)
00010  */
00011 
00012 #include <set>
00013 
00014 #include "CoinHelperFunctions.hpp"
00015 #include "exprQuad.hpp"
00016 
00017 //#define DEBUG
00018 
00019 //struct compExpr;
00020 
00026 struct compVar {
00027   inline bool operator () (exprVar* e0, exprVar* e1) const
00028   {return (e0 -> Index () < e1 -> Index ());}
00029 };
00030 
00031 
00032 
00035 
00036 bool exprQuad::impliedBound (int wind, CouNumber *l, CouNumber *u, t_chg_bounds *chg) {
00037 
00038   //return false; // !!!
00039 
00040   // three implied bound computations, of increasing complexity. The
00041   // first reduces this sum to a sum of aux and tries, after
00042   // tightening bounds of each aux, to infer new bounds
00043 
00044 #ifdef DEBUG
00045   printf ("################ implied bounds: [%g,%g], ", l [wind], u [wind]);
00046   print (); printf ("\n");
00047 #endif
00048 
00049   // Nevermind about the nonlinear part stored in arglist_...
00050 
00051   //std::set <int> indexSet;
00052   std::set <exprVar *, compVar> indexSet;
00053 
00054   // insert indices of linear part
00055   for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el)
00056     indexSet.insert (el -> first);
00057 
00058   // insert indices of quadratic part
00059   for (sparseQ::iterator row = matrix_.begin (); row != matrix_.end (); ++row) {
00060 
00061     indexSet.insert (row -> first);
00062 
00063     for (sparseQcol::iterator col = row -> second.begin (); col != row -> second.end (); ++col)
00064       indexSet.insert (col -> first);
00065   }
00066 
00067   // CAUTION: this relies on the first version of bound expressions
00068   // for quadratic form, i.e. the sum of bounds of independent terms
00069 
00070   CouNumber qMin, qMax;
00071 
00072   int indInfLo = -1, indInfUp = -1;
00073 
00074   // get bounds for nonlinear part of the sum
00075   expression *qlb, *qub;
00076   exprSum::getBounds (qlb, qub);
00077   qMin = (*qlb) (); delete qlb;
00078   qMax = (*qub) (); delete qub;
00079   //exprSum::getBounds (qMin, qMax);
00080 
00081   if (qMin < -COUENNE_INFINITY) indInfLo = -2;
00082   if (qMax >  COUENNE_INFINITY) indInfUp = -2;
00083 
00084   if ((indInfLo == -2) && 
00085       (indInfUp == -2)) 
00086     return false;
00087   
00088 #ifdef DEBUG
00089   printf ("1st phase... inf=(%d,%d) q=[%g,%g].\n", indInfLo, indInfUp, qMin, qMax);
00090   for (std::set <int>:: iterator iter = indexSet.begin ();
00091        iter != indexSet.end (); ++iter) 
00092     printf ("%4d [%+6g %+6g]\n", *iter, l [iter -> Index ()], u [iter -> Index ()]);
00093 #endif
00094 
00095   // compute bound on expression using only finite variable bounds
00096 
00097   computeQuadFiniteBound (qMin, qMax, l, u, indInfLo, indInfUp);
00098 
00099   // similar to impliedBounds-exprGroup. indInf* are -1 if no
00100   // variables are unbounded, i>0 if variable x_i is unbounded and -2
00101   // if at least two are, thus making implied bounds useless.
00102 
00103   qMin += c0_;
00104   qMax += c0_;
00105 
00106   if (((indInfLo == -2) && (indInfUp == -2)) || // at least two variables are unbounded
00107       ((indInfLo == -1) && (indInfUp == -1) &&  // or, none is (and qMin, qMax are exact) 
00108        (qMin > l [wind]) && (qMax < u [wind]))) // but explicit bounds are loose
00109     return false;
00110 
00111 #ifdef DEBUG
00112   printf ("2nd phase... inf=(%d,%d) q=[%g,%g].\n", indInfLo, indInfUp, qMin, qMax);
00113 #endif
00114 
00116   //
00117   // now fill in b_i (constant term in both linear coefficient vectors)
00118 
00119   // prepare data structure for scanning all variables
00120   int
00121     minindex = (*(indexSet.begin  ())) -> Index (), // minimum index
00122     maxindex = (*(indexSet.rbegin ())) -> Index (), // maximum index
00123     nvars = maxindex - minindex + 1;           // upper bound on # variables involved
00124 
00125   CouNumber 
00126     *linCoeMin = new CouNumber [nvars], // min coeff of var x_i
00127     *linCoeMax = new CouNumber [nvars], // max coeff of var x_i
00128     *qii       = new CouNumber [nvars], // quadratic coeff
00129     *bCutLb    = new CouNumber [nvars], // amount to be drawn from the overall lower bound
00130     *bCutUb    = new CouNumber [nvars]; // amount to be drawn from the overall upper bound
00131 
00132   // fill all with 0
00133   CoinFillN (linCoeMin, nvars, 0.);
00134   CoinFillN (linCoeMax, nvars, 0.);
00135   CoinFillN (qii,       nvars, 0.);
00136   CoinFillN (bCutLb,    nvars, 0.);
00137   CoinFillN (bCutUb,    nvars, 0.);
00138 
00139   // assume all coefficients are finite
00140   for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) {
00141     //  for (int i=0; i<nlterms_; i++) {
00142 
00143     int ind = el -> first -> Index ();//index_ [i];
00144 
00145     CouNumber
00146       coe = el -> second, //coeff_ [i], 
00147       li  = l [ind], 
00148       ui  = u [ind];
00149 
00150     ind -= minindex;
00151 
00152     linCoeMin [ind] += coe;
00153     linCoeMax [ind] += coe;
00154 
00155     if (coe > 0) { // contribution of linear term to bound depends on its coefficient
00156       if (li > -COUENNE_INFINITY) bCutLb [ind] += coe * li;
00157       if (ui <  COUENNE_INFINITY) bCutUb [ind] += coe * ui;
00158     } else {
00159       if (ui <  COUENNE_INFINITY) bCutLb [ind] += coe * ui;
00160       if (li > -COUENNE_INFINITY) bCutUb [ind] += coe * li;
00161     }
00162   }
00163 
00164 #ifdef DEBUG
00165   printf ("linear filling (%d,%d): -----------------------\n", minindex, maxindex);
00166   for (std::set <int>:: iterator iter = indexSet.begin ();
00167        iter != indexSet.end (); ++iter) 
00168     printf ("%4d [%+6g %+6g] [%+6g %+6g]\n", iter -> Index (), 
00169             linCoeMin [iter -> Index () - minindex], linCoeMax [iter -> Index () - minindex],
00170             bCutLb    [iter -> Index () - minindex], bCutUb    [iter -> Index () - minindex]);
00171 #endif
00172 
00173   // fill in remaining linear coefficients and quadratic ones
00174   for (sparseQ::iterator row = matrix_.begin (); row != matrix_.end (); ++row) {
00175 
00176     for (sparseQcol::iterator col = row -> second.begin (); col != row -> second.end (); ++col) {
00177 
00178       int
00179         qi = row -> first -> Index (),
00180         qj = col -> first -> Index (); //qindexJ_ [i];
00181 
00182       CouNumber coe = col -> second, //qcoeff_ [i],
00183         li = l [qi], lj = l [qj], 
00184         ui = u [qi], uj = u [qj];
00185 
00186       if (qi == qj) { // quadratic term
00187 
00188         qi -= minindex;
00189 
00190         qii [qi] = coe; // quadratic term
00191 
00192         CouNumber
00193           maxbUb = CoinMax (fabs (li), fabs (ui)),
00194           maxbLb = (li >= 0) ? (li) : (ui <= 0) ? (ui) : 0;
00195 
00196         if (maxbUb > COUENNE_INFINITY) maxbUb = 0;
00197 
00198         maxbUb *= maxbUb * coe;
00199         maxbLb *= maxbLb * coe;
00200 
00201         if (coe > 0) {
00202           bCutUb [qi] += maxbUb;
00203           bCutLb [qi] += maxbLb;
00204         } else {
00205           bCutUb [qi] += maxbLb;
00206           bCutLb [qi] += maxbUb;
00207         }
00208       } else { // product term
00209 
00210         coe *= 2;
00211 
00212         CouNumber *b1, *b2;
00213 
00214         if (coe > 0) {b1 = l; b2 = u;} 
00215         else         {b1 = u; b2 = l;}
00216 
00217         b1 += minindex;
00218         b2 += minindex;
00219 
00220         qi -= minindex;
00221         qj -= minindex;
00222 
00223         linCoeMin [qi] += coe * b1 [qj];
00224         linCoeMin [qj] += coe * b1 [qi];
00225 
00226         linCoeMax [qi] += coe * b2 [qj];
00227         linCoeMax [qj] += coe * b2 [qi];
00228 
00229         CouNumber
00230           addLo = CoinMin (CoinMin (li*lj, ui*uj),
00231                            CoinMin (ui*lj, li*uj)),
00232           addUp = CoinMax (CoinMax (li*lj, ui*uj), 
00233                            CoinMax (ui*lj, li*uj));
00234 
00235         if (addLo < -COUENNE_INFINITY) addLo = 0;
00236         if (addUp >  COUENNE_INFINITY) addUp = 0;
00237 
00238         addLo *= coe;
00239         addUp *= coe;
00240 
00241         if (coe > 0) {
00242           bCutLb [qi] += addLo; bCutUb [qi] += addUp;
00243           bCutLb [qj] += addLo; bCutUb [qj] += addUp;
00244         } else {
00245           bCutLb [qi] += addUp; bCutUb [qi] += addLo;
00246           bCutLb [qj] += addUp; bCutUb [qj] += addLo;
00247         }
00248       }
00249     }
00250   }
00251 
00252 #ifdef DEBUG
00253   printf ("quad filling: -----------------------\n");
00254   for (std::set <int>:: iterator iter = indexSet.begin ();
00255        iter != indexSet.end (); ++iter) 
00256     printf ("%4d [%+6g %+6g] [%+6g %+6g]\n", *iter, 
00257             linCoeMin [iter -> Index () - minindex], linCoeMax [iter -> Index () - minindex],
00258             bCutLb    [iter -> Index () - minindex], bCutUb    [iter -> Index () - minindex]);
00259 #endif
00260 
00261   // Done filling vectors /////////////////////////////////////////////////////////////
00262   // Now improve each independent variable in the set indexSet
00263 
00264   bool one_updated = false;
00265 
00266   for (std::set <exprVar *, compVar>:: iterator iter = indexSet.begin ();
00267        iter != indexSet.end (); ++iter) {
00268 
00269     bool
00270       updatedL = false,
00271       updatedU = false;
00272 
00273     int ind  = (*iter) -> Index (), 
00274         indn = ind - minindex;
00275 
00276     CouNumber 
00277       al = linCoeMin [indn],
00278       au = linCoeMax [indn],
00279       q  = qii       [indn];
00280 
00281 #ifdef DEBUG
00282     CouNumber
00283       ol = l [ind], 
00284       ou = u [ind];
00285 #endif
00286 
00287     if (fabs (q) < COUENNE_EPS) { // case 1: qii is zero, term is "linear"
00288 
00289       if ((al > 0) || (au < 0)) { // otherwise, min and max lin coe
00290                                   // contain zero, not much to do...
00291 
00292         //          l         <= b_i x_i + c <= u
00293         // <===>    l - c_MAX <= b_i x_i     <= u - c_MIN
00294         //
00295         // c_MAX = qMax - bCutUb [indn]
00296         // c_MIN = qMin - bCutLb [indn]
00297 
00298         CouNumber 
00299           l_b = l [wind] - qMax + bCutUb [indn],
00300           u_b = u [wind] - qMin + bCutLb [indn];
00301 
00302         if (al > 0) { // care about min -- see outer if, it means 0 < al < au
00303 
00304           if ((indInfUp == -1) || (indInfUp == ind))
00305             updatedL = updateBound (-1, l + ind, (l_b) / ((l_b < 0) ? al : au)) || updatedL;
00306           if ((indInfLo == -1) || (indInfLo == ind)) 
00307             updatedU = updateBound (+1, u + ind, (u_b) / ((u_b < 0) ? au : al)) || updatedU;
00308 
00309 #ifdef DEBUG
00310           if (l [ind] > ol) printf ("0. l%d: %g --> %g\n", ind, ol, l [ind]);
00311           if (u [ind] < ou) printf ("0. u%d: %g --> %g\n", ind, ou, u [ind]);
00312 #endif
00313         } else { // only look at max, as al < au < 0
00314 
00315           if ((indInfLo == -1) || (indInfLo == ind)) 
00316             updatedL = updateBound (-1, l + ind, (u_b) / ((u_b < 0) ? al : au)) || updatedL;
00317           if ((indInfUp == -1) || (indInfUp == ind)) 
00318             updatedU = updateBound (+1, u + ind, (l_b) / ((l_b < 0) ? au : al)) || updatedU;
00319 
00320 #ifdef DEBUG
00321           if (l [ind] > ol) printf ("1. l%d: %g --> %g\n", ind, ol, l [ind]);
00322           if (u [ind] < ou) printf ("1. u%d: %g --> %g\n", ind, ou, u [ind]);
00323 #endif
00324         }
00325       }
00326 
00327     } else if (q > 0) {
00328 
00329       // skip if constant term is unbounded from below
00330 
00331       if ((indInfLo != -1) && 
00332           (indInfLo != ind)) 
00333         continue;
00334 
00335       // case 2: qii is positive, the parabola is facing upwards and
00336       // we only need to look at w_U = u [wind]
00337 
00338       // there are two parabolas, with linear coefficient linCoeMin
00339       // and linCoeMax, respectively. If both cut the line $w=w_U$
00340       // then take the minimum of the cut points as new lower bound
00341       // and similarly for the new upper bound.
00342 
00343       // Fortunately there are just two values of linCoe which we have
00344       // to look at, as the parabola is of the form $q_{ii} x_i^2 +
00345       // \hat b_i x_i + c \le w_u$ and the solution contains $\sqrt
00346       // {b_i^2 - 4q_{ii}(c-u)}$, whose maximum is attained with b_i
00347       // maximum or minimum, that is, at linCoeMax and linCoeMin.
00348 
00349       CouNumber 
00350         deltaSecond = 4 * q * (qMin - bCutLb [indn] - u [wind]),
00351         deltaUp     = au*au - deltaSecond,
00352         deltaLo     = al*al - deltaSecond;
00353 
00354       // First case, both parabolas cut the line
00355 
00356       if ((deltaUp >= 0) && 
00357           (deltaLo >= 0)) {
00358 
00359         updatedL = updateBound (-1, l + ind, (- au - sqrt (deltaUp)) / (2*q)) || updatedL;
00360         updatedU = updateBound (+1, u + ind, (- al + sqrt (deltaLo)) / (2*q)) || updatedU;
00361 
00362 #ifdef DEBUG
00363         if (l [ind] > ol) printf ("2. l%d: %g --> %g\n", ind, ol, l [ind]);
00364         if (u [ind] < ou) printf ("2. u%d: %g --> %g\n", ind, ou, u [ind]);
00365 #endif
00366 
00367       } else if (deltaUp >= 0) { // only  left-leaning parabola does
00368 
00369         updatedL = updateBound (-1, l + ind, (- au - sqrt (deltaUp)) / (2*q)) || updatedL;
00370         updatedU = updateBound (+1, u + ind, (- au + sqrt (deltaUp)) / (2*q)) || updatedU;
00371         //      addCoeffCut ();
00372 
00373 #ifdef DEBUG
00374         if (l [ind] > ol) printf ("3. l%d: %g --> %g\n", ind, ol, l [ind]);
00375         if (u [ind] < ou) printf ("3. u%d: %g --> %g\n", ind, ou, u [ind]);
00376 #endif
00377 
00378       } else if (deltaLo >= 0) { // only right-leaning parabola does
00379 
00380         updatedL = updateBound (-1, l + ind, (- al - sqrt (deltaLo)) / (2*q)) || updatedL;
00381         updatedU = updateBound (+1, u + ind, (- al + sqrt (deltaLo)) / (2*q)) || updatedU;
00382         //      addCoeffCut ();
00383 
00384 #ifdef DEBUG
00385         if (l [ind] > ol) printf ("4. l%d: %g --> %g\n", ind, ol, l [ind]);
00386         if (u [ind] < ou) printf ("4. u%d: %g --> %g\n", ind, ou, u [ind]);
00387 #endif
00388 
00389       } else { // none of them does, the problem is infeasible
00390 
00391         updatedL = updateBound (-1, l+ind, +1) || updatedL;
00392         updatedU = updateBound (+1, u+ind, -1) || updatedU;
00393 
00394 #ifdef DEBUG
00395         printf ("5. infeasible!\n");
00396 #endif
00397       }
00398 
00399       // if only one parabola cuts the line, take its lower and upper
00400       // bounds as the new bounds
00401 
00402       // TODO: in the 2nd and 3rd cases, add constraint $\hat b \ge
00403       // \sqrt {4q_{ii}(c-u)}$ or the opposite, to ensure that
00404       // parabola is at least tangent to line w=w_U
00405 
00406       // Also, lower bound can be of help if x_i has a bound between
00407       // the two intersections of the parabola with line w=w_L
00408 
00409     } else {
00410 
00411       // case 3: qii is negative, the parabola is facing downwards and
00412       // we only need to look at l [wind]
00413 
00414       // skip if constant term is unbounded from above
00415       if ((indInfUp != -1) && 
00416           (indInfUp != ind)) 
00417         continue;
00418 
00419       CouNumber 
00420         deltaSecond = 4 * q * (qMax - bCutUb [indn] - l [wind]),
00421         deltaUp     = au*au - deltaSecond,
00422         deltaLo     = al*al - deltaSecond;
00423 
00424       // First case, both parabolas cut the line
00425 
00426       if ((deltaUp >= 0) && 
00427           (deltaLo >= 0)) {
00428 
00429         updatedL = updateBound (-1, l + ind, (al - sqrt (deltaLo)) / (-2*q)) || updatedL;
00430         updatedU = updateBound (+1, u + ind, (au + sqrt (deltaUp)) / (-2*q)) || updatedU;
00431 
00432 #ifdef DEBUG
00433         if (l [ind] > ol) printf ("6. l%d: %g --> %g\n", ind, ol, l [ind]);
00434         if (u [ind] < ou) printf ("6. u%d: %g --> %g\n", ind, ou, u [ind]);
00435 #endif
00436       } else if (deltaUp >= 0) { // only  left-leaning parabola does
00437 
00438         updatedL = updateBound (-1, l + ind, (au - sqrt (deltaUp)) / (-2*q)) || updatedU;
00439         updatedU = updateBound (+1, u + ind, (au + sqrt (deltaUp)) / (-2*q)) || updatedL;
00440         //      addCoeffCut ();
00441 
00442 #ifdef DEBUG
00443         if (l [ind] > ol) printf ("7. l%d: %g --> %g\n", ind, ol, l [ind]);
00444         if (u [ind] < ou) printf ("7. u%d: %g --> %g\n", ind, ou, u [ind]);
00445 #endif
00446 
00447       } else if (deltaLo >= 0) { // only right-leaning parabola does
00448 
00449         updatedL = updateBound (-1, l + ind, (al - sqrt (deltaLo)) / (-2*q)) || updatedL;
00450         updatedU = updateBound (+1, u + ind, (al + sqrt (deltaLo)) / (-2*q)) || updatedU;
00451         //      addCoeffCut ();
00452 #ifdef DEBUG
00453         if (l [ind] > ol) printf ("8. l%d: %g --> %g\n", ind, ol, l [ind]);
00454         if (u [ind] < ou) printf ("8. u%d: %g --> %g\n", ind, ou, u [ind]);
00455 #endif
00456 
00457       } else { // none of them does, the problem is infeasible
00458 
00459         updatedL = updateBound (-1, l+ind, +1) || updatedL;
00460         updatedU = updateBound (+1, u+ind, -1) || updatedU;
00461 
00462 #ifdef DEBUG
00463         printf ("9. infeasible\n");
00464 #endif
00465       }
00466     }
00467 
00468     // 
00469 
00470     if (updatedL) {
00471       one_updated = true;
00472       chg [ind].setLower(t_chg_bounds::CHANGED);
00473       if ((*iter) -> isInteger ())
00474         l [ind] = ceil (l [ind] - COUENNE_EPS);
00475     }
00476 
00477     if (updatedU) {
00478       one_updated = true;
00479       chg [ind].setUpper(t_chg_bounds::CHANGED);
00480       if ((*iter) -> isInteger ())
00481         u [ind] = floor (u [ind] + COUENNE_EPS);
00482     }
00483   }
00484 
00485   delete [] linCoeMin;
00486   delete [] linCoeMax;
00487   delete [] qii;
00488   delete [] bCutLb;
00489   delete [] bCutUb;
00490 
00491   return one_updated;
00492 }

Generated on Thu Oct 8 03:02:55 2009 by  doxygen 1.4.7