1
// Copyright (C) 2005, International Business Machines
2
// Corporation and others. All Rights Reserved.
4
// Turn off compiler warning about long names
5
# pragma warning(disable:4786)
12
// For Branch and bound
13
#include "OsiSolverInterface.hpp"
14
#include "CbcModel.hpp"
15
#include "CbcStrategy.hpp"
16
#include "CbcBranchUser.hpp"
17
#include "CbcCompareUser.hpp"
18
#include "CbcCutGenerator.hpp"
19
#include "CbcHeuristicLocal.hpp"
20
#include "OsiClpSolverInterface.hpp"
24
#include "CglGomory.hpp"
25
#include "CglProbing.hpp"
26
#include "CglKnapsackCover.hpp"
27
#include "CglRedSplit.hpp"
28
#include "CglClique.hpp"
29
#include "CglFlowCover.hpp"
30
#include "CglMixedIntegerRounding2.hpp"
32
#include "CglPreProcess.hpp"
36
#include "CbcHeuristic.hpp"
38
#include "CoinTime.hpp"
40
//#############################################################################
43
/************************************************************************
45
This main program reads in an integer model from an mps file.
47
It then sets up some Cgl cut generators and calls branch and cut.
49
This is designed to show two things :-
51
1) Use of CbcStrategy to do preprocessing - this should be cleaner than old way
52
2) Looping round modifying solver and redoing branch and cut. This uses resetToReferenceCopy
53
which resets stuff like the cutoff and any memory of previous branch and cut.
55
************************************************************************/
58
int main (int argc, const char *argv[])
61
// Define your favorite OsiSolver
63
OsiClpSolverInterface solver1;
65
// Read in model using argv[1]
66
// and assert that it is a clean model
67
std::string mpsFileName = "../../Data/Sample/p0033.mps";
68
if (argc>=2) mpsFileName = argv[1];
69
int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),"");
70
assert(numMpsReadErrors==0);
71
double time1 = CoinCpuTime();
74
preprocess to do preprocessing
76
if 2 parameters and numeric taken as time
78
bool preProcess=false;
81
for (int iParam=2; iParam<argc;iParam++) {
82
if (!strcmp(argv[iParam],"preprocess")) {
85
} else if (!strcmp(argv[iParam],"time")) {
86
if (iParam+1<argc&&isdigit(argv[iParam+1][0])) {
87
minutes=atof(argv[iParam+1]);
90
iParam++; // skip time
95
if (nGoodParam==0&&argc==3&&isdigit(argv[2][0])) {
96
// If time is given then stop after that number of minutes
97
minutes = atof(argv[2]);
101
if (nGoodParam!=argc-2&&argc>=2) {
102
printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n");
105
//solver1.getModelPtr()->setLogLevel(0);
106
solver1.messageHandler()->setLogLevel(0);
107
solver1.initialSolve();
109
solver1.setHintParam(OsiDoReducePrint,true,OsiHintTry);
110
CbcModel model(solver1);
111
model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry);
112
// Set up some cut generators and defaults
113
// Probing first as gets tight bounds on continuous
115
CglProbing generator1;
116
generator1.setUsingObjective(true);
117
generator1.setMaxPass(1);
118
generator1.setMaxPassRoot(5);
119
// Number of unsatisfied variables to look at
120
generator1.setMaxProbe(10);
121
generator1.setMaxProbeRoot(1000);
122
// How far to follow the consequences
123
generator1.setMaxLook(50);
124
generator1.setMaxLookRoot(500);
125
// Only look at rows with fewer than this number of elements
126
generator1.setMaxElements(200);
127
generator1.setRowCuts(3);
129
CglGomory generator2;
131
generator2.setLimit(300);
133
CglKnapsackCover generator3;
135
CglRedSplit generator4;
137
generator4.setLimit(200);
139
CglClique generator5;
140
generator5.setStarCliqueReport(false);
141
generator5.setRowCliqueReport(false);
143
CglMixedIntegerRounding2 mixedGen;
144
CglFlowCover flowGen;
147
// Experiment with -1 and -99 etc
148
model.addCutGenerator(&generator1,-1,"Probing");
149
model.addCutGenerator(&generator2,-1,"Gomory");
150
model.addCutGenerator(&generator3,-1,"Knapsack");
151
// model.addCutGenerator(&generator4,-1,"RedSplit");
152
model.addCutGenerator(&generator5,-1,"Clique");
153
model.addCutGenerator(&flowGen,-1,"FlowCover");
154
model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding");
155
OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver());
158
// Turn this off if you get problems
159
// Used to be automatically set
160
osiclp->setSpecialOptions(128);
161
if(osiclp->getNumRows()<300&&osiclp->getNumCols()<500) {
162
//osiclp->setupForRepeatedUse(2,1);
163
osiclp->setupForRepeatedUse(0,1);
166
// Uncommenting this should switch off most CBC messages
167
//model.messagesPointer()->setDetailMessages(10,5,5000);
168
// Allow rounding heuristic
170
CbcRounding heuristic1(model);
171
model.addHeuristic(&heuristic1);
173
// And local search when new solution found
175
CbcHeuristicLocal heuristic2(model);
176
model.addHeuristic(&heuristic2);
178
// Redundant definition of default branching (as Default == User)
179
CbcBranchUserDecision branch;
180
model.setBranchingMethod(&branch);
182
// Definition of node choice
183
CbcCompareUser compare;
184
model.setNodeComparison(compare);
186
// Do initial solve to continuous
187
model.initialSolve();
190
double objValue = model.solver()->getObjSense()*model.solver()->getObjValue();
191
double minimumDropA=CoinMin(1.0,fabs(objValue)*1.0e-3+1.0e-4);
192
double minimumDrop= fabs(objValue)*1.0e-4+1.0e-4;
193
printf("min drop %g (A %g)\n",minimumDrop,minimumDropA);
194
model.setMinimumDrop(minimumDrop);
196
if (model.getNumCols()<500)
197
model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible
198
else if (model.getNumCols()<5000)
199
model.setMaximumCutPassesAtRoot(100); // use minimum drop
201
model.setMaximumCutPassesAtRoot(20);
202
model.setMaximumCutPasses(10);
203
//model.setMaximumCutPasses(2);
205
// Switch off strong branching if wanted
206
// model.setNumberStrong(0);
207
// Do more strong branching if small
208
if (model.getNumCols()<5000)
209
model.setNumberStrong(10);
210
model.setNumberStrong(20);
211
//model.setNumberStrong(5);
212
model.setNumberBeforeTrust(5);
213
//model.setSizeMiniTree(2);
215
model.solver()->setIntParam(OsiMaxNumIterationHotStart,100);
217
// If time is given then stop after that number of minutes
219
std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl;
220
model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes);
222
// Switch off most output
223
if (model.getNumCols()<3000) {
224
model.messageHandler()->setLogLevel(1);
225
//model.solver()->messageHandler()->setLogLevel(0);
227
model.messageHandler()->setLogLevel(2);
228
model.solver()->messageHandler()->setLogLevel(1);
230
// Default strategy will leave cut generators as they exist already
231
// so cutsOnlyAtRoot (1) ignored
232
// numberStrong (2) is 5 (default)
233
// numberBeforeTrust (3) is 5 (default is 0)
234
// printLevel (4) defaults (0)
235
CbcStrategyDefault strategy(true,5,5);
236
// Set up pre-processing to find sos if wanted
238
strategy.setupPreProcessing(2);
239
model.setStrategy(strategy);
241
// Go round adding cuts to cutoff last solution
242
// Stop after finding 20 best solutions
243
for (int iPass=0;iPass<20;iPass++) {
244
time1 = CoinCpuTime();
245
// Do complete search
246
model.branchAndBound();
248
std::cout<<mpsFileName<<" took "<<CoinCpuTime()-time1<<" seconds, "
249
<<model.getNodeCount()<<" nodes with objective "
250
<<model.getObjValue()
251
<<(!model.status() ? " Finished" : " Not finished")
253
// Stop if infeasible
254
if (model.isProvenInfeasible())
256
// Print solution if finished - we can't get names from Osi! - so get from OsiClp
258
assert (model.getMinimizationObjValue()<1.0e50);
259
OsiSolverInterface * solver = model.solver();
260
int numberColumns = solver->getNumCols();
262
const double * solution = model.bestSolution();
263
//const double * lower = solver->getColLower();
264
//const double * upper = solver->getColUpper();
266
// Get names from solver1 (as OsiSolverInterface may lose)
267
std::vector<std::string> columnNames = *solver1.getModelPtr()->columnNames();
270
std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14);
272
std::cout<<"--------------------------------------"<<std::endl;
273
for (iColumn=0;iColumn<numberColumns;iColumn++) {
274
double value=solution[iColumn];
275
if (fabs(value)>1.0e-7&&solver->isInteger(iColumn))
276
std::cout<<std::setw(6)<<iColumn<<" "
277
<<columnNames[iColumn]<<" "
279
//<<" "<<lower[iColumn]<<" "<<upper[iColumn]
282
std::cout<<"--------------------------------------"<<std::endl;
284
std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific);
285
/* Now add cut to reference copy.
286
resetting to reference copy also gets rid of best solution so we
287
should either save best solution, reset, add cut OR
288
add cut to reference copy then reset - this is doing latter
290
OsiSolverInterface * refSolver = model.referenceSolver();
291
const double * bestSolution = model.bestSolution();
292
const double * originalLower = refSolver->getColLower();
293
const double * originalUpper = refSolver->getColUpper();
294
CoinPackedVector cut;
296
for (iColumn=0;iColumn<numberColumns;iColumn++) {
297
double value=bestSolution[iColumn];
298
if (solver->isInteger(iColumn)) {
299
// only works for 0-1 variables
300
assert (originalLower[iColumn]==0.0&&
301
originalUpper[iColumn]==1.0);
302
// double check integer
303
assert (fabs(floor(value+0.5)-value)<1.0e-5);
306
cut.insert(iColumn,-1.0);
310
cut.insert(iColumn,1.0);
315
refSolver->addRow(cut,rhs,COIN_DBL_MAX);
316
model.resetToReferenceSolver();