Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

SbbNode Class Reference

#include <SbbNode.hpp>

List of all members.

Public Member Functions

 SbbNode ()
 Default Constructor.

 SbbNode (SbbModel *model, SbbNode *lastNode)
 Construct and increment parent reference count.

 SbbNode (const SbbNode &)
 Copy constructor.

SbbNodeoperator= (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.

SbbNodeInfonodeInfo () 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

SbbNodeInfonodeInfo_
 Information to make basis and bounds.

double objectiveValue_
double guessedObjectiveValue_
SbbBranchingObjectbranch_
 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.


Detailed Description

Information required while the node is live

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.


Constructor & Destructor Documentation

SbbNode::~SbbNode  ) 
 

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 }


Member Function Documentation

int SbbNode::chooseBranch SbbModel model,
SbbNode lastNode
 

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:

  • 0: A branching object has been installed
  • -1: A monotone object was discovered
  • -2: An infeasible object was discovered

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 }

void SbbNode::createInfo SbbModel model,
SbbNode lastNode,
const CoinWarmStartBasis lastws,
const double *  lastLower,
const double *  lastUpper,
int  numberOldActiveCuts,
int  numberNewCuts
 

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 model are unused.

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, lastws, lastUpper, lastLower, numberOldActiveCuts, and numberNewCuts are used.)

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 }

void SbbNode::initializeInfo  ) 
 

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.

See also:
SbbNodeInfo::initializeInfo(int).

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 }

int SbbNode::variable  )  const [inline]
 

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().

00472   {if (branch_) return branch_->variable();else return -1;};


The documentation for this class was generated from the following files:
Generated on Wed Dec 3 14:36:26 2003 for Sbb by doxygen 1.3.5