00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "OsiSolverInterface.hpp"
00013
00014 #include "CbcBranchActual.hpp"
00015 #include "CbcModel.hpp"
00016
00017 #include "CouenneChooseVariable.hpp"
00018 #include "CouenneProblem.hpp"
00019 #include "CouenneProblemElem.hpp"
00020 #include "CouenneExprVar.hpp"
00021 #include "CouenneObject.hpp"
00022
00023 #ifdef COIN_HAS_NTY
00024 #include "Nauty.h"
00025 #endif
00026
00027 struct objPri {
00028 int objIndex_;
00029 int priority_;
00030 };
00031
00032 bool compPri (struct objPri *one, struct objPri *two) {
00033 return (one -> priority_ <
00034 two -> priority_);
00035 }
00036
00037 using namespace Couenne;
00038
00039 void eliminateIntegerObjects (OsiSolverInterface *model);
00040 void eliminateIntegerObjects (CbcModel *model);
00041
00043 CouenneChooseVariable::CouenneChooseVariable ():
00044 OsiChooseVariable (),
00045 problem_ (NULL) {}
00046
00047
00049 CouenneChooseVariable::CouenneChooseVariable (const OsiSolverInterface *si,
00050 CouenneProblem *p,
00051 JnlstPtr jnlst):
00052 OsiChooseVariable (si),
00053 problem_ (p),
00054 jnlst_ (jnlst) {}
00055
00056
00058 CouenneChooseVariable::CouenneChooseVariable (const CouenneChooseVariable &source):
00059 OsiChooseVariable (source),
00060 problem_ (source.problem_),
00061 jnlst_ (source.jnlst_) {}
00062
00063
00065 CouenneChooseVariable & CouenneChooseVariable::operator= (const CouenneChooseVariable& rhs) {
00066 problem_ = rhs.problem_;
00067 jnlst_ = rhs.jnlst_;
00068 return *this;
00069 }
00070
00071
00075 int CouenneChooseVariable::setupList (OsiBranchingInformation *info, bool initialize) {
00076
00077 static bool firstCall = true;
00078
00079 int n = problem_ -> nVars ();
00080
00081 problem_ -> domain () -> push
00082 (n,
00083 info -> solution_,
00084 info -> lower_,
00085 info -> upper_);
00086
00087 jnlst_ -> Printf (Ipopt::J_ITERSUMMARY, J_BRANCHING, "----------------- setup list\n");
00088 if (jnlst_ -> ProduceOutput (Ipopt::J_DETAILED, J_BRANCHING)) {
00089 printf ("----------------- setup list\n");
00090 for (int i=0; i<problem_ -> domain () -> current () -> Dimension (); i++)
00091 if (problem_ -> Var (i) -> Multiplicity () > 0) {
00092 printf ("%4d %20.4g [%20.4g %20.4g]", i, info -> solution_ [i], info -> lower_ [i], info -> upper_ [i]);
00093 if (problem_ -> Var (i) -> Type () == AUX) {
00094 printf (" expr. %20.4g [%+e] ", (*(problem_ -> Var (i) -> Image ())) (), (*(problem_ -> Var (i) -> Image ())) () - info -> solution_ [i]);
00095 problem_ -> Var (i) -> Image () -> print ();
00096 }
00097 printf ("\n");
00098 }
00099 }
00100
00101 int retval;
00102
00103
00104
00105
00106
00107
00108
00109 {
00110 if (initialize) {
00111 status_=-2;
00112 delete [] goodSolution_;
00113 bestObjectIndex_=-1;
00114 numberStrongDone_=0;
00115 numberStrongIterations_ = 0;
00116 numberStrongFixed_ = 0;
00117 goodSolution_ = NULL;
00118 goodObjectiveValue_ = COIN_DBL_MAX;
00119 }
00120
00121 numberOnList_=0;
00122 numberUnsatisfied_=0;
00123
00124 if (firstCall) {
00125
00126 eliminateIntegerObjects (const_cast <OsiSolverInterface *> (solver_));
00127 eliminateIntegerObjects (const_cast <OsiSolverInterface *> (info -> solver_));
00128
00129 firstCall = false;
00130 }
00131
00132 int numberObjects = solver_ -> numberObjects();
00133
00134 assert (numberObjects);
00135
00136 OsiObject ** object = info -> solver_ -> objects ();
00137
00138
00139 bool feasible = true;
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 #define NEW_SETUPLIST
00153
00154 #ifdef NEW_SETUPLIST
00155
00156 int way;
00157
00158 std::vector <struct objPri *> listPri;
00159
00160 for (int i=0; i<numberObjects; i++) {
00161
00162 struct objPri *singleton = new struct objPri;
00163 singleton -> objIndex_ = i;
00164 singleton -> priority_ = object [i] -> priority ();
00165
00166 listPri.push_back (singleton);
00167 }
00168
00169
00170
00171
00172
00173
00174 std::sort (listPri.begin (), listPri.end (), compPri);
00175
00176
00177
00178
00179
00180 int minPriority = -1;
00181
00182 double maxInfeas = 0.;
00183
00184 for (int i=0; i<numberObjects; ++i) {
00185
00186 int
00187 currIndex = listPri [i] -> objIndex_,
00188 priority = listPri [i] -> priority_;
00189
00190 if ((minPriority >= 0) &&
00191 (priority > minPriority))
00192 break;
00193
00194
00195 double infeas = object [currIndex] -> checkInfeasibility (info);
00196
00197
00198
00199 if (((minPriority < 0) || (priority == minPriority)) &&
00200 (infeas > maxInfeas)) {
00201
00202
00203
00204 if (minPriority < 0)
00205 minPriority = priority;
00206
00207 maxInfeas = infeas;
00208
00209 ++numberUnsatisfied_;
00210
00211 if (infeas == COIN_DBL_MAX) {
00212
00213 feasible = false;
00214 break;
00215
00216 } else {
00217
00218 list_ [0] = currIndex;
00219 useful_ [0] = infeas;
00220 }
00221 }
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231 for (std::vector <struct objPri *>::iterator i=listPri.begin (); i != listPri.end (); ++i)
00232 delete (*i);
00233
00234 #else
00235
00236 int maximumStrong = numberStrong_ ? CoinMin (numberStrong_, numberObjects) : 1;
00237
00238 double check = 0.0;
00239
00240 int
00241 checkIndex = 0,
00242 bestPriority = COIN_INT_MAX,
00243
00244 putOther = numberObjects;
00245
00246
00247
00248 for (int i=0; i < maximumStrong; i++) {
00249 list_ [i] = -1;
00250 useful_ [i] = 0.;
00251 }
00252
00253
00254
00255
00256
00257
00258
00259 for (int i=0; i<numberObjects; i++) {
00260
00261 int way;
00262
00263 double value = object [i] -> checkInfeasibility (info);
00264
00265 if (value > 0.) {
00266
00267 numberUnsatisfied_++;
00268
00269 if (value == COIN_DBL_MAX) {
00270 feasible = false;
00271 break;
00272 }
00273
00274 int priorityLevel = object [i] -> priority ();
00275
00276
00277 if (priorityLevel < bestPriority) {
00278
00279 for (int j=0; j<maximumStrong; j++) {
00280
00281 if (list_ [j] >= 0) {
00282
00283 int iObject = list_[j];
00284
00285 list_ [j] = -1;
00286 useful_ [j] = 0.;
00287 list_ [--putOther] = iObject;
00288 }
00289 }
00290
00291 bestPriority = priorityLevel;
00292 check = 0.;
00293 }
00294
00295 if ((priorityLevel == bestPriority)
00296 && (value > check)
00297
00298 ) {
00299
00300 int iObject = list_ [checkIndex];
00301 if (iObject >= 0)
00302 list_ [--putOther] = iObject;
00303
00304
00305 list_ [checkIndex] = i;
00306 useful_ [checkIndex] = value;
00307
00308
00309 check=COIN_DBL_MAX;
00310 for (int j=0;j<maximumStrong;j++) {
00311 if (list_[j]>=0) {
00312 if (useful_[j]<check) {
00313 check=useful_[j];
00314 checkIndex=j;
00315 }
00316 } else {
00317 check=0.0;
00318 checkIndex = j;
00319 break;
00320 }
00321 }
00322 } else list_ [--putOther] = i;
00323
00324 }
00325 }
00326 #endif
00327
00328
00329 numberOnList_=0;
00330
00331 if (feasible) {
00332 #ifndef NEW_SETUPLIST
00333 for (int i=0;i<maximumStrong;i++) {
00334 if (list_[i]>=0) {
00335 list_[numberOnList_]=list_[i];
00336 useful_[numberOnList_++]=-useful_[i];
00337 }
00338 }
00339 if (numberOnList_) {
00340
00341 CoinSort_2(useful_,useful_+numberOnList_,list_);
00342
00343 int i = numberOnList_;
00344 for (;putOther<numberObjects;putOther++)
00345 list_[i++]=list_[putOther];
00346 assert (i==numberUnsatisfied_);
00347 if (!numberStrong_)
00348 numberOnList_=0;
00349 }
00350 #endif
00351 } else {
00352
00353 numberUnsatisfied_ = -1;
00354 }
00355
00356 retval = numberUnsatisfied_;
00357 }
00358
00360
00361
00362
00364
00365 problem_ -> domain () -> pop ();
00366
00367 jnlst_ -> Printf (Ipopt::J_ITERSUMMARY, J_BRANCHING, "----------------- setup list done, %d objects\n", retval);
00368
00369
00370
00371
00372
00373
00374
00375
00376 return retval;
00377 }
00378
00379
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399 bool CouenneChooseVariable::feasibleSolution (const OsiBranchingInformation * info,
00400 const double * solution,
00401 int numberObjects,
00402 const OsiObject ** objects) {
00403
00404 #ifdef FM_CHECKNLP2
00405 bool isFeas = problem_->checkNLP2(solution,
00406 0,
00407 false,
00408 true,
00409 true,
00410 problem_ -> getFeasTol());
00411
00412 return isFeas;
00413 #else
00414 int indobj = problem_ -> Obj (0) -> Body () -> Index ();
00415 double obj = indobj >= 0 ? solution [indobj] : problem_ -> Obj (0) -> Body () -> Value ();
00416 return problem_ -> checkNLP (solution, obj);
00417 #endif
00418 }
00419
00420
00422 void CouenneChooseVariable::registerOptions (Ipopt::SmartPtr <Bonmin::RegisteredOptions> roptions) {
00423
00424 roptions -> AddStringOption2
00425 ("enable_sos",
00426 "Use Special Ordered Sets (SOS) as indicated in the MINLP model",
00427 "no",
00428 "no","",
00429 "yes","");
00430
00431 roptions -> AddStringOption2
00432 ("branch_fbbt",
00433 "Apply bound tightening before branching",
00434 "yes",
00435 "no","",
00436 "yes","",
00437 "After applying a branching rule and before re-solving the subproblem, apply Bound Tightening.");
00438
00439 roptions -> AddStringOption2
00440 ("branch_conv_cuts",
00441 "Apply convexification cuts before branching (for now only within strong branching)",
00442 "yes",
00443 "no","",
00444 "yes","",
00445 "After applying a branching rule and before resolving the subproblem, generate a round of linearization cuts with the new bounds enforced by the rule."
00446 );
00447
00448 roptions -> AddStringOption6
00449 ("branch_pt_select",
00450 "Chooses branching point selection strategy",
00451 "mid-point",
00452 "lp-clamped", "LP point clamped in [k,1-k] of the bound intervals (k defined by lp_clamp)",
00453 "lp-central", "LP point if within [k,1-k] of the bound intervals, middle point otherwise"
00454 "(k defined by branch_lp_clamp)",
00455 "balanced", "minimizes max distance from curve to convexification",
00456 "min-area", "minimizes total area of the two convexifications",
00457 "mid-point", "convex combination of current point and mid point",
00458 "no-branch", "do not branch, return null infeasibility; for testing purposes only",
00459 "");
00460
00461 std::string br_ops [] = {"prod", "div", "exp", "log", "trig",
00462 "pow", "negpow", "sqr", "cube", ""};
00463
00464 for (int i=0; br_ops [i] != ""; i++) {
00465
00466 char optname [40], optname2 [40], description [90];
00467 sprintf (optname, "branch_pt_select_%s", br_ops [i].c_str ());
00468 sprintf (optname2, "branch_lp_clamp_%s", br_ops [i].c_str ());
00469 sprintf (description, "Chooses branching point selection strategy for operator %s.",
00470 br_ops [i].c_str ());
00471
00472 roptions -> AddStringOption7
00473 (optname,
00474 description,
00475 "common",
00476 "common", "use strategy defined for generic operators",
00477 "lp-clamped", "LP point clamped in [k,1-k] of the bound intervals "
00478 "(k defined by lp_clamp_${this operator}$)",
00479 "lp-central", "LP point if within [k,1-k] of the bound intervals, middle point otherwise"
00480 "(k defined by branch_lp_clamp_${this operator}$)",
00481 "balanced", "minimizes max distance from curve to convexification",
00482 "min-area", "minimizes total area of the two convexifications",
00483 "mid-point", "convex combination of current point and mid point",
00484 "no-branch", "do not branch, return null infeasibility; for testing purposes only",
00485 "");
00486
00487 roptions -> AddBoundedNumberOption
00488 (optname2,
00489 "Defines safe interval percentage [0,0.5] for using LP point as a branching point.",
00490 0.,false,
00491 0.5,false,
00492 0.2);
00493 }
00494
00495 roptions -> AddBoundedNumberOption
00496 ("branch_midpoint_alpha",
00497 "Defines convex combination of mid point and current LP point: "
00498 "b = alpha x_lp + (1-alpha) (lb+ub)/2.",
00499 0.,false,
00500 1.,false,
00501 default_alpha);
00502
00503 roptions -> AddBoundedNumberOption
00504 ("branch_lp_clamp",
00505 "Defines safe interval percentage for using LP point as a branching point.",
00506 0.,false,
00507 1.,false,
00508 0.2);
00509
00510
00511
00512
00513 roptions -> AddLowerBoundedIntegerOption
00514 ("cont_var_priority",
00515 "Priority of continuous variable branching",
00516 1, 99,
00517 "When branching, this is compared to the priority of integer variables, whose priority is given by int_var_priority, and SOS, whose priority is 10. "
00518 "Higher values mean smaller priority."
00519 );
00520
00521 roptions -> AddLowerBoundedIntegerOption
00522 ("int_var_priority",
00523 "Priority of integer variable branching",
00524 1, 98,
00525 "When branching, this is compared to the priority of continuous variables, whose priority is given by cont_var_priority, and SOS, whose priority is 10. "
00526 "Higher values mean smaller priority."
00527 );
00528
00529 roptions -> AddStringOption2
00530 ("red_cost_branching",
00531 "Apply Reduced Cost Branching (instead of the Violation Transfer) -- MUST have vt_obj enabled",
00532 "no",
00533 "no", "Use Violation Transfer with $\\sum |\\pi_i a_{ij}|$",
00534 "yes","Use Reduced cost branching with $|\\sum \\pi_i a_{ij}|$");
00535
00536 roptions -> AddStringOption2
00537 ("orbital_branching",
00538 "detect symmetries and apply orbital branching",
00539 "no",
00540 "yes", "",
00541 "no", "");
00542
00543 roptions -> AddLowerBoundedIntegerOption
00544 ("orbital_branching_depth",
00545 "Maximum depth at which the symmetry group is computed",
00546 -1, 10,
00547 "Select -1 if you want to compute the symmetry group at all nodes");
00548 }
00549
00550
00551
00552
00553
00554
00555 int gutsofEIO (OsiObject **objects, int nco) {
00556
00557 int
00558 nRealObj,
00559 currObj = 0;
00560
00561 for (; currObj < nco; ++currObj)
00562
00563 if ((NULL != dynamic_cast <CbcSimpleInteger *> (objects [currObj])) ||
00564 (NULL != dynamic_cast <OsiSimpleInteger *> (objects [currObj]))) {
00565
00566
00567 delete objects [currObj];
00568 objects [currObj] = NULL;
00569 }
00570
00571
00572
00573 for (nRealObj = 0, currObj = -1; nRealObj < nco; ++nRealObj)
00574
00575 if (NULL == objects [nRealObj]) {
00576
00577 if (currObj < 0)
00578 currObj = nRealObj + 1;
00579
00580 while ((currObj < nco) &&
00581 (NULL == objects [currObj]))
00582 ++currObj;
00583
00584 if (currObj >= nco)
00585 break;
00586
00587 objects [nRealObj] =
00588 objects [currObj];
00589
00590 objects [currObj] = NULL;
00591 }
00592
00593
00594
00595 return nRealObj;
00596 }
00597
00598 void eliminateIntegerObjects (OsiSolverInterface *model) {model -> setNumberObjects (gutsofEIO (model -> objects (), model -> numberObjects ()));}
00599 void eliminateIntegerObjects (CbcModel *model) {model -> setNumberObjects (gutsofEIO (model -> objects (), model -> numberObjects ()));}