source: trunk/Cbc/examples/repeat.cpp

Last change on this file was 2469, checked in by unxusr, 6 weeks ago

formatting

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1// $Id: repeat.cpp 2469 2019-01-06 23:17:46Z unxusr $
2// Copyright (C) 2005, International Business Machines
3// Corporation and others.  All Rights Reserved.
4// This code is licensed under the terms of the Eclipse Public License (EPL).
5
6#include <cassert>
7#include <iomanip>
8
9#include "CoinPragma.hpp"
10
11// For Branch and bound
12#include "OsiSolverInterface.hpp"
13#include "CbcModel.hpp"
14#include "CbcStrategy.hpp"
15#include "CbcBranchUser.hpp"
16#include "CbcCompareUser.hpp"
17#include "CbcCutGenerator.hpp"
18#include "CbcHeuristicLocal.hpp"
19#include "OsiClpSolverInterface.hpp"
20
21// Cuts
22
23#include "CglGomory.hpp"
24#include "CglProbing.hpp"
25#include "CglKnapsackCover.hpp"
26#include "CglRedSplit.hpp"
27#include "CglClique.hpp"
28#include "CglFlowCover.hpp"
29#include "CglMixedIntegerRounding2.hpp"
30// Preprocessing
31#include "CglPreProcess.hpp"
32
33// Heuristics
34
35#include "CbcHeuristic.hpp"
36
37#include "CoinTime.hpp"
38
39//#############################################################################
40
41/************************************************************************
42
43This main program reads in an integer model from an mps file.
44
45It then sets up some Cgl cut generators and calls branch and cut.
46
47This is designed to show two things :-
48
491) Use of CbcStrategy to do preprocessing - this should be cleaner than old way
502) Looping round modifying solver and redoing branch and cut.  This uses resetToReferenceCopy
51   which resets stuff like the cutoff and any memory of previous branch and cut.
52
53************************************************************************/
54
55int main(int argc, const char *argv[])
56{
57
58  // Define your favorite OsiSolver
59
60  OsiClpSolverInterface solver1;
61
62  // Read in model using argv[1]
63  // and assert that it is a clean model
64  std::string mpsFileName;
65#if defined(SAMPLEDIR)
66  mpsFileName = SAMPLEDIR "/p0033.mps";
67#else
68  if (argc < 2) {
69    fprintf(stderr, "Do not know where to find sample MPS files.\n");
70    exit(1);
71  }
72#endif
73  if (argc >= 2)
74    mpsFileName = argv[1];
75  int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(), "");
76  if (numMpsReadErrors != 0) {
77    printf("%d errors reading MPS file\n", numMpsReadErrors);
78    return numMpsReadErrors;
79  }
80  double time1 = CoinCpuTime();
81
82  /* Options are:
83     preprocess to do preprocessing
84     time in minutes
85     if 2 parameters and numeric taken as time
86  */
87  bool preProcess = false;
88  double minutes = -1.0;
89  int nGoodParam = 0;
90  for (int iParam = 2; iParam < argc; iParam++) {
91    if (!strcmp(argv[iParam], "preprocess")) {
92      preProcess = true;
93      nGoodParam++;
94    } else if (!strcmp(argv[iParam], "time")) {
95      if (iParam + 1 < argc && isdigit(argv[iParam + 1][0])) {
96        minutes = atof(argv[iParam + 1]);
97        if (minutes >= 0.0) {
98          nGoodParam += 2;
99          iParam++; // skip time
100        }
101      }
102    }
103  }
104  if (nGoodParam == 0 && argc == 3 && isdigit(argv[2][0])) {
105    // If time is given then stop after that number of minutes
106    minutes = atof(argv[2]);
107    if (minutes >= 0.0)
108      nGoodParam = 1;
109  }
110  if (nGoodParam != argc - 2 && argc >= 2) {
111    printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n");
112    exit(1);
113  }
114  //solver1.getModelPtr()->setLogLevel(0);
115  solver1.messageHandler()->setLogLevel(0);
116  solver1.initialSolve();
117  // Reduce printout
118  solver1.setHintParam(OsiDoReducePrint, true, OsiHintTry);
119  CbcModel model(solver1);
120  model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
121  // Set up some cut generators and defaults
122  // Probing first as gets tight bounds on continuous
123
124  CglProbing generator1;
125  generator1.setUsingObjective(true);
126  generator1.setMaxPass(1);
127  generator1.setMaxPassRoot(5);
128  // Number of unsatisfied variables to look at
129  generator1.setMaxProbe(10);
130  generator1.setMaxProbeRoot(1000);
131  // How far to follow the consequences
132  generator1.setMaxLook(50);
133  generator1.setMaxLookRoot(500);
134  // Only look at rows with fewer than this number of elements
135  generator1.setMaxElements(200);
136  generator1.setRowCuts(3);
137
138  CglGomory generator2;
139  // try larger limit
140  generator2.setLimit(300);
141
142  CglKnapsackCover generator3;
143
144  CglRedSplit generator4;
145  // try larger limit
146  generator4.setLimit(200);
147
148  CglClique generator5;
149  generator5.setStarCliqueReport(false);
150  generator5.setRowCliqueReport(false);
151
152  CglMixedIntegerRounding2 mixedGen;
153  CglFlowCover flowGen;
154
155  // Add in generators
156  // Experiment with -1 and -99 etc
157  model.addCutGenerator(&generator1, -1, "Probing");
158  model.addCutGenerator(&generator2, -1, "Gomory");
159  model.addCutGenerator(&generator3, -1, "Knapsack");
160  // model.addCutGenerator(&generator4,-1,"RedSplit");
161  model.addCutGenerator(&generator5, -1, "Clique");
162  model.addCutGenerator(&flowGen, -1, "FlowCover");
163  model.addCutGenerator(&mixedGen, -1, "MixedIntegerRounding");
164  OsiClpSolverInterface *osiclp = dynamic_cast< OsiClpSolverInterface * >(model.solver());
165  // go faster stripes
166  if (osiclp) {
167    // Turn this off if you get problems
168    // Used to be automatically set
169    osiclp->setSpecialOptions(128);
170    if (osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500) {
171      //osiclp->setupForRepeatedUse(2,1);
172      osiclp->setupForRepeatedUse(0, 1);
173    }
174  }
175  // Uncommenting this should switch off most CBC messages
176  //model.messagesPointer()->setDetailMessages(10,5,5000);
177  // Allow rounding heuristic
178
179  CbcRounding heuristic1(model);
180  model.addHeuristic(&heuristic1);
181
182  // And local search when new solution found
183
184  CbcHeuristicLocal heuristic2(model);
185  model.addHeuristic(&heuristic2);
186
187  // Redundant definition of default branching (as Default == User)
188  CbcBranchUserDecision branch;
189  model.setBranchingMethod(&branch);
190
191  // Definition of node choice
192  CbcCompareUser compare;
193  model.setNodeComparison(compare);
194
195  // Do initial solve to continuous
196  model.initialSolve();
197
198  // Could tune more
199  double objValue = model.solver()->getObjSense() * model.solver()->getObjValue();
200  double minimumDropA = CoinMin(1.0, fabs(objValue) * 1.0e-3 + 1.0e-4);
201  double minimumDrop = fabs(objValue) * 1.0e-4 + 1.0e-4;
202  printf("min drop %g (A %g)\n", minimumDrop, minimumDropA);
203  model.setMinimumDrop(minimumDrop);
204
205  if (model.getNumCols() < 500)
206    model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible
207  else if (model.getNumCols() < 5000)
208    model.setMaximumCutPassesAtRoot(100); // use minimum drop
209  else
210    model.setMaximumCutPassesAtRoot(20);
211  model.setMaximumCutPasses(10);
212  //model.setMaximumCutPasses(2);
213
214  // Switch off strong branching if wanted
215  // model.setNumberStrong(0);
216  // Do more strong branching if small
217  if (model.getNumCols() < 5000)
218    model.setNumberStrong(10);
219  model.setNumberStrong(20);
220  //model.setNumberStrong(5);
221  model.setNumberBeforeTrust(5);
222  //model.setSizeMiniTree(2);
223
224  model.solver()->setIntParam(OsiMaxNumIterationHotStart, 100);
225
226  // If time is given then stop after that number of minutes
227  if (minutes >= 0.0) {
228    std::cout << "Stopping after " << minutes << " minutes" << std::endl;
229    model.setDblParam(CbcModel::CbcMaximumSeconds, 60.0 * minutes);
230  }
231  // Switch off most output
232  if (model.getNumCols() < 3000) {
233    model.messageHandler()->setLogLevel(1);
234    //model.solver()->messageHandler()->setLogLevel(0);
235  } else {
236    model.messageHandler()->setLogLevel(2);
237    model.solver()->messageHandler()->setLogLevel(1);
238  }
239  // Default strategy will leave cut generators as they exist already
240  // so cutsOnlyAtRoot (1) ignored
241  // numberStrong (2) is 5 (default)
242  // numberBeforeTrust (3) is 5 (default is 0)
243  // printLevel (4) defaults (0)
244  CbcStrategyDefault strategy(true, 5, 5);
245  // Set up pre-processing to find sos if wanted
246  if (preProcess)
247    strategy.setupPreProcessing(2);
248  model.setStrategy(strategy);
249
250  // Go round adding cuts to cutoff last solution
251  // Stop after finding 20 best solutions
252  for (int iPass = 0; iPass < 20; iPass++) {
253    time1 = CoinCpuTime();
254    // Do complete search
255    model.branchAndBound();
256
257    std::cout << mpsFileName << " took " << CoinCpuTime() - time1 << " seconds, "
258              << model.getNodeCount() << " nodes with objective "
259              << model.getObjValue()
260              << (!model.status() ? " Finished" : " Not finished")
261              << std::endl;
262    // Stop if infeasible
263    if (model.isProvenInfeasible())
264      break;
265    // Print solution if finished - we can't get names from Osi! - so get from OsiClp
266
267    assert(model.getMinimizationObjValue() < 1.0e50);
268    OsiSolverInterface *solver = model.solver();
269    int numberColumns = solver->getNumCols();
270
271    const double *solution = model.bestSolution();
272    //const double * lower = solver->getColLower();
273    //const double * upper = solver->getColUpper();
274
275    // Get names from solver1 (as OsiSolverInterface may lose)
276    std::vector< std::string > columnNames = *solver1.getModelPtr()->columnNames();
277
278    int iColumn;
279    std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14);
280
281    std::cout << "--------------------------------------" << std::endl;
282    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
283      double value = solution[iColumn];
284      if (fabs(value) > 1.0e-7 && solver->isInteger(iColumn))
285        std::cout << std::setw(6) << iColumn << " "
286                  << columnNames[iColumn] << " "
287                  << value
288                  //<<" "<<lower[iColumn]<<" "<<upper[iColumn]
289                  << std::endl;
290    }
291    std::cout << "--------------------------------------" << std::endl;
292
293    std::cout << std::resetiosflags(std::ios::fixed | std::ios::showpoint | std::ios::scientific);
294    /* Now add cut to reference copy.
295       resetting to reference copy also gets rid of best solution so we
296       should either save best solution, reset, add cut OR
297       add cut to reference copy then reset - this is doing latter
298    */
299    OsiSolverInterface *refSolver = model.referenceSolver();
300    const double *bestSolution = model.bestSolution();
301#ifndef NDEBUG
302    const double *originalLower = refSolver->getColLower();
303    const double *originalUpper = refSolver->getColUpper();
304#endif
305    CoinPackedVector cut;
306    double rhs = 1.0;
307    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
308      double value = bestSolution[iColumn];
309      if (solver->isInteger(iColumn)) {
310        // only works for 0-1 variables
311        assert(originalLower[iColumn] == 0.0 && originalUpper[iColumn] == 1.0);
312        // double check integer
313        assert(fabs(floor(value + 0.5) - value) < 1.0e-5);
314        if (value > 0.5) {
315          // at 1.0
316          cut.insert(iColumn, -1.0);
317          rhs -= 1.0;
318        } else {
319          // at 0.0
320          cut.insert(iColumn, 1.0);
321        }
322      }
323    }
324    // now add cut
325    refSolver->addRow(cut, rhs, COIN_DBL_MAX);
326    model.resetToReferenceSolver();
327  }
328  return 0;
329}
Note: See TracBrowser for help on using the repository browser.