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 ? -sqrt (-lb) : sqrt (ub));
00040
00041
00042
00043
00044 } else {
00045
00046 if (!direction)
00047 return -sqrt (-lb);
00048
00049 if (x < -COUENNE_EPS) return (CoinMin (0., (x+ub)/2));
00050 else if (x > COUENNE_EPS) return ((x + (ub-x)/AGGR_DIV));
00051 else return ((ub/AGGR_DIV));
00052
00053
00054
00055
00056 }
00057 }
00058 else {
00059 if (ub > LARGE_BOUND) {
00060
00061 if (direction)
00062 return sqrt (ub);
00063
00064 if (x < -COUENNE_EPS) return ((x - (x-lb) / AGGR_DIV));
00065 else if (x > COUENNE_EPS) return (CoinMax (0.,(x+lb)/2));
00066 else return (lb/AGGR_DIV);
00067
00068
00069
00070
00071
00072 } else
00073 return (direction ?
00074 (x + (ub-x) / AGGR_DIV) :
00075 (x - (x-lb) / AGGR_DIV));
00076 }
00077 }
00078
00079
00080
00081
00082
00083
00084
00085 int CouenneProblem::
00086 fake_tighten (char direction,
00087 int index,
00088 const double *X,
00089 CouNumber *olb,
00090 CouNumber *oub,
00091 t_chg_bounds *chg_bds,
00092 t_chg_bounds *f_chg) const {
00093
00094 int
00095 ncols = nVars (),
00096 objind = Obj (0) -> Body () -> Index ();
00097
00098
00099
00100 bool
00101 tightened = false,
00102 intvar = variables_ [index] -> isInteger ();
00103
00104 CouNumber
00105 xcur = X [index],
00106 inner = xcur,
00107 outer = (direction ? oub : olb) [index],
00108 fb = fictBounds (direction, xcur, Lb (index), Ub (index));
00109
00110
00111
00112
00113
00114 jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING,
00115 " x_%d. x = %10g, lb = %g, cutoff = %g-----------------\n",
00116 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,
00180 " [%10g,%10g] lb = %g {fea=%d,btr=%d} ",
00181 Lb (index), Ub (index), objind >= 0 ? Lb (objind) : 0., feasible,betterbds);
00182
00183 if (feasible && !betterbds) {
00184
00185
00186 inner = fb;
00187
00188
00189 CoinCopyN (chg_bds, ncols, f_chg);
00190 CoinCopyN (olb, ncols, Lb ());
00191 CoinCopyN (oub, ncols, Ub ());
00192
00193 } else {
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 if (optimum_ &&
00207 ((!direction &&
00208 (optimum_ [index] >= olb [index]) &&
00209 (optimum_ [index] <= Lb (index) - COUENNE_EPS)) ||
00210 (direction &&
00211 (optimum_ [index] <= oub [index]) &&
00212 (optimum_ [index] >= Ub (index) + COUENNE_EPS)))) {
00213
00214 jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING,
00215 "fake tightening CUTS optimum: x%d=%g in [%g,%g] but not in [%g,%g]\n",
00216 index, olb [index], oub [index], Lb (index), Ub (index));
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
00242
00243 if (direction) {
00244
00245 oub [index] = Ub (index) = intvar ? floor (fb + COUENNE_EPS) : fb;
00246 chg_bds [index]. setUpper (t_chg_bounds::CHANGED);
00247
00248 } else {
00249
00250 olb [index] = Lb (index) = intvar ? ceil (fb - COUENNE_EPS) : fb;
00251 chg_bds [index]. setLower (t_chg_bounds::CHANGED);
00252 }
00253
00254 outer = fb;
00255
00256 tightened = true;
00257
00258
00259
00260 CoinCopyN (chg_bds, ncols, f_chg);
00261 CoinCopyN (olb, ncols, Lb ());
00262 CoinCopyN (oub, ncols, Ub ());
00263
00264
00265
00266 if (!(btCore (chg_bds))) {
00267
00268 jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING,
00269 "\n pruned by Probing\n");
00270 return -1;
00271
00272 } else {
00273
00274
00275
00276 CoinCopyN (Lb (), ncols, olb);
00277 CoinCopyN (Ub (), ncols, oub);
00278 }
00279
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289 CouNumber
00290 lb = Lb (index),
00291 ub = Ub (index);
00292
00293 if ((!direction && ((inner > ub) || (outer < lb))) ||
00294 ( direction && ((inner < lb) || (outer > ub)))) {
00295
00296
00297
00298 inner = direction ? lb : ub;
00299 outer = direction ? ub : lb;
00300 }
00301
00302 CouNumber diff = fabs (inner - outer);
00303
00304 if (diff <= COUENNE_EPS) break;
00305
00306 if (diff > 1.) {
00307
00308 CouNumber L = log (diff) / log (10.);
00309
00310 if (direction) fb = inner + exp (log (10.) * L/2);
00311 else fb = inner - exp (log (10.) * L/2);
00312
00313 } else fb = (inner + outer)/2;
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 jnlst_ -> Printf (Ipopt::J_ERROR, J_BOUNDTIGHTENING, "\n");
00324 }
00325
00326 Jnlst()->Printf(Ipopt::J_MOREVECTOR, J_BOUNDTIGHTENING, "\n");
00327 if (tightened)
00328 Jnlst()->Printf(Ipopt::J_MOREVECTOR, J_BOUNDTIGHTENING,
00329 " [x%2d] pruned %s [%g, %g] -- lb = %g cutoff = %g\n",
00330 index,direction?"right":"left",
00331 olb[index],oub[index], objind >= 0 ? Lb (objind) : 0., getCutOff ());
00332
00333 return tightened ? 1 : 0;
00334 }