00001
00002
00003 #if defined(_MSC_VER)
00004
00005 # pragma warning(disable:4786)
00006 #endif
00007
00008 #include <climits>
00009 #include "BonNWayChoose.hpp"
00010 #include "BonNWayObject.hpp"
00011 #include "CoinTime.hpp"
00012
00013 #ifndef NDEBUG
00014 #define ASSERTED_CAST static_cast
00015 #else
00016 #define ASSERTED_CAST dynamic_cast
00017 #endif
00018 namespace Bonmin
00019 {
00020
00021
00022 BonNWayChoose::BonNWayChoose(BabSetupBase &b, const OsiSolverInterface* solver):
00023 OsiChooseVariable(solver),
00024 br_depth_(0),
00025 bounds_(),
00026 unit_changes_(),
00027 num_ps_costs_(),
00028 num_eval_(),
00029 geo_means_(0)
00030 {
00031 Ipopt::SmartPtr<Ipopt::OptionsList> options = b.options();
00032 options->GetNumericValue("time_limit", time_limit_, b.prefix());
00033 options->GetNumericValue("cutoff_multiplier", cutoff_multiplier_, b.prefix());
00034 options->GetNumericValue("pseudocost_trust_value", pseudocost_trust_value_, b.prefix());
00035 options->GetIntegerValue("strong_branch_depth", br_depth_, b.prefix());
00036 options->GetIntegerValue("nway_branch_log_level", log_, b.prefix());
00037 options->GetEnumValue("do_fixings", do_fixings_, b.prefix());
00038 options->GetEnumValue("use_geo_means", geo_means_, b.prefix());
00040 int numberObjects = solver_->numberObjects();
00041 std::cout<<"Number objects "<<numberObjects<<std::endl;
00042 start_time_ = CoinCpuTime();
00043 OsiObject ** object = solver->objects();
00044 for (int i=0;i<numberObjects;i++) {
00045 BonNWayObject * nway = dynamic_cast<BonNWayObject *>(object[i]);
00046 if(!nway) continue;
00047 start_nway_ = i;
00048 break;
00049 }
00050 numberObjects -= start_nway_;
00051 }
00052
00053 BonNWayChoose::BonNWayChoose(const BonNWayChoose & rhs) :
00054 OsiChooseVariable(rhs),
00055 br_depth_(rhs.br_depth_),
00056 do_fixings_(rhs.do_fixings_),
00057 cutoff_multiplier_(rhs.cutoff_multiplier_),
00058 pseudocost_trust_value_(rhs.pseudocost_trust_value_),
00059 time_limit_(rhs.time_limit_),
00060 start_time_(rhs.start_time_),
00061 start_nway_(rhs.start_nway_),
00062 log_(rhs.log_),
00063 bounds_(rhs.bounds_),
00064 unit_changes_(rhs.unit_changes_),
00065 num_ps_costs_(rhs.num_ps_costs_),
00066 num_eval_(rhs.num_eval_),
00067 geo_means_(rhs.geo_means_)
00068 {
00069 }
00070
00071 BonNWayChoose &
00072 BonNWayChoose::operator=(const BonNWayChoose & rhs)
00073 {
00074 if (this != &rhs) {
00075 br_depth_ = rhs.br_depth_;
00076 do_fixings_ = rhs.do_fixings_;
00077 cutoff_multiplier_ = rhs.cutoff_multiplier_;
00078 pseudocost_trust_value_ = rhs.pseudocost_trust_value_;
00079 time_limit_ = rhs.time_limit_;
00080 start_time_ = rhs.start_time_;
00081 log_ = rhs.log_;
00082 start_nway_ = rhs.start_nway_;
00083 OsiChooseVariable::operator=(rhs);
00084 bounds_ = rhs.bounds_;
00085 unit_changes_ = rhs.unit_changes_;
00086 num_ps_costs_ = rhs.num_ps_costs_;
00087 num_eval_ = rhs.num_eval_;
00088 geo_means_ = rhs.geo_means_;
00089 }
00090 return *this;
00091 }
00092
00093 OsiChooseVariable *
00094 BonNWayChoose::clone() const
00095 {
00096 return new BonNWayChoose(*this);
00097 }
00098
00099 BonNWayChoose::~BonNWayChoose ()
00100 {
00101 }
00102
00103 void
00104 BonNWayChoose::registerOptions(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions)
00105 {
00106 roptions->SetRegisteringCategory("NWay Strong branching setup", RegisteredOptions::BonminCategory);
00107 roptions->AddLowerBoundedIntegerOption("nway_branch_log_level",
00108 "Log level for the branching on nways",
00109 0,1,
00110 "");
00111
00112 roptions->AddLowerBoundedIntegerOption("strong_branch_depth",
00113 "To which level do we perform strong-branching",
00114 0,0,
00115 "");
00116
00117 roptions->AddLowerBoundedNumberOption("cutoff_multiplier",
00118 "multiplier applied to cutoff_ for computing pseudo-cost of infeasible sub-problems",
00119 1.,0,3.,
00120 "");
00121
00122 roptions->AddLowerBoundedNumberOption("pseudocost_trust_value",
00123 "Trust pseudo cost of best nway object if it is above this value",
00124 0.,0,0,
00125 "");
00126
00127 roptions->AddStringOption2("use_geo_means", "Use geometrical means to average pseudo-costs",
00128 "yes",
00129 "no", "Use artihmetical means",
00130 "yes", "Use geometrical means","");
00131
00132 roptions->AddStringOption4("do_fixings",
00133 "Do we fix variables in strong branching?",
00134 "all",
00135 "none", "Don't do any.",
00136 "in-tree", "Fix only variables in the tree",
00137 "strong-branching", "Fix variable in strong branching only",
00138 "all", "Fix whenever possible",
00139 "");
00140
00141
00142 }
00143
00144 double
00145 BonNWayChoose::compute_usefulness(int objectIndex, const OsiBranchingInformation * info) const
00146 {
00147 int nwayIndex = objectIndex - start_nway_;
00148
00149 BonNWayObject * nway = ASSERTED_CAST<BonNWayObject *>(info->solver_->objects()[objectIndex]);
00150 assert(nway);
00151 size_t n = nway->numberMembers();
00152 const int * vars = nway->members();
00153
00154 std::vector<double> unit_changes(unit_changes_[nwayIndex]);
00155 if(geo_means_){
00156 for(size_t k = 0 ; k < unit_changes.size() ; k++) unit_changes[k] = (num_ps_costs_[nwayIndex][k]) ? pow(unit_changes[k], 1./(double) num_ps_costs_[nwayIndex][k]): unit_changes[k];
00157 }
00158 else {
00159 for(size_t k = 0 ; k < unit_changes.size() ; k++) unit_changes[k] = (num_ps_costs_[nwayIndex][k]) ? unit_changes[k]/(double) num_ps_costs_[nwayIndex][k]: unit_changes[k];
00160 }
00161
00162
00163 double r_val = compute_usefulness(info, n, vars, bounds_[nwayIndex], unit_changes);
00164 return r_val;
00165 }
00166
00167 double
00168 BonNWayChoose::compute_usefulness(const OsiBranchingInformation * info,
00169 size_t n, const int * vars,const std::vector<double> &bounds, const std::vector<double> &unit_changes) const
00170 {
00171 const double * solution = info->solution_;
00172 double obj_val = info->objectiveValue_;
00173 const double * lower = info->lower_;
00174 const double * upper = info->upper_;
00175 double integerTolerance = info->integerTolerance_;
00176 double cutoff = info->cutoff_*cutoff_multiplier_;
00177 double r_val = (geo_means_) ? 1 : 0;
00178
00179 for(size_t i = 0 ; i < n ; i++){
00180 int iCol = vars[i];
00181 if(fabs(lower[iCol] - upper[iCol]) < integerTolerance) {
00182
00183 continue;
00184 }
00185 assert(lower[iCol] < upper[iCol]);
00186 double residual = upper[iCol] - solution[iCol];
00187 double score = std::min(cutoff - obj_val, std::max(residual*unit_changes[i],bounds[i] - obj_val));
00188 if(geo_means_)
00189 r_val*=score;
00190 else
00191 r_val += score;
00192 }
00193 return r_val;
00194 }
00195
00196 int
00197 BonNWayChoose::setupList ( OsiBranchingInformation *info, bool initialize)
00198 {
00199 assert(initialize);
00200 if (initialize) {
00201 status_=-2;
00202 delete [] goodSolution_;
00203 bestObjectIndex_=-1;
00204 goodSolution_ = NULL;
00205 goodObjectiveValue_ = COIN_DBL_MAX;
00206 }
00207
00208
00209 numberOnList_=0;
00210 numberUnsatisfied_=0;
00211 int numberObjects = info->solver_->numberObjects() - start_nway_;
00212 double cutoff = info->cutoff_;
00213 if(info->depth_ == 0){
00214 bounds_.resize(0);
00215 unit_changes_.resize(0);
00216 bounds_.resize(numberObjects, std::vector<double>(numberObjects,cutoff));
00217 unit_changes_.resize(numberObjects, std::vector<double>(numberObjects,0));
00218 num_eval_.resize(numberObjects, 0);
00219 num_ps_costs_.resize(numberObjects, std::vector<int>(numberObjects,0));
00220 }
00221 else {
00222 assert(unit_changes_.size() == numberObjects);
00223 assert(bounds_.size() == unit_changes_.size());
00224 }
00225
00226 int maximumStrong = numberObjects;
00227
00228 double check = -COIN_DBL_MAX;
00229 int checkIndex=0;
00230 int bestPriority=COIN_INT_MAX;
00231 int putOther = numberObjects;
00232 int i;
00233 for (i=0;i<numberObjects;i++) {
00234 list_[i]=-1;
00235 useful_[i]=0.0;
00236 }
00237
00238 OsiObject ** object = info->solver_->objects();
00239 object += start_nway_;
00240
00241
00242 bool feasible = true;
00243 for ( i=0;i<numberObjects;i++) {
00244 int way;
00245 double value = object[i]->infeasibility(info,way);
00246 if (value>0.0) {
00247 numberUnsatisfied_++;
00248 int priorityLevel = object[i]->priority();
00249
00250 if (priorityLevel<bestPriority) {
00251 for (int j=maximumStrong-1;j>=0;j--) {
00252 if (list_[j]>=0) {
00253 int iObject = list_[j];
00254 list_[j]=-1;
00255 useful_[j]=0.0;
00256 list_[--putOther]=iObject;
00257 }
00258 }
00259 bestPriority = priorityLevel;
00260 check=-COIN_DBL_MAX;
00261 checkIndex=0;
00262 }
00263 if (priorityLevel==bestPriority) {
00264
00265
00266 if(info->depth_ != 0){
00267 value = compute_usefulness(i + start_nway_, info);
00268 }
00269
00270 if (value>check) {
00271
00272 int iObject = list_[checkIndex];
00273 if (iObject>=0) {
00274 assert (list_[putOther-1]<0);
00275 list_[--putOther]=iObject;
00276 }
00277 list_[checkIndex]= i + start_nway_;
00278 assert (checkIndex<putOther);
00279 useful_[checkIndex]=value;
00280
00281 check=COIN_DBL_MAX;
00282 maximumStrong = CoinMin(maximumStrong,putOther);
00283 for (int j=0;j<maximumStrong;j++) {
00284 if (list_[j]>=0) {
00285 if (useful_[j]<check) {
00286 check=useful_[j];
00287 checkIndex=j;
00288 }
00289 }
00290 else {
00291 check=0.0;
00292 checkIndex = j;
00293 break;
00294 }
00295 }
00296 }
00297 else {
00298
00299 assert (list_[putOther-1]<0);
00300 list_[--putOther]=i + start_nway_;
00301 maximumStrong = CoinMin(maximumStrong,putOther);
00302 }
00303 }
00304 else {
00305
00306
00307 assert (list_[putOther-1]<0);
00308 list_[--putOther]=i + start_nway_;
00309 maximumStrong = CoinMin(maximumStrong,putOther);
00310 }
00311 }
00312 }
00313
00314
00315 numberOnList_=0;
00316 if (feasible) {
00317 maximumStrong = CoinMin(maximumStrong,putOther);
00318 for (i=0;i<maximumStrong;i++) {
00319 if (list_[i]>=0) {
00320 list_[numberOnList_]=list_[i];
00321 useful_[numberOnList_++]=-useful_[i];
00322 }
00323 }
00324 if (numberOnList_) {
00325
00326 CoinSort_2(useful_,useful_+numberOnList_,list_);
00327
00328 i = numberOnList_;
00329 for (;putOther<numberObjects;putOther++)
00330 list_[i++]=list_[putOther];
00331 assert (i==numberUnsatisfied_);
00332 if (!numberStrong_)
00333 numberOnList_=0;
00334 }
00335 }
00336 else {
00337
00338 numberUnsatisfied_=-1;
00339 }
00340
00341 info->defaultDual_ = -1.0;
00342 delete [] info->usefulRegion_;
00343 delete [] info->indexRegion_;
00344
00345 return numberUnsatisfied_;
00346 }
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 int
00361 BonNWayChoose::chooseVariable(
00362 OsiSolverInterface * solver,
00363 OsiBranchingInformation *info,
00364 bool fixVariables)
00365 {
00366 if(!numberUnsatisfied_) return 1;
00367
00368
00369 double cutoff = info->cutoff_;
00370 double obj_val = info->objectiveValue_;
00371 if(info->depth_ > br_depth_ && ( (- useful_[0] > pseudocost_trust_value_ )|| num_eval_[list_[0] - start_nway_] >= 18) ){
00372 const double * lower = info->lower_;
00373 const double * upper = info->upper_;
00374
00375
00376
00377 int n_fixed = 0;
00378 if(do_fixings_ > 1){
00379 for(int i = 0 ; i < numberUnsatisfied_ ; i++){
00380 int iObject = list_[i];
00381 int nwayIndex = iObject - start_nway_;
00382 const BonNWayObject * nway = ASSERTED_CAST<const BonNWayObject *>(solver->object(iObject));
00383
00384 size_t n = nway->numberMembers();
00385 const int * vars = nway->members();
00386 for(size_t j = 0 ; j < n ; j++){
00387 int iCol = vars[j];
00388 if(upper[iCol] < lower[iCol] + 0.5) continue;
00389 if(bounds_[nwayIndex][j] > cutoff){
00390 solver->setColUpper(iCol, lower[iCol]);
00391 n_fixed ++;
00392 }
00393 }
00394 }
00395 if(n_fixed && log_ > 1)
00396 printf("NWAY: Fixed %i variables\n", n_fixed);
00397 }
00398
00399 assert(bounds_.size() == unit_changes_.size());
00400 assert(unit_changes_.size() == info->solver_->numberObjects() - start_nway_);
00401
00402 bestObjectIndex_ = list_[0];
00403 bestWhichWay_ = 1;
00404 OsiObject * obj = solver->objects()[bestObjectIndex_];
00405 obj->setWhichWay(bestWhichWay_);
00406
00407 if(log_ > 1){
00408 printf("level %i branch on %i bound %g usefullness %g.\n",
00409 info->depth_, bestObjectIndex_ - start_nway_, obj_val, - useful_[0]);
00410 }
00411 if(n_fixed) return 2;
00412 return 0;
00413 }
00414
00415
00416 if(log_ > 0)
00417 printf("Restarting strong branching loop....\n\n");
00418
00419 numberStrongIterations_ = 0;
00420 numberStrongDone_ = 0;
00421 int numberLeft = numberOnList_;
00422 int returnCode=0;
00423 bestObjectIndex_ = -1;
00424 bestWhichWay_ = -1;
00425 firstForcedObjectIndex_ = -1;
00426 firstForcedWhichWay_ =-1;
00427 double best_score = -COIN_DBL_MAX;
00428 int bestPriority=0;
00429
00430 int n = solver->getNumCols();
00431 std::vector<double> saveLower(n);
00432 std::vector<double> saveUpper(n);
00433 std::copy(info->lower_, info->lower_ + n, saveLower.begin());
00434 std::copy(info->upper_, info->upper_ + n, saveUpper.begin());
00435
00436
00437 solver->markHotStart();
00438 for (int i=0;i<numberLeft;i++) {
00439 int iObject = list_[i];
00440 const int objectPriority = solver->object(iObject)->priority();
00441 if (objectPriority >= bestPriority){
00442 bestPriority = objectPriority;
00443 }
00444 else break;
00445 double score;
00446 int r_val = doStrongBranching(solver, info, iObject, saveLower.data(),
00447 saveUpper.data(), score);
00448 if(r_val == -1) {
00449 if(log_ > 0)
00450 std::cout<<"This is Infeasible"<<std::endl;
00451 returnCode = -1;
00452 break;
00453 }
00454
00455 if(do_fixings_ > 1 && r_val == 1 && info->depth_ == 0) returnCode=2;
00456
00457 if(log_ > 0)
00458 printf("Usefullness from strong branching on %i : %g\n", iObject - start_nway_, score);
00459 if(score > best_score){
00460 best_score = score;
00461 bestObjectIndex_ = iObject;
00462 bestWhichWay_ = 0;
00463 }
00464 if (r_val==3) {
00465 returnCode = 3;
00466
00467 if(bestObjectIndex_ < 0){
00468 bestObjectIndex_ = list_[0];
00469 bestWhichWay_ = 0;
00470 }
00471 break;
00472 }
00473 }
00474 solver->unmarkHotStart();
00475 return returnCode;
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487 int
00488 BonNWayChoose::doStrongBranching( OsiSolverInterface * solver,
00489 OsiBranchingInformation *info,
00490 int objectIndex,
00491 double * saveLower,
00492 double * saveUpper, double & score)
00493 {
00494 int nwayIndex = objectIndex - start_nway_;
00495 const double * lower = info->lower_;
00496 const double * upper = info->upper_;
00497
00498 int numberColumns = solver->getNumCols();
00499 double timeStart = CoinCpuTime();
00500
00501 int numberObjects = info->solver_->numberObjects();
00502 const BonNWayObject * nway = ASSERTED_CAST<const BonNWayObject *>(solver->object(objectIndex));
00503 assert(nway);
00504 BonNWayBranchingObject * branch = ASSERTED_CAST<BonNWayBranchingObject *>(nway->createBranch(solver, info, 1));
00505
00506 int branches_left = branch->numberBranchesLeft();
00507 int number_branches = branch->numberBranchesLeft();
00508 int n_can_be_fixed = 0;
00509
00510 double big_val = cutoff_multiplier_*info->cutoff_;
00511 if(big_val > 1e10){ big_val = 10*info->objectiveValue_;}
00512 big_val += fabs(big_val)*1e-5;
00513 std::vector<double> unit_changes(numberObjects - start_nway_, -DBL_MAX);
00514
00515 while(branches_left){
00516
00517 branch->branch(solver);
00518 int v_br = branch->var_branched_on();
00519 int s_br = branch->seq_branched_on();
00520 double residual = upper[v_br] - info->solution_[v_br];
00521 solver->solveFromHotStart() ;
00522 numberStrongIterations_ += solver->getIterationCount();
00523 numberStrongDone_++;
00524
00525 double obj_val = solver->getObjValue();
00526
00527 if(solver->isProvenPrimalInfeasible() ||
00528 (solver->isProvenOptimal() && obj_val > info->cutoff_)){
00529 if(info->depth_ == 0){
00530 bounds_[nwayIndex][s_br] = big_val;
00531 }
00532 unit_changes[s_br] = (big_val - info->objectiveValue_)/residual;
00533 if(do_fixings_ > 1){
00534 n_can_be_fixed++;
00535 if(log_ > 0)
00536 printf("Fixing variable %i to 0 the cutoff is %g\n", v_br, big_val);
00537 saveUpper[v_br] = saveLower[v_br];
00538 }
00539 }
00540 else{
00541 if(info->depth_ == 0){
00542 bounds_[nwayIndex][s_br] = obj_val;
00543 }
00544 unit_changes[s_br] = (obj_val - info->objectiveValue_)/residual;
00545 }
00546
00547
00548 for (int j=0;j<numberColumns;j++) {
00549 if (saveLower[j] != lower[j])
00550 solver->setColLower(j,saveLower[j]);
00551 if (saveUpper[j] != upper[j])
00552 solver->setColUpper(j,saveUpper[j]);
00553 }
00554 branches_left = branch->numberBranchesLeft();
00555 }
00556
00557 score = compute_usefulness(info, nway->numberMembers(), nway->members(), bounds_[nwayIndex], unit_changes);
00558 if(info->depth_ == 0){
00559 if(do_fixings_ == 1 || do_fixings_ == 3)
00560 nway->set_bounds(bounds_[nwayIndex]);
00561 for(size_t k = 0 ; k < unit_changes.size() ; k++){
00562 num_ps_costs_[nwayIndex][k]=1;
00563 }
00564 unit_changes_[nwayIndex] = unit_changes;
00565 num_eval_[nwayIndex] = 1;
00566 }
00567 else if (n_can_be_fixed < number_branches -1){
00568 num_eval_[nwayIndex]++;
00569 for(size_t k = 0 ; k < unit_changes.size() ; k++){
00570 if(unit_changes[k] > 0.){
00571 if(geo_means_)
00572 unit_changes_[nwayIndex][k] *= unit_changes[k];
00573 else
00574 unit_changes_[nwayIndex][k] += unit_changes[k];
00575 num_ps_costs_[nwayIndex][k]++;
00576 }
00577 }
00578 }
00579 if(n_can_be_fixed == number_branches){
00580 return -1;
00581 }
00582 if(n_can_be_fixed){
00583 return 1;
00584 }
00585 bool hitMaxTime = ( CoinCpuTime()-timeStart > info->timeRemaining_)
00586 || ( CoinCpuTime() - start_time_ > time_limit_);
00587 if (hitMaxTime) {
00588 return 3;
00589 }
00590 return 0;
00591 }
00592
00593 }
00594