00001
00002
00003
00004
00005
00006
00007
00008
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
00023
00024
00025
00027 static bool obbt_updateBound (OsiSolverInterface *csi,
00028 int sense,
00029 CouNumber &bound,
00030 bool isint) {
00031
00032
00033 csi -> setDblParam (OsiDualObjectiveLimit, COIN_DBL_MAX);
00034 csi -> setDblParam (OsiPrimalObjectiveLimit, (sense==1) ? bound : -bound);
00035
00036
00038
00039
00040 csi -> resolve ();
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
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
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) {
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 {
00130
00131
00132 int indInd = *(deplist.begin ());
00133
00134
00135
00136
00137 if
00138 ((((chg_bds [indInd].lower() & t_chg_bounds::EXACT) &&
00139 (chg_bds [indInd].upper() & t_chg_bounds::EXACT)) ||
00140
00141
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
00174 if (!issimple &&
00175 ((Var (index) -> Type () == VAR) ||
00176 (Var (index) -> Multiplicity () > 0)) &&
00177 (Lb (index) < Ub (index) - COUENNE_EPS) &&
00178
00179 ((index != objind)
00180
00181 || ((sense == 1) && !(chg_bds [index].lower() & t_chg_bounds::EXACT))
00182 )) {
00183
00184
00185 bool isInt = (Var (index) -> isInteger ());
00186
00187 objcoe [index] = sense;
00188
00189 csi -> setObjective (objcoe);
00190 csi -> setObjSense (1);
00191
00192
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
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 csi -> setWarmStart (warmstart);
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
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
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
00285
00286
00287
00288
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
00301
00302 CouNumber *redcost = NULL;
00303
00304
00305
00306
00307
00308 for (int j=0; j<ncols; j++)
00309 if ((j!=index) && (j!=objind)) {
00310
00311
00312
00313
00314
00315
00316
00317 if (!(chg_bds [j].lower & EXACT)) {
00318 }
00319
00320 if (!(chg_bds [j].upper & EXACT)) {
00321 }
00322 }
00323 #endif
00324
00325
00326
00327
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
00335
00336
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;
00341 }
00342
00343 nImprov++;
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
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 }