#include <SbbModel.hpp>
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 | |
SbbModel * | findCliques (bool makeEquality, int atLeastThisMany, int lessThanThis, int defaultValue=1000) |
SbbModel * | integerPresolve (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 | |
int | numberObjects () const |
Get the number of objects. | |
SbbObject ** | objects () const |
Get the array of objects. | |
const SbbObject * | object (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 | |
SbbBranchDecision * | branchingMethod () 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 () |
CoinWarmStartBasis * | getEmptyBasis (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. | |
SbbCutGenerator * | cutGenerator (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) |
CoinMessageHandler * | messageHandler () const |
Return handler. | |
CoinMessages | messages () |
Return messages. | |
CoinMessages * | messagesPointer () |
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. | |
SbbModel & | operator= (const SbbModel &rhs) |
Assignment operator. | |
~SbbModel () | |
Destructor. | |
OsiSolverInterface * | solver () const |
Returns solver - has current state. | |
OsiSolverInterface * | continuousSolver () const |
Returns solver with continuous state. | |
void | gutsOfDestructor () |
Clears out as much as possible (except solver). | |
Private Attributes | |
Private member data | |
OsiSolverInterface * | solver_ |
The solver associated with this model. | |
bool | ourSolver_ |
OsiSolverInterface * | continuousSolver_ |
A copy of the solver, taken at the continuous (root) node. | |
CoinMessageHandler * | handler_ |
Message handler. | |
bool | defaultHandler_ |
CoinMessages | messages_ |
Sbb messages. | |
int | intParam_ [SbbLastIntParam] |
Array for integer parameters. | |
double | dblParam_ [SbbLastDblParam] |
Array for double parameters. | |
CoinWarmStart * | emptyWarmStart_ |
CoinWarmStartBasis * | basis_ |
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. | |
SbbBranchDecision * | branchingMethod_ |
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. |
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.
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:
For a typical subproblem, the sequence of events is as follows:
Definition at line 80 of file SbbModel.hpp.
|
Definition at line 103 of file SbbModel.hpp.
00103 { 00106 SbbIntegerTolerance=0, 00109 SbbInfeasibilityWeight, 00112 SbbCutoffIncrement, 00119 SbbAllowableGap, 00122 SbbMaximumSeconds, 00124 SbbLastDblParam 00125 }; |
|
Definition at line 84 of file SbbModel.hpp.
00084 { 00086 SbbMaxNumNode=0, 00088 SbbMaxNumSol, 00098 SbbFathomDiscipline, 00100 SbbLastIntParam 00101 }; |
|
|
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 } |
|
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 } |
|
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 } |
|
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.
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 } |
|
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 } |
|
Assign a solver to the model (model assumes ownership)
On return,
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 } |
|
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_;}; |
|
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 ; } |
|
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 } |
|
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_;}; |
|
Test the current solution for feasiblility.
Scan all objects for indications of infeasibility. This is broken down into simple integer infeasibility ( 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 } |
|
Identify cliques and construct corresponding objects.
Find cliques with size in the range [ 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 } |
|
Identify integer variables and create corresponding objects.
Record integer variables and create an SbbSimpleInteger object for each one. If 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 } |
|
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 } |
|
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) ; } |
|
Get the weight per integer infeasibility Definition at line 364 of file SbbModel.hpp. References getDblParam(), and SbbInfeasibilityWeight.
00364 { 00365 return getDblParam(SbbInfeasibilityWeight); 00366 } |
|
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 } |
|
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_;}; |
|
Get the maximum number of cut passes at root node Definition at line 400 of file SbbModel.hpp. References maximumCutPassesAtRoot_.
00401 { return maximumCutPassesAtRoot_;}; |
|
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 } |
|
Get pointer to array[getNumRows()] of rows right-hand sides
Definition at line 529 of file SbbModel.hpp. References OsiSolverInterface::getRightHandSide(), and solver_.
00530 { return solver_->getRightHandSide();}; |
|
Get pointer to array[getNumRows()] of row ranges.
Definition at line 540 of file SbbModel.hpp. References OsiSolverInterface::getRowRange(), and solver_.
00541 { return solver_->getRowRange();}; |
|
Get pointer to array[getNumRows()] of row constraint senses.
Definition at line 518 of file SbbModel.hpp. References OsiSolverInterface::getRowSense(), and solver_.
00519 { return solver_->getRowSense();}; |
|
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 } |
|
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
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 } |
|
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 } |
|
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().
|
|
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_;}; |
|
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 } |
|
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 ; } |
|
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 ; } |
|
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 } |
|
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;}; |
|
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); } |
|
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 } |
|
Set the integrality tolerance Definition at line 343 of file SbbModel.hpp. References SbbIntegerTolerance, and setDblParam().
00343 { 00344 return setDblParam(SbbIntegerTolerance,value); 00345 } |
|
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;}; |
|
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;}; |
|
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 } |
|
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 } |
|
Set the print frequency.
Controls the number of nodes evaluated between status prints. If Definition at line 430 of file SbbModel.hpp. References printFrequency_.
00431 { printFrequency_=number;}; |
|
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 ; } |
|
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_;}; |
|
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 } |
|
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 } |
|
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 } |
|
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
If
If 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 } |
|
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(). |
|
Pointer to a warm start basis. Definition at line 950 of file SbbModel.hpp. Referenced by addCuts(), assignSolver(), branchAndBound(), gutsOfDestructor(), operator=(), SbbModel(), and solveWithCuts(). |
|
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=(). |
|
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(). |
|
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(). |
|
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(). |
|
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(). |
|
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(). |
|
Integer and Clique and ... information.
Definition at line 1051 of file SbbModel.hpp. Referenced by addObjects(), branchAndBound(), checkSolution(), deleteObjects(), feasibleSolution(), findCliques(), findIntegers(), gutsOfDestructor(), object(), objects(), operator=(), SbbModel(), and synchronizeModel(). |
|
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(). |
|
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(). |