00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "CoinHelperFunctions.hpp"
00012
00013 #include "CouenneProblem.hpp"
00014 #include "CouenneProblemElem.hpp"
00015 #include "CouenneExprVar.hpp"
00016
00017 #include "BonBabInfos.hpp"
00018
00019 using namespace Couenne;
00020
00021 #define MAX_ITER 3 // max # fake tightening (inner) iterations
00022 #define AGGR_MUL 2 // the larger, the more conservative. Must be > 0
00023 #define AGGR_DIV 2 // the smaller, the more conservative. Must be > 1
00024
00025
00026 const CouNumber phi = 0.5 * (1. + sqrt (5.));
00027
00028
00029 CouNumber fictBounds (char direction,
00030 CouNumber x,
00031 CouNumber lb,
00032 CouNumber ub) {
00033
00034 #define LARGE_BOUND 1e10
00035
00036 if (lb < -LARGE_BOUND) {
00037 if (ub > LARGE_BOUND) {
00038
00039 return (!direction ? -LARGE_BOUND / AGGR_DIV : LARGE_BOUND / AGGR_DIV);
00040
00041
00042
00043
00044
00045
00046 } else {
00047
00048 if (!direction)
00049 return -LARGE_BOUND / AGGR_DIV;
00050
00051 if (x < -COUENNE_EPS) return (CoinMin (0., (x+ub)/2));
00052 else if (x > COUENNE_EPS) return ((x + (ub-x)/AGGR_DIV));
00053 else return ((ub/AGGR_DIV));
00054
00055
00056
00057
00058 }
00059 }
00060 else {
00061 if (ub > LARGE_BOUND) {
00062
00063 if (direction)
00064 return LARGE_BOUND / AGGR_DIV;
00065
00066 if (x < -COUENNE_EPS) return ((x - (x-lb) / AGGR_DIV));
00067 else if (x > COUENNE_EPS) return (CoinMax (0.,(x+lb)/2));
00068 else return (lb/AGGR_DIV);
00069
00070
00071
00072
00073
00074 } else
00075 return (direction ?
00076 (x + (ub-x) / AGGR_DIV) :
00077 (x - (x-lb) / AGGR_DIV));
00078 }
00079 }
00080
00081
00082
00083
00084
00085
00086
00087 int CouenneProblem::
00088 fake_tighten (char direction,
00089 int index,
00090 const double *X,
00091 CouNumber *olb,
00092 CouNumber *oub,
00093 t_chg_bounds *chg_bds,
00094 t_chg_bounds *f_chg) const {
00095
00096 int
00097 ncols = nVars (),
00098 objind = Obj (0) -> Body () -> Index ();
00099
00100
00101
00102 bool
00103 tightened = false,
00104 intvar = variables_ [index] -> isInteger ();
00105
00106 CouNumber
00107 xcur = X [index],
00108 inner = xcur,
00109 outer = (direction ? oub : olb) [index],
00110 fb = fictBounds (direction, xcur, Lb (index), Ub (index));
00111
00112
00113
00114
00115
00116 jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING, " x_%d. x = %10g, lb = %g, cutoff = %g-----------------\n", index,xcur,objind >= 0 ? Lb (objind) : 0., getCutOff());
00117
00118
00119
00120
00121
00122 for (int iter = 0; iter < MAX_ITER; iter++) {
00123
00124 if (intvar) {
00125
00126 if (!direction) {inner = floor (inner + COUENNE_EPS); outer = ceil (outer - COUENNE_EPS);}
00127 else {inner = ceil (inner - COUENNE_EPS); outer = floor (outer + COUENNE_EPS);}
00128
00129 if ( (direction && (inner > outer + .5)) ||
00130 (!direction && (inner < outer - .5))) {
00131
00132
00133
00134
00135 if (direction) {oub[index] = Ub (index) = fb; chg_bds[index].setUpper(t_chg_bounds::CHANGED);}
00136 else {olb[index] = Lb (index) = fb; chg_bds[index].setLower(t_chg_bounds::CHANGED);}
00137
00138 tightened = true;
00139
00140 if (!(btCore (f_chg)))
00141 return -1;
00142
00143 CoinCopyN (Lb (), ncols, olb);
00144 CoinCopyN (Ub (), ncols, oub);
00145
00146
00147 CoinCopyN (chg_bds, ncols, f_chg);
00148
00149
00150
00151 break;
00152 }
00153
00154 if ( (direction && ((fb < inner) || (fb > outer))) ||
00155 (!direction && ((fb > inner) || (fb < outer))))
00156 fb = 0.5 * (inner + outer);
00157 }
00158
00159 if (direction) {
00160 Lb (index) = intvar ? ceil (fb - COUENNE_EPS) : fb;
00161 f_chg [index].setLower (t_chg_bounds::CHANGED);
00162 } else {
00163 Ub (index) = intvar ? floor (fb + COUENNE_EPS) : fb;
00164 f_chg [index].setUpper (t_chg_bounds::CHANGED);
00165 }
00166
00167
00168
00169 if (jnlst_ -> ProduceOutput (Ipopt::J_ERROR, J_BOUNDTIGHTENING)) {
00170 char c1 = direction ? '-' : '>', c2 = direction ? '<' : '-';
00171 printf (" # x%d = %g iter %3d: [%+10g -%c %+10g %c- %+10g] /\\/\\ ",index,xcur,iter,olb[index],c1,fb,c2, oub [index]);
00172 printf (" [%10g,%10g]<%g,%g>=> ",Lb (index),Ub (index),CoinMin(inner,outer),CoinMax(inner,outer));
00173 }
00174
00175 bool
00176 feasible = btCore (f_chg),
00177 betterbds = objind >= 0 && (Lb (objind) > getCutOff () + COUENNE_EPS);
00178
00179 jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING, " [%10g,%10g] lb = %g {fea=%d,btr=%d} ", Lb (index), Ub (index), objind >= 0 ? Lb (objind) : 0., feasible,betterbds);
00180
00181 if (feasible && !betterbds) {
00182
00183
00184 inner = fb;
00185
00186
00187 CoinCopyN (chg_bds, ncols, f_chg);
00188 CoinCopyN (olb, ncols, Lb ());
00189 CoinCopyN (oub, ncols, Ub ());
00190
00191 } else {
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 if (optimum_ &&
00205 ((!direction &&
00206 (optimum_ [index] >= olb [index]) &&
00207 (optimum_ [index] <= Lb (index) - COUENNE_EPS)) ||
00208 (direction &&
00209 (optimum_ [index] <= oub [index]) &&
00210 (optimum_ [index] >= Ub (index) + COUENNE_EPS)))) {
00211
00212 jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING,
00213 "fake tightening CUTS optimum: x%d=%g in [%g,%g] but not in [%g,%g]\n",
00214 index, olb [index], oub [index], Lb (index), Ub (index));
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 if (direction) {
00242
00243 oub [index] = Ub (index) = intvar ? floor (fb + COUENNE_EPS) : fb;
00244 chg_bds [index]. setUpper (t_chg_bounds::CHANGED);
00245
00246 } else {
00247
00248 olb [index] = Lb (index) = intvar ? ceil (fb - COUENNE_EPS) : fb;
00249 chg_bds [index]. setLower (t_chg_bounds::CHANGED);
00250 }
00251
00252 outer = fb;
00253
00254 tightened = true;
00255
00256
00257
00258 CoinCopyN (chg_bds, ncols, f_chg);
00259 CoinCopyN (olb, ncols, Lb ());
00260 CoinCopyN (oub, ncols, Ub ());
00261
00262
00263
00264 if (!(btCore (chg_bds))) {
00265
00266 jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING,
00267 "\n pruned by Probing\n");
00268 return -1;
00269
00270 } else {
00271
00272
00273
00274 CoinCopyN (Lb (), ncols, olb);
00275 CoinCopyN (Ub (), ncols, oub);
00276 }
00277
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287 CouNumber
00288 lb = Lb (index),
00289 ub = Ub (index);
00290
00291 if ((!direction && ((inner > ub) || (outer < lb))) ||
00292 ( direction && ((inner < lb) || (outer > ub)))) {
00293
00294
00295
00296 inner = direction ? lb : ub;
00297 outer = direction ? ub : lb;
00298 }
00299
00300 CouNumber diff = fabs (inner - outer);
00301
00302 if (diff <= COUENNE_EPS) break;
00303
00304 if (diff > 1.) {
00305
00306 CouNumber L = log (diff) / log (10.);
00307
00308 if (direction) fb = inner + exp (log (10.) * L/2);
00309 else fb = inner - exp (log (10.) * L/2);
00310
00311 } else fb = (inner + outer)/2;
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING, "\n");
00322 }
00323
00324 Jnlst()->Printf(Ipopt::J_MOREVECTOR, J_BOUNDTIGHTENING, "\n");
00325 if (tightened) Jnlst()->Printf(Ipopt::J_MOREVECTOR, J_BOUNDTIGHTENING, " [x%2d] pruned %s [%g, %g] -- lb = %g cutoff = %g\n", index,direction?"right":"left", olb[index],oub[index], objind >= 0 ? Lb (objind) : 0., getCutOff ());
00326
00327 return tightened ? 1 : 0;
00328 }