#include <SbbNode.hpp>
Public Member Functions | |
SbbNode () | |
Default Constructor. | |
SbbNode (SbbModel *model, SbbNode *lastNode) | |
Construct and increment parent reference count. | |
SbbNode (const SbbNode &) | |
Copy constructor. | |
SbbNode & | operator= (const SbbNode &rhs) |
Assignment operator. | |
~SbbNode () | |
Destructor. | |
void | createInfo (SbbModel *model, SbbNode *lastNode, const CoinWarmStartBasis *lastws, const double *lastLower, const double *lastUpper, int numberOldActiveCuts, int numberNewCuts) |
int | chooseBranch (SbbModel *model, SbbNode *lastNode) |
void | decrementCuts (int change=1) |
Decrement active cut counts. | |
void | decrementParentCuts (int change=1) |
Decrement all active cut counts in chain starting at parent. | |
void | nullNodeInfo () |
Nulls out node info. | |
void | initializeInfo () |
int | branch () |
Does next branch and updates state. | |
SbbNodeInfo * | nodeInfo () const |
double | objectiveValue () const |
void | setObjectiveValue (double value) |
int | numberBranches () const |
Number of arms defined for the attached SbbBranchingObject. | |
int | variable () const |
int | way () const |
int | depth () const |
Depth in branch-and-cut search tree. | |
int | numberUnsatisfied () const |
Get the number of objects unsatisfied at this node. | |
double | guessedObjectiveValue () const |
void | setGuessedObjectiveValue (double value) |
Private Attributes | |
SbbNodeInfo * | nodeInfo_ |
Information to make basis and bounds. | |
double | objectiveValue_ |
double | guessedObjectiveValue_ |
SbbBranchingObject * | branch_ |
Branching object for this node. | |
int | depth_ |
Depth of the node in the search tree. | |
int | numberUnsatisfied_ |
The number of objects unsatisfied at this node. |
When a subproblem is initially created, it is represented by an SbbNode object and an attached SbbNodeInfo object.
The SbbNode contains information (depth, branching instructions), that's needed while the subproblem remains `live', i.e., while the subproblem is not fathomed and there are branch arms still be be evaluated. The SbbNode is deleted when the last branch arm has been evaluated.
The SbbNodeInfo object contains the information needed to maintain the search tree and recreate the subproblem for the node. It remains in existence until there are no nodes remaining in the subtree rooted at this node.
Definition at line 368 of file SbbNode.hpp.
|
Destructor. parent->decrement(1); Definition at line 1398 of file SbbNode.cpp. References branch_, SbbNodeInfo::decrement(), nodeInfo_, SbbNodeInfo::nullOwner(), SbbNodeInfo::numberBranchesLeft(), and SbbNodeInfo::numberPointingToThis().
01399 { 01400 #ifdef CHECK_NODE 01401 if (nodeInfo_) 01402 printf("SbbNode %x Destructor nodeInfo %x (%d)\n", 01403 this,nodeInfo_,nodeInfo_->numberPointingToThis()); 01404 else 01405 printf("SbbNode %x Destructor nodeInfo %x (?)\n", 01406 this,nodeInfo_); 01407 #endif 01408 if (nodeInfo_) { 01409 nodeInfo_->nullOwner(); 01410 int numberToDelete=nodeInfo_->numberBranchesLeft(); 01411 // SbbNodeInfo * parent = nodeInfo_->parent(); 01412 if (nodeInfo_->decrement(numberToDelete)==0) { 01413 delete nodeInfo_; 01414 } else { 01415 //printf("node %x nodeinfo %x parent %x\n",this,nodeInfo_,parent); 01416 // anyway decrement parent 01417 //if (parent) 01419 } 01420 } 01421 delete branch_; 01422 } |
|
Create a branching object for the node The routine scans the object list of the model and selects a set of unsatisfied objects as candidates for branching. The candidates are evaluated, and an appropriate branch object is installed. If evaluation determines that an object is monotone or infeasible, the routine returns immediately. In the case of a monotone object, the branch object has already been called to modify the model. Return value:
Definition at line 803 of file SbbNode.cpp. References SbbBranchDecision::bestBranch(), SbbBranchDecision::betterBranch(), branch_, SbbModel::branchingMethod(), SbbObject::createBranch(), depth_, SbbModel::feasibleSolution(), OsiSolverInterface::getColLower(), OsiSolverInterface::getColSolution(), OsiSolverInterface::getColUpper(), SbbModel::getCutoff(), SbbModel::getDblParam(), SbbModel::getForcePriority(), OsiSolverInterface::getIntParam(), OsiSolverInterface::getIterationCount(), OsiClpSolverInterface::getModelPtr(), SbbModel::getNodeCount(), SbbModel::getNumCols(), OsiSolverInterface::getObjSense(), OsiSolverInterface::getObjValue(), SbbModel::getSolutionCount(), OsiSolverInterface::getWarmStart(), SbbObject::infeasibility(), SbbModel::integerVariable(), OsiSolverInterface::isDualObjectiveLimitReached(), OsiSolverInterface::isIterationLimitReached(), OsiSolverInterface::isProvenOptimal(), ClpModel::logLevel(), OsiSolverInterface::markHotStart(), ClpModel::maximumIterations(), CoinMessageHandler::message(), SbbModel::messageHandler(), SbbModel::messages(), SbbSimpleInteger::modelSequence(), SbbModel::numberObjects(), SbbModel::numberStrong(), numberUnsatisfied_, SbbModel::object(), SbbModel::priority(), SbbModel::setBestSolution(), OsiSolverInterface::setColLower(), OsiSolverInterface::setColSolution(), OsiSolverInterface::setColUpper(), OsiSolverInterface::setIntParam(), ClpModel::setLogLevel(), ClpModel::setMaximumIterations(), OsiSolverInterface::setWarmStart(), OsiSolverInterface::solveFromHotStart(), SbbModel::solver(), ClpSimplex::strongBranching(), OsiSolverInterface::unmarkHotStart(), and SbbBranchingObject::way(). Referenced by SbbModel::branchAndBound().
00805 { if (lastNode) 00806 depth_ = lastNode->depth_+1; 00807 else 00808 depth_ = 0; 00809 delete branch_; 00810 branch_=NULL; 00811 OsiSolverInterface * solver = model->solver(); 00812 double saveObjectiveValue = solver->getObjValue(); 00813 double objectiveValue = solver->getObjSense()*saveObjectiveValue; 00814 const double * lower = solver->getColLower(); 00815 const double * upper = solver->getColUpper(); 00816 00817 int anyAction=0; 00818 double integerTolerance = 00819 model->getDblParam(SbbModel::SbbIntegerTolerance); 00820 int i; 00821 bool beforeSolution = model->getSolutionCount()==0; 00822 int numberStrong=model->numberStrong(); 00823 int numberObjects = model->numberObjects(); 00824 int maximumStrong = max(min(model->numberStrong(),numberObjects),1); 00825 int numberColumns = model->getNumCols(); 00826 double * saveUpper = new double[numberColumns]; 00827 double * saveLower = new double[numberColumns]; 00828 00829 // Save solution in case heuristics need good solution later 00830 00831 double * saveSolution = new double[numberColumns]; 00832 memcpy(saveSolution,solver->getColSolution(),numberColumns*sizeof(double)); 00833 00834 /* 00835 Get a branching decision object. Use the default decision criteria unless 00836 the user has loaded a decision method into the model. 00837 */ 00838 SbbBranchDecision *decision = model->branchingMethod(); 00839 if (!decision) 00840 decision = new SbbBranchDefaultDecision(); 00841 00842 typedef struct { 00843 SbbBranchingObject * possibleBranch; // what a branch would do 00844 double upMovement; // cost going up (and initial away from feasible) 00845 double downMovement; // cost going down 00846 int numIntInfeasUp ; // without odd ones 00847 int numObjInfeasUp ; // just odd ones 00848 bool finishedUp; // true if solver finished 00849 int numItersUp ; // number of iterations in solver 00850 int numIntInfeasDown ; // without odd ones 00851 int numObjInfeasDown ; // just odd ones 00852 bool finishedDown; // true if solver finished 00853 int numItersDown; // number of iterations in solver 00854 int objectNumber; // Which object it is 00855 } Strong; 00856 Strong * choice = new Strong[maximumStrong]; 00857 for (i=0;i<numberColumns;i++) { 00858 saveLower[i] = lower[i]; 00859 saveUpper[i] = upper[i]; 00860 } 00861 00862 // compute current state 00863 int numberIntegerInfeasibilities; // without odd ones 00864 int numberObjectInfeasibilities; // just odd ones 00865 model->feasibleSolution( 00866 numberIntegerInfeasibilities, 00867 numberObjectInfeasibilities); 00868 /* 00869 Original comment ``Put in coding for forcePriority for hot starts.'' Looks 00870 like a `to do' to me, given the assert. -- lh, 2003.08. 00871 */ 00872 assert(model->getForcePriority()<0); 00873 00874 double saveOtherWay=0.0; // just for non-strong branching 00875 numberUnsatisfied_ = 0; 00876 int bestPriority=INT_MAX; 00877 /* 00878 Scan for branching objects that indicate infeasibility. Choose the best 00879 maximumStrong candidates, using priority as the first criteria, then 00880 integer infeasibility. 00881 00882 The algorithm is to fill the choice array with a set of good candidates (by 00883 infeasibility) with priority bestPriority. Finding a candidate with 00884 priority better (less) than bestPriority flushes the choice array. (This 00885 serves as initialization when the first candidate is found.) 00886 00887 A new candidate is added to choices only if its infeasibility exceeds the 00888 current max infeasibility (mostAway). When a candidate is added, it 00889 replaces the candidate with the smallest infeasibility (tracked by 00890 iSmallest). 00891 */ 00892 int iSmallest ; 00893 double mostAway ; 00894 for (i = 0 ; i < maximumStrong ; i++) choice[i].possibleBranch = NULL ; 00895 numberStrong=0; 00896 for (i=0;i<numberObjects;i++) { 00897 const SbbObject * object = model->object(i); 00898 int preferredWay; 00899 double otherWay; 00900 double infeasibility = object->infeasibility(preferredWay,otherWay); 00901 if (infeasibility>integerTolerance) { 00902 numberUnsatisfied_++; 00903 int priorityLevel = model->priority(i); 00904 // Better priority? Flush choices. 00905 if (priorityLevel<bestPriority) { 00906 int j; 00907 iSmallest=0; 00908 for (j=0;j<maximumStrong;j++) { 00909 choice[j].upMovement=0.0; 00910 delete choice[j].possibleBranch; 00911 choice[j].possibleBranch=NULL; 00912 } 00913 bestPriority = priorityLevel; 00914 mostAway=integerTolerance; 00915 numberStrong=0; 00916 } else if (priorityLevel>bestPriority) { 00917 continue; 00918 } 00919 // Check for suitability based on infeasibility. 00920 if (infeasibility>mostAway) { 00921 //add to list 00922 choice[iSmallest].upMovement=infeasibility; 00923 choice[iSmallest].downMovement=otherWay; 00924 saveOtherWay=otherWay; 00925 delete choice[iSmallest].possibleBranch; 00926 choice[iSmallest].possibleBranch=object->createBranch(preferredWay); 00927 numberStrong = max(numberStrong,iSmallest+1); 00928 // Save which object it was 00929 choice[iSmallest].objectNumber=i; 00930 int j; 00931 iSmallest=-1; 00932 mostAway = 1.0e50; 00933 for (j=0;j<maximumStrong;j++) { 00934 if (choice[j].upMovement<mostAway) { 00935 mostAway=choice[j].upMovement; 00936 iSmallest=j; 00937 } 00938 } 00939 } 00940 } 00941 } 00942 /* Some solvers can do the strong branching calculations faster if 00943 they do them all at once. At present only Clp does for ordinary 00944 integers but I think this coding would be easy to modify 00945 */ 00946 bool allNormal=true; // to say if we can do fast strong branching 00947 for (i=0;i<numberStrong;i++) { 00948 choice[i].numIntInfeasUp = numberUnsatisfied_; 00949 choice[i].numIntInfeasDown = numberUnsatisfied_; 00950 if (!dynamic_cast <const SbbSimpleInteger *> (model->object(choice[i].objectNumber))) 00951 allNormal=false; // Something odd so lets skip clever fast branching 00952 } 00953 /* 00954 Is strong branching enabled? If so, set up and do it. Otherwise, we'll 00955 fall through to simple branching. 00956 00957 Setup for strong branching involves saving the current basis (for restoration 00958 afterwards) and setting up for hot starts. 00959 */ 00960 if (model->numberStrong()) { 00961 00962 bool solveAll=false; // set true to say look at all even if some fixed (experiment) 00963 // Save basis 00964 CoinWarmStart * ws = solver->getWarmStart(); 00965 // save limit 00966 int saveLimit; 00967 solver->getIntParam(OsiMaxNumIterationHotStart,saveLimit); 00968 if (beforeSolution) 00969 solver->setIntParam(OsiMaxNumIterationHotStart,10000); // go to end 00970 00971 /* If we are doing all strong branching in one go then we create new arrays 00972 to store information. If clp NULL then doing old way. 00973 Going down - 00974 outputSolution[2*i] is final solution. 00975 outputStuff[2*i] is status (0 - finished, 1 infeas, other unknown 00976 outputStuff[2*i+numberStrong] is number iterations 00977 On entry newUpper[i] is new upper bound, on exit obj change 00978 Going up - 00979 outputSolution[2*i+1] is final solution. 00980 outputStuff[2*i+1] is status (0 - finished, 1 infeas, other unknown 00981 outputStuff[2*i+1+numberStrong] is number iterations 00982 On entry newLower[i] is new lower bound, on exit obj change 00983 */ 00984 OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (solver); 00985 ClpSimplex * clp=NULL; 00986 double * newLower = NULL; 00987 double * newUpper = NULL; 00988 double ** outputSolution=NULL; 00989 int * outputStuff=NULL; 00990 int saveLogLevel; 00991 // For moment - until full testing - go back to normal way 00992 //allNormal=false; 00993 if (osiclp&& allNormal) { 00994 clp = osiclp->getModelPtr(); 00995 saveLogLevel = clp->logLevel(); 00996 int saveMaxIts = clp->maximumIterations(); 00997 clp->setMaximumIterations(saveLimit); 00998 clp->setLogLevel(0); 00999 // Clp - do a different way 01000 newLower = new double[numberStrong]; 01001 newUpper = new double[numberStrong]; 01002 outputSolution = new double * [2*numberStrong]; 01003 outputStuff = new int [4*numberStrong]; 01004 int * which = new int[numberStrong]; 01005 for (i=0;i<numberStrong;i++) { 01006 int iObject = choice[i].objectNumber; 01007 const SbbObject * object = model->object(iObject); 01008 const SbbSimpleInteger * simple = dynamic_cast <const SbbSimpleInteger *> (object); 01009 int iSequence = simple->modelSequence(); 01010 newLower[i]= ceil(saveSolution[iSequence]); 01011 newUpper[i]= floor(saveSolution[iSequence]); 01012 which[i]=iSequence; 01013 outputSolution[2*i]= new double [numberColumns]; 01014 outputSolution[2*i+1]= new double [numberColumns]; 01015 } 01016 clp->strongBranching(numberStrong,which, 01017 newLower, newUpper,outputSolution, 01018 outputStuff,outputStuff+2*numberStrong,!solveAll,false); 01019 clp->setMaximumIterations(saveMaxIts); 01020 delete [] which; 01021 } else { 01022 // Doing normal way 01023 // Mark hot start 01024 solver->markHotStart(); 01025 } 01026 /* 01027 Open a loop to do the strong branching LPs. For each candidate variable, 01028 solve an LP with the variable forced down, then up. If a direction turns 01029 out to be infeasible or monotonic (i.e., over the dual objective cutoff), 01030 force the objective change to be big (1.0e100). If we determine the problem 01031 is infeasible, or find a monotone variable, escape the loop. 01032 01033 TODO: The `restore bounds' part might be better encapsulated as an 01034 unbranch() method. Branching objects more exotic than simple integers 01035 or cliques might not restrict themselves to variable bounds. 01036 01037 TODO: Virtuous solvers invalidate the current solution (or give bogus 01038 results :-) when the bounds are changed out from under them. So we 01039 need to do all the work associated with finding a new solution before 01040 restoring the bounds. 01041 */ 01042 for (i = 0 ; i < numberStrong ; i++) 01043 { double objectiveChange ; 01044 double newObjectiveValue=1.0e100; 01045 // status is 0 finished, 1 infeasible and other 01046 int iStatus; 01047 /* 01048 Try the down direction first. (Specify the initial branching alternative as 01049 down with a call to way(-1). Each subsequent call to branch() performs the 01050 specified branch and advances the branch object state to the next branch 01051 alternative.) 01052 */ 01053 if (!clp) { 01054 choice[i].possibleBranch->way(-1) ; 01055 choice[i].possibleBranch->branch() ; 01056 solver->solveFromHotStart() ; 01057 // restore bounds 01058 for (int j=0;j<numberColumns;j++) { 01059 if (saveLower[j] != lower[j]) 01060 solver->setColLower(j,saveLower[j]); 01061 if (saveUpper[j] != upper[j]) 01062 solver->setColUpper(j,saveUpper[j]); 01063 } 01064 01065 /* 01066 We now have an estimate of objective degradation that we can use for strong 01067 branching. If we're over the cutoff, the variable is monotone up. 01068 If we actually made it to optimality, check for a solution, and if we have 01069 a good one, call setBestSolution to process it. Note that this may reduce the 01070 cutoff, so we check again to see if we can declare this variable monotone. 01071 */ 01072 if (solver->isProvenOptimal()) 01073 iStatus=0; // optimal 01074 else if (solver->isIterationLimitReached() 01075 &&!solver->isDualObjectiveLimitReached()) 01076 iStatus=2; // unknown 01077 else 01078 iStatus=1; // infeasible 01079 newObjectiveValue = solver->getObjSense()*solver->getObjValue(); 01080 choice[i].numItersDown = solver->getIterationCount(); 01081 objectiveChange = newObjectiveValue-objectiveValue ; 01082 } else { 01083 iStatus = outputStuff[2*i]; 01084 choice[i].numItersDown = outputStuff[2*numberStrong+2*i]; 01085 newObjectiveValue = objectiveValue+newUpper[i]; 01086 solver->setColSolution(outputSolution[2*i]); 01087 } 01088 objectiveChange = newObjectiveValue - objectiveValue; 01089 if (!iStatus) { 01090 choice[i].finishedDown = true ; 01091 if (newObjectiveValue>model->getCutoff()) { 01092 objectiveChange = 1.0e100; // say infeasible 01093 } else { 01094 // See if integer solution 01095 if (model->feasibleSolution(choice[i].numIntInfeasDown, 01096 choice[i].numObjInfeasDown)) 01097 { model->setBestSolution(SBB_STRONGSOL, 01098 newObjectiveValue, 01099 solver->getColSolution()) ; 01100 if (newObjectiveValue > model->getCutoff()) // *new* cutoff 01101 objectiveChange = 1.0e100 ; 01102 } 01103 } 01104 } else if (iStatus==1) { 01105 objectiveChange = 1.0e100 ; 01106 } else { 01107 // Can't say much as we did not finish 01108 choice[i].finishedDown = false ; 01109 } 01110 choice[i].downMovement = objectiveChange ; 01111 //printf("Down on %d, status is %d, obj %g its %d cost %g finished %d inf %d infobj %d\n", 01112 // choice[i].objectNumber,iStatus,newObjectiveValue,choice[i].numItersDown, 01113 // choice[i].downMovement,choice[i].finishedDown,choice[i].numIntInfeasDown, 01114 // choice[i].numObjInfeasDown); 01115 01116 // repeat the whole exercise, forcing the variable up 01117 if (!clp) { 01118 choice[i].possibleBranch->branch(); 01119 solver->solveFromHotStart(); 01120 // restore bounds 01121 for (int j=0;j<numberColumns;j++) { 01122 if (saveLower[j] != lower[j]) 01123 solver->setColLower(j,saveLower[j]); 01124 if (saveUpper[j] != upper[j]) 01125 solver->setColUpper(j,saveUpper[j]); 01126 } 01127 if (solver->isProvenOptimal()) 01128 iStatus=0; // optimal 01129 else if (solver->isIterationLimitReached() 01130 &&!solver->isDualObjectiveLimitReached()) 01131 iStatus=2; // unknown 01132 else 01133 iStatus=1; // infeasible 01134 newObjectiveValue = solver->getObjSense()*solver->getObjValue(); 01135 choice[i].numItersUp = solver->getIterationCount(); 01136 objectiveChange = newObjectiveValue-objectiveValue ; 01137 } else { 01138 iStatus = outputStuff[2*i+1]; 01139 choice[i].numItersUp = outputStuff[2*numberStrong+2*i+1]; 01140 newObjectiveValue = objectiveValue+newLower[i]; 01141 solver->setColSolution(outputSolution[2*i+1]); 01142 } 01143 objectiveChange = newObjectiveValue - objectiveValue; 01144 if (!iStatus) { 01145 choice[i].finishedUp = true ; 01146 if (newObjectiveValue>model->getCutoff()) { 01147 objectiveChange = 1.0e100; // say infeasible 01148 } else { 01149 // See if integer solution 01150 if (model->feasibleSolution(choice[i].numIntInfeasUp, 01151 choice[i].numObjInfeasUp)) 01152 { model->setBestSolution(SBB_STRONGSOL, 01153 newObjectiveValue, 01154 solver->getColSolution()) ; 01155 if (newObjectiveValue > model->getCutoff()) // *new* cutoff 01156 objectiveChange = 1.0e100 ; 01157 } 01158 } 01159 } else if (iStatus==1) { 01160 objectiveChange = 1.0e100 ; 01161 } else { 01162 // Can't say much as we did not finish 01163 choice[i].finishedUp = false ; 01164 } 01165 choice[i].upMovement = objectiveChange ; 01166 //printf("Up on %d, status is %d, obj %g its %d cost %g finished %d inf %d infobj %d\n", 01167 // choice[i].objectNumber,iStatus,newObjectiveValue,choice[i].numItersUp, 01168 // choice[i].upMovement,choice[i].finishedUp,choice[i].numIntInfeasUp, 01169 // choice[i].numObjInfeasUp); 01170 01171 /* 01172 End of evaluation for this candidate variable. Possibilities are: 01173 * Both sides below cutoff; this variable is a candidate for branching. 01174 * Both sides infeasible or above the objective cutoff: no further action 01175 here. Break from the evaluation loop and assume the node will be purged 01176 by the caller. 01177 * One side below cutoff: Install the branch (i.e., fix the variable). Break 01178 from the evaluation loop and assume the node will be reoptimised by the 01179 caller. 01180 */ 01181 if (choice[i].upMovement<1.0e100) { 01182 if(choice[i].downMovement<1.0e100) { 01183 // feasible - no action 01184 } else { 01185 // up feasible, down infeasible 01186 anyAction=-1; 01187 if (!solveAll) { 01188 choice[i].possibleBranch->way(1); 01189 choice[i].possibleBranch->branch(); 01190 break; 01191 } 01192 } 01193 } else { 01194 if(choice[i].downMovement<1.0e100) { 01195 // down feasible, up infeasible 01196 anyAction=-1; 01197 if (!solveAll) { 01198 choice[i].possibleBranch->way(-1); 01199 choice[i].possibleBranch->branch(); 01200 break; 01201 } 01202 } else { 01203 // neither side feasible 01204 anyAction=-2; 01205 break; 01206 } 01207 } 01208 } 01209 01210 if (!clp) { 01211 // Delete the snapshot 01212 solver->unmarkHotStart(); 01213 } else { 01214 clp->setLogLevel(saveLogLevel); 01215 delete [] newLower; 01216 delete [] newUpper; 01217 delete [] outputStuff; 01218 int i; 01219 for (i=0;i<2*numberStrong;i++) 01220 delete [] outputSolution[i]; 01221 delete [] outputSolution; 01222 } 01223 solver->setIntParam(OsiMaxNumIterationHotStart,saveLimit); 01224 // restore basis 01225 solver->setWarmStart(ws); 01226 delete ws; 01227 01228 /* 01229 anyAction >= 0 indicates that strong branching didn't produce any monotone 01230 variables. Sift through the candidates for the best one. 01231 01232 QUERY: Setting numberNodes looks to be a distributed noop. numberNodes is 01233 local to this code block. Perhaps should be numberNodes_ from model? 01234 Unclear what this calculation is doing. 01235 */ 01236 if (anyAction>=0) { 01237 01238 int numberNodes = model->getNodeCount(); 01239 // get average cost per iteration and assume stopped ones 01240 // would stop after 50% more iterations at average cost??? !!! ??? 01241 double averageCostPerIteration=0.0; 01242 double totalNumberIterations=1.0; 01243 int smallestNumberInfeasibilities=INT_MAX; 01244 for (i=0;i<numberStrong;i++) { 01245 totalNumberIterations += choice[i].numItersDown + 01246 choice[i].numItersUp ; 01247 averageCostPerIteration += choice[i].downMovement + 01248 choice[i].upMovement; 01249 smallestNumberInfeasibilities= 01250 min(min(choice[i].numIntInfeasDown , 01251 choice[i].numIntInfeasUp ), 01252 smallestNumberInfeasibilities); 01253 } 01254 if (smallestNumberInfeasibilities>=numberIntegerInfeasibilities) 01255 numberNodes=1000000; // switch off search for better solution 01256 numberNodes=1000000; // switch off anyway 01257 averageCostPerIteration /= totalNumberIterations; 01258 // all feasible - choose best bet 01259 01260 #if 0 01261 for (i = 0 ; i < numberStrong ; i++) 01262 { int iColumn = 01263 model->integerVariable()[choice[i].possibleBranch->variable()] ; 01264 model->messageHandler()->message(SBB_STRONG,model->messages()) 01265 << i << iColumn 01266 <<choice[i].downMovement<<choice[i].numIntInfeasDown 01267 <<choice[i].upMovement<<choice[i].numIntInfeasUp 01268 <<choice[i].possibleBranch->value() 01269 <<CoinMessageEol; 01270 int betterWay = decision->betterBranch(choice[i].possibleBranch, 01271 branch_, 01272 choice[i].upMovement, 01273 choice[i].numIntInfeasUp , 01274 choice[i].downMovement, 01275 choice[i].numIntInfeasDown ); 01276 if (betterWay) { 01277 delete branch_; 01278 // C) create branching object 01279 branch_ = choice[i].possibleBranch; 01280 choice[i].possibleBranch=NULL; 01281 branch_->way(betterWay); 01282 } 01283 } 01284 #else 01285 // New method does all at once so it can be more sophisticated 01286 // in deciding how to balance actions. 01287 // But it does need arrays 01288 double * changeUp = new double [numberStrong]; 01289 int * numberInfeasibilitiesUp = new int [numberStrong]; 01290 double * changeDown = new double [numberStrong]; 01291 int * numberInfeasibilitiesDown = new int [numberStrong]; 01292 SbbBranchingObject ** objects = new SbbBranchingObject * [ numberStrong]; 01293 for (i = 0 ; i < numberStrong ; i++) { 01294 int iColumn = 01295 model->integerVariable()[choice[i].possibleBranch->variable()] ; 01296 model->messageHandler()->message(SBB_STRONG,model->messages()) 01297 << i << iColumn 01298 <<choice[i].downMovement<<choice[i].numIntInfeasDown 01299 <<choice[i].upMovement<<choice[i].numIntInfeasUp 01300 <<choice[i].possibleBranch->value() 01301 <<CoinMessageEol; 01302 changeUp[i]=choice[i].upMovement; 01303 numberInfeasibilitiesUp[i] = choice[i].numIntInfeasUp; 01304 changeDown[i]=choice[i].downMovement; 01305 numberInfeasibilitiesDown[i] = choice[i].numIntInfeasDown; 01306 objects[i] = choice[i].possibleBranch; 01307 } 01308 int whichObject = decision->bestBranch(objects,numberStrong,numberUnsatisfied_, 01309 changeUp,numberInfeasibilitiesUp, 01310 changeDown,numberInfeasibilitiesDown, 01311 objectiveValue); 01312 // move branching object and make sure it will not be deleted 01313 if (whichObject>=0) { 01314 branch_ = objects[whichObject]; 01315 choice[whichObject].possibleBranch=NULL; 01316 } 01317 delete [] changeUp; 01318 delete [] numberInfeasibilitiesUp; 01319 delete [] changeDown; 01320 delete [] numberInfeasibilitiesDown; 01321 delete [] objects; 01322 #endif 01323 } 01324 } 01325 /* 01326 Simple branching. Why are we choosing choice[0]? Seems arbitrary. Why not 01327 the final candidate? (It will have the greatest infeasibility.) 01328 01329 (jjf) you can choose the first or last as if we get here choice has length 1! 01330 */ 01331 else { 01332 // not strong 01333 // C) create branching object 01334 branch_ = choice[0].possibleBranch; 01335 choice[0].possibleBranch=NULL; 01336 // we could use otherWay - think a bit 01337 } 01338 /* 01339 Cleanup, then we're outta here. 01340 */ 01341 if (!model->branchingMethod()) 01342 delete decision; 01343 01344 for (i=0;i<maximumStrong;i++) 01345 delete choice[i].possibleBranch; 01346 delete [] choice; 01347 delete [] saveLower; 01348 delete [] saveUpper; 01349 01350 // restore solution 01351 solver->setColSolution(saveSolution); 01352 delete [] saveSolution; 01353 return anyAction; 01354 } |
|
Create a description of the subproblem at this node The SbbNodeInfo structure holds the information (basis & variable bounds) required to recreate the subproblem for this node. It also links the node to its parent (via the parent's SbbNodeInfo object).
If lastNode == NULL, a SbbFullNodeInfo object will be created. All parameters except
If lastNode != NULL, a SbbPartialNodeInfo object will be created. Basis and bounds information will be stored in the form of differences between the parent subproblem and this subproblem. (More precisely, Definition at line 626 of file SbbNode.cpp. References SbbModel::addedCuts(), CoinWarmStartBasis::clone(), SbbModel::currentNumberCuts(), CoinWarmStartBasis::generateDiff(), CoinWarmStartBasis::getArtifStatus(), OsiSolverInterface::getColLower(), OsiSolverInterface::getColUpper(), OsiSolverInterface::getNumCols(), OsiSolverInterface::getNumRows(), OsiSolverInterface::getWarmStart(), nodeInfo_, SbbModel::numberRowsAtContinuous(), CoinWarmStartBasis::print(), CoinWarmStartBasis::resize(), CoinWarmStartBasis::setArtifStatus(), and SbbModel::solver(). Referenced by SbbModel::branchAndBound().
00631 { OsiSolverInterface * solver = model->solver(); 00632 /* 00633 The root --- no parent. Create full basis and bounds information. 00634 */ 00635 if (!lastNode) 00636 { nodeInfo_=new SbbFullNodeInfo(model,solver->getNumRows()); } 00637 /* 00638 Not the root. Create an edit from the parent's basis & bound information. 00639 This is not quite as straightforward as it seems. We need to reintroduce 00640 cuts we may have dropped out of the basis, in the correct position, because 00641 this whole process is strictly positional. Start by grabbing the current 00642 basis. 00643 */ 00644 else 00645 { const CoinWarmStartBasis* ws = 00646 dynamic_cast<const CoinWarmStartBasis*>(solver->getWarmStart()); 00647 assert(ws!=NULL); // make sure not volume 00648 //int numberArtificials = lastws->getNumArtificial(); 00649 int numberColumns = solver->getNumCols(); 00650 00651 const double * lower = solver->getColLower(); 00652 const double * upper = solver->getColUpper(); 00653 00654 int i; 00655 /* 00656 Create a clone and resize it to hold all the structural constraints, plus 00657 all the cuts: old cuts, both active and inactive (currentNumberCuts), and 00658 new cuts (numberNewCuts). 00659 00660 TODO: You'd think that the set of constraints (logicals) in the expanded 00661 basis should match the set represented in lastws. At least, that's 00662 what I thought. But it turns out that lastws is actually the stripped 00663 basis produced at the end of addCuts(), rather than the raw basis 00664 handed back by addCuts1(). The expanded basis here is equivalent to 00665 the raw basis of addCuts1(). I said ``whoa, that's not good'' and went 00666 back to John's code to see where I'd gone wrong. And discovered the 00667 same `error' in his code. 00668 00669 After a bit of thought, my conclusion is that correctness is not 00670 affected by whether lastws is the stripped or raw basis. The diffs 00671 have no semantics --- just a set of changes that need to be made 00672 to convert lastws into expanded. I think the only effect is that we 00673 store a lot more diffs (everything in expanded that's not covered by 00674 the stripped basis). But I need to give this more thought. There 00675 may well be some subtle error cases. 00676 00677 In the mean time, I've twiddled addCuts() to set lastws to the raw 00678 basis. Makes me less nervous to compare apples to apples. 00679 */ 00680 CoinWarmStartBasis *expanded = 00681 dynamic_cast<CoinWarmStartBasis *>(ws->clone()) ; 00682 int numberRowsAtContinuous = model->numberRowsAtContinuous(); 00683 int iFull = numberRowsAtContinuous+model->currentNumberCuts()+ 00684 numberNewCuts; 00685 //int numberArtificialsNow = iFull; 00686 //int maxBasisLength = ((iFull+15)>>4)+((numberColumns+15)>>4); 00687 //printf("l %d full %d\n",maxBasisLength,iFull); 00688 expanded->resize(iFull,numberColumns); 00689 #ifdef FULL_DEBUG 00690 printf("Before expansion: orig %d, old %d, new %d, current %d\n", 00691 numberRowsAtContinuous,numberOldActiveCuts,numberNewCuts, 00692 model->currentNumberCuts()) ; 00693 ws->print(); 00694 #endif 00695 /* 00696 Now fill in the expanded basis. Anything indices beyond nPartial must 00697 be cuts created while processing this node --- they can be copied directly 00698 into the expanded basis. From nPartial down, pull the status of active cuts 00699 from ws, interleaving with a B entry for the deactivated (loose) cuts. 00700 */ 00701 int numberDropped = model->currentNumberCuts()-numberOldActiveCuts; 00702 int iCompact=iFull-numberDropped; 00703 SbbCountRowCut ** cut = model->addedCuts(); 00704 int nPartial = model->currentNumberCuts()+numberRowsAtContinuous; 00705 iFull--; 00706 for (;iFull>=nPartial;iFull--) { 00707 CoinWarmStartBasis::Status status = ws->getArtifStatus(--iCompact); 00708 assert (status != CoinWarmStartBasis::basic); 00709 expanded->setArtifStatus(iFull,status); 00710 } 00711 for (;iFull>=numberRowsAtContinuous;iFull--) { 00712 if (cut[iFull-numberRowsAtContinuous]) { 00713 CoinWarmStartBasis::Status status = ws->getArtifStatus(--iCompact); 00714 assert (status != CoinWarmStartBasis::basic); 00715 expanded->setArtifStatus(iFull,status); 00716 } else { 00717 expanded->setArtifStatus(iFull,CoinWarmStartBasis::basic); 00718 } 00719 } 00720 #ifdef FULL_DEBUG 00721 printf("Expanded basis\n"); 00722 expanded->print() ; 00723 printf("Diffing against\n") ; 00724 lastws->print() ; 00725 #endif 00726 /* 00727 Now that we have two bases in proper positional correspondence, creating 00728 the actual diff is dead easy. 00729 */ 00730 00731 CoinWarmStartDiff *basisDiff = expanded->generateDiff(lastws) ; 00732 /* 00733 Diff the bound vectors. It's assumed the number of structural variables is 00734 not changing. Assuming that branching objects all involve integer variables, 00735 we should see at least one bound change as a consequence of processing this 00736 subproblem. Different types of branching objects could break this assertion. 00737 */ 00738 double *boundChanges = new double [2*numberColumns] ; 00739 int *variables = new int [2*numberColumns] ; 00740 int numberChangedBounds=0; 00741 for (i=0;i<numberColumns;i++) { 00742 if (lower[i]!=lastLower[i]) { 00743 variables[numberChangedBounds]=i; 00744 boundChanges[numberChangedBounds++]=lower[i]; 00745 } 00746 if (upper[i]!=lastUpper[i]) { 00747 variables[numberChangedBounds]=i|0x80000000; 00748 boundChanges[numberChangedBounds++]=upper[i]; 00749 } 00750 #ifdef SBB_DEBUG 00751 if (lower[i]!=lastLower[i]) 00752 printf("lower on %d changed from %g to %g\n", 00753 i,lastLower[i],lower[i]); 00754 if (upper[i]!=lastUpper[i]) 00755 printf("upper on %d changed from %g to %g\n", 00756 i,lastUpper[i],upper[i]); 00757 #endif 00758 } 00759 #ifdef SBB_DEBUG 00760 printf("%d changed bounds\n",numberChangedBounds) ; 00761 #endif 00762 assert (numberChangedBounds); 00763 /* 00764 Hand the lot over to the SbbPartialNodeInfo constructor, then clean up and 00765 return. 00766 */ 00767 nodeInfo_ = 00768 new SbbPartialNodeInfo(lastNode->nodeInfo_,this,numberChangedBounds, 00769 variables,boundChanges,basisDiff) ; 00770 delete basisDiff ; 00771 delete [] boundChanges; 00772 delete [] variables; 00773 delete expanded ; 00774 delete ws; 00775 } 00776 } |
|
Initialize reference counts in attached SbbNodeInfo This is a convenience routine, which will initialize the reference counts in the attached SbbNodeInfo object based on the attached SbbBranchingObject.
Definition at line 1444 of file SbbNode.cpp. References branch_, SbbNodeInfo::initializeInfo(), nodeInfo_, and SbbBranchingObject::numberBranches(). Referenced by SbbModel::branchAndBound().
01445 { 01446 assert(nodeInfo_ && branch_) ; 01447 nodeInfo_->initializeInfo(branch_->numberBranches()); 01448 } |
|
Branching `variable' associated with the attached SbbBranchingObject. Check SbbBranchingObject::variable() for a longer explanation of `variable'. Definition at line 471 of file SbbNode.hpp. References branch_, and SbbBranchingObject::variable(). Referenced by SbbModel::branchAndBound().
|