00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "CouenneProblem.hpp"
00013 #include "CouenneProblemElem.hpp"
00014 #include "CouenneObject.hpp"
00015 #include "CouenneBranchingObject.hpp"
00016
00017 #include "CoinHelperFunctions.hpp"
00018
00019 using namespace Ipopt;
00020 using namespace Couenne;
00021
00022 static const double init_estimate = COUENNE_EPS;
00023
00025 CouenneObject::CouenneObject ():
00026
00027 OsiObject (),
00028 cutGen_ (NULL),
00029 problem_ (NULL),
00030 reference_ (NULL),
00031 strategy_ (MID_INTERVAL),
00032 jnlst_ (NULL),
00033 alpha_ (default_alpha),
00034 lp_clamp_ (default_clamp),
00035 feas_tolerance_ (feas_tolerance_default),
00036 doFBBT_ (true),
00037 doConvCuts_ (true),
00038 downEstimate_ (init_estimate),
00039 upEstimate_ (init_estimate),
00040 pseudoMultType_ (INFEASIBILITY) {}
00041
00042
00044 CouenneObject::CouenneObject (CouenneCutGenerator *cutgen,
00045 CouenneProblem *p,
00046 exprVar *ref,
00047 Bonmin::BabSetupBase *base,
00048 JnlstPtr jnlst):
00049 OsiObject (),
00050
00051 cutGen_ (cutgen),
00052 problem_ (p),
00053 reference_ (ref),
00054 strategy_ (MID_INTERVAL),
00055 jnlst_ (jnlst),
00056 alpha_ (default_alpha),
00057 lp_clamp_ (default_clamp),
00058 feas_tolerance_ (feas_tolerance_default),
00059 doFBBT_ (true),
00060 doConvCuts_ (true),
00061 downEstimate_ (init_estimate),
00062 upEstimate_ (init_estimate),
00063 pseudoMultType_ (INFEASIBILITY) {
00064
00065
00066 setParameters (base);
00067
00068
00069
00070 if (reference_ &&
00071 (reference_ -> Type () == AUX) &&
00072 jnlst_ -> ProduceOutput (J_SUMMARY, J_BRANCHING)) {
00073
00074 printf ("created Expression Object: "); reference_ -> print ();
00075 if (reference_ -> Image ()) {
00076 printf (" := ");
00077 reference_ -> Image () -> print ();
00078 }
00079
00080 printf (" with %s strategy [clamp=%g, alpha=%g]\n",
00081 (strategy_ == LP_CLAMPED) ? "lp-clamped" :
00082 (strategy_ == LP_CENTRAL) ? "lp-central" :
00083 (strategy_ == BALANCED) ? "balanced" :
00084 (strategy_ == MIN_AREA) ? "min-area" :
00085 (strategy_ == MID_INTERVAL) ? "mid-point" :
00086 (strategy_ == NO_BRANCH) ? "no-branching (null infeasibility)" :
00087 "no strategy",
00088 lp_clamp_, alpha_);
00089 }
00090 }
00091
00092
00094 CouenneObject::CouenneObject (exprVar *ref,
00095 Bonmin::BabSetupBase *base,
00096 JnlstPtr jnlst):
00097
00098 OsiObject (),
00099 cutGen_ (NULL),
00100 problem_ (NULL),
00101 reference_ (ref),
00102 strategy_ (MID_INTERVAL),
00103 jnlst_ (jnlst),
00104 alpha_ (default_alpha),
00105 lp_clamp_ (default_clamp),
00106 feas_tolerance_ (feas_tolerance_default),
00107 doFBBT_ (true),
00108 doConvCuts_ (true),
00109 downEstimate_ (init_estimate),
00110 upEstimate_ (init_estimate),
00111 pseudoMultType_ (INFEASIBILITY) {
00112
00113
00114 setParameters (base);
00115 }
00116
00117
00119 CouenneObject::CouenneObject (const CouenneObject &src):
00120 OsiObject (src),
00121 cutGen_ (src.cutGen_),
00122 problem_ (src.problem_),
00123 reference_ (src.reference_),
00124 strategy_ (src.strategy_),
00125 jnlst_ (src.jnlst_),
00126 alpha_ (src.alpha_),
00127 lp_clamp_ (src.lp_clamp_),
00128 feas_tolerance_ (src.feas_tolerance_),
00129 doFBBT_ (src.doFBBT_),
00130 doConvCuts_ (src.doConvCuts_),
00131 downEstimate_ (src.downEstimate_),
00132 upEstimate_ (src.upEstimate_),
00133 pseudoMultType_ (src.pseudoMultType_) {}
00134
00135
00139
00140 double CouenneObject::intInfeasibility (double value, double lb, double ub) const {
00141
00142 if (value < lb) value = lb;
00143 else if (value > ub) value = ub;
00144
00145 return CoinMin (value - floor (value + COUENNE_EPS),
00146 ceil (value - COUENNE_EPS) - value);
00147 }
00148
00149
00151 OsiBranchingObject *CouenneObject::createBranch (OsiSolverInterface *si,
00152 const OsiBranchingInformation *info,
00153 int way) const {
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163 if (jnlst_ -> ProduceOutput (J_ITERSUMMARY, J_BRANCHING)) {
00164 printf ("CouObj::createBranch on ");
00165 reference_ -> print (); printf ("\n");
00166 }
00167
00168
00169 problem_ -> domain () -> push
00170 (problem_ -> nVars (),
00171 info -> solution_,
00172 info -> lower_,
00173 info -> upper_,
00174 false);
00175
00176 CouNumber
00177 *brPts = NULL,
00178 *brDist = NULL;
00179
00180 expression *brVar = NULL;
00181 int whichWay = 0;
00182
00183 CouNumber improv;
00184
00185 if (reference_ -> Image ())
00186 improv = reference_ -> Image () ->
00187 selectBranch (this, info,
00188 brVar, brPts, brDist, whichWay);
00189 else {
00190
00191
00192
00193 brVar = reference_;
00194 brPts = (double *) realloc (brPts, sizeof (double));
00195 brDist = (double *) realloc (brDist, 2 * sizeof (double));
00196
00197 double point = info -> solution_ [reference_ -> Index ()];
00198
00199 *brPts = point;
00200 improv = 0.;
00201
00202 if (point > floor (point)) {improv = brDist [0] = point - floor (point);}
00203 if (point < ceil (point)) {improv = CoinMin (improv, brDist [1] = ceil (point) - point);}
00204
00205 point -= floor (point);
00206 whichWay = (point < 0.45) ? TWO_LEFT : (point > 0.55) ? TWO_RIGHT : TWO_RAND;
00207 }
00208
00209 assert (brVar);
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 if (pseudoMultType_ == PROJECTDIST) {
00223 downEstimate_ = brDist [0];
00224 upEstimate_ = brDist [1];
00225 } else setEstimates (info, NULL, brPts);
00226
00228 if (jnlst_ -> ProduceOutput (J_MOREMATRIX, J_BRANCHING)) {
00229 printf ("brpts for "); reference_ -> print ();
00230 if (reference_ -> Image ()) {printf (" := "); reference_ -> Image () -> print ();}
00231 printf (" is on "); brVar -> print ();
00232 printf (" @ %.12g [%.12g,%.12g]\n", *brPts,
00233 problem_ -> Lb (brVar -> Index ()),
00234 problem_ -> Ub (brVar -> Index ()));
00235
00236 if (brVar) {
00237
00238 if (improv <= COUENNE_EPS) {
00239 printf ("### warning, infeas = %g for ", improv);
00240 reference_ -> print ();
00241 if (reference_ -> Image ()) {printf (":="); reference_ -> Image () -> print ();}
00242 printf ("\n");
00243 }
00244
00245 int index = brVar -> Index ();
00246 if (info -> lower_ [index] >=
00247 info -> upper_ [index] - COUENNE_EPS) {
00248 printf ("### warning, tiny bounding box [%g,%g] for x_%d\n",
00249 info -> lower_ [index],
00250 info -> upper_ [index], index);
00251 }
00252 }
00253 }
00254
00255
00256 OsiBranchingObject *brObj = new CouenneBranchingObject
00257 (si, this, jnlst_, cutGen_, problem_, brVar, way, *brPts, doFBBT_, doConvCuts_);
00258
00259 problem_ -> domain () -> pop ();
00260
00261 if (brPts) free (brPts);
00262 if (brDist) free (brDist);
00263
00264 return brObj;
00265 }
00266
00267
00269 CouNumber CouenneObject::midInterval (CouNumber x, CouNumber l, CouNumber u,
00270 const OsiBranchingInformation *info) const {
00271
00272 CouNumber curAlpha = alpha_;
00273
00274 #if 1
00275 if (info) {
00276
00277
00278 int objInd = problem_ -> Obj (0) -> Body () -> Index ();
00279
00280 double
00281 lb = objInd >= 0 ? info -> lower_ [objInd] : problem_ -> Obj (0) -> Body () -> Value (),
00282 ub = problem_ -> getCutOff (),
00283 currentGap =
00284 (ub > COUENNE_INFINITY / 10 ||
00285 lb < -Couenne_large_bound / 10) ? 1.e3 :
00286 fabs (ub - lb) / (1.e-3 + CoinMin (fabs (ub), fabs (lb)));
00287
00288 #if 1
00289 if (currentGap < 1e-3) {
00290
00291 currentGap *= 1e3;
00292
00293 assert ((currentGap >= 0.) &&
00294 (currentGap <= 1.));
00295
00296 curAlpha = currentGap * alpha_ + (1 - currentGap);
00297 }
00298 #else
00299
00300
00301 curAlpha += (1 - alpha_) / (1. + currentGap);
00302 #endif
00303
00304
00305
00306
00307
00308 }
00309 #endif
00310
00311 if (u < l + COUENNE_EPS)
00312 return (0.5 * (l + u));
00313
00314 if (x<l) x = l;
00315 else if (x>u) x = u;
00316
00317 if (l < -large_bound)
00318 if (u > COUENNE_EPS) return 0.;
00319 else return CoinMax ((l+u)/2, (AGGR_MUL * (-1. + u)));
00320 else
00321 if (u > large_bound)
00322 if (l < - COUENNE_EPS) return 0.;
00323 else return CoinMin ((l+u)/2, (AGGR_MUL * (1. + l)));
00324 else {
00325
00326 CouNumber point = curAlpha * x + (1. - curAlpha) * (l + u) / 2.;
00327
00328 if ((point-l) / (u-l) < closeToBounds) point = l + (u-l) * closeToBounds;
00329 else if ((u-point) / (u-l) < closeToBounds) point = u + (l-u) * closeToBounds;
00330
00331 return point;
00332 }
00333 }
00334
00335
00337 CouNumber CouenneObject::getBrPoint (funtriplet *ft, CouNumber x0, CouNumber l, CouNumber u,
00338 const OsiBranchingInformation *info) const {
00339
00340 if ((l < -COUENNE_EPS) &&
00341 (u > COUENNE_EPS) &&
00342 (-l/u >= THRES_ZERO_SYMM) &&
00343 (-u/l >= THRES_ZERO_SYMM))
00344 return 0.;
00345
00346 CouNumber width = lp_clamp_ * (u-l);
00347
00348 switch (strategy_) {
00349
00350 case CouenneObject::MIN_AREA: return maxHeight (ft, l, u);
00351 case CouenneObject::BALANCED: return minMaxDelta (ft, l, u);
00352 case CouenneObject::LP_CLAMPED: return CoinMax (l + width, CoinMin (x0, u - width));
00353 case CouenneObject::LP_CENTRAL: return ((x0 < l + width) || (x0 > u - width)) ? (l+u)/2 : x0;
00354 case CouenneObject::MID_INTERVAL: return midInterval (x0, l, u, info);
00355
00356 default:
00357 printf ("Couenne: unknown branching point selection strategy\n");
00358 exit (-1);
00359 }
00360 }
00361
00362
00364 double CouenneObject::infeasibility (const OsiBranchingInformation *info, int &way) const {
00365
00366 if (strategy_ == NO_BRANCH) {
00367 upEstimate_ = downEstimate_ = init_estimate;
00368 return 0;
00369 }
00370
00371 problem_ -> domain () -> push
00372 (problem_ -> nVars (),
00373 info -> solution_,
00374 info -> lower_,
00375 info -> upper_,
00376 false);
00377
00378 double retval = checkInfeasibility (info);
00379
00380 problem_ -> domain () -> pop ();
00381
00382 bool isInt = reference_ -> isInteger ();
00383
00384 int refInd = reference_ -> Index ();
00385 double point = info -> solution_ [refInd];
00386
00387 if (pseudoMultType_ == INFEASIBILITY) {
00388
00389 if (isInt) {
00390 CouNumber intInfeas = intInfeasibility (point, info -> lower_ [refInd], info -> upper_ [refInd]);
00391
00392 if (retval < intInfeas) {
00393 if (downEstimate_ < point - floor (point)) downEstimate_ = point - floor (point);
00394 if (upEstimate_ < ceil (point) - point) upEstimate_ = ceil (point) - point;
00395 retval = intInfeas;
00396 }
00397 }
00398 else upEstimate_ = downEstimate_ = retval;
00399 }
00400 else setEstimates (info, &retval, NULL);
00401
00402 return (isInt ?
00403 CoinMax (retval, intInfeasibility (point, info -> lower_ [refInd], info -> upper_ [refInd])) :
00404 retval);
00405 }
00406
00407
00411 double CouenneObject::checkInfeasibility (const OsiBranchingInformation *info) const {
00412
00413 int refInd = reference_ -> Index ();
00414
00415 if (reference_ -> Type () == VAR)
00416 return (reference_ -> isInteger ()) ?
00417 intInfeasibility (info -> solution_ [refInd],
00418 info -> lower_ [refInd],
00419 info -> upper_ [refInd]) : 0.;
00420
00421 double
00422 vval = info -> solution_ [reference_ -> Index ()],
00423 fval = (*(reference_ -> Image ())) (),
00424 denom = CoinMax (1., reference_ -> Image () -> gradientNorm (info -> solution_));
00425
00426
00427 if (CoinIsnan (fval)) {
00428 fval = vval + 1.;
00429 denom = 1.;
00430 }
00431
00432 if (fabs (fval) > COUENNE_INFINITY)
00433 fval = COUENNE_INFINITY;
00434
00435 double
00436 retval =
00437 ((reference_ -> sign () == expression::AUX_GEQ) && (vval >= fval)) ? 0. :
00438 ((reference_ -> sign () == expression::AUX_LEQ) && (vval <= fval)) ? 0. : fabs (vval - fval),
00439
00440 ratio = (CoinMax (1., fabs (vval)) /
00441 CoinMax (1., fabs (fval)));
00442
00443
00444
00445 if ((ratio < 2) &&
00446 (ratio > .5) &&
00447 ((retval /= denom) < CoinMin (COUENNE_EPS, feas_tolerance_)))
00448 retval = 0.;
00449
00450 if (
00451 (jnlst_ -> ProduceOutput (J_DETAILED, J_BRANCHING))) {
00452
00453 printf (" infeas %g: ", retval);
00454 reference_ -> print ();
00455 if (reference_ -> Image ()) {printf (" := "); reference_ -> Image () -> print ();}
00456 printf ("\n");
00457 }
00458
00459
00460
00461
00462
00463 if (retval > 1.e40)
00464 retval = 1.e20;
00465
00466 return (reference_ -> isInteger ()) ?
00467 CoinMax (retval, intInfeasibility (info -> solution_ [refInd],
00468 info -> lower_ [refInd],
00469 info -> upper_ [refInd])) :
00470 retval;
00471 }
00472
00473
00475 void CouenneObject::setParameters (Bonmin::BabSetupBase *base) {
00476
00477 if (!base) return;
00478
00479 std::string s;
00480
00481 base -> options () -> GetStringValue ("pseudocost_mult", s, "couenne.");
00482
00483 if (s == "interval_lp") pseudoMultType_ = INTERVAL_LP;
00484 else if (s == "interval_lp_rev") pseudoMultType_ = INTERVAL_LP_REV;
00485 else if (s == "interval_br") pseudoMultType_ = INTERVAL_BR;
00486 else if (s == "interval_br_rev") pseudoMultType_ = INTERVAL_BR_REV;
00487 else if (s == "infeasibility") pseudoMultType_ = INFEASIBILITY;
00488 else if (s == "projectDist") pseudoMultType_ = PROJECTDIST;
00489
00490 base -> options() -> GetStringValue ("branch_fbbt", s, "couenne."); doFBBT_ = (s=="yes");
00491 base -> options() -> GetStringValue ("branch_conv_cuts", s, "couenne."); doConvCuts_ = (s=="yes");
00492
00493 base -> options() -> GetNumericValue ("feas_tolerance", feas_tolerance_, "couenne.");
00494
00495 std::string brtype;
00496 base -> options () -> GetStringValue ("branch_pt_select", brtype, "couenne.");
00497
00498 if (brtype == "balanced") strategy_ = BALANCED;
00499 else if (brtype == "lp-clamped") strategy_ = LP_CLAMPED;
00500 else if (brtype == "lp-central") strategy_ = LP_CENTRAL;
00501 else if (brtype == "min-area") strategy_ = MIN_AREA;
00502 else if (brtype == "no-branch") strategy_ = NO_BRANCH;
00503 else if (brtype == "mid-point") {
00504 strategy_ = MID_INTERVAL;
00505 base -> options () -> GetNumericValue ("branch_midpoint_alpha", alpha_, "couenne.");
00506 }
00507
00508 if (strategy_ == LP_CLAMPED ||
00509 strategy_ == LP_CENTRAL)
00510 base -> options () -> GetNumericValue ("branch_lp_clamp", lp_clamp_, "couenne.");
00511
00512
00513 if (reference_ && reference_ -> Type () == AUX) {
00514
00515 std::string br_operator = "";
00516
00517 switch (reference_ -> Image () -> code ()) {
00518
00519 case COU_EXPRPOW: {
00520
00521
00522 base -> options () -> GetStringValue ("branch_pt_select_pow", brtype, "couenne.");
00523
00524 CouNumber expon = reference_ -> Image () -> ArgList () [1] -> Value ();
00525
00526 if (fabs (expon - 2.) < COUENNE_EPS) br_operator = "sqr";
00527 else if (fabs (expon - 3.) < COUENNE_EPS) br_operator = "cube";
00528 else if (expon < 0.) br_operator = "negpow";
00529 else br_operator = "pow";
00530 } break;
00531
00532 case COU_EXPRMUL:
00533 br_operator = (reference_ -> Image () -> ArgList () [0] -> Index () !=
00534 reference_ -> Image () -> ArgList () [1] -> Index ()) ?
00535 "prod" : "sqr";
00536 break;
00537 case COU_EXPRINV: br_operator = "negpow"; break;
00538 case COU_EXPRDIV: br_operator = "div"; break;
00539 case COU_EXPRLOG: br_operator = "log"; break;
00540 case COU_EXPREXP: br_operator = "exp"; break;
00541 case COU_EXPRSIN:
00542 case COU_EXPRCOS: br_operator = "trig"; break;
00543 default: break;
00544 }
00545
00546 if (br_operator != "") {
00547
00548 char select [40], sel_clamp [40];
00549 double lp_clamp_fun = default_clamp;
00550 sprintf (select, "branch_pt_select_%s", br_operator.c_str ());
00551 sprintf (sel_clamp, "branch_lp_clamp_%s", br_operator.c_str ());
00552 base -> options () -> GetStringValue (select, brtype, "couenne.");
00553 base -> options () -> GetNumericValue (sel_clamp, lp_clamp_fun, "couenne.");
00554
00555 if (lp_clamp_fun != default_clamp)
00556 lp_clamp_ = lp_clamp_fun;
00557
00558 if (brtype == "balanced") strategy_ = BALANCED;
00559 else if (brtype == "lp-clamped") strategy_ = LP_CLAMPED;
00560 else if (brtype == "lp-central") strategy_ = LP_CENTRAL;
00561 else if (brtype == "min-area") strategy_ = MIN_AREA;
00562 else if (brtype == "no-branch") strategy_ = NO_BRANCH;
00563 else if (brtype == "mid-point") {
00564 strategy_ = MID_INTERVAL;
00565 double alpha_fun = default_alpha;
00566 base -> options () -> GetNumericValue ("branch_midpoint_alpha", alpha_fun, "couenne.");
00567 if (alpha_fun != default_alpha)
00568 alpha_ = alpha_fun;
00569 }
00570 }
00571 }
00572 }
00573
00574
00576 void CouenneObject::setEstimates (const OsiBranchingInformation *info,
00577 CouNumber *infeasibility,
00578 CouNumber *brpoint) const {
00579
00580 int index = reference_ -> Index ();
00581
00582
00583
00584 CouNumber
00585 *up = &upEstimate_,
00586 *down = &downEstimate_,
00587 point = 0.,
00588 lower = info -> lower_ [index],
00589 upper = info -> upper_ [index];
00590
00592
00593
00594
00595 if ((pseudoMultType_ == INTERVAL_LP_REV) ||
00596 (pseudoMultType_ == INTERVAL_BR_REV)) {
00597
00598 up = &downEstimate_;
00599 down = &upEstimate_;
00600 }
00601
00603 if (info &&
00604 ((pseudoMultType_ == INTERVAL_LP) ||
00605 (pseudoMultType_ == INTERVAL_LP_REV)))
00606
00607 point = info -> solution_ [index];
00608
00609 else if (brpoint &&
00610 ((pseudoMultType_ == INTERVAL_BR) ||
00611 (pseudoMultType_ == INTERVAL_BR_REV)))
00612
00613 point = *brpoint;
00614
00615
00616
00617
00618
00619
00620 point = midInterval (point, lower, upper, info);
00621
00622
00623
00624 if ((lower > -COUENNE_INFINITY) &&
00625 (upper < COUENNE_INFINITY)) {
00626
00627 CouNumber delta = closeToBounds * (upper - lower);
00628
00629 if (point < lower + delta)
00630 point = lower + delta;
00631 else if (point > upper - delta)
00632 point = upper - delta;
00633 }
00634
00636 switch (pseudoMultType_) {
00637
00638 case INFEASIBILITY:
00639
00640 if (infeasibility)
00641 upEstimate_ = downEstimate_ = *infeasibility;
00642
00643 break;
00644
00645 case INTERVAL_LP:
00646 case INTERVAL_LP_REV:
00647 case INTERVAL_BR:
00648 case INTERVAL_BR_REV:
00649 assert (info);
00650 *up = CoinMin (max_pseudocost, COUENNE_EPS + fabs (upper - point));
00651 *down = CoinMin (max_pseudocost, COUENNE_EPS + fabs ( point - lower));
00652 break;
00653
00654 case PROJECTDIST:
00655 break;
00656
00657 default:
00658 printf ("Couenne: invalid estimate setting procedure\n");
00659 exit (-1);
00660 }
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679 assert (downEstimate_ > 0. &&
00680 upEstimate_ > 0.);
00681 }