/** \brief Execute the actions required to branch, as specified by the current state of the branching object, and advance the object's state. Returns change in guessed objective on next branch */ virtual double branch() {return branch(NULL);}
/* Choose a variable Returns - -1 Node is infeasible 0 Normal termination - we have a candidate 1 All looks satisfied - no candidate 2 We can change the bound on a variable - but we also have a strong branching candidate 3 We can change the bound on a variable - but we have a non-strong branching candidate 4 We can change the bound on a variable - no other candidates We can pick up branch from whichObject() and whichWay() We can pick up a forced branch (can change bound) from whichForcedObject() and whichForcedWay() If we have a solution then we can pick up from goodObjectiveValue() and goodSolution() */ int OsiChooseStrong::chooseVariable( OsiSolverInterface * solver, OsiBranchingInformation *info, bool fixVariables) { if (numberUnsatisfied_) { const double* upTotalChange = pseudoCosts_.upTotalChange(); const double* downTotalChange = pseudoCosts_.downTotalChange(); const int* upNumber = pseudoCosts_.upNumber(); const int* downNumber = pseudoCosts_.downNumber(); int numberBeforeTrusted = pseudoCosts_.numberBeforeTrusted(); // Somehow we can get here with it 0 ! if (!numberBeforeTrusted) { numberBeforeTrusted=5; pseudoCosts_.setNumberBeforeTrusted(numberBeforeTrusted); } int numberLeft = CoinMin(numberStrong_-numberStrongDone_,numberUnsatisfied_); int numberToDo=0; resetResults(numberLeft); int returnCode=0; bestObjectIndex_ = -1; bestWhichWay_ = -1; firstForcedObjectIndex_ = -1; firstForcedWhichWay_ =-1; double bestTrusted=-COIN_DBL_MAX; for (int i=0;i<numberLeft;i++) { int iObject = list_[i]; if (upNumber[iObject]<numberBeforeTrusted||downNumber[iObject]<numberBeforeTrusted) { results_[numberToDo++] = OsiHotInfo(solver, info, solver->objects(), iObject); } else { const OsiObject * obj = solver->object(iObject); double upEstimate = (upTotalChange[iObject]*obj->upEstimate())/upNumber[iObject]; double downEstimate = (downTotalChange[iObject]*obj->downEstimate())/downNumber[iObject]; double value = MAXMIN_CRITERION*CoinMin(upEstimate,downEstimate) + (1.0-MAXMIN_CRITERION)*CoinMax(upEstimate,downEstimate); if (value > bestTrusted) { bestObjectIndex_=iObject; bestWhichWay_ = upEstimate>downEstimate ? 0 : 1; bestTrusted = value; } } } int numberFixed=0; if (numberToDo) { returnCode = doStrongBranching(solver, info, numberToDo, 1); if (returnCode>=0&&returnCode<=2) { if (returnCode) { returnCode=4; if (bestObjectIndex_>=0) returnCode=3; } for (int i=0;i<numResults_;i++) { int iObject = results_[i].whichObject(); double upEstimate; if (results_[i].upStatus()!=1) { assert (results_[i].upStatus()>=0); upEstimate = results_[i].upChange(); } else { // infeasible - just say expensive if (info->cutoff_<1.0e50) upEstimate = 2.0*(info->cutoff_-info->objectiveValue_); else upEstimate = 2.0*fabs(info->objectiveValue_); if (firstForcedObjectIndex_ <0) { firstForcedObjectIndex_ = iObject; firstForcedWhichWay_ =0; } numberFixed++; if (fixVariables) { const OsiObject * obj = solver->object(iObject); OsiBranchingObject * branch = obj->createBranch(solver,info,0); branch->branch(solver); delete branch; } } double downEstimate; if (results_[i].downStatus()!=1) { assert (results_[i].downStatus()>=0); downEstimate = results_[i].downChange(); } else { // infeasible - just say expensive if (info->cutoff_<1.0e50) downEstimate = 2.0*(info->cutoff_-info->objectiveValue_); else downEstimate = 2.0*fabs(info->objectiveValue_); if (firstForcedObjectIndex_ <0) { firstForcedObjectIndex_ = iObject; firstForcedWhichWay_ =1; } numberFixed++; if (fixVariables) { const OsiObject * obj = solver->object(iObject); OsiBranchingObject * branch = obj->createBranch(solver,info,1); branch->branch(solver); delete branch; } } double value = MAXMIN_CRITERION*CoinMin(upEstimate,downEstimate) + (1.0-MAXMIN_CRITERION)*CoinMax(upEstimate,downEstimate); if (value>bestTrusted) { bestTrusted = value; bestObjectIndex_ = iObject; bestWhichWay_ = upEstimate>downEstimate ? 0 : 1; // but override if there is a preferred way const OsiObject * obj = solver->object(iObject); if (obj->preferredWay()>=0&&obj->infeasibility()) bestWhichWay_ = obj->preferredWay(); if (returnCode) returnCode=2; } } } else if (returnCode==3) { // max time - just choose one bestObjectIndex_ = list_[0]; bestWhichWay_ = 0; returnCode=0; } } else { bestObjectIndex_=list_[0]; } if ( bestObjectIndex_ >=0 ) { OsiObject * obj = solver->objects()[bestObjectIndex_]; obj->setWhichWay( bestWhichWay_); } if (numberFixed==numberUnsatisfied_&&numberFixed) returnCode=4; return returnCode; } else { return 1; } }
/** \brief Execute the actions required to branch, as specified by the current state of the branching object, and advance the object's state. Returns change in guessed objective on next branch */ virtual double branch() {return branch(nullptr);}
/* This is a utility function which does strong branching on a list of objects and stores the results in OsiHotInfo.objects. On entry the object sequence is stored in the OsiHotInfo object and maybe more. It returns - -1 - one branch was infeasible both ways 0 - all inspected - nothing can be fixed 1 - all inspected - some can be fixed (returnCriterion==0) 2 - may be returning early - one can be fixed (last one done) (returnCriterion==1) 3 - returning because max time */ int OsiChooseStrong::doStrongBranching( OsiSolverInterface * solver, OsiBranchingInformation *info, int numberToDo, int returnCriterion) { // Might be faster to extend branch() to return bounds changed double * saveLower = NULL; double * saveUpper = NULL; int numberColumns = solver->getNumCols(); solver->markHotStart(); const double * lower = info->lower_; const double * upper = info->upper_; saveLower = CoinCopyOfArray(info->lower_,numberColumns); saveUpper = CoinCopyOfArray(info->upper_,numberColumns); numResults_=0; int returnCode=0; double timeStart = CoinCpuTime(); for (int iDo=0;iDo<numberToDo;iDo++) { OsiHotInfo * result = results_ + iDo; // For now just 2 way OsiBranchingObject * branch = result->branchingObject(); assert (branch->numberBranches()==2); /* Try the first direction. Each subsequent call to branch() performs the specified branch and advances the branch object state to the next branch alternative.) */ OsiSolverInterface * thisSolver = solver; if (branch->boundBranch()) { // ordinary branch->branch(solver); // maybe we should check bounds for stupidities here? solver->solveFromHotStart() ; } else { // adding cuts or something thisSolver = solver->clone(); branch->branch(thisSolver); // set hot start iterations int limit; thisSolver->getIntParam(OsiMaxNumIterationHotStart,limit); thisSolver->setIntParam(OsiMaxNumIteration,limit); thisSolver->resolve(); } // can check if we got solution // status is 0 finished, 1 infeasible and 2 unfinished and 3 is solution int status0 = result->updateInformation(thisSolver,info,this); numberStrongIterations_ += thisSolver->getIterationCount(); if (status0==3) { // new solution already saved if (trustStrongForSolution_) { info->cutoff_ = goodObjectiveValue_; status0=0; } } if (solver!=thisSolver) delete thisSolver; // Restore bounds for (int j=0;j<numberColumns;j++) { if (saveLower[j] != lower[j]) solver->setColLower(j,saveLower[j]); if (saveUpper[j] != upper[j]) solver->setColUpper(j,saveUpper[j]); } /* Try the next direction */ thisSolver = solver; if (branch->boundBranch()) { // ordinary branch->branch(solver); // maybe we should check bounds for stupidities here? solver->solveFromHotStart() ; } else { // adding cuts or something thisSolver = solver->clone(); branch->branch(thisSolver); // set hot start iterations int limit; thisSolver->getIntParam(OsiMaxNumIterationHotStart,limit); thisSolver->setIntParam(OsiMaxNumIteration,limit); thisSolver->resolve(); } // can check if we got solution // status is 0 finished, 1 infeasible and 2 unfinished and 3 is solution int status1 = result->updateInformation(thisSolver,info,this); numberStrongDone_++; numberStrongIterations_ += thisSolver->getIterationCount(); if (status1==3) { // new solution already saved if (trustStrongForSolution_) { info->cutoff_ = goodObjectiveValue_; status1=0; } } if (solver!=thisSolver) delete thisSolver; // Restore bounds for (int j=0;j<numberColumns;j++) { if (saveLower[j] != lower[j]) solver->setColLower(j,saveLower[j]); if (saveUpper[j] != upper[j]) solver->setColUpper(j,saveUpper[j]); } /* End of evaluation for this candidate variable. Possibilities are: * Both sides below cutoff; this variable is a candidate for branching. * Both sides infeasible or above the objective cutoff: no further action here. Break from the evaluation loop and assume the node will be purged by the caller. * One side below cutoff: Install the branch (i.e., fix the variable). Possibly break from the evaluation loop and assume the node will be reoptimised by the caller. */ numResults_++; if (status0==1&&status1==1) { // infeasible returnCode=-1; break; // exit loop } else if (status0==1||status1==1) { numberStrongFixed_++; if (!returnCriterion) { returnCode=1; } else { returnCode=2; break; } } bool hitMaxTime = ( CoinCpuTime()-timeStart > info->timeRemaining_); if (hitMaxTime) { returnCode=3; break; } } delete [] saveLower; delete [] saveUpper; // Delete the snapshot solver->unmarkHotStart(); return returnCode; }