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

SbbModel Class Reference

#include <SbbModel.hpp>

List of all members.

Public Types

enum  SbbIntParam { SbbMaxNumNode = 0, SbbMaxNumSol, SbbFathomDiscipline, SbbLastIntParam }
enum  SbbDblParam {
  SbbIntegerTolerance = 0, SbbInfeasibilityWeight, SbbCutoffIncrement, SbbAllowableGap,
  SbbMaximumSeconds, SbbLastDblParam
}

Public Member Functions

Solve methods
void initialSolve ()
 Solve the initial LP relaxation.

void branchAndBound ()
 Invoke the branch & cut algorithm.

bool solveWithCuts (OsiCuts &cuts, int numberTries, SbbNode *node, int &numberOldActiveCuts, int &numberNewCuts, int &maximumWhich, int *&whichGenerator)
 Evaluate a subproblem using cutting planes and heuristics.

bool resolve ()
 Reoptimise an LP relaxation.

Presolve methods
SbbModelfindCliques (bool makeEquality, int atLeastThisMany, int lessThanThis, int defaultValue=1000)
SbbModelintegerPresolve (bool weak=false)
bool integerPresolveThisModel (OsiSolverInterface *originalSolver, bool weak=false)
void originalModel (SbbModel *presolvedModel, bool weak)
 Put back information into the original model after integer presolve.

bool tightenVubs (int type, bool allowMultipleBinary=false, double useCutoff=1.0e50)
 For variables involved in VUB constraints, see if we can tighten bounds by solving lp's.

bool tightenVubs (int numberVubs, const int *which, double useCutoff=1.0e50)
 For variables involved in VUB constraints, see if we can tighten bounds by solving lp's.

Object manipulation routines
See SbbObject for an explanation of `object' in the context of SbbModel.

int numberObjects () const
 Get the number of objects.

SbbObject ** objects () const
 Get the array of objects.

const SbbObjectobject (int which) const
 Get the specified object.

void deleteObjects ()
 Delete all object information.

void addObjects (int numberObjects, SbbObject **objects)
void synchronizeModel ()
 Ensure attached objects point to this model.

void findIntegers (bool startAgain)
 Identify integer variables and create corresponding objects.

Parameter set/get methods
The set methods return true if the parameter was set to the given value, false if the value of the parameter is out of range.

The get methods return the value of the parameter.

bool setIntParam (SbbIntParam key, int value)
 Set an integer parameter.

bool setDblParam (SbbDblParam key, double value)
 Set a double parameter.

int getIntParam (SbbIntParam key) const
 Get an integer parameter.

double getDblParam (SbbDblParam key) const
 Get a double parameter.

void setCutoff (double value)
 Set cutoff bound on the objective function.

double getCutoff () const
 Get the cutoff bound on the objective function - always as minimize.

bool setMaximumNodes (int value)
 Set the maximum node limit .

int getMaximumNodes () const
 Get the maximum node limit .

bool setMaximumSolutions (int value)
int getMaximumSolutions () const
bool setIntegerTolerance (double value)
double getIntegerTolerance () const
bool setInfeasibilityWeight (double value)
double getInfeasibilityWeight () const
bool setAllowableGap (double value)
double getAllowableGap () const
void setForcePriority (int value)
 Set the force priority level.

int getForcePriority () const
 Get the force priority level.

void setMinimumDrop (double value)
 Set the minimum drop to continue cuts.

double getMinimumDrop () const
 Get the minimum drop to continue cuts.

void setMaximumCutPassesAtRoot (int value)
int getMaximumCutPassesAtRoot () const
void setMaximumCutPasses (int value)
int getMaximumCutPasses () const
void setNumberStrong (int number)
int numberStrong () const
void setPrintFrequency (int number)
int printFrequency () const
 Get the print frequency.

Methods returning info on how the solution process terminated
bool isAbandoned () const
 Are there a numerical difficulties?

bool isProvenOptimal () const
 Is optimality proven?

bool isProvenInfeasible () const
 Is infeasiblity proven (or none better than cutoff)?

bool isNodeLimitReached () const
 Node limit reached?

bool isSolutionLimitReached () const
 Solution limit reached?

int getIterationCount () const
 Get how many iterations it took to solve the problem.

int getNodeCount () const
 Get how many Nodes it took to solve the problem.

int status () const
Problem information methods
These methods call the solver's query routines to return information about the problem referred to by the current object. Querying a problem that has no data associated with it result in zeros for the number of rows and columns, and NULL pointers from the methods that return vectors.

Const pointers returned from any data-query method are valid as long as the data is unchanged and the solver is not called.

int numberRowsAtContinuous () const
 Number of rows in continuous (root) problem.

int getNumCols () const
 Get number of columns.

int getNumRows () const
 Get number of rows.

int getNumElements () const
 Get number of nonzero elements.

int numberIntegers () const
 Number of integers in problem.

const int * integerVariable () const
const double * getColLower () const
 Get pointer to array[getNumCols()] of column lower bounds.

const double * getColUpper () const
 Get pointer to array[getNumCols()] of column upper bounds.

const char * getRowSense () const
const double * getRightHandSide () const
const double * getRowRange () const
const double * getRowLower () const
 Get pointer to array[getNumRows()] of row lower bounds.

const double * getRowUpper () const
 Get pointer to array[getNumRows()] of row upper bounds.

const double * getObjCoefficients () const
 Get pointer to array[getNumCols()] of objective function coefficients.

double getObjSense () const
 Get objective function sense (1 for min (default), -1 for max).

bool isContinuous (int colIndex) const
 Return true if variable is continuous.

bool isBinary (int colIndex) const
 Return true if variable is binary.

bool isInteger (int colIndex) const
bool isIntegerNonBinary (int colIndex) const
 Return true if variable is general integer.

bool isFreeBinary (int colIndex) const
 Return true if variable is binary and not fixed at either bound.

const CoinPackedMatrix * getMatrixByRow () const
 Get pointer to row-wise copy of matrix.

const CoinPackedMatrix * getMatrixByCol () const
 Get pointer to column-wise copy of matrix.

double getInfinity () const
 Get solver's value for infinity.

Methods related to querying the solution
void setBestSolution (SBB_Message how, double &objectiveValue, const double *solution, bool fixVariables=false)
 Record a new incumbent solution and update objectiveValue.

double checkSolution (double cutoff, const double *solution, bool fixVariables)
bool feasibleSolution (int &numberIntegerInfeasibilities, int &numberObjectInfeasibilities) const
double * currentSolution () const
const double * getColSolution () const
 Get pointer to array[getNumCols()] of primal solution vector.

const double * getRowPrice () const
 Get pointer to array[getNumRows()] of dual prices.

const double * getReducedCost () const
 Get a pointer to array[getNumCols()] of reduced costs.

const double * getRowActivity () const
 Get pointer to array[getNumRows()] of row activity levels.

double getCurrentObjValue () const
 Get current objective function value.

double getObjValue () const
 Get best objective function value.

const double * bestSolution () const
int getSolutionCount () const
 Get number of solutions.

void setSolutionCount (int value)
 Set number of solutions (so heuristics will be different).

int getNumberHeuristicSolutions () const
 Get number of heuristic solutions.

void setObjSense (double s)
 Set objective function sense (1 for min (default), -1 for max,).

double getContinuousObjective () const
 Value of objective at continuous.

void setContinuousObjective (double value)
int getContinuousInfeasibilities () const
 Number of infeasibilities at continuous.

void setContinuousInfeasibilities (int value)
Node selection
SbbCompareBase * nodeComparison () const
void setNodeComparison (SbbCompareBase *compare)
void setNodeComparison (SbbCompareBase &compare)
Branching Decisions
See the SbbBranchDecision class for additional information.

SbbBranchDecisionbranchingMethod () const
 Get the current branching decision method.

void setBranchingMethod (SbbBranchDecision *method)
 Set the branching decision method.

void setBranchingMethod (SbbBranchDecision &method)
Row (constraint) and Column (variable) cut generation
void reducedCostFix ()
CoinWarmStartBasisgetEmptyBasis (int ns=0, int na=0) const
 Get an empty basis object.

void takeOffCuts (OsiCuts &cuts, int *whichGenerator, int &numberOldActiveCuts, int &numberNewCuts, bool allowResolve)
int addCuts (SbbNode *node, CoinWarmStartBasis *&lastws)
void addCuts1 (SbbNode *node, CoinWarmStartBasis *&lastws)
SbbCountRowCut ** addedCuts () const
 Return the list of cuts initially collected for this subproblem.

int currentNumberCuts () const
 Number of entries in the list returned by addedCuts().

int numberCutGenerators () const
 Get the number of cut generators.

SbbCutGenerator ** cutGenerators () const
 Get the list of cut generators.

SbbCutGeneratorcutGenerator (int i) const
 Get the specified cut generator.

void addCutGenerator (CglCutGenerator *generator, int howOften=1, const char *name=NULL, bool normal=true, bool atSolution=false, bool infeasible=false)
Heuristics and priorities
void addHeuristic (SbbHeuristic *generator)
 Add one heuristic.

void passInPriorities (const int *priorities, bool ifClique, int defaultValue=1000)
const int * priority () const
 Priorities.

int priority (int sequence) const
 Returns priority level for an object (or 1000 if no priorities exist).

Message handling
void passInMessageHandler (CoinMessageHandler *handler)
 Pass in Message handler (not deleted at end).

void newLanguage (CoinMessages::Language language)
 Set language.

void setLanguage (CoinMessages::Language language)
CoinMessageHandlermessageHandler () const
 Return handler.

CoinMessages messages ()
 Return messages.

CoinMessagesmessagesPointer ()
 Return pointer to messages.

Constructors and destructors etc
 SbbModel ()
 Default Constructor.

 SbbModel (const OsiSolverInterface &)
 Constructor from solver.

void assignSolver (OsiSolverInterface *&solver)
 SbbModel (const SbbModel &)
 Copy constructor.

SbbModeloperator= (const SbbModel &rhs)
 Assignment operator.

 ~SbbModel ()
 Destructor.

OsiSolverInterfacesolver () const
 Returns solver - has current state.

OsiSolverInterfacecontinuousSolver () const
 Returns solver with continuous state.

void gutsOfDestructor ()
 Clears out as much as possible (except solver).


Private Attributes

Private member data
OsiSolverInterfacesolver_
 The solver associated with this model.

bool ourSolver_
OsiSolverInterfacecontinuousSolver_
 A copy of the solver, taken at the continuous (root) node.

CoinMessageHandlerhandler_
 Message handler.

bool defaultHandler_
CoinMessages messages_
 Sbb messages.

int intParam_ [SbbLastIntParam]
 Array for integer parameters.

double dblParam_ [SbbLastDblParam]
 Array for double parameters.

CoinWarmStartemptyWarmStart_
CoinWarmStartBasisbasis_
double bestObjective_
 Best objective.

double * bestSolution_
 Array holding the incumbent (best) solution.

double * currentSolution_
OsiCuts globalCuts_
 Global cuts.

double minimumDrop_
 Minimum degradation in objective value to continue cut generation.

int numberSolutions_
 Number of solutions.

int forcePriority_
 Force priority level.

int numberHeuristicSolutions_
 Number of heuristic solutions.

int numberNodes_
 Cumulative number of nodes.

int numberIterations_
 Cumulative number of iterations.

int status_
 Status of problem - 0 finished, 1 stopped, 2 difficulties.

int numberIntegers_
 Number of integers in problem.

int numberRowsAtContinuous_
 Number of rows at continuous.

int maximumNumberCuts_
 Maximum number of cuts.

int currentNumberCuts_
 Number of entries in addedCuts_.

int maximumDepth_
SbbNodeInfo ** walkback_
SbbCountRowCut ** addedCuts_
int * integerVariable_
 Indices of integer variables.

int strategy_
 0 bit gomory, 1 probing, 2 knapsack, 3 oddhole

SbbCompareBase * nodeCompare_
 User node comparison function.

SbbBranchDecisionbranchingMethod_
 Variable selection function.

int numberStrong_
int printFrequency_
 Print frequency.

int numberCutGenerators_
 Number of cut generators.

SbbCutGenerator ** generator_
int numberHeuristics_
 Number of heuristics.

SbbHeuristic ** heuristic_
int numberObjects_
 Total number of objects.

SbbObject ** object_
 Integer and Clique and ... information.

int * originalColumns_
 Original columns as created by integerPresolve.

int * priority_
 Priorities.

int howOftenGlobalScan_
 How often to scan global cuts.

double continuousObjective_
int continuousInfeasibilities_
 Number of infeasibilities at continuous.

int maximumCutPassesAtRoot_
 Maximum number of cut passes at root.

int maximumCutPasses_
 Maximum number of cut passes.


Detailed Description

Simple Branch and bound class

The initialSolve() method solves the initial LP relaxation of the MIP problem. The branchAndBound() method can then be called to finish using a branch and cut algorithm.

Search Tree Traversal

Subproblems (aka nodes) requiring additional evaluation are stored using the SbbNode and SbbNodeInfo objects. Ancestry linkage is maintained in the SbbNodeInfo object. Evaluation of a subproblem within branchAndBound() proceeds as follows:

Note that there is never a node representing the active subproblem; the model and solver represent the active subproblem.

Row (Constraint) Cut Handling

For a typical subproblem, the sequence of events is as follows:

See SbbCountRowCut for details of the bookkeeping associated with cut management.

Definition at line 80 of file SbbModel.hpp.


Member Enumeration Documentation

enum SbbModel::SbbDblParam
 

Enumeration values:
SbbIntegerTolerance  The maximum amount the value of an integer variable can vary from integer and still be considered feasible.
SbbInfeasibilityWeight  The objective is assumed to worsen by this amount for each integer infeasibility.
SbbCutoffIncrement  The amount by which to tighten the objective function cutoff when a new solution is discovered.
SbbAllowableGap  Stop when the gap between the objective value of the best known solution and the best bound on the objective of any solution is less than this.

This is an absolute value. Conversion from a percentage is left to the client.

SbbMaximumSeconds  The maximum number of seconds before terminating. A double should be adequate!
SbbLastDblParam  Just a marker, so that a static sized array can store parameters.

Definition at line 103 of file SbbModel.hpp.

enum SbbModel::SbbIntParam
 

Enumeration values:
SbbMaxNumNode  The maximum number of nodes before terminating
SbbMaxNumSol  The maximum number of solutions before terminating
SbbFathomDiscipline  Fathoming discipline

Controls objective function comparisons for purposes of fathoming by bound or determining monotonic variables.

If 1, action is taken only when the current objective is strictly worse than the target. Implementation is handled by adding a small tolerance to the target.

SbbLastIntParam  Just a marker, so that a static sized array can store parameters.

Definition at line 84 of file SbbModel.hpp.

00084                  {
00086   SbbMaxNumNode=0,
00088   SbbMaxNumSol,
00098   SbbFathomDiscipline,
00100   SbbLastIntParam
00101 };


Constructor & Destructor Documentation

SbbModel::SbbModel  ) 
 

Default Constructor.

Default Constructor

Creates an empty model without an associated solver.

Definition at line 1264 of file SbbModel.cpp.

References branchingMethod_, dblParam_, handler_, intParam_, messages_, nodeCompare_, SbbAllowableGap, SbbCutoffIncrement, SbbFathomDiscipline, SbbInfeasibilityWeight, SbbIntegerTolerance, SbbMaximumSeconds, SbbMaxNumNode, SbbMaxNumSol, and CoinMessageHandler::setLogLevel().

Referenced by findCliques(), and integerPresolve().

01266 :
01267   solver_(NULL),
01268   ourSolver_(true),
01269   continuousSolver_(NULL),
01270   defaultHandler_(true),
01271   emptyWarmStart_(NULL),
01272   basis_(NULL),
01273   bestObjective_(DBL_MAX),
01274   bestSolution_(NULL),
01275   currentSolution_(NULL),
01276   minimumDrop_(1.0e-4),
01277   numberSolutions_(0),
01278   forcePriority_(-1),
01279   numberHeuristicSolutions_(0),
01280   numberNodes_(0),
01281   numberIterations_(0),
01282   status_(0),
01283   numberIntegers_(0),
01284   numberRowsAtContinuous_(0),
01285   maximumNumberCuts_(0),
01286   currentNumberCuts_(0),
01287   maximumDepth_(0),
01288   walkback_(NULL),
01289   addedCuts_(NULL),
01290   integerVariable_(NULL),
01291   strategy_(0),
01292   numberStrong_(5),
01293   printFrequency_(0),
01294   numberCutGenerators_(0),
01295   generator_(NULL),
01296   numberHeuristics_(0),
01297   heuristic_(NULL),
01298   numberObjects_(0),
01299   object_(NULL),
01300   originalColumns_(NULL),
01301   priority_(NULL),
01302   howOftenGlobalScan_(1),
01303   continuousObjective_(DBL_MAX),
01304   continuousInfeasibilities_(INT_MAX),
01305   maximumCutPassesAtRoot_(20),
01306   maximumCutPasses_(10)
01307 {
01308   intParam_[SbbMaxNumNode] = 9999999;
01309   intParam_[SbbMaxNumSol] = 9999999;
01310   intParam_[SbbFathomDiscipline] = 0;
01311 
01312   dblParam_[SbbIntegerTolerance] = 1e-6;
01313   dblParam_[SbbInfeasibilityWeight] = 0.0;
01314   dblParam_[SbbCutoffIncrement] = 1e-5;
01315   dblParam_[SbbAllowableGap] = 1.0e-10;
01316   dblParam_[SbbMaximumSeconds] = 1.0e100;
01317   nodeCompare_=NULL;
01318   branchingMethod_=NULL;
01319   handler_ = new CoinMessageHandler();
01320   handler_->setLogLevel(2);
01321   messages_ = SbbMessage();
01322 }

SbbModel::SbbModel const OsiSolverInterface rhs  ) 
 

Constructor from solver.

Constructor from solver.

Creates a model complete with a clone of the solver passed as a parameter.

Definition at line 1329 of file SbbModel.cpp.

References bestSolution_, branchingMethod_, OsiSolverInterface::clone(), currentSolution_, dblParam_, OsiSolverInterface::getNumCols(), handler_, integerVariable_, intParam_, OsiSolverInterface::isInteger(), messages_, nodeCompare_, numberIntegers_, ourSolver_, SbbAllowableGap, SbbCutoffIncrement, SbbFathomDiscipline, SbbInfeasibilityWeight, SbbIntegerTolerance, SbbMaximumSeconds, SbbMaxNumNode, SbbMaxNumSol, CoinMessageHandler::setLogLevel(), and solver_.

01330 :
01331   continuousSolver_(NULL),
01332   defaultHandler_(true),
01333   emptyWarmStart_(NULL),
01334   basis_(NULL) ,
01335   bestObjective_(DBL_MAX),
01336   minimumDrop_(1.0e-4),
01337   numberSolutions_(0),
01338   forcePriority_(-1),
01339   numberHeuristicSolutions_(0),
01340   numberNodes_(0),
01341   numberIterations_(0),
01342   status_(0),
01343   numberRowsAtContinuous_(0),
01344   maximumNumberCuts_(0),
01345   currentNumberCuts_(0),
01346   maximumDepth_(0),
01347   walkback_(NULL),
01348   addedCuts_(NULL),
01349   strategy_(0),
01350   numberStrong_(5),
01351   printFrequency_(0),
01352   numberCutGenerators_(0),
01353   generator_(NULL),
01354   numberHeuristics_(0),
01355   heuristic_(NULL),
01356   numberObjects_(0),
01357   object_(NULL),
01358   originalColumns_(NULL),
01359   priority_(NULL),
01360   howOftenGlobalScan_(-1),
01361   continuousObjective_(DBL_MAX),
01362   continuousInfeasibilities_(INT_MAX),
01363   maximumCutPassesAtRoot_(20),
01364   maximumCutPasses_(10)
01365 {
01366   intParam_[SbbMaxNumNode] = 9999999;
01367   intParam_[SbbMaxNumSol] = 9999999;
01368   intParam_[SbbFathomDiscipline] = 0;
01369 
01370   dblParam_[SbbIntegerTolerance] = 1e-6;
01371   dblParam_[SbbInfeasibilityWeight] = 0.0;
01372   dblParam_[SbbCutoffIncrement] = 1e-5;
01373   dblParam_[SbbAllowableGap] = 1.0e-10;
01374   dblParam_[SbbMaximumSeconds] = 1.0e100;
01375 
01376   nodeCompare_=NULL;
01377   branchingMethod_=NULL;
01378   handler_ = new CoinMessageHandler();
01379   handler_->setLogLevel(2);
01380   messages_ = SbbMessage();
01381   solver_ = rhs.clone();
01382   ourSolver_ = true ;
01383 
01384   // Initialize solution and integer variable vectors
01385   bestSolution_ = NULL; // to say no solution found
01386   numberIntegers_=0;
01387   int numberColumns = solver_->getNumCols();
01388   int iColumn;
01389   if (numberColumns) {
01390     // Space for current solution
01391     currentSolution_ = new double[numberColumns];
01392     for (iColumn=0;iColumn<numberColumns;iColumn++) {
01393       if( solver_->isInteger(iColumn)) 
01394         numberIntegers_++;
01395     }
01396   } else {
01397     // empty model
01398     currentSolution_=NULL;
01399   }
01400   if (numberIntegers_) {
01401     integerVariable_ = new int [numberIntegers_];
01402     numberIntegers_=0;
01403     for (iColumn=0;iColumn<numberColumns;iColumn++) {
01404       if( solver_->isInteger(iColumn)) 
01405         integerVariable_[numberIntegers_++]=iColumn;
01406     }
01407   } else {
01408     integerVariable_ = NULL;
01409   }
01410 }


Member Function Documentation

void SbbModel::addCutGenerator CglCutGenerator generator,
int  howOften = 1,
const char *  name = NULL,
bool  normal = true,
bool  atSolution = false,
bool  infeasible = false
 

Add one generator - up to user to delete generators. howoften affects how generator is used. 0 or 1 means always, >1 means every that number of nodes. Negative values have same meaning as positive but they may be switched off (-> -100) by code if not many cuts generated at continuous. -99 is just done at root. Name is just for printout

Definition at line 1865 of file SbbModel.cpp.

References numberCutGenerators_.

01869 {
01870   SbbCutGenerator ** temp = generator_;
01871   generator_ = new SbbCutGenerator * [numberCutGenerators_+1];
01872   memcpy(generator_,temp,numberCutGenerators_*sizeof(SbbCutGenerator *));
01873   delete[] temp ;
01874   generator_[numberCutGenerators_++]= 
01875     new SbbCutGenerator(this,generator, howOften, name,
01876                         normal,atSolution,whenInfeasible);
01877                                                           
01878 }

int SbbModel::addCuts SbbNode node,
CoinWarmStartBasis *&  lastws
 

Determine and install the active cuts that need to be added for the current subproblem

The whole truth is a bit more complicated. The first action is a call to addCuts1(). addCuts() then sorts through the list, installs the tight cuts in the model, and does bookkeeping (adjusts reference counts). The basis returned from addCuts1() is adjusted accordingly.

If it turns out that the node should really be fathomed by bound, addCuts() simply treats all the cuts as loose as it does the bookkeeping.

Definition at line 1997 of file SbbModel.cpp.

References addCuts(), addCuts1(), addedCuts_, OsiSolverInterface::applyRowCuts(), basis_, CoinWarmStartBasis::clone(), currentNumberCuts(), currentNumberCuts_, SbbCountRowCut::decrement(), SbbNode::depth(), CoinWarmStartBasis::getArtifStatus(), getCutoff(), getNumCols(), SbbNode::nodeInfo(), SbbNodeInfo::numberBranchesLeft(), numberNodes_, numberRowsAtContinuous_, SbbNode::numberUnsatisfied(), SbbNode::objectiveValue(), CoinWarmStartBasis::print(), printFrequency_, CoinWarmStartBasis::resize(), CoinWarmStartBasis::setArtifStatus(), OsiSolverInterface::setWarmStart(), solver_, and status().

Referenced by addCuts(), branchAndBound(), and solveWithCuts().

01998 {
01999 /*
02000   addCuts1 performs step 1 of restoring the subproblem at this node; see the
02001   comments there.
02002 */
02003   addCuts1(node,lastws);
02004   int i;
02005   int numberColumns = getNumCols();
02006   SbbNodeInfo * nodeInfo = node->nodeInfo();
02007   double cutoff = getCutoff() ;
02008   int currentNumberCuts=currentNumberCuts_;
02009 /*
02010   If the node can't be fathomed by bound, reinstall tight cuts in the
02011   constraint system.
02012 */
02013   if (node->objectiveValue() < cutoff)
02014   { int numberToAdd = 0;
02015     OsiRowCut * addCuts;
02016     if (currentNumberCuts == 0)
02017       addCuts = NULL;
02018     else
02019       addCuts = new OsiRowCut[currentNumberCuts];
02020 #   ifdef CHECK_CUT_COUNTS
02021     printf("addCuts: expanded basis; rows %d+%d\n",
02022            numberRowsAtContinuous_,currentNumberCuts);
02023     lastws->print();
02024 #   endif
02025 /*
02026   Adjust the basis and constraint system so that we retain only active cuts.
02027   There are three steps:
02028     1) Scan the basis. If the logical associated with the cut is basic, it's
02029        loose and we drop it. The status of the logical for tight cuts is
02030        written back into the status array, compressing as we go.
02031     2) Resize the basis to fit the number of active cuts, stash a clone, and
02032        install with a call to setWarmStart().
02033     3) Install the tight cuts into the constraint system (applyRowCuts).
02034 
02035   TODO: After working through the code in createInfo, I'm more comfortable if
02036         inactive cuts are retained in lastws. So, instead of cloning
02037         lastws into basis_ after the compression loop, do it ahead of time
02038         and then recover lastws from basis_ after the setWarmStart().
02039         (Minimal code change :-). See SbbNode::createInfo for more.
02040 */
02041     if (basis_) delete basis_ ;
02042     basis_= dynamic_cast<CoinWarmStartBasis *>(lastws->clone()) ;
02043     for (i=0;i<currentNumberCuts;i++) {
02044       CoinWarmStartBasis::Status status = 
02045         lastws->getArtifStatus(i+numberRowsAtContinuous_);
02046       if (status != CoinWarmStartBasis::basic&&addedCuts_[i]) {
02047 #       ifdef CHECK_CUT_COUNTS
02048         printf("Using cut %d %x as row %d\n",i,addedCuts_[i],
02049                numberRowsAtContinuous_+numberToAdd);
02050 #       endif
02051         lastws->setArtifStatus(numberToAdd+numberRowsAtContinuous_,status);
02052         addCuts[numberToAdd++] = OsiRowCut(*addedCuts_[i]);
02053       } else {
02054 #       ifdef CHECK_CUT_COUNTS
02055         printf("Dropping cut %d %x\n",i,addedCuts_[i]);
02056 #       endif
02057         addedCuts_[i]=NULL;
02058       }
02059     }
02060     int numberRowsNow=numberRowsAtContinuous_+numberToAdd;
02061     lastws->resize(numberRowsNow,numberColumns);
02062 #ifdef FULL_DEBUG
02063     printf("addCuts: stripped basis; rows %d + %d\n",
02064            numberRowsAtContinuous_,numberToAdd);
02065     lastws->print();
02066 #endif
02067 /*
02068   Apply the cuts and set the basis in the solver.
02069 */
02070     solver_->applyRowCuts(numberToAdd,addCuts);
02071     solver_->setWarmStart(lastws);
02072 /*
02073   TODO: Undo the debugging change. Delete lastws and assign basis_.
02074 */
02075   delete lastws ;
02076   lastws = basis_ ;
02077   basis_ = 0 ;
02078 
02079 #if 0
02080     if ((numberNodes_%printFrequency_)==0) {
02081       printf("Objective %g, depth %d, unsatisfied %d\n",
02082              node->objectiveValue(),
02083              node->depth(),node->numberUnsatisfied());
02084     }
02085 #endif
02086 /*
02087   Clean up and we're out of here.
02088 */
02089     delete [] addCuts;
02090     numberNodes_++;
02091     return 0;
02092   } 
02093 /*
02094   This node has been fathomed by bound as we try to revive it out of the live
02095   set. Adjust the cut reference counts to reflect that we no longer need to
02096   explore the remaining branch arms, hence they will no longer reference any
02097   cuts. Cuts whose reference count falls to zero are deleted.
02098 */
02099   else
02100   { int i;
02101     int numberLeft = nodeInfo->numberBranchesLeft();
02102     for (i = 0 ; i < currentNumberCuts ; i++)
02103     { if (addedCuts_[i])
02104       { if (!addedCuts_[i]->decrement(numberLeft))
02105         { delete addedCuts_[i];
02106           addedCuts_[i] = NULL; } } }
02107     return 1 ; }
02108 }

void SbbModel::addCuts1 SbbNode node,
CoinWarmStartBasis *&  lastws
 

Traverse the tree from node to root and prep the model

addCuts1() begins the job of prepping the model to match the current subproblem. The model is stripped of all cuts, and the search tree is traversed from node to root to determine the changes required. Appropriate bounds changes are installed, a list of cuts is collected but not installed, and an appropriate basis (minus the cuts, but big enough to accommodate them) is constructed.

Todo:
addCuts1() is called in contexts where it's known in advance that all that's desired is to determine a list of cuts and do the bookkeeping (adjust the reference counts). The work of installing bounds and building a basis goes to waste.

Definition at line 1909 of file SbbModel.cpp.

References addedCuts_, SbbNodeInfo::applyToModel(), currentNumberCuts(), currentNumberCuts_, OsiSolverInterface::deleteRows(), getNumCols(), OsiSolverInterface::getNumRows(), maximumDepth_, maximumNumberCuts_, SbbNode::nodeInfo(), SbbNodeInfo::numberCuts(), numberRowsAtContinuous_, CoinWarmStartBasis::setSize(), solver_, and walkback_.

Referenced by addCuts(), and tree::cleanTree().

01910 { int i;
01911   int nNode=0;
01912   int numberColumns = getNumCols();
01913   SbbNodeInfo * nodeInfo = node->nodeInfo();
01914 
01915 /*
01916   Remove all cuts from the constraint system.
01917   (original comment includes ``see note below for later efficiency'', but
01918   the reference isn't clear to me).
01919 */
01920   int currentNumberCuts = solver_->getNumRows()-numberRowsAtContinuous_;
01921   int *which = new int[currentNumberCuts];
01922   for (i = 0 ; i < currentNumberCuts ; i++)
01923     which[i] = i+numberRowsAtContinuous_;
01924   solver_->deleteRows(currentNumberCuts,which);
01925   delete [] which;
01926 /*
01927   Accumulate the path from node to the root in walkback_, and accumulate a
01928   cut count in currentNumberCuts.
01929 
01930   original comment: when working then just unwind until where new node joins
01931   old node (for cuts?)
01932 */
01933   currentNumberCuts = 0;
01934   while (nodeInfo) {
01935     //printf("nNode = %d, nodeInfo = %x\n",nNode,nodeInfo);
01936     walkback_[nNode++]=nodeInfo;
01937     currentNumberCuts += nodeInfo->numberCuts() ;
01938     nodeInfo = nodeInfo->parent() ;
01939     if (nNode==maximumDepth_) {
01940       maximumDepth_ *= 2;
01941       SbbNodeInfo ** temp = new SbbNodeInfo * [maximumDepth_];
01942       for (i=0;i<nNode;i++) 
01943         temp[i] = walkback_[i];
01944       delete [] walkback_;
01945       walkback_ = temp;
01946     }
01947   }
01948 /*
01949   Create an empty basis with sufficient capacity for the constraint system
01950   we'll construct: original system plus cuts. Make sure we have capacity to
01951   record those cuts in addedCuts_.
01952 
01953   The method of adjusting the basis at a FullNodeInfo object (the root, for
01954   example) is to use a copy constructor to duplicate the basis held in the
01955   nodeInfo, then resize it and return the new basis object. Guaranteed,
01956   lastws will point to a different basis when it returns. We pass in a basis
01957   because we need the parameter to return the allocated basis, and it's an
01958   easy way to pass in the size. But we take a hit for memory allocation.
01959 */
01960   currentNumberCuts_=currentNumberCuts;
01961   if (currentNumberCuts >= maximumNumberCuts_) {
01962     maximumNumberCuts_ = currentNumberCuts;
01963     delete [] addedCuts_;
01964     addedCuts_ = new SbbCountRowCut * [maximumNumberCuts_];
01965   }
01966   lastws->setSize(numberColumns,numberRowsAtContinuous_+currentNumberCuts);
01967 /*
01968   This last bit of code traverses the path collected in walkback_ from the
01969   root back to node. At the end of the loop,
01970    * lastws will be an appropriate basis for node;
01971    * variable bounds in the constraint system will be set to be correct for
01972      node; and
01973    * addedCuts_ will be set to a list of cuts that need to be added to the
01974      constraint system at node.
01975   applyToModel does all the heavy lifting.
01976 */
01977   currentNumberCuts=0;
01978   while (nNode) {
01979     --nNode;
01980     walkback_[nNode]->applyToModel(this,lastws,addedCuts_,currentNumberCuts);
01981   }
01982 }

void SbbModel::addObjects int  numberObjects,
SbbObject **  objects
 

Add in object information.

Objects are cloned; the owner can delete the originals.

Definition at line 3355 of file SbbModel.cpp.

References SbbObject::clone(), numberObjects_, object_, and SbbObject::setModel().

Referenced by findCliques().

03356 {
03357   int newNumberObjects= numberObjects+numberObjects_;
03358   SbbObject ** temp  = new SbbObject * [newNumberObjects];
03359   int i;
03360   for (i=0;i<numberObjects_;i++) 
03361     temp[i]=object_[i];
03362   for (;i<newNumberObjects;i++) { 
03363     temp[i]=objects[i-numberObjects_]->clone();
03364     temp[i]->setModel(this);
03365   }
03366   delete [] object_;
03367   object_ = temp;
03368   numberObjects_ = newNumberObjects;
03369 }

void SbbModel::assignSolver OsiSolverInterface *&  solver  ) 
 

Assign a solver to the model (model assumes ownership)

On return, solver will be NULL.

Note:
Parameter settings in the outgoing solver are not inherited by the incoming solver.

Definition at line 1431 of file SbbModel.cpp.

References basis_, emptyWarmStart_, OsiSolverInterface::getNumCols(), integerVariable_, OsiSolverInterface::isInteger(), CoinMessageHandler::logLevel(), OsiSolverInterface::messageHandler(), numberIntegers_, ourSolver_, CoinMessageHandler::setLogLevel(), and solver_.

01433 {
01434   // Keep the current message level for solver (if solver exists)
01435   if (solver_)
01436     solver->messageHandler()->setLogLevel(solver_->messageHandler()->logLevel()) ;
01437 
01438   if (ourSolver_) delete solver_ ;
01439   solver_ = solver;
01440   solver = NULL ;
01441   ourSolver_ = true ;
01442 /*
01443   Basis information is solver-specific.
01444 */
01445   if (basis_)
01446   { delete basis_ ;
01447     basis_ = 0 ; }
01448   if (emptyWarmStart_)
01449   { delete emptyWarmStart_  ;
01450     emptyWarmStart_ = 0 ; }
01451 /*
01452   Initialize integer variable vector.
01453 */
01454   numberIntegers_=0;
01455   int numberColumns = solver_->getNumCols();
01456   int iColumn;
01457   for (iColumn=0;iColumn<numberColumns;iColumn++) {
01458     if( solver_->isInteger(iColumn)) 
01459       numberIntegers_++;
01460   }
01461   if (numberIntegers_) {
01462     integerVariable_ = new int [numberIntegers_];
01463     numberIntegers_=0;
01464     for (iColumn=0;iColumn<numberColumns;iColumn++) {
01465       if( solver_->isInteger(iColumn)) 
01466         integerVariable_[numberIntegers_++]=iColumn;
01467     }
01468   } else {
01469     integerVariable_ = NULL;
01470   }
01471 
01472   return ;
01473 }

const double* SbbModel::bestSolution  )  const [inline]
 

The best solution to the integer programming problem.

The best solution to the integer programming problem found during the search. If no solution is found, the method returns null.

Definition at line 657 of file SbbModel.hpp.

References bestSolution_.

Referenced by SbbLocalSearch::solution().

00658   { return bestSolution_;};

void SbbModel::branchAndBound  ) 
 

Invoke the branch & cut algorithm.

The method assumes that initialSolve() has been called to solve the LP relaxation. It processes the root node, then proceeds to explore the branch & cut search tree. The search ends when the tree is exhausted or one of several execution limits is reached.

Definition at line 507 of file SbbModel.cpp.

References OsiSolverInterface::activateRowCutDebugger(), addCuts(), SbbNodeInfo::addCuts(), addedCuts_, basis_, bestObjective_, bestSolution_, SbbNode::branch(), SbbNode::chooseBranch(), tree::cleanTree(), CoinWarmStartBasis::clone(), OsiSolverInterface::clone(), continuousInfeasibilities_, continuousObjective_, continuousSolver_, SbbNode::createInfo(), currentNumberCuts(), currentNumberCuts_, currentSolution_, dblParam_, SbbNodeInfo::decrement(), SbbCountRowCut::decrement(), OsiSolverInterface::deleteRows(), SbbNode::depth(), findIntegers(), getColLower(), OsiSolverInterface::getColSolution(), getColUpper(), getCutoff(), getIntegerTolerance(), getNumCols(), OsiSolverInterface::getNumRows(), getNumRows(), OsiSolverInterface::getObjSense(), OsiSolverInterface::getObjValue(), OsiSolverInterface::getRowCutDebugger(), OsiSolverInterface::getStrParam(), OsiSolverInterface::getWarmStart(), globalCuts_, handler_, SbbCountRowCut::increment(), SbbNodeInfo::increment(), SbbObject::infeasibility(), SbbNode::initializeInfo(), OsiSolverInterface::initialSolve(), integerVariable_, intParam_, isNodeLimitReached(), OsiSolverInterface::isProvenOptimal(), maximumCutPasses_, maximumCutPassesAtRoot_, maximumDepth_, maximumNumberCuts_, CoinMessageHandler::message(), OsiSolverInterface::messageHandler(), messageHandler(), messages(), messages_, nodeCompare_, SbbNode::nodeInfo(), SbbNode::numberBranches(), SbbNodeInfo::numberBranchesLeft(), numberHeuristics_, numberHeuristicSolutions_, numberIterations_, numberNodes_, numberObjects_, SbbNodeInfo::numberPointingToThis(), numberRowsAtContinuous_, numberSolutions_, SbbNode::numberUnsatisfied(), object_, SbbNode::objectiveValue(), OsiRowCutDebugger::onOptimalPath(), tree::pop(), CoinWarmStartBasis::print(), printFrequency_, tree::push(), SbbObject::resetBounds(), OsiSolverInterface::resolve(), resolve(), SbbAllowableGap, SbbInfeasibilityWeight, SbbMaximumSeconds, SbbMaxNumNode, SbbMaxNumSol, setBestSolution(), tree::setComparison(), setCutoff(), SbbNode::setGuessedObjectiveValue(), OsiSolverInterface::setHintParam(), CoinMessageHandler::setLogLevel(), SbbNode::setObjectiveValue(), SbbHeuristic::solution(), solver_, solveWithCuts(), status_, synchronizeModel(), takeOffCuts(), tree::top(), SbbNode::variable(), and walkback_.

Referenced by originalModel().

00509 {
00510 # ifdef SBB_DEBUG
00511   std::string problemName ;
00512   solver_->getStrParam(OsiProbName,problemName) ;
00513   printf("Problem name - %s\n",problemName.c_str()) ;
00514   solver_->setHintParam(OsiDoReducePrint,false,OsiHintDo,0) ;
00515 # endif
00516 /*
00517   Assume we're done, and see if we're proven wrong.
00518 */
00519   status_ = 0 ;
00520 /*
00521   Scan the variables, noting the integer variables. Create an
00522   SbbSimpleInteger object for each integer variable.
00523 */
00524   findIntegers(false) ;
00525 /*
00526   Ensure that objects on the lists of SbbObjects, heuristics, and cut
00527   generators attached to this model all refer to this model.
00528 */
00529   synchronizeModel() ;
00530 /*
00531   Capture a time stamp before we start.
00532 */
00533   double time1 = CoinCpuTime() ;
00534 /*
00535   Solve the relaxation.
00536 
00537   Apparently there are circumstances where this will be non-trivial --- i.e.,
00538   we've done something since initialSolve that's trashed the solution to the
00539   continuous relaxation.
00540 */
00541   bool feasible = resolve() ;
00542 /*
00543   If the linear relaxation of the root is infeasible, bail out now. Otherwise,
00544   continue with processing the root node.
00545 */
00546   if (!feasible)
00547   { handler_->message(SBB_INFEAS,messages_)<< CoinMessageEol ;
00548     status_ = 1 ;
00549     return ; }
00550 
00551 # ifdef SBB_DEBUG
00552 /*
00553   OsiRowCutDebugger knows an optimal answer for a subset of MIP problems.
00554   Assuming it recognises the problem, when called upon it will check a cut to
00555   see if it cuts off the optimal answer.
00556 */
00557   solver_->activateRowCutDebugger(problemName.c_str()) ;
00558 # endif
00559 
00560 /*
00561   Begin setup to process a feasible root node.
00562 */
00563   bestObjective_ = 1.0e50 ;
00564   numberSolutions_ = 0 ;
00565   numberHeuristicSolutions_ = 0 ;
00566   // Everything is minimization
00567   double cutoff=getCutoff() ;
00568   double direction = solver_->getObjSense() ;
00569   if (cutoff < 1.0e20&&direction<0.0)
00570     messageHandler()->message(SBB_CUTOFF_WARNING1,
00571                                     messages())
00572                                       << cutoff << -cutoff << CoinMessageEol ;
00573   if (cutoff > bestObjective_)
00574     cutoff = bestObjective_ ;
00575   setCutoff(cutoff) ;
00576 /*
00577   We probably already have a current solution, but just in case ...
00578 */
00579   int numberColumns = getNumCols() ;
00580   if (!currentSolution_)
00581     currentSolution_ = new double[numberColumns] ;
00582 /*
00583   Create a copy of the solver, thus capturing the original (root node)
00584   constraint system (aka the continuous system).
00585 */
00586   continuousSolver_ = solver_->clone() ;
00587   numberRowsAtContinuous_ = getNumRows() ;
00588 /*
00589   Check the objective to see if we can deduce a nontrivial increment. If
00590   it's better than the current value for SbbCutoffIncrement, it'll be
00591   installed.
00592 */
00593   analyseObjective(*this) ;
00594 /*
00595   Set up for cut generation. addedCuts_ holds the cuts which are relevant for
00596   the active subproblem. whichGenerator will be used to record the generator
00597   that produced a given cut.
00598 */
00599   int maximumWhich = 1000 ;
00600   int * whichGenerator = new int[maximumWhich] ;
00601   int currentNumberCuts = 0 ;
00602   maximumNumberCuts_ = 0 ;
00603   currentNumberCuts_ = 0 ;
00604   delete [] addedCuts_ ;
00605   addedCuts_ = NULL ;
00606 /*
00607   Set up an empty heap and associated data structures to hold the live set
00608   (problems which require further exploration).
00609 */
00610   tree branchingTree ;
00611   SbbCompareObjective compareObjective ;
00612   SbbCompareDepth compareDepth ;
00613   SbbCompareDefault compareDefault(dblParam_[SbbInfeasibilityWeight]) ;
00614   if (!nodeCompare_)
00615     branchingTree.setComparison(compareDepth) ;
00616   else
00617     branchingTree.setComparison(*nodeCompare_) ;
00618 /*
00619   Used to record the path from a node to the root of the search tree, so that
00620   we can then traverse from the root to the node when restoring a subproblem.
00621 */
00622   maximumDepth_ = 10 ;
00623   delete [] walkback_ ;
00624   walkback_ = new SbbNodeInfo * [maximumDepth_] ;
00625 /*
00626   Used to generate bound edits for SbbPartialNodeInfo.
00627 */
00628   double * lowerBefore = new double [numberColumns] ;
00629   double * upperBefore = new double [numberColumns] ;
00630 /*
00631   
00632   Generate cuts at the root node and reoptimise. solveWithCuts does the heavy
00633   lifting. It will iterate a generate/reoptimise loop (including reduced cost
00634   fixing) until no cuts are generated, the change in objective falls off,  or
00635   the limit on the number of rounds of cut generation is exceeded.
00636 
00637   At the end of all this, any cuts will be recorded in cuts and also
00638   installed in the solver's constraint system. We'll have reoptimised, and
00639   removed any slack cuts (numberOldActiveCuts and numberNewCuts have been
00640   adjusted accordingly).
00641 
00642   TODO: Why don't we make a copy of the solution after solveWithCuts?
00643   TODO: If numberUnsatisfied == 0, don't we have a solution?
00644 */
00645   OsiCuts cuts ;
00646   int anyAction = -1 ;
00647   int numberOldActiveCuts = 0 ;
00648   int numberNewCuts = 0 ;
00649   { int iObject ;
00650     int preferredWay ;
00651     double otherWay ;
00652     int numberUnsatisfied = 0 ;
00653     double integerTolerance = getIntegerTolerance() ;
00654 
00655     memcpy(currentSolution_,solver_->getColSolution(),
00656            numberColumns*sizeof(double)) ;
00657 
00658     for (iObject = 0 ; iObject < numberObjects_ ; iObject++)
00659     { double infeasibility =
00660           object_[iObject]->infeasibility(preferredWay,otherWay) ;
00661       if (infeasibility > integerTolerance) numberUnsatisfied++ ; }
00662     if (numberUnsatisfied)
00663     { feasible = solveWithCuts(cuts,maximumCutPassesAtRoot_,
00664                                NULL,numberOldActiveCuts,numberNewCuts,
00665                                maximumWhich, whichGenerator) ; } }
00666   currentNumberCuts_ = numberNewCuts ;
00667 /*
00668   We've taken the continuous relaxation as far as we can. Time to branch.
00669   The first order of business is to actually create a node. chooseBranch
00670   currently uses strong branching to evaluate branch object candidates,
00671   unless forced back to simple branching. If chooseBranch concludes that a
00672   branching candidate is monotone (anyAction == -1) or infeasible (anyAction
00673   == -2) when forced to integer values, it returns here immediately.
00674 
00675   Monotone variables trigger a call to resolve(). If the problem remains
00676   feasible, try again to choose a branching variable. At the end of the loop,
00677   resolved == true indicates that some variables were fixed.
00678 
00679   Loss of feasibility will result in the deletion of newNode.
00680 */
00681 
00682   bool resolved = false ;
00683   SbbNode *newNode = NULL ;
00684 
00685   if (feasible)
00686   { newNode = new SbbNode ;
00687     newNode->setObjectiveValue(direction*solver_->getObjValue()) ;
00688     anyAction = -1 ;
00689     while (anyAction == -1)
00690     { anyAction = newNode->chooseBranch(this,NULL) ;
00691       if (anyAction == -1)
00692       { feasible = resolve() ;
00693         resolved = true ;
00694 #       ifdef SBB_DEBUG
00695         printf("Resolve (root) as something fixed, Obj value %g %d rows\n",
00696                   solver_->getObjValue(),
00697                   solver_->getNumRows()) ;
00698 #       endif
00699         if (!feasible) anyAction = -2 ; }
00700       if (anyAction == -2)
00701       { delete newNode ;
00702         newNode = NULL ;
00703         feasible = false ; } } }
00704 /*
00705   At this point, the root subproblem is infeasible or fathomed by bound
00706   (newNode == NULL), or we're live with an objective value that satisfies the
00707   current objective cutoff.
00708 */
00709   assert (!newNode || newNode->objectiveValue() < getCutoff()) ;
00710 /*
00711   The common case is that the lp relaxation is feasible but doesn't satisfy
00712   integrality (i.e., newNode->variable() >= 0, indicating we've been able to
00713   select a branching variable). Remove any cuts that have gone slack due to
00714   forcing monotone variables. Then tack on an SbbFullNodeInfo object and full
00715   basis (via createInfo()) and stash the new cuts in the nodeInfo (via
00716   addCuts()). If, by some miracle, we have an integral solution at the root
00717   (newNode->variable() < 0), takeOffCuts() will ensure that the solver holds
00718   a valid solution for use by setBestSolution().
00719 */
00720   CoinWarmStartBasis *lastws = 0 ;
00721   if (feasible && newNode->variable() >= 0)
00722   { if (resolved)
00723     { bool needValidSolution = (newNode->variable() < 0) ;
00724       takeOffCuts(cuts,whichGenerator,numberOldActiveCuts,numberNewCuts,
00725                   needValidSolution) ;
00726 #     ifdef CHECK_CUT_COUNTS
00727       { printf("Number of rows after chooseBranch fix (root)"
00728                "(active only) %d\n",
00729                 numberRowsAtContinuous_+numberNewCuts+numberOldActiveCuts) ;
00730         const CoinWarmStartBasis* debugws =
00731           dynamic_cast <const CoinWarmStartBasis*>(solver_->getWarmStart()) ;
00732         debugws->print() ;
00733         delete debugws ; }
00734 #     endif
00735     }
00736     newNode->createInfo(this,NULL,NULL,NULL,NULL,0,0) ;
00737     newNode->nodeInfo()->addCuts(cuts,
00738                                  newNode->numberBranches(),whichGenerator) ;
00739 /*
00740   Courtesy of createInfo, there's now a full basis stashed in
00741   newNode->nodeInfo_->basis_. We're about to make two more copies, lastws and
00742   model.basis_.
00743 
00744   (jf) With some thought I should be able to get rid of lastws and use
00745   basis_.
00746   (lh) I agree, but haven't pursued it to the end.
00747 */
00748     if (basis_) delete basis_ ;
00749     basis_ = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()) ;
00750     if (lastws) delete lastws ;
00751     lastws = dynamic_cast<CoinWarmStartBasis*>(basis_->clone()) ; }
00752 /*
00753   Continuous data to be used later
00754 */
00755   continuousObjective_ = 0.0 ;
00756   continuousInfeasibilities_ = 0 ;
00757   if (newNode)
00758   { continuousObjective_ = newNode->objectiveValue() ;
00759     continuousInfeasibilities_ = newNode->numberUnsatisfied() ; }
00760 /*
00761   Bound may have changed so reset in objects
00762 */
00763   { int i ;
00764     for (i = 0;i < numberObjects_;i++)
00765       object_[i]->resetBounds() ; }
00766 /*
00767   For printing totals
00768 */
00769   numberIterations_ = 0 ;
00770   numberNodes_ = 0 ;
00771   bool stoppedOnGap = false ;
00772 /*
00773   Feasible? Then we should have either a live node prepped for future
00774   expansion (indicated by variable() >= 0), or (miracle of miracles) an
00775   integral solution at the root node.
00776 
00777   initializeInfo sets the reference counts in the nodeInfo object.  Since
00778   this node is still live, push it onto the heap that holds the live set.
00779 */
00780   if (newNode) {
00781     if (newNode->variable() >= 0) {
00782       newNode->initializeInfo() ;
00783       branchingTree.push(newNode) ;
00784 #     ifdef CHECK_NODE
00785       printf("Node %x on tree\n",newNode) ;
00786 #     endif
00787     } else {
00788       // continuous is integer
00789       double objectiveValue = newNode->objectiveValue();
00790       setBestSolution(SBB_SOLUTION,objectiveValue,
00791                       solver_->getColSolution()) ;
00792       delete newNode ;
00793       newNode = NULL ;
00794     }
00795   }
00796 
00797   if (printFrequency_ <= 0) {
00798     printFrequency_ = 1000 ;
00799     if (getNumCols() > 2000)
00800       printFrequency_ = 100 ;
00801   }
00802 /*
00803   At last, the actual branch-and-cut search loop, which will iterate until
00804   the live set is empty or we hit some limit (integrality gap, time, node
00805   count, etc.). The overall flow is to rebuild a subproblem, reoptimise using
00806   solveWithCuts(), choose a branching pattern with chooseBranch(), and finally
00807   add the node to the live set.
00808 
00809   The first action is to winnow the live set to remove nodes which are worse
00810   than the current objective cutoff.
00811 */
00812   double bestValue = 0.0 ;
00813   while (!branchingTree.empty())
00814   { if (cutoff > getCutoff()) {
00815       // Do from deepest
00816       branchingTree.cleanTree(this, getCutoff()) ;
00817       if (!nodeCompare_) {
00818         if (!compareDefault.getWeight()) {
00819           // set to get close to this
00820           double costPerInteger = 
00821             (bestObjective_-continuousObjective_)/
00822             ((double) continuousInfeasibilities_) ;
00823           compareDefault.setWeight(0.98*costPerInteger) ;
00824           /*printf("Setting weight per infeasibility to %g\n",
00825             0.98*costPerInteger);*/
00826         }
00827         branchingTree.setComparison(compareDefault) ;
00828         //branchingTree.setComparison(compareObjective) ;
00829       } else {
00830         nodeCompare_->newSolution(this) ;
00831         nodeCompare_->newSolution(this,continuousObjective_,
00832                                   continuousInfeasibilities_) ;
00833         branchingTree.setComparison(*nodeCompare_) ;
00834       }
00835       if (branchingTree.empty())
00836         break; // finished
00837     }
00838     cutoff = getCutoff() ;
00839 /*
00840   Periodic activities: Opportunities to
00841     + tweak the nodeCompare criteria,
00842     + check if we've closed the integrality gap enough to quit, 
00843     + print a summary line to let the user know we're working
00844 */
00845     if ((numberNodes_%1000) == 0&&nodeCompare_) 
00846       nodeCompare_->every1000Nodes(this, numberNodes_) ;
00847     if ((numberNodes_%printFrequency_) == 0) {
00848       int j ;
00849       int nNodes = branchingTree.size() ;
00850       bestValue = 1.0e100 ;
00851       for (j = 0;j < nNodes;j++) {
00852         SbbNode * node = branchingTree[j] ;
00853         if (node->objectiveValue() < bestValue)
00854           bestValue = node->objectiveValue() ;
00855       }
00856       messageHandler()->message(SBB_STATUS,messages())
00857         << numberNodes_<< nNodes<< bestObjective_<< bestValue
00858         << CoinMessageEol ;
00859       // See if can stop on gap
00860       if (bestObjective_-bestValue < dblParam_[SbbAllowableGap]) {
00861         stoppedOnGap = true ;
00862       }
00863     }
00864 
00865 #   ifdef CHECK_NODE_FULL
00866     verifyTreeNodes(branchingTree,*this) ;
00867 #   endif
00868 #   ifdef CHECK_CUT_COUNTS
00869     verifyCutCounts(branchingTree,*this) ;
00870 #   endif
00871 
00872 /*
00873   Now we come to the meat of the loop. To create the active subproblem, we'll
00874   pop the most promising node in the live set, rebuild the subproblem it
00875   represents, and then execute the current arm of the branch to create the
00876   active subproblem.
00877 */
00878     SbbNode *node = branchingTree.top() ;
00879     branchingTree.pop() ;
00880 
00881 #   ifdef CHECK_NODE
00882 /*
00883   WARNING: The use of integerVariable_[*] here will break as soon as the
00884            branching object is something other than an integer variable.
00885            This needs some thought.
00886 */
00887     printf("Node %x popped from tree - %d left, %d count\n",node,
00888            node->nodeInfo()->numberBranchesLeft(),
00889            node->nodeInfo()->numberPointingToThis()) ;
00890     printf("\tdepth = %d, z =  %g, unsat = %d, var = %d.\n",
00891            node->depth(),node->objectiveValue(),
00892            node->numberUnsatisfied(),
00893            integerVariable_[node->variable()]) ;
00894 #   endif
00895 
00896 /*
00897   Rebuild the subproblem for this node:  Call addCuts() to adjust the model
00898   to recreate the subproblem for this node (set proper variable bounds, add
00899   cuts, create a basis).  This may result in the problem being fathomed by
00900   bound or infeasibility. Returns 1 if node is fathomed.
00901   Execute the current arm of the branch: If the problem survives, save the
00902   resulting variable bounds and call branch() to modify variable bounds
00903   according to the current arm of the branching object. If we're processing
00904   the final arm of the branching object, flag the node for removal from the
00905   live set.
00906 */
00907     SbbNodeInfo * nodeInfo = node->nodeInfo() ;
00908     newNode = NULL ;
00909     if (!addCuts(node,lastws))
00910     { int i ;
00911       const double * lower = getColLower() ;
00912       const double * upper = getColUpper() ;
00913       for (i = 0 ; i < numberColumns ; i++)
00914       { lowerBefore[i]= lower[i] ;
00915         upperBefore[i]= upper[i] ; }
00916       bool deleteNode ;
00917       if (node->branch())
00918       { branchingTree.push(node) ;
00919         deleteNode = false ;
00920 #       ifdef CHECK_NODE
00921         printf("Node %x pushed back on tree - %d left, %d count\n",node,
00922                nodeInfo->numberBranchesLeft(),
00923                nodeInfo->numberPointingToThis()) ;
00924 #       endif
00925       }
00926       else
00927       { deleteNode = true ; }
00928 
00929 #     ifdef SBB_DEBUG
00930 /*
00931   This doesn't work as intended --- getRowCutDebugger will return null
00932   unless the current feasible solution region includes the optimal solution
00933   that RowCutDebugger knows. There's no way to tell inactive from off the
00934   optimal path.
00935 */
00936       const OsiRowCutDebugger *debugger = solver_->getRowCutDebugger() ;
00937       if (debugger)
00938       { if(debugger->onOptimalPath(*solver_))
00939           printf("On optimal path\n") ;
00940         else
00941           printf("Not on optimal path\n") ; }
00942 #     endif
00943 /*
00944   Reoptimize, possibly generating cuts and/or using heuristics to find
00945   solutions.  Cut reference counts are unaffected unless we lose feasibility,
00946   in which case solveWithCuts() will make the adjustment.
00947 */
00948       cuts = OsiCuts() ;
00949       currentNumberCuts = solver_->getNumRows()-numberRowsAtContinuous_ ;
00950       feasible = solveWithCuts(cuts,maximumCutPasses_,node,
00951                                numberOldActiveCuts,numberNewCuts,
00952                                maximumWhich,whichGenerator) ;
00953 /*
00954   Check for abort on limits: node count, solution count, time, integrality gap.
00955 */
00956       double totalTime = CoinCpuTime()-time1 ;
00957       if (numberNodes_ < intParam_[SbbMaxNumNode] &&
00958           numberSolutions_ < intParam_[SbbMaxNumSol] &&
00959           totalTime < dblParam_[SbbMaximumSeconds] &&
00960           !stoppedOnGap) 
00961       {
00962 /*
00963   Are we still feasible? If so, create a node and do the work to attach a
00964   branching object, reoptimising as needed if chooseBranch() identifies
00965   monotone objects.
00966 
00967   Finally, attach a partial nodeInfo object and store away any cuts that we
00968   created back in solveWithCuts. addCuts() will also deal with the cut
00969   reference counts.
00970 
00971   TODO: (lh) I'm confused. We create a nodeInfo without checking whether we
00972         have a solution or not. Then we use numberUnsatisfied() to decide
00973         whether to stash the cuts and bump reference counts. Other places we
00974         use variable() (i.e., presence of a branching variable). Equivalent?
00975 */
00976         if (feasible)
00977         { newNode = new SbbNode ;
00978           newNode->setObjectiveValue(direction*solver_->getObjValue()) ;
00979           anyAction =-1 ;
00980           resolved = false ;
00981           while (anyAction == -1)
00982           { anyAction = newNode->chooseBranch(this,node) ;
00983             if (anyAction == -1)
00984             { feasible = resolve() ;
00985               resolved = true ;
00986               if (feasible)
00987               { newNode->setObjectiveValue(direction*
00988                                            solver_->getObjValue()) ; }
00989               else
00990               { anyAction = -2 ; } } }
00991           if (anyAction >= 0)
00992           { if (resolved)
00993             { bool needValidSolution = (newNode->variable() < 0) ;
00994               takeOffCuts(cuts,whichGenerator,numberOldActiveCuts,
00995                           numberNewCuts,needValidSolution) ; 
00996 #             ifdef CHECK_CUT_COUNTS
00997               { printf("Number of rows after chooseBranch fix (node)"
00998                        "(active only) %d\n",
00999                         numberRowsAtContinuous_+numberNewCuts+
01000                         numberOldActiveCuts) ;
01001                 const CoinWarmStartBasis* debugws =
01002                   dynamic_cast<const CoinWarmStartBasis*>
01003                     (solver_->getWarmStart()) ;
01004                 debugws->print() ;
01005                 delete debugws ; }
01006 #             endif
01007             }
01008             newNode->createInfo(this,node,lastws,lowerBefore,upperBefore,
01009                                 numberOldActiveCuts,numberNewCuts) ;
01010             if (newNode->numberUnsatisfied())
01011               newNode->nodeInfo()->addCuts(cuts,newNode->numberBranches(),
01012                                            whichGenerator) ; } }
01013         else
01014         { anyAction = -2 ; }
01015         // May have slipped through i.e. anyAction == 0 and objective above cutoff
01016         if ( anyAction >=0 ) {
01017           assert (newNode);
01018           if (newNode->objectiveValue() > getCutoff()) 
01019             anyAction = -2; // say bad after all
01020         }
01021 /*
01022   If we end up infeasible, we can delete the new node immediately. Since this
01023   node won't be needing the cuts we collected, decrement the reference counts.
01024   If we are feasible, then we'll be placing this node into the live set, so
01025   increment the reference count in the current (parent) nodeInfo.
01026 */
01027         if (anyAction == -2)
01028         { delete newNode ;
01029           newNode = NULL ;
01030           for (i = 0 ; i < currentNumberCuts_ ; i++)
01031           { if (addedCuts_[i])
01032             { if (!addedCuts_[i]->decrement(1))
01033                 delete addedCuts_[i] ; } } }
01034         else
01035         { nodeInfo->increment() ; }
01036 /*
01037   At this point, there are three possibilities:
01038     * We have a live node (variable() >= 0) which will require further
01039       branching to resolve. Before we push it onto the search tree, try for
01040       a heuristic solution.
01041     * We have a solution, in which case newNode is non-null but we have no
01042       branching variable. Decrement the cut counts and save the solution.
01043     * The node was found to be infeasible, in which case it's already been
01044       deleted, and newNode is null.
01045 
01046   TODO: (lh) Now I'm more confused. I thought that the call to addCuts() above
01047         took care of incrementing the reference counts for cuts at newNode.
01048         Clearly I need to look more carefully.
01049 */
01050         assert (!newNode || newNode->objectiveValue() <= getCutoff()) ;
01051         if (newNode)
01052         { if (newNode->variable() >= 0)
01053           { handler_->message(SBB_BRANCH,messages_)
01054                << numberNodes_<< newNode->objectiveValue()
01055                << newNode->numberUnsatisfied()<< newNode->depth()
01056                << integerVariable_[newNode->variable()]
01057                << newNode->variable()
01058                << CoinMessageEol ;
01059             // Increment cut counts (taking off current)
01060             int numberLeft = newNode->numberBranches() ;
01061             for (i = 0;i < currentNumberCuts_;i++)
01062             { if (addedCuts_[i])
01063               {
01064 #               ifdef CHECK_CUT_COUNTS
01065                 printf("Count on cut %x increased by %d\n",addedCuts_[i],
01066                         numberLeft-1) ;
01067 #               endif
01068                 addedCuts_[i]->increment(numberLeft-1) ; } }
01069 
01070             double estValue = 1.0e100 ;
01071             int found = -1 ;
01072             solver_->resolve() ;        // double check current optimal
01073             double * newSolution = new double [numberColumns] ;
01074             double heurValue = getCutoff() ;
01075             int iHeur ;
01076             for (iHeur = 0 ; iHeur < numberHeuristics_ ; iHeur++)
01077             { double saveValue = heurValue ;
01078               int ifSol = heuristic_[iHeur]->solution(heurValue,newSolution) ;
01079               if (ifSol > 0)    // new solution found
01080               { found = iHeur ; }
01081               else
01082               if (ifSol < 0)    // just returning an estimate
01083               { estValue = min(heurValue,estValue) ;
01084                 heurValue = saveValue ; } }
01085             if (found >= 0)
01086             { setBestSolution(SBB_ROUNDING,heurValue,newSolution) ; }
01087             delete [] newSolution ;
01088             newNode->setGuessedObjectiveValue(estValue) ;
01089             branchingTree.push(newNode) ;
01090 #           ifdef CHECK_NODE
01091             printf("Node %x pushed on tree c\n",newNode) ;
01092 #           endif
01093           }
01094           else
01095           { for (i = 0 ; i < currentNumberCuts_ ; i++)
01096             { if (addedCuts_[i])
01097               { if (!addedCuts_[i]->decrement(1))
01098                   delete addedCuts_[i] ; } }
01099           double objectiveValue = newNode->objectiveValue();
01100             setBestSolution(SBB_SOLUTION,objectiveValue,
01101                             solver_->getColSolution()) ;
01102             assert(nodeInfo->numberPointingToThis() <= 2) ;
01103             // avoid accidental pruning, if newNode was final branch arm
01104             nodeInfo->increment();
01105             delete newNode ;
01106             nodeInfo->decrement() ; } }
01107 /*
01108   This node has been completely expanded and can be removed from the live
01109   set.
01110 */
01111         if (deleteNode) 
01112           delete node ; }
01113 /*
01114   End of the non-abort actions. The next block of code is executed if we've
01115   aborted because we hit one of the limits. Clean up by deleting the live set
01116   and break out of the node processing loop.
01117 */
01118       else
01119       { branchingTree.cleanTree(this,-DBL_MAX) ;
01120         if (stoppedOnGap)
01121         { messageHandler()->message(SBB_GAP,messages())
01122             << bestObjective_-bestValue
01123             << dblParam_[SbbAllowableGap]
01124             << CoinMessageEol ;
01125           status_ = 0 ; }
01126         else
01127         if (isNodeLimitReached())
01128         { handler_->message(SBB_MAXNODES,messages_) << CoinMessageEol ;
01129           status_ = 1 ; }
01130         else
01131         if (totalTime >= dblParam_[SbbMaximumSeconds])
01132         { handler_->message(SBB_MAXTIME,messages_) << CoinMessageEol ; }
01133         else
01134         { handler_->message(SBB_MAXSOLS,messages_) << CoinMessageEol ;
01135           status_ = 1 ; }
01136         break ; }
01137 /*
01138   Delete cuts to get back to the original system.
01139 
01140   I'm thinking this is redundant --- the call to addCuts that conditions entry
01141   to this code block also performs this action.
01142 */
01143       int numberToDelete = getNumRows()-numberRowsAtContinuous_ ;
01144       if (numberToDelete)
01145       { int * delRows = new int[numberToDelete] ;
01146         int i ;
01147         for (i = 0 ; i < numberToDelete ; i++)
01148         { delRows[i] = i+numberRowsAtContinuous_ ; }
01149         solver_->deleteRows(numberToDelete,delRows) ;
01150         delete [] delRows ; } }
01151 /*
01152   This node fathomed when addCuts atttempted to revive it. Toss it.
01153 */
01154     else
01155     { delete node ; } }
01156 /*
01157   That's it, we've exhausted the search tree, or broken out of the loop because
01158   we hit some limit on evaluation.
01159 */
01160   if (!status_)
01161     handler_->message(SBB_END_GOOD,messages_)
01162       << bestObjective_ << numberIterations_ << numberNodes_
01163       << CoinMessageEol ;
01164   else
01165     handler_->message(SBB_END,messages_)
01166       << numberIterations_ << numberNodes_ << CoinMessageEol ;
01167 /*
01168   If we think we have a solution, restore and confirm it with a call to
01169   setBestSolution().  We need to reset the cutoff value so as not to fathom
01170   the solution on bounds.  Note that calling setBestSolution( ..., true)
01171   leaves the continuousSolver_ bounds vectors fixed at the solution value.
01172 
01173   Running resolve() here is a failsafe --- setBestSolution has already
01174   reoptimised using the continuousSolver_. If for some reason we fail to
01175   prove optimality, run the problem again after instructing the solver to
01176   tell us more.
01177 
01178   If all looks good, replace solver_ with continuousSolver_, so that the
01179   outside world will be able to obtain information about the solution using
01180   public methods.
01181 */
01182   if (bestSolution_)
01183     { setCutoff(1.0e50) ; // As best solution should be worse than cutoff
01184     setBestSolution(SBB_SOLUTION,bestObjective_,bestSolution_,true) ;
01185     continuousSolver_->resolve() ;
01186     if (!continuousSolver_->isProvenOptimal())
01187     { continuousSolver_->messageHandler()->setLogLevel(2) ;
01188       continuousSolver_->initialSolve() ; }
01189     delete solver_ ;
01190     solver_ = continuousSolver_ ;
01191     continuousSolver_ = NULL ; }
01192 /*
01193   Clean up dangling objects. continuousSolver_ may already be toast.
01194 */
01195   delete lastws ;
01196   delete [] whichGenerator ;
01197   delete [] lowerBefore ;
01198   delete [] upperBefore ;
01199   delete [] walkback_ ;
01200   walkback_ = NULL ;
01201   delete [] addedCuts_ ;
01202   addedCuts_ = NULL ;
01203   if (continuousSolver_)
01204   { delete continuousSolver_ ;
01205     continuousSolver_ = NULL ; }
01206 /*
01207   Destroy global cuts by replacing with an empty OsiCuts object.
01208 */
01209   globalCuts_= OsiCuts() ;
01210   
01211   return ; }

double SbbModel::checkSolution double  cutoff,
const double *  solution,
bool  fixVariables
 

Call this to really test if a valid solution can be feasible Solution is number columns in size. If fixVariables true then bounds of continuous solver updated. Returns objective value (worse than cutoff if not feasible)

Definition at line 3418 of file SbbModel.cpp.

References continuousSolver_, currentSolution_, SbbObject::feasibleRegion(), getColLower(), OsiSolverInterface::getColSolution(), getColUpper(), OsiSolverInterface::getDblParam(), OsiSolverInterface::getHintParam(), getIntegerTolerance(), OsiSolverInterface::getMatrixByCol(), OsiSolverInterface::getNumCols(), OsiSolverInterface::getNumRows(), OsiSolverInterface::getObjSense(), OsiSolverInterface::getObjValue(), OsiSolverInterface::getRowLower(), OsiSolverInterface::getRowUpper(), handler_, OsiSolverInterface::initialSolve(), OsiSolverInterface::isInteger(), OsiSolverInterface::isProvenOptimal(), CoinMessageHandler::message(), messages_, numberObjects_, object_, OsiSolverInterface::setColLower(), OsiSolverInterface::setColSolution(), OsiSolverInterface::setColUpper(), OsiSolverInterface::setHintParam(), OsiSolverInterface::setWarmStart(), and solver_.

Referenced by setBestSolution().

03421 { int numberColumns = solver_->getNumCols();
03422 
03423   /*
03424     Grab the continuous solver (the pristine copy of the problem, made before
03425     starting to work on the root node). Save the bounds on the variables.
03426     Install the solution passed as a parameter, and copy it to the model's
03427     currentSolution_.
03428     
03429     TODO: This is a belt-and-suspenders approach. Once the code has settled
03430           a bit, we can cast a critical eye here.
03431   */
03432   OsiSolverInterface * saveSolver = solver_;
03433   solver_ = continuousSolver_;
03434   // move solution to continuous copy
03435   solver_->setColSolution(solution);
03436   // Put current solution in safe place
03437   memcpy(currentSolution_,solver_->getColSolution(),
03438          numberColumns*sizeof(double));
03439   //solver_->messageHandler()->setLogLevel(4);
03440 
03441   // save original bounds
03442   double * saveUpper = new double[numberColumns];
03443   double * saveLower = new double[numberColumns];
03444   memcpy(saveUpper,getColUpper(),numberColumns*sizeof(double));
03445   memcpy(saveLower,getColLower(),numberColumns*sizeof(double));
03446 
03447   /*
03448     Run through the objects and use feasibleRegion() to set variable bounds
03449     so as to fix the variables specified in the objects at their value in this
03450     solution.
03451   */
03452   int i;
03453   for (i=0;i<numberObjects_;i++)
03454     object_[i]->feasibleRegion();
03455   /*
03456     (lh) Original comment was ``solve with all slack basis so fixed will be
03457     clean''.  A typical initialSolve will probably do this, but I'm asking
03458     ``Why the call to setWarmStart?''
03459 
03460     (jf) The answer is that most "initialSolves" use current basis.
03461 
03462     (lh) Hmmm ... says to me that we should be more explicit in the OSI
03463     specifications. initialSolve should force the solver to do whatever it
03464     would do when handed a fresh problem? setWarmStart should manufacture an
03465     all-slack basis when handed an empty basis (or called without
03466     parameter)?
03467 
03468     (JF) But it is better to get the right answer.  initialSolve should
03469     not force anything as solver should be saying - how can I solve this
03470     problem when I am a long way from optimal.  I am putting back all
03471     slack basis as some problems are failing.
03472   */
03473   CoinWarmStartBasis slack;
03474   solver_->setWarmStart(&slack);
03475   // Give a hint not to do scaling
03476   //bool saveTakeHint;
03477   //OsiHintStrength saveStrength;
03478   //bool gotHint = (solver_->getHintParam(OsiDoScale,saveTakeHint,saveStrength));
03479   //assert (gotHint);
03480   //solver_->setHintParam(OsiDoScale,false,OsiHintTry);
03481   solver_->initialSolve();
03482   //solver_->setHintParam(OsiDoScale,saveTakeHint,saveStrength);
03483   if (!solver_->isProvenOptimal())
03484     { std::cout << "checkSolution infeas! Retrying wihout scaling."
03485               << std::endl ;
03486     bool saveTakeHint;
03487     OsiHintStrength saveStrength;
03488     bool savePrintHint;
03489     bool gotHint = (solver_->getHintParam(OsiDoReducePrint,savePrintHint,saveStrength));
03490     gotHint = (solver_->getHintParam(OsiDoScale,saveTakeHint,saveStrength));
03491     solver_->setHintParam(OsiDoScale,false,OsiHintTry);
03492     solver_->setHintParam(OsiDoReducePrint,false,OsiHintTry) ;
03493     solver_->initialSolve();
03494     solver_->setHintParam(OsiDoScale,saveTakeHint,saveStrength);
03495     solver_->setHintParam(OsiDoReducePrint,savePrintHint,OsiHintTry) ;
03496     }
03497   assert(solver_->isProvenOptimal());
03498   double objectiveValue = solver_->getObjValue()*solver_->getObjSense();
03499 
03500   /*
03501     Check that the solution still beats the objective cutoff.
03502 
03503     If it passes, make a copy of the primal variable values and do some
03504     cleanup and checks:
03505     + Values of all variables are are within original bounds and values of
03506       all integer variables are within tolerance of integral.
03507     + There are no constraint violations.
03508     There really should be no need for the check against original bounds.
03509     Perhaps an opportunity for a sanity check?
03510   */
03511   if (solver_->isProvenOptimal() && objectiveValue <= cutoff)
03512   { solution = solver_->getColSolution() ;
03513     memcpy(currentSolution_,solution,numberColumns*sizeof(double)) ;
03514 
03515     const double * rowLower = solver_->getRowLower() ;
03516     const double * rowUpper = solver_->getRowUpper() ;
03517     int numberRows = solver_->getNumRows() ;
03518     double *rowActivity = new double[numberRows] ;
03519     memset(rowActivity,0,numberRows*sizeof(double)) ;
03520 
03521     double integerTolerance = getIntegerTolerance() ;
03522 
03523     int iColumn;
03524     for (iColumn = 0 ; iColumn < numberColumns ; iColumn++)
03525     { double value = currentSolution_[iColumn] ;
03526       value = max(value, saveLower[iColumn]) ;
03527       value = min(value, saveUpper[iColumn]) ;
03528       if (solver_->isInteger(iColumn)) 
03529         assert(fabs(value-currentSolution_[iColumn]) <= integerTolerance) ;
03530       currentSolution_[iColumn] = value ; }
03531     
03532     solver_->getMatrixByCol()->times(currentSolution_,rowActivity) ;
03533     double primalTolerance ;
03534     solver_->getDblParam(OsiPrimalTolerance,primalTolerance) ;
03535     double largestInfeasibility =0.0;
03536     for (i=0 ; i < numberRows ; i++) {
03537       largestInfeasibility = max(largestInfeasibility,
03538                                  rowLower[i]-rowActivity[i]);
03539       largestInfeasibility = max(largestInfeasibility,
03540                                  rowActivity[i]-rowUpper[i]);
03541     }
03542     if (largestInfeasibility>100.0*primalTolerance)
03543       handler_->message(SBB_NOTFEAS3, messages_)
03544         << largestInfeasibility << CoinMessageEol ;
03545 
03546     delete [] rowActivity ; }
03547   else
03548   { objectiveValue=1.0e50 ; }
03549   /*
03550     Regardless of what we think of the solution, we may need to restore the
03551     original bounds of the continuous solver. Unfortunately, const'ness
03552     prevents us from simply reversing the memcpy used to make these snapshots.
03553   */
03554   if (!fixVariables)
03555   { for (int iColumn = 0 ; iColumn < numberColumns ; iColumn++)
03556     { solver_->setColLower(iColumn,saveLower[iColumn]) ;
03557       solver_->setColUpper(iColumn,saveUpper[iColumn]) ; } }
03558   delete [] saveLower;
03559   delete [] saveUpper;
03560     
03561   /*
03562     Restore the usual solver.
03563   */
03564   solver_=saveSolver;
03565   return objectiveValue;
03566 }

double* SbbModel::currentSolution  )  const [inline]
 

Solution to the most recent lp relaxation.

The solver's solution to the most recent lp relaxation.

Definition at line 624 of file SbbModel.hpp.

References currentSolution_.

Referenced by SbbSimpleInteger::createBranch(), SbbClique::createBranch(), SbbSimpleInteger::feasibleRegion(), SbbClique::feasibleRegion(), SbbSimpleInteger::infeasibility(), SbbClique::infeasibility(), SbbSimpleInteger::notPreferredNewFeasible(), and SbbSimpleInteger::preferredNewFeasible().

00625   { return currentSolution_;};

bool SbbModel::feasibleSolution int &  numberIntegerInfeasibilities,
int &  numberObjectInfeasibilities
const
 

Test the current solution for feasiblility.

Scan all objects for indications of infeasibility. This is broken down into simple integer infeasibility (numberIntegerInfeasibilities) and all other reports of infeasibility (numberObjectInfeasibilities).

Definition at line 3671 of file SbbModel.cpp.

References currentSolution_, OsiSolverInterface::getColSolution(), getIntegerTolerance(), OsiSolverInterface::getNumCols(), SbbObject::infeasibility(), numberIntegers_, numberObjects_, object(), object_, and solver_.

Referenced by SbbNode::chooseBranch(), and originalModel().

03673 {
03674   int numberUnsatisfied=0;
03675   double sumUnsatisfied=0.0;
03676   int preferredWay;
03677   double otherWay;
03678   double integerTolerance = getIntegerTolerance();
03679   int j;
03680   // Put current solution in safe place
03681   memcpy(currentSolution_,solver_->getColSolution(),
03682          solver_->getNumCols()*sizeof(double));
03683   for (j=0;j<numberIntegers_;j++) {
03684     const SbbObject * object = object_[j];
03685     double infeasibility = object->infeasibility(preferredWay,otherWay);
03686     if (infeasibility>integerTolerance) {
03687       numberUnsatisfied++;
03688       sumUnsatisfied += infeasibility;
03689     }
03690   }
03691   numberIntegerInfeasibilities = numberUnsatisfied;
03692   for (;j<numberObjects_;j++) {
03693     const SbbObject * object = object_[j];
03694     double infeasibility = object->infeasibility(preferredWay,otherWay);
03695     if (infeasibility>integerTolerance) {
03696       numberUnsatisfied++;
03697       sumUnsatisfied += infeasibility;
03698     }
03699   }
03700   numberObjectInfeasibilities = numberUnsatisfied-numberIntegerInfeasibilities;
03701   return (!numberUnsatisfied);
03702 }

SbbModel * SbbModel::findCliques bool  makeEquality,
int  atLeastThisMany,
int  lessThanThis,
int  defaultValue = 1000
 

Identify cliques and construct corresponding objects.

Find cliques with size in the range [atLeastThisMany, lessThanThis] and construct corresponding SbbClique objects. If makeEquality is true then a new model may be returned if modifications had to be made, otherwise this is returned. If the problem is infeasible numberObjects_ is set to -1. A client must use deleteObjects() before a second call to findCliques(). If priorities exist, clique priority is set to the default.

Definition at line 2937 of file SbbModel.cpp.

References OsiSolverInterface::addCol(), addObjects(), findIntegers(), getColLower(), getColUpper(), OsiSolverInterface::getMatrixByCol(), OsiSolverInterface::getMatrixByRow(), OsiSolverInterface::getNumCols(), OsiSolverInterface::getNumRows(), getRowLower(), getRowUpper(), integerVariable_, numberIntegers_, numberObjects_, object(), object_, originalColumns_, priority_, SbbModel(), OsiSolverInterface::setColLower(), OsiSolverInterface::setColUpper(), OsiSolverInterface::setInteger(), OsiSolverInterface::setRowLower(), OsiSolverInterface::setRowUpper(), solver(), solver_, and synchronizeModel().

02939 {
02940   // No objects are allowed to exist
02941   assert(numberObjects_==numberIntegers_);
02942   CoinPackedMatrix matrixByRow(*solver_->getMatrixByRow());
02943   int numberRows = solver_->getNumRows();
02944   int numberColumns = solver_->getNumCols();
02945 
02946   // We may want to add columns
02947   int numberSlacks=0;
02948   int * rows = new int[numberRows];
02949   double * element =new double[numberRows];
02950 
02951   int iRow;
02952 
02953   findIntegers(true);
02954   numberObjects_=numberIntegers_;
02955 
02956   int numberCliques=0;
02957   SbbObject ** object = new SbbObject * [numberRows];
02958   int * which = new int[numberIntegers_];
02959   char * type = new char[numberIntegers_];
02960   int * lookup = new int[numberColumns];
02961   int i;
02962   for (i=0;i<numberColumns;i++) 
02963     lookup[i]=-1;
02964   for (i=0;i<numberIntegers_;i++) 
02965     lookup[integerVariable_[i]]=i;
02966 
02967   // Statistics
02968   int totalP1=0,totalM1=0;
02969   int numberBig=0,totalBig=0;
02970   int numberFixed=0;
02971 
02972   // Row copy
02973   const double * elementByRow = matrixByRow.getElements();
02974   const int * column = matrixByRow.getIndices();
02975   const int * rowStart = matrixByRow.getVectorStarts();
02976   const int * rowLength = matrixByRow.getVectorLengths();
02977 
02978   // Column lengths for slacks
02979   const int * columnLength = solver_->getMatrixByCol()->getVectorLengths();
02980 
02981   const double * lower = getColLower();
02982   const double * upper = getColUpper();
02983   const double * rowLower = getRowLower();
02984   const double * rowUpper = getRowUpper();
02985 
02986   for (iRow=0;iRow<numberRows;iRow++) {
02987     int numberP1=0, numberM1=0;
02988     int j;
02989     double upperValue=rowUpper[iRow];
02990     double lowerValue=rowLower[iRow];
02991     bool good=true;
02992     int slack = -1;
02993     for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
02994       int iColumn = column[j];
02995       int iInteger=lookup[iColumn];
02996       if (upper[iColumn]-lower[iColumn]<1.0e-8) {
02997         // fixed
02998         upperValue -= lower[iColumn]*elementByRow[j];
02999         lowerValue -= lower[iColumn]*elementByRow[j];
03000         continue;
03001       } else if (upper[iColumn]!=1.0||lower[iColumn]!=0.0) {
03002         good = false;
03003         break;
03004       } else if (iInteger<0) {
03005         good = false;
03006         break;
03007       } else {
03008         if (columnLength[iColumn]==1)
03009           slack = iInteger;
03010       }
03011       if (fabs(elementByRow[j])!=1.0) {
03012         good=false;
03013         break;
03014       } else if (elementByRow[j]>0.0) {
03015         which[numberP1++]=iInteger;
03016       } else {
03017         numberM1++;
03018         which[numberIntegers_-numberM1]=iInteger;
03019       }
03020     }
03021     int iUpper = (int) floor(upperValue+1.0e-5);
03022     int iLower = (int) ceil(lowerValue-1.0e-5);
03023     int state=0;
03024     if (upperValue<1.0e6) {
03025       if (iUpper==1-numberM1)
03026         state=1;
03027       else if (iUpper==-numberM1)
03028         state=2;
03029       else if (iUpper<-numberM1)
03030         state=3;
03031     }
03032     if (!state&&lowerValue>-1.0e6) {
03033       if (-iLower==1-numberP1)
03034         state=-1;
03035       else if (-iLower==-numberP1)
03036         state=-2;
03037       else if (-iLower<-numberP1)
03038         state=-3;
03039     }
03040     if (good&&state) {
03041       if (abs(state)==3) {
03042         // infeasible
03043         numberObjects_=-1;
03044         break;
03045       } else if (abs(state)==2) {
03046         // we can fix all
03047         numberFixed += numberP1+numberM1;
03048         if (state>0) {
03049           // fix all +1 at 0, -1 at 1
03050           for (i=0;i<numberP1;i++)
03051             solver_->setColUpper(integerVariable_[which[i]],0.0);
03052           for (i=0;i<numberM1;i++)
03053             solver_->setColLower(integerVariable_[which[numberIntegers_-i-1]],
03054                                  1.0);
03055         } else {
03056           // fix all +1 at 1, -1 at 0
03057           for (i=0;i<numberP1;i++)
03058             solver_->setColLower(integerVariable_[which[i]],1.0);
03059           for (i=0;i<numberM1;i++)
03060             solver_->setColUpper(integerVariable_[which[numberIntegers_-i-1]],
03061                                  0.0);
03062         }
03063       } else {
03064         int length = numberP1+numberM1;
03065         if (length >= atLeastThisMany&&length<lessThanThis) {
03066           // create object
03067           bool addOne=false;
03068           int objectType;
03069           if (iLower==iUpper) {
03070             objectType=1;
03071           } else {
03072             if (makeEquality) {
03073               objectType=1;
03074               element[numberSlacks]=state;
03075               rows[numberSlacks++]=iRow;
03076               addOne=true;
03077             } else {
03078               objectType=0;
03079             }
03080           }
03081           if (state>0) {
03082             totalP1 += numberP1;
03083             totalM1 += numberM1;
03084             for (i=0;i<numberP1;i++)
03085               type[i]=1;
03086             for (i=0;i<numberM1;i++) {
03087               which[numberP1]=which[numberIntegers_-i-1];
03088               type[numberP1++]=0;
03089             }
03090           } else {
03091             totalP1 += numberM1;
03092             totalM1 += numberP1;
03093             for (i=0;i<numberP1;i++)
03094               type[i]=0;
03095             for (i=0;i<numberM1;i++) {
03096               which[numberP1]=which[numberIntegers_-i-1];
03097               type[numberP1++]=1;
03098             }
03099           }
03100           if (addOne) {
03101             // add in slack
03102             which[numberP1]=numberIntegers_+numberSlacks-1;
03103             slack = numberP1;
03104             type[numberP1++]=1;
03105           } else if (slack >= 0) {
03106             for (i=0;i<numberP1;i++) {
03107               if (which[i]==slack) {
03108                 slack=i;
03109               }
03110             }
03111           }
03112           object[numberCliques++] = new SbbClique(this,objectType,numberP1,
03113                                               which,type,
03114                                                1000000+numberCliques,slack);
03115         } else if (numberP1+numberM1 >= lessThanThis) {
03116           // too big
03117           numberBig++;
03118           totalBig += numberP1+numberM1;
03119         }
03120       }
03121     }
03122   }
03123   delete [] which;
03124   delete [] type;
03125   delete [] lookup;
03126   if (numberCliques<0) {
03127     printf("*** Problem infeasible\n");
03128   } else {
03129     if (numberCliques)
03130       printf("%d cliques of average size %g found, %d P1, %d M1\n",
03131              numberCliques,
03132              ((double)(totalP1+totalM1))/((double) numberCliques),
03133              totalP1,totalM1);
03134     else
03135       printf("No cliques found\n");
03136     if (numberBig)
03137       printf("%d large cliques ( >= %d) found, total %d\n",
03138              numberBig,lessThanThis,totalBig);
03139     if (numberFixed)
03140       printf("%d variables fixed\n",numberFixed);
03141   }
03142   if (numberCliques>0&&numberSlacks&&makeEquality) {
03143     printf("adding %d integer slacks\n",numberSlacks);
03144     // add variables to make equality rows
03145     int * temp = new int[numberIntegers_+numberSlacks];
03146     memcpy(temp,integerVariable_,numberIntegers_*sizeof(int));
03147     // Get new model
03148     SbbModel * newModel = new SbbModel(*this);
03149     OsiSolverInterface * newSolver = newModel->solver();
03150     for (i=0;i<numberSlacks;i++) {
03151       temp[i+numberIntegers_]=i+numberColumns;
03152       int iRow = rows[i];
03153       double value = element[i];
03154       double lowerValue = 0.0;
03155       double upperValue = 1.0;
03156       double objValue  = 0.0;
03157       CoinPackedVector column(1,&iRow,&value);
03158       newSolver->addCol(column,lowerValue,upperValue,objValue);
03159       // set integer
03160       newSolver->setInteger(numberColumns+i);
03161       if (value >0)
03162         newSolver->setRowLower(iRow,rowUpper[iRow]);
03163       else
03164         newSolver->setRowUpper(iRow,rowLower[iRow]);
03165     }
03166     // replace list of integers
03167     for (i=0;i<newModel->numberObjects_;i++)
03168       delete newModel->object_[i];
03169     newModel->numberObjects_ = 0;
03170     delete [] newModel->object_;
03171     newModel->object_=NULL;
03172     newModel->findIntegers(true); //Set up all integer objects
03173     if (priority_) {
03174       // old model had priorities
03175       delete [] newModel->priority_;
03176       newModel->priority_ = new int[newModel->numberIntegers_+numberCliques];
03177       memcpy(newModel->priority_,priority_,numberIntegers_*sizeof(int));
03178       for (i=numberIntegers_;i<newModel->numberIntegers_+numberCliques;i++)
03179         newModel->priority_[i]=defaultValue;
03180     }
03181     if (originalColumns_) {
03182       // old model had originalColumns
03183       delete [] newModel->originalColumns_;
03184       newModel->originalColumns_ = new int[numberColumns+numberSlacks];
03185       memcpy(newModel->originalColumns_,originalColumns_,numberColumns*sizeof(int));
03186       // mark as not in previous model
03187       for (i=numberColumns;i<numberColumns+numberSlacks;i++)
03188         newModel->originalColumns_[i]=-1;
03189     }
03190     delete [] rows;
03191     delete [] element;
03192     newModel->addObjects(numberCliques,object);
03193     for (;i<numberCliques;i++) 
03194       delete object[i];
03195     delete [] object;
03196     newModel->synchronizeModel();
03197     return newModel;
03198   } else {
03199     if (numberCliques>0) {
03200       addObjects(numberCliques,object);
03201       for (;i<numberCliques;i++) 
03202         delete object[i];
03203       synchronizeModel();
03204     }
03205     delete [] object;
03206     if (priority_) {
03207       // model had priorities
03208       int * temp = new int[numberIntegers_+numberCliques];
03209       memcpy(temp,priority_,numberIntegers_*sizeof(int));
03210       delete [] priority_;
03211       priority_=temp;
03212       for (i=numberIntegers_;i<numberIntegers_+numberCliques;i++)
03213         priority_[i]=defaultValue;
03214     }
03215     delete [] rows;
03216     delete [] element;
03217     return this;
03218   }
03219 }

void SbbModel::findIntegers bool  startAgain  ) 
 

Identify integer variables and create corresponding objects.

Record integer variables and create an SbbSimpleInteger object for each one. If startAgain is true, a new scan is forced, overwriting any existing integer variable information.

Definition at line 3300 of file SbbModel.cpp.

References getNumCols(), handler_, integerVariable_, isInteger(), CoinMessageHandler::message(), messages_, numberIntegers_, numberObjects_, object_, and solver_.

Referenced by branchAndBound(), deleteObjects(), findCliques(), integerPresolveThisModel(), originalModel(), and passInPriorities().

03301 {
03302   assert(solver_);
03303 /*
03304   No need to do this if we have previous information, unless forced to start
03305   over.
03306 */
03307   if (numberIntegers_&&!startAgain&&object_)
03308     return;
03309 /*
03310   Clear out the old integer variable list, then count the number of integer
03311   variables.
03312 */
03313   delete [] integerVariable_;
03314   numberIntegers_=0;
03315   int numberColumns = getNumCols();
03316   int iColumn;
03317   for (iColumn=0;iColumn<numberColumns;iColumn++) {
03318     if (isInteger(iColumn)) 
03319       numberIntegers_++;
03320   }
03321 /*
03322   Found any? Allocate an array to hold the indices of the integer variables.
03323   If we don't already have an array of object pointers, make one.
03324 */
03325   if (numberIntegers_) {
03326     if (!object_) {
03327       object_ = new SbbObject * [numberIntegers_];
03328       memset(object_,0,numberIntegers_*sizeof(SbbObject *));
03329       numberObjects_=numberIntegers_;
03330     }
03331     integerVariable_ = new int [numberIntegers_];
03332 /*
03333   Walk the variables again, filling in the indices and creating objects for
03334   the integer variables. Initially, the objects hold the index and upper &
03335   lower bounds.
03336 */
03337     numberIntegers_=0;
03338     for (iColumn=0;iColumn<numberColumns;iColumn++) {
03339       if(isInteger(iColumn)) {
03340         delete object_[numberIntegers_];
03341         object_[numberIntegers_] =
03342             new SbbSimpleInteger(this,numberIntegers_,iColumn);
03343         integerVariable_[numberIntegers_++]=iColumn;
03344       }
03345     }
03346   } else {
03347     handler_->message(SBB_NOINT,messages_) << CoinMessageEol ;
03348     return;
03349   }
03350 }

double SbbModel::getAllowableGap  )  const [inline]
 

Get the allowable gap between the best known solution and the best possible solution.

Definition at line 377 of file SbbModel.hpp.

References getDblParam(), and SbbAllowableGap.

00377                                         {
00378     return getDblParam(SbbAllowableGap);
00379   }

CoinWarmStartBasis * SbbModel::getEmptyBasis int  ns = 0,
int  na = 0
const
 

Get an empty basis object.

Return an empty basis object of the specified size

A useful utility when constructing a basis for a subproblem from scratch. The object returned will be of the requested capacity and appropriate for the solver attached to the model.

Definition at line 1232 of file SbbModel.cpp.

References CoinWarmStart::clone(), emptyWarmStart_, OsiSolverInterface::getEmptyWarmStart(), CoinWarmStartBasis::setSize(), and solver_.

Referenced by tree::cleanTree().

01234 { CoinWarmStartBasis *emptyBasis ;
01235 /*
01236   Acquire an empty basis object, if we don't yet have one.
01237 */
01238   if (emptyWarmStart_ == 0)
01239   { if (solver_ == 0)
01240     { throw CoinError("Cannot construct basis without solver!",
01241                       "getEmptyBasis","SbbModel") ; }
01242     emptyBasis =
01243         dynamic_cast<CoinWarmStartBasis *>(solver_->getEmptyWarmStart()) ;
01244     if (emptyBasis == 0)
01245     { throw CoinError(
01246         "Solver does not appear to use a basis-oriented warm start.",
01247         "getEmptyBasis","SbbModel") ; }
01248     emptyBasis->setSize(0,0) ;
01249     emptyWarmStart_ = dynamic_cast<CoinWarmStart *>(emptyBasis) ; }
01250 /*
01251   Clone the empty basis object, resize it as requested, and return.
01252 */
01253   emptyBasis = dynamic_cast<CoinWarmStartBasis *>(emptyWarmStart_->clone()) ;
01254   assert(emptyBasis) ;
01255   if (ns != 0 || na != 0) emptyBasis->setSize(ns,na) ;
01256 
01257   return (emptyBasis) ; }

double SbbModel::getInfeasibilityWeight  )  const [inline]
 

Get the weight per integer infeasibility

Definition at line 364 of file SbbModel.hpp.

References getDblParam(), and SbbInfeasibilityWeight.

00364                                                {
00365     return getDblParam(SbbInfeasibilityWeight);
00366   }

double SbbModel::getIntegerTolerance  )  const [inline]
 

Get the integrality tolerance

Definition at line 349 of file SbbModel.hpp.

References getDblParam(), and SbbIntegerTolerance.

Referenced by branchAndBound(), checkSolution(), and feasibleSolution().

00349                                             {
00350     return getDblParam(SbbIntegerTolerance);
00351   }

int SbbModel::getMaximumCutPasses  )  const [inline]
 

Get the maximum number of cut passes at other nodes (default 10)

Definition at line 408 of file SbbModel.hpp.

References maximumCutPasses_.

00409   { return maximumCutPasses_;};

int SbbModel::getMaximumCutPassesAtRoot  )  const [inline]
 

Get the maximum number of cut passes at root node

Definition at line 400 of file SbbModel.hpp.

References maximumCutPassesAtRoot_.

00401   { return maximumCutPassesAtRoot_;};

int SbbModel::getMaximumSolutions  )  const [inline]
 

Get the maximum number of solutions desired.

Definition at line 336 of file SbbModel.hpp.

References getIntParam(), and SbbMaxNumSol.

00336                                          {
00337     return getIntParam(SbbMaxNumSol);
00338   }

const double* SbbModel::getRightHandSide  )  const [inline]
 

Get pointer to array[getNumRows()] of rows right-hand sides

  • if rowsense()[i] == 'L' then rhs()[i] == rowupper()[i]
  • if rowsense()[i] == 'G' then rhs()[i] == rowlower()[i]
  • if rowsense()[i] == 'R' then rhs()[i] == rowupper()[i]
  • if rowsense()[i] == 'N' then rhs()[i] == 0.0

Definition at line 529 of file SbbModel.hpp.

References OsiSolverInterface::getRightHandSide(), and solver_.

00530   { return solver_->getRightHandSide();};

const double* SbbModel::getRowRange  )  const [inline]
 

Get pointer to array[getNumRows()] of row ranges.

  • if rowsense()[i] == 'R' then rowrange()[i] == rowupper()[i] - rowlower()[i]
  • if rowsense()[i] != 'R' then rowrange()[i] is 0.0

Definition at line 540 of file SbbModel.hpp.

References OsiSolverInterface::getRowRange(), and solver_.

00541   { return solver_->getRowRange();};

const char* SbbModel::getRowSense  )  const [inline]
 

Get pointer to array[getNumRows()] of row constraint senses.

  • 'L': <= constraint
  • 'E': = constraint
  • 'G': >= constraint
  • 'R': ranged constraint
  • 'N': free constraint

Definition at line 518 of file SbbModel.hpp.

References OsiSolverInterface::getRowSense(), and solver_.

00519   { return solver_->getRowSense();};

void SbbModel::initialSolve  ) 
 

Solve the initial LP relaxation.

Invoke the solver's initialSolve() method.

Definition at line 1217 of file SbbModel.cpp.

References OsiSolverInterface::initialSolve(), and solver_.

01218 {
01219   assert (solver_);
01220   solver_->initialSolve();
01221 }

SbbModel * SbbModel::integerPresolve bool  weak = false  ) 
 

Do integer presolve, creating a new (presolved) model.

Returns the new model, or NULL if feasibility is lost. If weak is true then just does a normal presolve

Todo:
It remains to work out the cleanest way of getting a solution to the original problem at the end. So this is very preliminary.

Definition at line 4078 of file SbbModel.cpp.

References handler_, integerPresolveThisModel(), CoinMessageHandler::message(), messageHandler(), messages_, resolve(), SbbModel(), CoinMessageHandler::setLogLevel(), solver_, status_, and synchronizeModel().

04079 {
04080   status_ = 0;
04081   // solve LP
04082   bool feasible = resolve();
04083 
04084   SbbModel * newModel = NULL;
04085   if (feasible) {
04086 
04087     // get a new model
04088     newModel = new SbbModel(*this);
04089     newModel->messageHandler()->setLogLevel(messageHandler()->logLevel());
04090 
04091     feasible = newModel->integerPresolveThisModel(solver_,weak);
04092   }
04093   if (!feasible) {
04094     handler_->message(SBB_INFEAS,messages_)
04095     <<CoinMessageEol;
04096     status_ = 1;
04097     delete newModel;
04098     return NULL;
04099   } else {
04100     newModel->synchronizeModel(); // make sure everything that needs solver has it
04101     return newModel;
04102   }
04103 }

bool SbbModel::integerPresolveThisModel OsiSolverInterface originalSolver,
bool  weak = false
 

Do integer presolve, modifying the current model.

Returns true if the model remains feasible after presolve.

Definition at line 4108 of file SbbModel.cpp.

References OsiSolverInterface::activateRowCutDebugger(), addedCuts_, bestObjective_, OsiSolverInterface::clone(), continuousSolver_, OsiSolverInterface::copyParameters(), currentNumberCuts_, currentSolution_, dblParam_, deleteObjects(), findIntegers(), OsiSolverInterface::getColLower(), getColLower(), OsiSolverInterface::getColUpper(), getColUpper(), getCutoff(), OsiClpSolverInterface::getModelPtr(), OsiClpSolverInterface::getNumCols(), getNumCols(), getNumRows(), OsiSolverInterface::getObjCoefficients(), OsiSolverInterface::getObjSense(), OsiSolverInterface::getRowCutDebugger(), OsiSolverInterface::getStrParam(), integerVariable_, isInteger(), OsiSolverInterface::isInteger(), maximumCutPassesAtRoot_, maximumDepth_, maximumNumberCuts_, CoinMessageHandler::message(), messageHandler(), messages(), numberHeuristics_, numberHeuristicSolutions_, numberIntegers_, numberRowsAtContinuous_, numberSolutions_, OsiRowCutDebugger::onOptimalPath(), originalColumns_, priority_, resolve(), SbbCutoffIncrement, setBestSolution(), OsiSolverInterface::setColLower(), OsiSolverInterface::setColUpper(), setCutoff(), SbbHeuristic::solution(), solver_, solveWithCuts(), status_, synchronizeModel(), and walkback_.

Referenced by integerPresolve().

04110 {
04111   status_ = 0;
04112   // solve LP
04113   bool feasible = resolve();
04114 
04115   bestObjective_=1.0e50;
04116   numberSolutions_=0;
04117   numberHeuristicSolutions_=0;
04118   double cutoff = getCutoff() ;
04119   double direction = solver_->getObjSense();
04120   if (cutoff < 1.0e20&&direction<0.0)
04121     messageHandler()->message(SBB_CUTOFF_WARNING1,
04122                                     messages())
04123                                       << cutoff << -cutoff << CoinMessageEol ;
04124   if (cutoff > bestObjective_)
04125     cutoff = bestObjective_ ;
04126   setCutoff(cutoff) ;
04127   int iColumn;
04128   int numberColumns = getNumCols();
04129   int originalNumberColumns = numberColumns;
04130   int numberPasses=0;
04131   synchronizeModel(); // make sure everything that needs solver has it
04132   // just point to solver_
04133   delete continuousSolver_;
04134   continuousSolver_ = solver_;
04135   // get a copy of original so we can fix bounds
04136   OsiSolverInterface * cleanModel = originalSolver->clone();
04137 #ifdef SBB_DEBUG
04138   std::string problemName;
04139   cleanModel->getStrParam(OsiProbName,problemName);
04140   printf("Problem name - %s\n",problemName.c_str());
04141   cleanModel->activateRowCutDebugger(problemName.c_str());
04142   const OsiRowCutDebugger * debugger = cleanModel->getRowCutDebugger();
04143 #endif
04144 
04145   // array which points from original columns to presolved
04146   int * original = new int[numberColumns];
04147   // arrays giving bounds - only ones found by probing 
04148   // rest will be found by presolve
04149   double * originalLower = new double[numberColumns];
04150   double * originalUpper = new double[numberColumns];
04151   {
04152     const double * lower = getColLower();
04153     const double * upper = getColUpper();
04154     for (iColumn=0;iColumn<numberColumns;iColumn++) {
04155       original[iColumn]=iColumn;
04156       originalLower[iColumn] = lower[iColumn];
04157       originalUpper[iColumn] = upper[iColumn];
04158     }
04159   }
04160   findIntegers(true);
04161   // save original integers
04162   int * originalPriority = NULL;
04163   int * originalIntegers = new int[numberIntegers_];
04164   int originalNumberIntegers = numberIntegers_;
04165   memcpy(originalIntegers,integerVariable_,numberIntegers_*sizeof(int));
04166 
04167   if (priority_) {
04168     originalPriority = new int[numberIntegers_];
04169     memcpy(originalPriority,priority_,numberIntegers_*sizeof(int));
04170     delete [] priority_;
04171     priority_=NULL;
04172   }
04173   int todo=20;
04174   if (weak)
04175     todo=1;
04176   while (numberPasses<todo) {
04177    
04178     numberPasses++;
04179     numberSolutions_=0;
04180     // this will be set false to break out of loop with presolved problem
04181     bool doIntegerPresolve=(numberPasses!=20);
04182     
04183     // Current number of free integer variables
04184     // Get increment in solutions
04185     {
04186       const double * objective = cleanModel->getObjCoefficients();
04187       const double * lower = cleanModel->getColLower();
04188       const double * upper = cleanModel->getColUpper();
04189       double maximumCost=0.0;
04190       bool possibleMultiple=true;
04191       int numberChanged=0;
04192       for (iColumn=0;iColumn<originalNumberColumns;iColumn++) {
04193         if (originalUpper[iColumn]>originalLower[iColumn]) {
04194           if( cleanModel->isInteger(iColumn)) {
04195             maximumCost = max(maximumCost,fabs(objective[iColumn]));
04196           } else if (objective[iColumn]) {
04197             possibleMultiple=false;
04198           }
04199         }
04200         if (originalUpper[iColumn]<upper[iColumn]) {
04201 #ifdef SBB_DEBUG
04202           printf("Changing upper bound on %d from %g to %g\n",
04203                  iColumn,upper[iColumn],originalUpper[iColumn]);
04204 #endif
04205           cleanModel->setColUpper(iColumn,originalUpper[iColumn]);
04206           numberChanged++;
04207         }
04208         if (originalLower[iColumn]>lower[iColumn]) {
04209 #ifdef SBB_DEBUG
04210           printf("Changing lower bound on %d from %g to %g\n",
04211                  iColumn,lower[iColumn],originalLower[iColumn]);
04212 #endif
04213           cleanModel->setColLower(iColumn,originalLower[iColumn]);
04214           numberChanged++;
04215         }
04216       }
04217       // if first pass - always try
04218       if (numberPasses==1)
04219         numberChanged += 1;
04220       if (possibleMultiple) {
04221         int increment=0; 
04222         double multiplier = 2520.0;
04223         while (10.0*multiplier*maximumCost<1.0e8)
04224           multiplier *= 10.0;
04225         for (iColumn=0;iColumn<originalNumberColumns;iColumn++) {
04226           if (originalUpper[iColumn]>originalLower[iColumn]) {
04227             if( isInteger(iColumn)&&objective[iColumn]) {
04228               double value = fabs(objective[iColumn])*multiplier;
04229               int nearest = (int) floor(value+0.5);
04230               if (fabs(value-floor(value+0.5))>1.0e-8) {
04231                 increment=0;
04232                 break; // no good
04233               } else if (!increment) {
04234                 // first
04235                 increment=nearest;
04236               } else {
04237                 increment = gcd(increment,nearest);
04238               }
04239             }
04240           }
04241         }
04242         if (increment) {
04243           double value = increment;
04244           value /= multiplier;
04245           if (value*0.999>dblParam_[SbbCutoffIncrement]) {
04246             messageHandler()->message(SBB_INTEGERINCREMENT,messages())
04247               <<value
04248               <<CoinMessageEol;
04249             dblParam_[SbbCutoffIncrement]=value*0.999;
04250           }
04251         }
04252       }
04253       if (!numberChanged) {
04254         doIntegerPresolve=false; // not doing any better
04255       }
04256     }
04257 #ifdef SBB_DEBUG
04258     if (debugger) 
04259       assert(debugger->onOptimalPath(*cleanModel));
04260 #endif
04261 #ifdef COIN_USE_CLP
04262     // do presolve - for now just clp but easy to get osi interface
04263     OsiClpSolverInterface * clpSolver 
04264       = dynamic_cast<OsiClpSolverInterface *> (cleanModel);
04265     assert (clpSolver);
04266     ClpSimplex * clp = clpSolver->getModelPtr();
04267     ClpPresolve pinfo;
04268     ClpSimplex * model2 = pinfo.presolvedModel(*clp,1.0e-8);
04269     if (!model2) {
04270       // presolve found to be infeasible
04271       feasible=false;
04272     } else {
04273       // update original array
04274       const int * originalColumns = pinfo.originalColumns();
04275       // just slot in new solver
04276       OsiClpSolverInterface * temp = new OsiClpSolverInterface(model2);
04277       numberColumns = temp->getNumCols();
04278       for (iColumn=0;iColumn<originalNumberColumns;iColumn++)
04279         original[iColumn]=-1;
04280       for (iColumn=0;iColumn<numberColumns;iColumn++)
04281         original[originalColumns[iColumn]]=iColumn;
04282       // copy parameters
04283       temp->copyParameters(*solver_);
04284       delete solver_;
04285       solver_ = temp;
04286       setCutoff(cutoff);
04287       deleteObjects();
04288       synchronizeModel(); // make sure everything that needs solver has it
04289       // just point to solver_
04290       continuousSolver_ = solver_;
04291       feasible=resolve();
04292       if (!feasible||!doIntegerPresolve||weak) break;
04293       // see if we can get solution by heuristics
04294       int found=-1;
04295       int iHeuristic;
04296       double * newSolution = new double [numberColumns];
04297       double heuristicValue=getCutoff();
04298       for (iHeuristic=0;iHeuristic<numberHeuristics_;iHeuristic++) {
04299         double saveValue=heuristicValue;
04300         int ifSol = heuristic_[iHeuristic]->solution(heuristicValue,
04301                                                      newSolution);
04302         if (ifSol>0) {
04303           // better solution found
04304           found=iHeuristic;
04305         } else if (ifSol<0) {
04306           heuristicValue = saveValue;
04307         }
04308       }
04309       if (found >= 0) {
04310         // We probably already have a current solution, but just in case ...
04311         int numberColumns = getNumCols() ;
04312         if (!currentSolution_)
04313           currentSolution_ = new double[numberColumns] ;
04314         // better solution save
04315         setBestSolution(SBB_ROUNDING,heuristicValue,
04316                         newSolution);
04317         // update cutoff
04318         cutoff = getCutoff();
04319       }
04320       delete [] newSolution;
04321       // Space for type of cuts
04322       int maximumWhich=1000;
04323       int * whichGenerator = new int[maximumWhich];
04324       // save number of rows
04325       numberRowsAtContinuous_ = getNumRows();
04326       maximumNumberCuts_=0;
04327       currentNumberCuts_=0;
04328       delete [] addedCuts_;
04329       addedCuts_ = NULL;
04330       
04331       // maximum depth for tree walkback
04332       maximumDepth_=10;
04333       delete [] walkback_;
04334       walkback_ = new SbbNodeInfo * [maximumDepth_];
04335       
04336       OsiCuts cuts;
04337       int numberOldActiveCuts=0;
04338       int numberNewCuts = 0;
04339       feasible = solveWithCuts(cuts,maximumCutPassesAtRoot_,
04340                                NULL,numberOldActiveCuts,numberNewCuts,
04341                                maximumWhich, whichGenerator);
04342       currentNumberCuts_=numberNewCuts;
04343       delete [] whichGenerator;
04344       delete [] walkback_;
04345       walkback_ = NULL;
04346       delete [] addedCuts_;
04347       addedCuts_=NULL;
04348       if (feasible) {
04349         // fix anything in original which integer presolve fixed
04350         // for now just integers
04351         const double * lower = solver_->getColLower();
04352         const double * upper = solver_->getColUpper();
04353         int i;
04354         for (i=0;i<originalNumberIntegers;i++) {
04355           iColumn = originalIntegers[i];
04356           int jColumn = original[iColumn];
04357           if (jColumn >= 0) {
04358             if (upper[jColumn]<originalUpper[iColumn]) 
04359               originalUpper[iColumn]  = upper[jColumn];
04360             if (lower[jColumn]>originalLower[iColumn]) 
04361               originalLower[iColumn]  = lower[jColumn];
04362           }
04363         }
04364       }
04365     }
04366 #endif
04367     if (!feasible||!doIntegerPresolve) {
04368       break;
04369     }
04370   }
04371   //solver_->writeMps("xx");
04372   delete cleanModel;
04373   // create new priorities and save list of original columns
04374   if (originalPriority) {
04375     priority_ = new int[numberIntegers_];
04376     int i;
04377     int number=0;
04378     // integer variables are in same order if they exist at all
04379     for (i=0;i<originalNumberIntegers;i++) {
04380       iColumn = originalIntegers[i];
04381       int newColumn=original[iColumn];
04382       if (newColumn >= 0) 
04383         priority_[number++]=originalPriority[i];
04384     }
04385     assert (number==numberIntegers_);
04386     delete [] originalPriority;
04387   }
04388   delete [] originalIntegers;
04389   numberColumns = getNumCols();
04390   delete [] originalColumns_;
04391   originalColumns_ = new int[numberColumns];
04392   numberColumns=0;
04393   for (iColumn=0;iColumn<originalNumberColumns;iColumn++) {
04394     int jColumn = original[iColumn];
04395     if (jColumn >= 0) 
04396       originalColumns_[numberColumns++]=iColumn;
04397   }
04398   delete [] original;
04399   delete [] originalLower;
04400   delete [] originalUpper;
04401   
04402   deleteObjects();
04403   synchronizeModel(); // make sure everything that needs solver has it
04404   continuousSolver_=NULL;
04405   currentNumberCuts_=0;
04406   return feasible;
04407 }

bool SbbModel::isInteger int  colIndex  )  const [inline]
 

Return true if column is integer. Note: This function returns true if the the column is binary or a general integer.

Definition at line 571 of file SbbModel.hpp.

References OsiSolverInterface::isInteger(), and solver_.

Referenced by findIntegers(), and integerPresolveThisModel().

00572   { return solver_->isInteger(colIndex);};

int SbbModel::numberStrong  )  const [inline]
 

Get the maximum number of candidates to be evaluated for strong branching.

Definition at line 420 of file SbbModel.hpp.

References numberStrong_.

Referenced by SbbNode::chooseBranch(), SbbParam::intParameter(), and SbbParam::setIntParameter().

00421   { return numberStrong_;};

void SbbModel::passInPriorities const int *  priorities,
bool  ifClique,
int  defaultValue = 1000
 

Pass in branching priorities.

If ifClique then priorities are on cliques otherwise priorities are on integer variables. Other type (if exists set to default) 1 is highest priority. (well actually -INT_MAX is but that's ugly) If a priority < forcePriority() then branches are created to force the variable to the value given by best solution. This enables a sort of hot start. The node choice should be greatest depth and forcePriority should normally be switched off after a solution.

Definition at line 3231 of file SbbModel.cpp.

References findIntegers(), numberIntegers_, numberObjects_, and priority_.

03233 {
03234   findIntegers(false);
03235   int i;
03236   if (!priority_) {
03237     priority_ = new int[numberObjects_];
03238     for (i=0;i<numberObjects_;i++)
03239       priority_[i]=defaultValue;
03240   }
03241   if (priorities) {
03242     if (ifObject)
03243       memcpy(priority_+numberIntegers_,priorities,
03244              (numberObjects_-numberIntegers_)*sizeof(int));
03245     else
03246       memcpy(priority_,priorities,numberIntegers_*sizeof(int));
03247   }
03248 }

void SbbModel::reducedCostFix  ) 
 

Perform reduced cost fixing

Fixes integer variables at their current value based on reduced cost penalties.

Definition at line 2118 of file SbbModel.cpp.

References OsiSolverInterface::getColLower(), OsiSolverInterface::getColSolution(), OsiSolverInterface::getColUpper(), getCutoff(), getDblParam(), OsiSolverInterface::getObjSense(), OsiSolverInterface::getObjValue(), OsiSolverInterface::getReducedCost(), integerVariable_, numberIntegers_, SbbIntegerTolerance, OsiSolverInterface::setColLower(), OsiSolverInterface::setColUpper(), and solver_.

Referenced by solveWithCuts().

02120 { double cutoff = getCutoff() ;
02121   double direction = solver_->getObjSense() ;
02122   double gap = cutoff - solver_->getObjValue()*direction ;
02123   double integerTolerance = getDblParam(SbbIntegerTolerance) ;
02124 
02125   const double *lower = solver_->getColLower() ;
02126   const double *upper = solver_->getColUpper() ;
02127   const double *solution = solver_->getColSolution() ;
02128   const double *reducedCost = solver_->getReducedCost() ;
02129 
02130   int numberFixed = 0 ;
02131   for (int i = 0 ; i < numberIntegers_ ; i++)
02132   { int iColumn = integerVariable_[i] ;
02133     double djValue = direction*reducedCost[iColumn] ;
02134     if (upper[iColumn]-lower[iColumn] > integerTolerance)
02135     { if (solution[iColumn] < lower[iColumn]+integerTolerance && djValue > gap)
02136       { solver_->setColUpper(iColumn,lower[iColumn]) ;
02137         numberFixed++ ; }
02138       else
02139       if (solution[iColumn] > upper[iColumn]-integerTolerance && -djValue > gap)
02140       { solver_->setColLower(iColumn,upper[iColumn]) ;
02141         numberFixed++ ; } } }
02142   
02143   return ; }

bool SbbModel::resolve  ) 
 

Reoptimise an LP relaxation.

Invoke the solver's resolve() method.

Definition at line 2905 of file SbbModel.cpp.

References getIterationCount(), OsiSolverInterface::getNumRows(), OsiSolverInterface::getRowLower(), OsiSolverInterface::getRowUpper(), OsiSolverInterface::isDualObjectiveLimitReached(), OsiSolverInterface::isProvenOptimal(), numberIterations_, numberRowsAtContinuous_, OsiSolverInterface::resolve(), and solver_.

Referenced by branchAndBound(), integerPresolve(), integerPresolveThisModel(), originalModel(), and solveWithCuts().

02906 {
02907   // We may have deliberately added in violated cuts - check to avoid message
02908   int iRow;
02909   int numberRows = solver_->getNumRows();
02910   const double * rowLower = solver_->getRowLower();
02911   const double * rowUpper = solver_->getRowUpper();
02912   bool feasible=true;
02913   for (iRow= numberRowsAtContinuous_;iRow<numberRows;iRow++) {
02914     if (rowLower[iRow]>rowUpper[iRow]+1.0e-8)
02915       feasible=false;
02916   }
02917 /*
02918   Reoptimize. Consider the possibility that we should fathom on bounds. But be
02919   careful --- where the objective takes on integral values, we may want to keep
02920   a solution where the objective is right on the cutoff.
02921 */
02922   if (feasible)
02923   { solver_->resolve() ;
02924     numberIterations_ += getIterationCount() ;
02925     feasible = (solver_->isProvenOptimal() &&
02926                 !solver_->isDualObjectiveLimitReached()) ; }
02927   return feasible ; }

bool SbbModel::setAllowableGap double  value  )  [inline]
 

Set the allowable gap between the best known solution and the best possible solution.

Definition at line 371 of file SbbModel.hpp.

References SbbAllowableGap, and setDblParam().

00371                                              {
00372     return setDblParam(SbbAllowableGap,value);
00373   }

void SbbModel::setBranchingMethod SbbBranchDecision method  )  [inline]
 

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Set the branching method

Definition at line 713 of file SbbModel.hpp.

References branchingMethod_.

00714   { branchingMethod_ = &method;};

void SbbModel::setCutoff double  value  ) 
 

Set cutoff bound on the objective function.

When using strict comparison, the bound is adjusted by a tolerance to avoid accidentally cutting off the optimal solution.

Definition at line 3388 of file SbbModel.cpp.

References OsiSolverInterface::getDblParam(), getIntParam(), OsiSolverInterface::getObjSense(), SbbFathomDiscipline, OsiSolverInterface::setDblParam(), and solver_.

Referenced by branchAndBound(), integerPresolveThisModel(), setBestSolution(), and tightenVubs().

03390 { double tol = 0 ;
03391   int fathomStrict = getIntParam(SbbFathomDiscipline) ;
03392   double direction = solver_->getObjSense();
03393   if (fathomStrict == 1)
03394   { solver_->getDblParam(OsiDualTolerance,tol) ;
03395   tol = tol*(1+fabs(value))  ;
03396   
03397   value += tol ; }
03398   // Solvers know about direction
03399   solver_->setDblParam(OsiDualObjectiveLimit,value*direction); }

bool SbbModel::setInfeasibilityWeight double  value  )  [inline]
 

Set the weight per integer infeasibility

Definition at line 357 of file SbbModel.hpp.

References SbbInfeasibilityWeight, and setDblParam().

00357                                                     {
00358     return setDblParam(SbbInfeasibilityWeight,value);
00359   }

bool SbbModel::setIntegerTolerance double  value  )  [inline]
 

Set the integrality tolerance

Definition at line 343 of file SbbModel.hpp.

References SbbIntegerTolerance, and setDblParam().

00343                                                  {
00344     return setDblParam(SbbIntegerTolerance,value);
00345   }

void SbbModel::setMaximumCutPasses int  value  )  [inline]
 

Set the maximum number of cut passes at other nodes (default 10) Minimum drop can also be used for fine tuning

Definition at line 405 of file SbbModel.hpp.

References maximumCutPasses_.

00406   {maximumCutPasses_=value;};

void SbbModel::setMaximumCutPassesAtRoot int  value  )  [inline]
 

Set the maximum number of cut passes at root node (default 20) Minimum drop can also be used for fine tuning

Definition at line 397 of file SbbModel.hpp.

References maximumCutPassesAtRoot_.

00398   {maximumCutPassesAtRoot_=value;};

bool SbbModel::setMaximumSolutions int  value  )  [inline]
 

Set the maximum number of solutions desired.

Definition at line 329 of file SbbModel.hpp.

References SbbMaxNumSol, and setIntParam().

00329                                               {
00330     return setIntParam(SbbMaxNumSol,value);
00331   }

void SbbModel::setNumberStrong int  number  ) 
 

Set the maximum number of candidates to be evaluated for strong branching.

A value of 0 disables strong branching.

Definition at line 1856 of file SbbModel.cpp.

References numberStrong_.

Referenced by SbbParam::setIntParameter().

01857 {
01858   if (number<0)
01859     numberStrong_=0;
01860    else
01861     numberStrong_=number;
01862 }

void SbbModel::setPrintFrequency int  number  )  [inline]
 

Set the print frequency.

Controls the number of nodes evaluated between status prints. If number <=0 the print frequency is set to 100 nodes for large problems, 1000 for small problems. Print frequency has very slight overhead if small.

Definition at line 430 of file SbbModel.hpp.

References printFrequency_.

00431   { printFrequency_=number;};

bool SbbModel::solveWithCuts OsiCuts cuts,
int  numberTries,
SbbNode node,
int &  numberOldActiveCuts,
int &  numberNewCuts,
int &  maximumWhich,
int *&  whichGenerator
 

Evaluate a subproblem using cutting planes and heuristics.

The method invokes a main loop which generates cuts, applies heuristics, and reoptimises using the solver's native resolve() method. It returns true if the subproblem remains feasible at the end of the evaluation.

Definition at line 2163 of file SbbModel.cpp.

References addCuts(), addedCuts_, OsiSolverInterface::applyRowCuts(), basis_, OsiCuts::colCutPtr(), currentNumberCuts_, SbbCountRowCut::decrement(), SbbCutGenerator::generateCuts(), OsiSolverInterface::getColLower(), OsiSolverInterface::getColSolution(), OsiSolverInterface::getColUpper(), getCutoff(), getDblParam(), CoinPackedVector::getElements(), CoinPackedVector::getIndices(), OsiSolverInterface::getIterationCount(), OsiSolverInterface::getNumCols(), CoinPackedVector::getNumElements(), OsiSolverInterface::getNumRows(), OsiSolverInterface::getObjSense(), OsiSolverInterface::getObjValue(), OsiSolverInterface::getRowCutDebugger(), OsiSolverInterface::getWarmStart(), globalCuts_, OsiCut::globallyValid(), handler_, SbbCutGenerator::howOften(), howOftenGlobalScan_, OsiCuts::insert(), OsiRowCutDebugger::invalidCut(), OsiSolverInterface::isDualObjectiveLimitReached(), OsiSolverInterface::isProvenOptimal(), OsiColCut::lbs(), CoinMessageHandler::logLevel(), CoinMessageHandler::message(), messages_, minimumDrop_, numberCutGenerators_, numberHeuristics_, numberNodes_, numberRowsAtContinuous_, OsiRowCutDebugger::onOptimalPath(), CoinWarmStartBasis::print(), OsiCuts::printCuts(), reducedCostFix(), CoinWarmStartBasis::resize(), resolve(), OsiCuts::rowCut(), OsiCuts::rowCutPtr(), SbbIntegerTolerance, CoinWarmStartBasis::setArtifStatus(), setBestSolution(), OsiSolverInterface::setColLower(), OsiSolverInterface::setColUpper(), OsiSolverInterface::setWarmStart(), OsiCuts::sizeColCuts(), OsiCuts::sizeRowCuts(), solver_, takeOffCuts(), OsiColCut::ubs(), OsiRowCut::violated(), and OsiColCut::violated().

Referenced by branchAndBound(), and integerPresolveThisModel().

02167             :
02168     numberTries: (i) the maximum number of iterations for this round of cut
02169                      generation; no a priori limit if 0
02170     
02171     cuts:       (o) all cuts generated in this round of cut generation
02172     whichGenerator: (i/o) whichGenerator[i] is loaded with the index of the
02173                         generator that produced cuts[i]; reallocated as
02174                         required
02175     numberOldActiveCuts: (o) the number of active cuts at this node from
02176                         previous rounds of cut generation
02177     numberNewCuts: (o) the number of cuts produced in this round of cut
02178                        generation
02179     maximumWhich: (i/o) capacity of whichGenerator; may be updated if
02180                         whichGenerator grows.
02181 
02182     node: (currently unused)
02183 */
02184                         
02185 
02186 { bool feasible = true ;
02187   int lastNumberCuts = 0 ;
02188   double lastObjective = -1.0e100 ;
02189   int violated = 0 ;
02190   int numberRowsAtStart = solver_->getNumRows() ;
02191   int numberColumns = solver_->getNumCols() ;
02192 
02193   numberOldActiveCuts = numberRowsAtStart-numberRowsAtContinuous_ ;
02194   numberNewCuts = 0 ;
02195 
02196 # ifdef SBB_DEBUG
02197 /*
02198   See OsiRowCutDebugger for details. In a nutshell, make sure that current
02199   variable values do not conflict with a known optimal solution. (Obviously
02200   this can be fooled when there are multiple solutions.)
02201 */
02202   bool onOptimalPath = false ;
02203   const OsiRowCutDebugger *debugger = solver_->getRowCutDebugger() ;
02204   if (debugger) 
02205     onOptimalPath = (debugger->onOptimalPath(*solver_)) ;
02206 # endif
02207 
02208 /*
02209   Resolve the problem. If we've lost feasibility, might as well bail out right
02210   after the debug stuff.
02211 */
02212   feasible = resolve() ;
02213 
02214 #ifdef SBB_DEBUG
02215   if (feasible)
02216   { printf("Obj value %g (%s) %d rows\n",solver_->getObjValue(),
02217            (solver_->isProvenOptimal())?"proven":"unproven",
02218            solver_->getNumRows()) ; }
02219   else
02220   { printf("Infeasible %d rows\n",solver_->getNumRows()) ; }
02221 /*
02222   If the RowCutDebugger said we were compatible with the optimal solution,
02223   and now we're suddenly infeasible, we might be confused. Then again, we
02224   may have fathomed by bound, heading for a rediscovery of an optimal solution.
02225 */
02226   if (onOptimalPath && !solver_->isDualObjectiveLimitReached())
02227     assert(feasible) ;
02228 # endif
02229 
02230   if (!feasible) return (false) ;
02231 /*
02232   Do reduced cost fixing, and then grab the primal solution and bounds vectors.
02233 */
02234   reducedCostFix() ;
02235   const double *lower = solver_->getColLower() ;
02236   const double *upper = solver_->getColUpper() ;
02237   const double *solution = solver_->getColSolution() ;
02238 /*
02239   Set up for at most numberTries rounds of cut generation. If numberTries is
02240   negative, we'll ignore the minimumDrop_ cutoff and keep generating cuts for
02241   the specified number of rounds.
02242 */
02243   double minimumDrop = minimumDrop_ ;
02244   if (numberTries<0)
02245   { numberTries = -numberTries ;
02246     minimumDrop = -1.0 ; }
02247 /*
02248   Is it time to scan the cuts in order to remove redundant cuts? If so, set
02249   up to do it.
02250 */
02251 # define SCANCUTS 100  
02252   int *countColumnCuts = NULL ;
02253   int *countRowCuts = NULL ;
02254   bool fullScan = false ;
02255   if ((numberNodes_%SCANCUTS) == 0)
02256   { fullScan = true ;
02257     countColumnCuts = new int[numberCutGenerators_+numberHeuristics_] ;
02258     countRowCuts = new int[numberCutGenerators_+numberHeuristics_] ;
02259     memset(countColumnCuts,0,
02260            (numberCutGenerators_+numberHeuristics_)*sizeof(int)) ;
02261     memset(countRowCuts,0,
02262            (numberCutGenerators_+numberHeuristics_)*sizeof(int)) ; }
02263 
02264   double direction = solver_->getObjSense() ;
02265   double startObjective = solver_->getObjValue()*direction ;
02266 
02267   int numberPasses = 0 ;
02268   double primalTolerance = 1.0e-7 ;
02269 /*
02270   Begin cut generation loop. Cuts generated during each iteration are
02271   collected in theseCuts. The loop can be divided into four phases:
02272    1) Prep: Fix variables using reduced cost. In the first iteration only,
02273       consider scanning globalCuts_ and activating any applicable cuts.
02274    2) Cut Generation: Call each generator and heuristic registered in the
02275       generator_ and heuristic_ arrays. Newly generated global cuts are
02276       copied to globalCuts_ at this time.
02277    3) Cut Installation and Reoptimisation: Install column and row cuts in
02278       the solver. Copy row cuts to cuts (parameter). Reoptimise.
02279    4) Cut Purging: takeOffCuts() removes inactive cuts from the solver, and
02280       does the necessary bookkeeping in the model.
02281 */
02282   do
02283   { numberPasses++ ;
02284     numberTries-- ;
02285     OsiCuts theseCuts ;
02286 
02287 /*
02288   Scan previously generated global column and row cuts to see if any are
02289   useful.
02290   Unclear this code is exercised at present --- howOftenGlobalScan is
02291   initialized to -1 and never changed. In any event, I can't see why this code
02292   needs its own copy of the primal solution. Removed the dec'l.
02293 */
02294     if (numberPasses == 1 && howOftenGlobalScan_ > 0 &&
02295         (numberNodes_%howOftenGlobalScan_) == 0)
02296     { int numberCuts = globalCuts_.sizeColCuts() ;
02297       int i;
02298       for ( i = 0 ; i < numberCuts ; i++)
02299       { const OsiColCut *thisCut = globalCuts_.colCutPtr(i) ;
02300         if (thisCut->violated(solution)>primalTolerance) {
02301           printf("Global cut added - violation %g\n",
02302                  thisCut->violated(solution)) ;
02303           theseCuts.insert(*thisCut) ;
02304         }
02305       }
02306       numberCuts = globalCuts_.sizeRowCuts() ;
02307       for ( i = 0;i<numberCuts;i++) {
02308         const OsiRowCut * thisCut = globalCuts_.rowCutPtr(i) ;
02309         if (thisCut->violated(solution)>primalTolerance) {
02310           printf("Global cut added - violation %g\n",
02311                  thisCut->violated(solution)) ;
02312           theseCuts.insert(*thisCut) ;
02313         }
02314       }
02315     }
02316 /*
02317   Generate new cuts (global and/or local) and/or apply heuristics.  If
02318   CglProbing is used, then it should be first as it can fix continuous
02319   variables.
02320 
02321   At present, CglProbing is the only case where generateCuts will return
02322   true. generateCuts actually modifies variable bounds in the solver when
02323   CglProbing indicates that it can fix a variable. Reoptimisation is required
02324   to take full advantage.
02325 */
02326     double * newSolution = new double [numberColumns] ;
02327     double heuristicValue = getCutoff() ;
02328     int found = -1; // no solution found
02329 
02330     for (int i = 0;i<numberCutGenerators_+numberHeuristics_;i++) {
02331       int numberRowCutsBefore = theseCuts.sizeRowCuts() ;
02332       int numberColumnCutsBefore = theseCuts.sizeColCuts() ;
02333       if (i<numberCutGenerators_) {
02334         bool mustResolve = 
02335             generator_[i]->generateCuts(theseCuts,fullScan) ;
02336         if (mustResolve) {
02337           feasible = resolve() ;
02338 #         ifdef SBB_DEBUG
02339           debugger = solver_->getRowCutDebugger() ;
02340           if (debugger) 
02341             onOptimalPath = (debugger->onOptimalPath(*solver_)) ;
02342           if (onOptimalPath && !solver_->isDualObjectiveLimitReached())
02343             assert(feasible) ;
02344 #         endif
02345           if (!feasible)
02346             break ;
02347         }
02348       } else {
02349         // see if heuristic will do anything
02350         double saveValue = heuristicValue ;
02351         int ifSol = 
02352           heuristic_[i-numberCutGenerators_]->solution(heuristicValue,
02353                                                        newSolution,
02354                                                        theseCuts) ;
02355         if (ifSol>0) {
02356           // better solution found
02357           found = i ;
02358         } else if (ifSol<0) {
02359           heuristicValue = saveValue ;
02360         }
02361       }
02362       int numberRowCutsAfter = theseCuts.sizeRowCuts() ;
02363       int numberColumnCutsAfter = theseCuts.sizeColCuts() ;
02364 
02365 #ifdef SBB_DEBUG
02366       if (onOptimalPath) {
02367         int k ;
02368         for (k = numberRowCutsBefore;k<numberRowCutsAfter;k++) {
02369           OsiRowCut thisCut = theseCuts.rowCut(k) ;
02370           assert(!debugger->invalidCut(thisCut)) ;
02371         }
02372       }
02373 #endif
02374 
02375 /*
02376   The cut generator/heuristic has done its thing, and maybe it generated some
02377   cuts and/or a new solution.  Do a bit of bookkeeping: load
02378   whichGenerator[i] with the index of the generator responsible for a cut,
02379   and place cuts flagged as global in the global cut pool for the model.
02380 
02381   lastNumberCuts is the sum of cuts added in previous iterations; it's the
02382   offset to the proper starting position in whichGenerator.
02383 
02384   TODO: Why is whichGenerator increased to 2*maximumWhich when it grows? 
02385 */
02386       int numberBefore =
02387             numberRowCutsBefore+numberColumnCutsBefore+lastNumberCuts ;
02388       int numberAfter =
02389             numberRowCutsAfter+numberColumnCutsAfter+lastNumberCuts ;
02390       if (numberAfter > maximumWhich) {
02391         maximumWhich = max(maximumWhich*2+100,numberAfter) ;
02392         int * temp = new int[2*maximumWhich] ;
02393         memcpy(temp,whichGenerator,numberBefore*sizeof(int)) ;
02394         delete [] whichGenerator ;
02395         whichGenerator = temp ;
02396       }
02397       int j ;
02398       if (fullScan) {
02399         // counts
02400         countRowCuts[i] += numberRowCutsAfter-numberRowCutsBefore ;
02401         countColumnCuts[i] += numberColumnCutsAfter-numberColumnCutsBefore ;
02402       }
02403       
02404       for (j = numberRowCutsBefore;j<numberRowCutsAfter;j++) {
02405         whichGenerator[numberBefore++] = i ;
02406         const OsiRowCut * thisCut = theseCuts.rowCutPtr(j) ;
02407         if (thisCut->globallyValid()) {
02408           // add to global list
02409           globalCuts_.insert(*thisCut) ;
02410         }
02411       }
02412       for (j = numberColumnCutsBefore;j<numberColumnCutsAfter;j++) {
02413         whichGenerator[numberBefore++] = i ;
02414         const OsiColCut * thisCut = theseCuts.colCutPtr(j) ;
02415         if (thisCut->globallyValid()) {
02416           // add to global list
02417           globalCuts_.insert(*thisCut) ;
02418         }
02419       }
02420     }
02421 /*
02422   End of the loop to exercise each generator/heuristic.
02423 
02424   Did any of the heuristics turn up a new solution? Record it before we free
02425   the vector.
02426 */
02427     if (found >= 0)
02428     { setBestSolution(SBB_ROUNDING,heuristicValue,newSolution) ; }
02429     delete [] newSolution ;
02430 
02431 #if 0
02432     // switch on to get all cuts printed
02433     theseCuts.printCuts() ;
02434 #endif
02435     int numberColumnCuts = theseCuts.sizeColCuts() ;
02436     int numberRowCuts = theseCuts.sizeRowCuts() ;
02437     violated = numberRowCuts + numberColumnCuts ;
02438 /*
02439   Apply column cuts (aka bound tightening). This may be partially redundant
02440   for column cuts returned by CglProbing, as generateCuts installs bounds
02441   from CglProbing when it determines it can fix a variable.
02442 
02443   TODO: Looks like the use of violated has evolved. The value set above is
02444         completely ignored. All that's left is violated == -1 indicates some
02445         cut is violated, violated == -2 indicates infeasibility. Only
02446         infeasibility warrants exceptional action.
02447 
02448   TODO: Strikes me that this code will fail to detect infeasibility, because
02449         the breaks escape the inner loops but the outer loop keeps going.
02450         Infeasibility in an early cut will be overwritten if a later cut is
02451         merely violated.
02452 */
02453     if (numberColumnCuts) {
02454 
02455 #ifdef SBB_DEBUG
02456       double * oldLower = new double [numberColumns] ;
02457       double * oldUpper = new double [numberColumns] ;
02458       memcpy(oldLower,lower,numberColumns*sizeof(double)) ;
02459       memcpy(oldUpper,upper,numberColumns*sizeof(double)) ;
02460 #endif
02461 
02462       double integerTolerance = getDblParam(SbbIntegerTolerance) ;
02463       for (int i = 0;i<numberColumnCuts;i++) {
02464         const OsiColCut * thisCut = theseCuts.colCutPtr(i) ;
02465         const CoinPackedVector & lbs = thisCut->lbs() ;
02466         const CoinPackedVector & ubs = thisCut->ubs() ;
02467         int j ;
02468         int n ;
02469         const int * which ;
02470         const double * values ;
02471         n = lbs.getNumElements() ;
02472         which = lbs.getIndices() ;
02473         values = lbs.getElements() ;
02474         for (j = 0;j<n;j++) {
02475           int iColumn = which[j] ;
02476           double value = solution[iColumn] ;
02477 #ifdef SBB_DEBUG
02478           printf("%d %g %g %g %g\n",iColumn,oldLower[iColumn],
02479                  solution[iColumn],oldUpper[iColumn],values[j]) ;
02480 #endif
02481           solver_->setColLower(iColumn,values[j]) ;
02482           if (value<values[j]-integerTolerance)
02483             violated = -1 ;
02484           if (values[j]>upper[iColumn]+integerTolerance) {
02485             // infeasible
02486             violated = -2 ;
02487             break ;
02488           }
02489         }
02490         n = ubs.getNumElements() ;
02491         which = ubs.getIndices() ;
02492         values = ubs.getElements() ;
02493         for (j = 0;j<n;j++) {
02494           int iColumn = which[j] ;
02495           double value = solution[iColumn] ;
02496 #ifdef SBB_DEBUG
02497           printf("%d %g %g %g %g\n",iColumn,oldLower[iColumn],
02498                  solution[iColumn],oldUpper[iColumn],values[j]) ;
02499 #endif
02500           solver_->setColUpper(iColumn,values[j]) ;
02501           if (value>values[j]+integerTolerance)
02502             violated = -1 ;
02503           if (values[j]<lower[iColumn]-integerTolerance) {
02504             // infeasible
02505             violated = -2 ;
02506             break ;
02507           }
02508         }
02509       }
02510 #ifdef SBB_DEBUG
02511       delete [] oldLower ;
02512       delete [] oldUpper ;
02513 #endif
02514     }
02515 /*
02516   End installation of column cuts. The break here escapes the numberTries
02517   loop.
02518 */
02519     if (violated == -2) {
02520       // infeasible
02521       feasible = false ;
02522       break ;
02523     }
02524 /*
02525   Now apply the row (constraint) cuts. This is a bit more work because we need
02526   to obtain and augment the current basis.
02527 
02528   TODO: Why do this work, if there are no row cuts? The current basis will do
02529         just fine.
02530 */
02531     int numberRowsNow = solver_->getNumRows() ;
02532     assert(numberRowsNow == numberRowsAtStart+lastNumberCuts) ;
02533     int numberToAdd = theseCuts.sizeRowCuts() ;
02534     numberNewCuts = lastNumberCuts+numberToAdd ;
02535 /*
02536   Get a basis by asking the solver for warm start information. Resize it
02537   (retaining the basis) so it can accommodate the cuts.
02538 */
02539     delete basis_ ;
02540     basis_ = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()) ;
02541     assert(basis_ != NULL); // make sure not volume
02542     basis_->resize(numberRowsAtStart+numberNewCuts,numberColumns) ;
02543 /*
02544   Now actually add the row cuts and reoptimise.
02545 
02546   Install the cuts in the solver using applyRowCuts and
02547   augment the basis with the corresponding slack. We also add each row cut to
02548   the set of row cuts (cuts.insert()) supplied as a parameter. The new basis
02549   must be set with setWarmStart().
02550 
02551   TODO: It's not clear to me why we can't separate this into two sections.
02552         The first would add the row cuts, and be executed only if row cuts
02553         need to be installed. The second would call resolve() and would be
02554         executed if either row or column cuts have been installed.
02555 
02556   TODO: Seems to me the original code could allocate addCuts with size 0, if
02557         numberRowCuts was 0 and numberColumnCuts was nonzero. That might
02558         explain the memory fault noted in the comment by AJK.  Unfortunately,
02559         just commenting out the delete[] results in massive memory leaks. Try
02560         a revision to separate the row cut case. Why do we need addCuts at
02561         all? A typing issue, apparently: OsiCut vs. OsiRowCut.
02562 
02563   TODO: It looks to me as if numberToAdd and numberRowCuts are identical at
02564         this point. Confirm & get rid of one of them.
02565 
02566   TODO: Any reason why the three loops can't be consolidated?
02567 */
02568     if (numberRowCuts > 0 || numberColumnCuts > 0)
02569     { if (numberToAdd > 0)
02570       { int i ;
02571         OsiRowCut * addCuts = new OsiRowCut [numberToAdd] ;
02572         for (i = 0 ; i < numberToAdd ; i++)
02573         { addCuts[i] = theseCuts.rowCut(i) ; }
02574         solver_->applyRowCuts(numberToAdd,addCuts) ;
02575         // AJK this caused a memory fault on Win32
02576         delete [] addCuts ;
02577         for (i = 0 ; i < numberToAdd ; i++)
02578         { cuts.insert(theseCuts.rowCut(i)) ; }
02579         for (i = 0 ; i < numberToAdd ; i++)
02580         { basis_->setArtifStatus(numberRowsNow+i,
02581                                  CoinWarmStartBasis::basic) ; }
02582         if (solver_->setWarmStart(basis_) == false)
02583         { throw CoinError("Fail setWarmStart() after cut installation.",
02584                           "solveWithCuts","SbbModel") ; } }
02585       feasible = resolve() ;
02586 #     ifdef SBB_DEBUG
02587       printf("Obj value after cuts %g %d rows\n",solver_->getObjValue(),
02588               solver_->getNumRows()) ;
02589       if (onOptimalPath && !solver_->isDualObjectiveLimitReached())
02590         assert(feasible) ;
02591 #     endif
02592     }
02593 /*
02594   No cuts. Cut short the cut generation (numberTries) loop.
02595 */
02596     else
02597     { numberTries = 0 ; }
02598 /*
02599   If the problem is still feasible, first, call takeOffCuts() to remove cuts
02600   that are now slack. takeOffCuts() will call the solver to reoptimise if
02601   that's needed to restore a valid solution.
02602 
02603   Next, see if we should quit due to diminishing returns:
02604     * we've tried three rounds of cut generation and we're getting
02605       insufficient improvement in the objective; or
02606     * we generated no cuts; or
02607     * the solver declared optimality with 0 iterations after we added the
02608       cuts generated in this round.
02609   If we decide to keep going, prep for the next iteration.
02610 
02611   It just seems more safe to tell takeOffCuts() to call resolve(), even if
02612   we're not continuing cut generation. Otherwise code executed between here
02613   and final disposition of the node will need to be careful not to access the
02614   lp solution. It can happen that we loose feasibility in takeOffCuts ---
02615   numerical jitters when the cutoff bound is epsilon less than the current
02616   best, and we're evaluating an alternative optimum.
02617 
02618   TODO: After successive rounds of code motion, there seems no need to
02619         distinguish between the two checks for aborting the cut generation
02620         loop. Confirm and clean up.
02621 */
02622     if (feasible)
02623     { int cutIterations = solver_->getIterationCount() ;
02624       takeOffCuts(cuts,whichGenerator,numberOldActiveCuts,numberNewCuts,true) ;
02625       if (solver_->isDualObjectiveLimitReached())
02626       { feasible = false ;
02627 #       ifdef SBB_DEBUG
02628         double z = solver_->getObjValue() ;
02629         double cut = getCutoff() ;
02630         printf("Lost feasibility by %g in takeOffCuts; z = %g, cutoff = %g\n",
02631                z-cut,z,cut) ;
02632 #       endif
02633       }
02634       if (feasible)
02635       { numberRowsAtStart = numberOldActiveCuts+numberRowsAtContinuous_ ;
02636         lastNumberCuts = numberNewCuts ;
02637         if (direction*solver_->getObjValue() < lastObjective+minimumDrop &&
02638             numberPasses >= 3)
02639         { numberTries = 0 ; }
02640         if (numberRowCuts+numberColumnCuts == 0 || cutIterations == 0)
02641         { break ; }
02642         if (numberTries > 0)
02643         { reducedCostFix() ;
02644           lastObjective = direction*solver_->getObjValue() ;
02645           lower = solver_->getColLower() ;
02646           upper = solver_->getColUpper() ;
02647           solution = solver_->getColSolution() ; } } }
02648 /*
02649   We've lost feasibility --- this node won't be referencing the cuts we've
02650   been collecting, so decrement the reference counts.
02651 
02652   TODO: Presumably this is in preparation for backtracking. Seems like it
02653         should be the `else' off the previous `if'.
02654 */
02655     if (!feasible)
02656     { int i ;
02657       for (i = 0;i<currentNumberCuts_;i++) {
02658         // take off node
02659         if (addedCuts_[i]) {
02660           if (!addedCuts_[i]->decrement())
02661             delete addedCuts_[i] ;
02662           addedCuts_[i] = NULL ;
02663         }
02664       }
02665       numberTries = 0 ;
02666     }
02667   } while (numberTries) ;
02668 /*
02669   End of cut generation loop.
02670 
02671   Now, consider if we want to disable or adjust the frequency of use for any
02672   of the cut generators. If the client specified a positive number for
02673   howOften, it will never change. If the original value was negative, it'll
02674   be converted to 1000000+|howOften|, and this value will be adjusted each
02675   time fullScan is true. Actual cut generation is performed every
02676   howOften%1000000 nodes; the 1000000 offset is just a convenient way to
02677   specify that the frequency is adjustable.
02678 
02679   During cut generation, we recorded the number of cuts produced by each
02680   generator for this node. For all cuts, whichGenerator records the generator
02681   that produced a cut.
02682 
02683   TODO: All this should probably be hidden in a method of the SbbCutGenerator
02684   class.
02685 */
02686   if (feasible&&fullScan&&numberCutGenerators_) {
02687     // Root node or every so often - see what to turn off
02688     int i ;
02689     double thisObjective = solver_->getObjValue()*direction ;
02690     double totalCuts = 0.0 ;
02691     for (i = 0;i<numberCutGenerators_;i++) 
02692       totalCuts += countRowCuts[i] + 5.0*countColumnCuts[i] ;
02693     if (!numberNodes_)
02694       handler_->message(SBB_ROOT,messages_)
02695         <<numberNewCuts
02696         <<startObjective<<thisObjective
02697         <<numberPasses
02698         <<CoinMessageEol ;
02699     int * count = new int[numberCutGenerators_] ;
02700     memset(count,0,numberCutGenerators_*sizeof(int)) ;
02701     for (i = 0;i<numberNewCuts;i++) 
02702       count[whichGenerator[i]]++ ;
02703     double small = (0.5* totalCuts) /
02704       ((double) numberCutGenerators_) ;
02705     for (i = 0;i<numberCutGenerators_;i++) {
02706       int howOften = generator_[i]->howOften() ;
02707       if (howOften<-99)
02708         continue ;
02709       if (howOften<0||howOften >= 1000000) {
02710         // If small number switch mostly off
02711         double thisCuts = countRowCuts[i] + 5.0*countColumnCuts[i] ;
02712         if (!thisCuts||howOften == -99) {
02713           if (howOften == -99)
02714             howOften = -100 ;
02715           else
02716             howOften = 1000000+SCANCUTS; // wait until next time
02717         } else if (thisCuts<small) {
02718           int k = (int) sqrt(small/thisCuts) ;
02719           howOften = k+1000000 ;
02720         } else {
02721           howOften = 1+1000000 ;
02722         }
02723       }
02724       generator_[i]->setHowOften(howOften) ;
02725       int newFrequency = generator_[i]->howOften()%1000000 ;
02726       if (handler_->logLevel()>1||!numberNodes_)
02727         handler_->message(SBB_GENERATOR,messages_)
02728           <<i
02729           <<generator_[i]->cutGeneratorName()
02730           <<countRowCuts[i]<<count[i]
02731           <<countColumnCuts[i]
02732           <<newFrequency
02733           <<CoinMessageEol ;
02734     }
02735     delete [] count ;
02736   }
02737 
02738   delete [] countRowCuts ;
02739   delete [] countColumnCuts ;
02740 
02741 
02742 #ifdef CHECK_CUT_COUNTS
02743   if (feasible)
02744   { delete basis_ ;
02745     basis_ = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()) ;
02746     printf("solveWithCuts: Number of rows at end (only active cuts) %d\n",
02747            numberRowsAtContinuous_+numberNewCuts+numberOldActiveCuts) ;
02748     basis_->print() ; }
02749 #endif
02750 #ifdef SBB_DEBUG
02751   if (onOptimalPath && !solver_->isDualObjectiveLimitReached())
02752     assert(feasible) ;
02753 #endif
02754 
02755   return feasible ; }

int SbbModel::status  )  const [inline]
 

Final status of problem

0 finished, 1 stopped, 2 difficulties

Definition at line 460 of file SbbModel.hpp.

References status_.

Referenced by addCuts(), and takeOffCuts().

00461     { return status_;};

void SbbModel::synchronizeModel  ) 
 

Ensure attached objects point to this model.

Ensure all attached objects (SbbObjects, heuristics, and cut generators) point to this model.

Definition at line 3269 of file SbbModel.cpp.

References numberCutGenerators_, numberHeuristics_, numberObjects_, object_, SbbCutGenerator::refreshModel(), SbbObject::setModel(), and SbbHeuristic::setModel().

Referenced by branchAndBound(), findCliques(), integerPresolve(), integerPresolveThisModel(), operator=(), originalModel(), and SbbModel().

03270 {
03271   int i;
03272   for (i=0;i<numberHeuristics_;i++) 
03273     heuristic_[i]->setModel(this);
03274   for (i=0;i<numberObjects_;i++)
03275     object_[i]->setModel(this);
03276   for (i=0;i<numberCutGenerators_;i++)
03277     generator_[i]->refreshModel(this);
03278 }

void SbbModel::takeOffCuts OsiCuts cuts,
int *  whichGenerator,
int &  numberOldActiveCuts,
int &  numberNewCuts,
bool  allowResolve
 

Remove inactive cuts from the model

An OsiSolverInterface is expected to maintain a valid basis, but not a valid solution, when loose cuts are deleted. Restoring a valid solution requires calling the solver to reoptimise. If it's certain the solution will not be required, set allowResolve to false to suppress reoptimisation.

Definition at line 2802 of file SbbModel.cpp.

References addedCuts_, currentNumberCuts_, SbbCountRowCut::decrement(), OsiSolverInterface::deleteRows(), OsiCuts::eraseRowCut(), CoinWarmStartBasis::getArtifStatus(), OsiSolverInterface::getIterationCount(), OsiSolverInterface::getWarmStart(), numberRowsAtContinuous_, OsiSolverInterface::resolve(), solver_, and status().

Referenced by branchAndBound(), and solveWithCuts().

02806 { // int resolveIterations = 0 ;
02807   int firstOldCut = numberRowsAtContinuous_ ;
02808   int totalNumberCuts = numberNewCuts+numberOldActiveCuts ;
02809   int *solverCutIndices = new int[totalNumberCuts] ;
02810   int *newCutIndices = new int[numberNewCuts] ;
02811   const CoinWarmStartBasis* ws ;
02812   CoinWarmStartBasis::Status status ;
02813   bool needPurge = true ;
02814 /*
02815   The outer loop allows repetition of purge in the event that reoptimisation
02816   changes the basis. To start an iteration, clear the deletion counts and grab
02817   the current basis.
02818 */
02819   while (needPurge)
02820   { int numberNewToDelete = 0 ;
02821     int numberOldToDelete = 0 ;
02822     int i ;
02823     ws = dynamic_cast<const CoinWarmStartBasis*>(solver_->getWarmStart()) ;
02824 /*
02825   Scan the basis entries of the old cuts generated prior to this round of cut
02826   generation.  Loose cuts are `removed' by decrementing their reference count
02827   and setting the addedCuts_ entry to NULL. (If the reference count falls to
02828   0, they're really deleted.  See SbbModel and SbbCountRowCut doc'n for
02829   principles of cut handling.)
02830 */
02831     int oldCutIndex = 0 ;
02832     for (i = 0 ; i < numberOldActiveCuts ; i++)
02833     { status = ws->getArtifStatus(i+firstOldCut) ;
02834       while (!addedCuts_[oldCutIndex]) oldCutIndex++ ;
02835       assert(oldCutIndex < currentNumberCuts_) ;
02836       if (status == CoinWarmStartBasis::basic)
02837       { solverCutIndices[numberOldToDelete++] = i+firstOldCut ;
02838         if (addedCuts_[oldCutIndex]->decrement() == 0)
02839           delete addedCuts_[oldCutIndex] ;
02840         addedCuts_[oldCutIndex] = NULL ;
02841         oldCutIndex++ ; }
02842       else
02843       { oldCutIndex++ ; } }
02844 /*
02845   Scan the basis entries of the new cuts generated with this round of cut
02846   generation.  At this point, newCuts is the only record of the new cuts, so
02847   when we delete loose cuts from newCuts, they're really gone. newCuts is a
02848   vector, so it's most efficient to compress it (eraseRowCut) from back to
02849   front.
02850 */
02851     int firstNewCut = firstOldCut+numberOldActiveCuts ;
02852     int k = 0 ;
02853     for (i = 0 ; i < numberNewCuts ; i++)
02854     { status = ws->getArtifStatus(i+firstNewCut) ;
02855       if (status == CoinWarmStartBasis::basic)
02856       { solverCutIndices[numberNewToDelete+numberOldToDelete] = i+firstNewCut ;
02857         newCutIndices[numberNewToDelete++] = i ; }
02858       else
02859       { // save which generator did it
02860         whichGenerator[k++] = whichGenerator[i] ; } }
02861     for (i = numberNewToDelete-1 ; i >= 0 ; i--)
02862     { int iCut = newCutIndices[i] ;
02863       newCuts.eraseRowCut(iCut) ; }
02864 /*
02865   Did we delete anything? If so, delete the cuts from the constraint system
02866   held in the solver and reoptimise unless we're forbidden to do so. If the
02867   call to resolve() results in pivots, there's the possibility we again have
02868   basic slacks. Repeat the purging loop.
02869 */
02870     if (numberNewToDelete+numberOldToDelete > 0)
02871     { solver_->deleteRows(numberNewToDelete+numberOldToDelete,
02872                           solverCutIndices) ;
02873       numberNewCuts -= numberNewToDelete ;
02874       numberOldActiveCuts -= numberOldToDelete ;
02875 #     ifdef SBB_DEBUG
02876       std::cout << "takeOffCuts: purged " << numberOldToDelete << "+"
02877                 << numberNewToDelete << " cuts." << std::endl ;
02878 #     endif
02879       if (allowResolve)
02880       { solver_->resolve() ;
02881         if (solver_->getIterationCount() == 0)
02882         { needPurge = false ; }
02883 #       ifdef SBB_DEBUG
02884         else
02885         { std::cout << "Repeating purging loop. "
02886                     << solver_->getIterationCount() << " iters."
02887                     << std::endl ; }
02888 #       endif
02889       }
02890       else
02891       { needPurge = false ; } }
02892     else
02893     { needPurge = false ; } }
02894 /*
02895   Clean up and return.
02896 */
02897   delete ws ;
02898   delete [] solverCutIndices ;
02899   delete [] newCutIndices ;
02900 }

bool SbbModel::tightenVubs int  numberVubs,
const int *  which,
double  useCutoff = 1.0e50
 

For variables involved in VUB constraints, see if we can tighten bounds by solving lp's.

This version is just handed a list of variables to be processed.

Definition at line 3794 of file SbbModel.cpp.

References OsiSolverInterface::addRow(), OsiSolverInterface::clone(), CglProbing::generateCutsAndModify(), SbbCutGenerator::generator(), OsiSolverInterface::getColLower(), OsiSolverInterface::getColSolution(), OsiSolverInterface::getColUpper(), getCutoff(), CglProbing::getMaxLook(), CglProbing::getMaxPass(), CglProbing::getMaxProbe(), OsiSolverInterface::getNumCols(), OsiSolverInterface::getObjCoefficients(), OsiSolverInterface::getObjSense(), OsiSolverInterface::getWarmStart(), handler_, SbbCutGenerator::howOften(), OsiSolverInterface::initialSolve(), CoinPackedVector::insert(), OsiSolverInterface::isInteger(), OsiSolverInterface::isProvenOptimal(), CoinMessageHandler::message(), messages_, numberCutGenerators_, printFrequency(), OsiSolverInterface::resolve(), CglProbing::rowCuts(), OsiSolverInterface::setColLower(), OsiSolverInterface::setColSolution(), OsiSolverInterface::setColUpper(), setCutoff(), SbbCutGenerator::setHowOften(), CglProbing::setMaxLook(), CglProbing::setMaxPass(), CglProbing::setMaxProbe(), OsiSolverInterface::setObjCoeff(), CglProbing::setRowCuts(), OsiSolverInterface::setWarmStart(), solver(), solver_, CglProbing::tightLower(), and CglProbing::tightUpper().

03796 {
03797 
03798   int numberColumns = solver_->getNumCols();
03799 
03800   int iColumn;
03801   
03802   OsiSolverInterface * solver = solver_;
03803   double saveCutoff = getCutoff() ;
03804   
03805   double * objective = new double[numberColumns];
03806   memcpy(objective,solver_->getObjCoefficients(),numberColumns*sizeof(double));
03807   double direction = solver_->getObjSense();
03808   
03809   // add in objective if there is a cutoff
03810   if (useCutoff<1.0e30) {
03811     // get new version of model
03812     solver = solver_->clone();
03813     CoinPackedVector newRow;
03814     for (iColumn=0;iColumn<numberColumns;iColumn++) {
03815       solver->setObjCoeff(iColumn,0.0); // zero out in new model
03816       if (objective[iColumn]) 
03817         newRow.insert(iColumn,direction * objective[iColumn]);
03818       
03819     }
03820     solver->addRow(newRow,-DBL_MAX,useCutoff);
03821     // signal no objective
03822     delete [] objective;
03823     objective=NULL;
03824   }
03825   setCutoff(DBL_MAX);
03826 
03827 
03828   bool * vub = new bool [numberColumns];
03829   int iVub;
03830 
03831   // mark vub columns
03832   for (iColumn=0;iColumn<numberColumns;iColumn++) 
03833     vub[iColumn]=false;
03834   for (iVub=0;iVub<numberSolves;iVub++) 
03835     vub[which[iVub]]=true;
03836   OsiCuts cuts;
03837   // First tighten bounds anyway if CglProbing there
03838   CglProbing* generator = NULL;
03839   int iGen;
03840   for (iGen=0;iGen<numberCutGenerators_;iGen++) {
03841     generator = dynamic_cast<CglProbing*>(generator_[iGen]->generator());
03842     if (generator)
03843       break;
03844   }
03845   int numberFixed=0;
03846   int numberTightened=0;
03847   int numberFixedByProbing=0;
03848   int numberTightenedByProbing=0;
03849   int printFrequency = (numberSolves+19)/20; // up to 20 messages
03850   int save[4];
03851   if (generator) {
03852     // set to cheaper and then restore at end
03853     save[0]=generator->getMaxPass();
03854     save[1]=generator->getMaxProbe();
03855     save[2]=generator->getMaxLook();
03856     save[3]=generator->rowCuts();
03857     generator->setMaxPass(1);
03858     generator->setMaxProbe(10);
03859     generator->setMaxLook(50);
03860     generator->setRowCuts(0);
03861     
03862     // Probing - return tight column bounds
03863     generator->generateCutsAndModify(*solver,cuts);
03864     const double * tightLower = generator->tightLower();
03865     const double * lower = solver->getColLower();
03866     const double * tightUpper = generator->tightUpper();
03867     const double * upper = solver->getColUpper();
03868     for (iColumn=0;iColumn<numberColumns;iColumn++) {
03869       double newUpper = tightUpper[iColumn];
03870       double newLower = tightLower[iColumn];
03871       if (newUpper<upper[iColumn]-1.0e-8*(fabs(upper[iColumn])+1)||
03872           newLower>lower[iColumn]+1.0e-8*(fabs(lower[iColumn])+1)) {
03873         if (newUpper<newLower) {
03874           fprintf(stderr,"Problem is infeasible\n");
03875           return false;
03876         }
03877         if (newUpper==newLower) {
03878           numberFixed++;
03879           numberFixedByProbing++;
03880           solver->setColLower(iColumn,newLower);
03881           solver->setColUpper(iColumn,newUpper);
03882         } else if (vub[iColumn]) {
03883           numberTightened++;
03884           numberTightenedByProbing++;
03885           if (!solver->isInteger(iColumn)) {
03886             // relax
03887             newLower=max(lower[iColumn],
03888                                     newLower
03889                                     -1.0e-5*(fabs(lower[iColumn])+1));
03890             newUpper=min(upper[iColumn],
03891                                     newUpper
03892                                     +1.0e-5*(fabs(upper[iColumn])+1));
03893           }
03894           solver->setColLower(iColumn,newLower);
03895           solver->setColUpper(iColumn,newUpper);
03896         }
03897       }
03898     }
03899   }
03900   CoinWarmStart * ws = solver->getWarmStart();
03901   double * solution = new double [numberColumns];
03902   memcpy(solution,solver->getColSolution(),numberColumns*sizeof(double));
03903   for (iColumn=0;iColumn<numberColumns;iColumn++) 
03904     solver->setObjCoeff(iColumn,0.0);
03905   //solver->messageHandler()->setLogLevel(2);
03906   for (iVub=0;iVub<numberSolves;iVub++) {
03907     iColumn = which[iVub];
03908     int iTry;
03909     for (iTry=0;iTry<2;iTry++) {
03910       double saveUpper = solver->getColUpper()[iColumn];
03911       double saveLower = solver->getColLower()[iColumn];
03912       double value;
03913       if (iTry==1) {
03914         // try all way up
03915         solver->setObjCoeff(iColumn,-1.0);
03916       } else {
03917         // try all way down
03918         solver->setObjCoeff(iColumn,1.0);
03919       }
03920       solver->initialSolve();
03921       value = solver->getColSolution()[iColumn];
03922       bool change=false;
03923       if (iTry==1) {
03924         if (value<saveUpper-1.0e-4) {
03925           if (solver->isInteger(iColumn)) {
03926             value = floor(value+0.00001);
03927           } else {
03928             // relax a bit
03929             value=min(saveUpper,value+1.0e-5*(fabs(saveUpper)+1));
03930           }
03931           if (value-saveLower<1.0e-7) 
03932             value = saveLower; // make sure exactly same
03933           solver->setColUpper(iColumn,value);
03934           saveUpper=value;
03935           change=true;
03936         }
03937       } else {
03938         if (value>saveLower+1.0e-4) {
03939           if (solver->isInteger(iColumn)) {
03940             value = ceil(value-0.00001);
03941           } else {
03942             // relax a bit
03943             value=max(saveLower,value-1.0e-5*(fabs(saveLower)+1));
03944           }
03945           if (saveUpper-value<1.0e-7) 
03946             value = saveUpper; // make sure exactly same
03947           solver->setColLower(iColumn,value);
03948           saveLower=value;
03949           change=true;
03950         }
03951       }
03952       solver->setObjCoeff(iColumn,0.0);
03953       if (change) {
03954         if (saveUpper==saveLower) 
03955           numberFixed++;
03956         else
03957           numberTightened++;
03958         int saveFixed=numberFixed;
03959         
03960         int jColumn;
03961         if (generator) {
03962           // Probing - return tight column bounds
03963           cuts = OsiCuts();
03964           generator->generateCutsAndModify(*solver,cuts);
03965           const double * tightLower = generator->tightLower();
03966           const double * lower = solver->getColLower();
03967           const double * tightUpper = generator->tightUpper();
03968           const double * upper = solver->getColUpper();
03969           for (jColumn=0;jColumn<numberColumns;jColumn++) {
03970             double newUpper = tightUpper[jColumn];
03971             double newLower = tightLower[jColumn];
03972             if (newUpper<upper[jColumn]-1.0e-8*(fabs(upper[jColumn])+1)||
03973                 newLower>lower[jColumn]+1.0e-8*(fabs(lower[jColumn])+1)) {
03974               if (newUpper<newLower) {
03975                 fprintf(stderr,"Problem is infeasible\n");
03976                 return false;
03977               }
03978               if (newUpper==newLower) {
03979                 numberFixed++;
03980                 numberFixedByProbing++;
03981                 solver->setColLower(jColumn,newLower);
03982                 solver->setColUpper(jColumn,newUpper);
03983               } else if (vub[jColumn]) {
03984                 numberTightened++;
03985                 numberTightenedByProbing++;
03986                 if (!solver->isInteger(jColumn)) {
03987                   // relax
03988                   newLower=max(lower[jColumn],
03989                                newLower
03990                                -1.0e-5*(fabs(lower[jColumn])+1));
03991                   newUpper=min(upper[jColumn],
03992                                newUpper
03993                                +1.0e-5*(fabs(upper[jColumn])+1));
03994                 }
03995                 solver->setColLower(jColumn,newLower);
03996                 solver->setColUpper(jColumn,newUpper);
03997               }
03998             }
03999           }
04000         }
04001         if (numberFixed>saveFixed) {
04002           // original solution may not be feasible
04003           // go back to true costs to solve if exists
04004           if (objective) {
04005             for (jColumn=0;jColumn<numberColumns;jColumn++) 
04006               solver->setObjCoeff(jColumn,objective[jColumn]);
04007           }
04008           solver->setColSolution(solution);
04009           solver->setWarmStart(ws);
04010           solver->resolve();
04011           if (!solver->isProvenOptimal()) {
04012             fprintf(stderr,"Problem is infeasible\n");
04013             return false;
04014           }
04015           delete ws;
04016           ws = solver->getWarmStart();
04017           memcpy(solution,solver->getColSolution(),
04018                  numberColumns*sizeof(double));
04019           for (jColumn=0;jColumn<numberColumns;jColumn++) 
04020             solver->setObjCoeff(jColumn,0.0);
04021         }
04022       }
04023       solver->setColSolution(solution);
04024       solver->setWarmStart(ws);
04025     }
04026     if (iVub%printFrequency==0) 
04027       handler_->message(SBB_VUB_PASS,messages_)
04028         <<iVub+1<<numberFixed<<numberTightened
04029         <<CoinMessageEol;
04030   }
04031   handler_->message(SBB_VUB_END,messages_)
04032     <<numberFixed<<numberTightened
04033     <<CoinMessageEol;
04034   delete ws;
04035   delete [] solution;
04036   // go back to true costs to solve if exists
04037   if (objective) {
04038     for (iColumn=0;iColumn<numberColumns;iColumn++) 
04039       solver_->setObjCoeff(iColumn,objective[iColumn]);
04040     delete [] objective;
04041   }
04042   delete [] vub;
04043   if (generator) {
04044     /*printf("Probing fixed %d and tightened %d\n",
04045            numberFixedByProbing,
04046            numberTightenedByProbing);*/
04047     if (generator_[iGen]->howOften()==-1&&
04048         (numberFixedByProbing+numberTightenedByProbing)*5>
04049         (numberFixed+numberTightened))
04050       generator_[iGen]->setHowOften(1000000+1);
04051     generator->setMaxPass(save[0]);
04052     generator->setMaxProbe(save[1]);
04053     generator->setMaxLook(save[2]);
04054     generator->setRowCuts(save[3]);
04055   }
04056 
04057   if (solver!=solver_) {
04058     // move bounds across
04059     const double * lower = solver->getColLower();
04060     const double * upper = solver->getColUpper();
04061     const double * lowerOrig = solver_->getColLower();
04062     const double * upperOrig = solver_->getColUpper();
04063     for (iColumn=0;iColumn<numberColumns;iColumn++) {
04064       solver_->setColLower(iColumn,max(lower[iColumn],lowerOrig[iColumn]));
04065       solver_->setColUpper(iColumn,min(upper[iColumn],upperOrig[iColumn]));
04066     }
04067     delete solver;
04068   }
04069   setCutoff(saveCutoff);
04070   return true;
04071 }

bool SbbModel::tightenVubs int  type,
bool  allowMultipleBinary = false,
double  useCutoff = 1.0e50
 

For variables involved in VUB constraints, see if we can tighten bounds by solving lp's.

Returns false if feasibility is lost. If CglProbing is available, it will be tried as well to see if it can tighten bounds. This routine is just a front end for tightenVubs(int,const int*,double).

If type = -1 all variables are processed (could be very slow). If type = 0 only variables involved in VUBs are processed. If type = n > 0, only the n most expensive VUB variables are processed, where it is assumed that x is at its maximum so delta would have to go to 1 (if x not at bound).

If allowMultipleBinary is true, then a VUB constraint is a row with one continuous variable and any number of binary variables.

If useCutoff < 1.0e30, the original objective is installed as a constraint with useCutoff as a bound.

Definition at line 3711 of file SbbModel.cpp.

References OsiSolverInterface::getColLower(), OsiSolverInterface::getColSolution(), OsiSolverInterface::getColUpper(), OsiSolverInterface::getMatrixByRow(), OsiSolverInterface::getNumCols(), OsiSolverInterface::getNumRows(), OsiSolverInterface::getObjCoefficients(), OsiSolverInterface::isFreeBinary(), and solver_.

03712 {
03713 
03714   CoinPackedMatrix matrixByRow(*solver_->getMatrixByRow());
03715   int numberRows = solver_->getNumRows();
03716   int numberColumns = solver_->getNumCols();
03717 
03718   int iRow,iColumn;
03719 
03720   // Row copy
03721   //const double * elementByRow = matrixByRow.getElements();
03722   const int * column = matrixByRow.getIndices();
03723   const int * rowStart = matrixByRow.getVectorStarts();
03724   const int * rowLength = matrixByRow.getVectorLengths();
03725 
03726   const double * colUpper = solver_->getColUpper();
03727   const double * colLower = solver_->getColLower();
03728   //const double * rowUpper = solver_->getRowUpper();
03729   //const double * rowLower = solver_->getRowLower();
03730 
03731   const double * objective = solver_->getObjCoefficients();
03732   //double direction = solver_->getObjSense();
03733   const double * colsol = solver_->getColSolution();
03734 
03735   int numberVub=0;
03736   int * continuous = new int[numberColumns];
03737   if (type >= 0) {
03738     double * sort = new double[numberColumns];
03739     for (iRow=0;iRow<numberRows;iRow++) {
03740       int j;
03741       int numberBinary=0;
03742       int numberUnsatisfiedBinary=0;
03743       int numberContinuous=0;
03744       int iCont=-1;
03745       double weight=1.0e30;
03746       for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
03747         int iColumn = column[j];
03748         if (colUpper[iColumn]-colLower[iColumn]>1.0e-8) {
03749           if (solver_->isFreeBinary(iColumn)) {
03750             numberBinary++;
03751             /* For sort I make naive assumption:
03752                x - a * delta <=0 or
03753                -x + a * delta >= 0
03754             */
03755             if (colsol[iColumn]>colLower[iColumn]+1.0e-6&&
03756                 colsol[iColumn]<colUpper[iColumn]-1.0e-6) {
03757               numberUnsatisfiedBinary++;
03758               weight = min(weight,fabs(objective[iColumn]));
03759             }
03760           } else {
03761             numberContinuous++;
03762             iCont=iColumn;
03763           }
03764         }
03765       }
03766       if (numberContinuous==1&&numberBinary) {
03767         if (numberBinary==1||allowMultipleBinary) {
03768           // treat as vub
03769           if (!numberUnsatisfiedBinary)
03770             weight=-1.0; // at end
03771           sort[numberVub]=-weight;
03772           continuous[numberVub++] = iCont;
03773         }
03774       }
03775     }
03776     if (type>0) {
03777       // take so many
03778       CoinSort_2(sort,sort+numberVub,continuous);
03779       numberVub = min(numberVub,type);
03780     }
03781     delete [] sort;
03782   } else {
03783     for (iColumn=0;iColumn<numberColumns;iColumn++) 
03784       continuous[iColumn]=iColumn;
03785     numberVub=numberColumns;
03786   }
03787   bool feasible = tightenVubs(numberVub,continuous,useCutoff);
03788   delete [] continuous;
03789 
03790   return feasible;
03791 }


Member Data Documentation

SbbCountRowCut** SbbModel::addedCuts_ [private]
 

The list of cuts initially collected for this subproblem

When the subproblem at this node is rebuilt, a set of cuts is collected for inclusion in the constraint system. If any of these cuts are subsequently removed because they have become loose, the corresponding entry is set to NULL.

Definition at line 1010 of file SbbModel.hpp.

Referenced by addCuts(), addCuts1(), addedCuts(), branchAndBound(), gutsOfDestructor(), integerPresolveThisModel(), operator=(), SbbModel(), solveWithCuts(), and takeOffCuts().

CoinWarmStartBasis* SbbModel::basis_ [private]
 

Pointer to a warm start basis.

Definition at line 950 of file SbbModel.hpp.

Referenced by addCuts(), assignSolver(), branchAndBound(), gutsOfDestructor(), operator=(), SbbModel(), and solveWithCuts().

double SbbModel::continuousObjective_ [private]
 

Value of objective at continuous

Should be an array with depths?

Definition at line 1063 of file SbbModel.hpp.

Referenced by branchAndBound(), getContinuousObjective(), and operator=().

double* SbbModel::currentSolution_ [private]
 

Array holding the current solution.

This array is used more as a temporary.

Definition at line 962 of file SbbModel.hpp.

Referenced by branchAndBound(), checkSolution(), currentSolution(), feasibleSolution(), gutsOfDestructor(), integerPresolveThisModel(), operator=(), originalModel(), SbbModel(), and setBestSolution().

bool SbbModel::defaultHandler_ [private]
 

Flag to say if handler_ is the default handler.

The default handler is deleted when the model is deleted. Other handlers (supplied by the client) will not be deleted.

Definition at line 928 of file SbbModel.hpp.

Referenced by operator=(), passInMessageHandler(), SbbModel(), and ~SbbModel().

CoinWarmStart* SbbModel::emptyWarmStart_ [mutable, private]
 

Pointer to an empty warm start object

It turns out to be useful to have this available as a base from which to build custom warm start objects. This is typed as CoinWarmStart rather than CoinWarmStartBasis to allow for the possibility that a client might want to apply a solver that doesn't use a basis-based warm start. See getEmptyBasis for an example of how this field can be used.

Definition at line 947 of file SbbModel.hpp.

Referenced by assignSolver(), getEmptyBasis(), gutsOfDestructor(), operator=(), and SbbModel().

int SbbModel::maximumDepth_ [private]
 

Current limit on search tree depth

The allocated size of walkback_. Increased as needed.

Definition at line 995 of file SbbModel.hpp.

Referenced by addCuts1(), branchAndBound(), integerPresolveThisModel(), operator=(), and SbbModel().

int SbbModel::numberStrong_ [private]
 

Maximum number of candidates to consider for strong branching.

To disable strong branching, set this to 0.

Definition at line 1025 of file SbbModel.hpp.

Referenced by numberStrong(), operator=(), and setNumberStrong().

SbbObject** SbbModel::object_ [private]
 

Integer and Clique and ... information.

Note:
The code assumes that the first objects on the list will be SimpleInteger objects for each integer variable, followed by Clique objects. Portions of the code that understand Clique objects will fail if they do not immediately follow the SimpleIntegers. Large chunks of the code will fail if the first objects are not SimpleInteger. As of 2003.08, SimpleIntegers and Cliques are the only objects.

Definition at line 1051 of file SbbModel.hpp.

Referenced by addObjects(), branchAndBound(), checkSolution(), deleteObjects(), feasibleSolution(), findCliques(), findIntegers(), gutsOfDestructor(), object(), objects(), operator=(), SbbModel(), and synchronizeModel().

bool SbbModel::ourSolver_ [private]
 

Ownership of the solver object

The convention is that SbbModel owns the null solver. Currently there is no public method to give SbbModel a solver without giving ownership, but the hook is here.

Definition at line 915 of file SbbModel.hpp.

Referenced by assignSolver(), operator=(), SbbModel(), and ~SbbModel().

SbbNodeInfo** SbbModel::walkback_ [private]
 

Array used to assemble the path between a node and the search tree root

The array is resized when necessary. maximumDepth_ is the current allocated size.

Definition at line 1001 of file SbbModel.hpp.

Referenced by addCuts1(), branchAndBound(), gutsOfDestructor(), integerPresolveThisModel(), operator=(), and SbbModel().


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