source: branches/devel/Cbc/src/CbcGeneric.cpp @ 591

Last change on this file since 591 was 591, checked in by lou, 13 years ago

Initial commit of cbc-generic source.

  • Property svn:eol-style set to native
File size: 11.8 KB
Line 
1/*
2  Copyright (C) 2007, Lou Hafer, International Business Machines Corporation
3  and others.  All Rights Reserved.
4
5  This file is part of cbc-generic.
6*/
7
8#include "CbcConfig.h"
9#include "CoinPragma.hpp"
10
11#include <cassert>
12#include <typeinfo>
13#include <cstdio>
14#include <cmath>
15#include <cfloat>
16#include <string>
17#include <iostream>
18
19#include "CoinFileIO.hpp"
20#include "CoinMpsIO.hpp"
21#include "CoinPackedMatrix.hpp"
22#include "CoinPackedVector.hpp"
23#include "CoinWarmStartBasis.hpp"
24#include "CoinTime.hpp"
25#include "OsiSolverInterface.hpp"
26#include "OsiCuts.hpp"
27#include "OsiRowCut.hpp"
28#include "OsiColCut.hpp"
29
30#include "CglCutGenerator.hpp"
31#include "CglProbing.hpp"
32#include "CglClique.hpp"
33#include "CglFlowCover.hpp"
34#include "CglGomory.hpp"
35#include "CglKnapsackCover.hpp"
36#include "CglMixedIntegerRounding2.hpp"
37#include "CglOddHole.hpp"
38#include "CglRedSplit.hpp"
39#include "CglTwomir.hpp"
40
41#include "CglPreProcess.hpp"
42
43#include "CbcModel.hpp"
44#include "CbcEventHandler.hpp"
45#include "CbcTree.hpp"
46#include "CbcCutGenerator.hpp"
47#include "CbcHeuristic.hpp"
48#include "CbcHeuristicFPump.hpp"
49#include "CbcHeuristicGreedy.hpp"
50#include "CbcHeuristicLocal.hpp"
51#include "CbcTreeLocal.hpp"
52#include "CbcCompareActual.hpp"
53
54#include "CoinParam.hpp"
55
56#include "CbcGenCtlBlk.hpp"
57#include "CbcGenParam.hpp"
58#include "CbcGenCbcParam.hpp"
59#include "CbcGenOsiParam.hpp"
60
61namespace CbcGenSolvers
62{
63  OsiSolverInterface *setupSolvers() ;
64  void deleteSolvers() ;
65}
66
67/*
68  Unnamed local namespace for cbc-generic support types and functions.
69*/
70
71namespace {
72
73/*
74  Utility to mark the parameter as having been set by the user. This is a
75  bit clumsy --- we need to cast to a derived parameter type to get the
76  parameter code. But it'll do 'til I think of a better way.
77*/
78
79void markAsSetByUser (CbcGenCtlBlk &ctlBlk, CoinParam *param)
80
81{ CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
82  CbcCbcParam *cbcParam = dynamic_cast<CbcCbcParam *>(param) ;
83  CbcOsiParam *osiParam = dynamic_cast<CbcOsiParam *>(param) ;
84  int code = -1 ;
85
86  if (genParam != 0)
87  { code = genParam->paramCode() ; }
88  else
89  if (cbcParam != 0)
90  { code = cbcParam->paramCode() ; }
91  else
92  if (osiParam != 0)
93  { code = osiParam->paramCode() ; }
94  else
95  { std::cerr
96      << "Unrecognised parameter class! Serious internal confusion."
97      << std::endl ; }
98
99  if (code >= 0)
100  { ctlBlk.setByUser_[code] = true ; }
101
102  return ; }
103
104
105} // end unnamed namespace
106
107int main (int argc, const char *argv[])
108{
109/*
110  This interior block contains all memory allocation; useful for debugging.
111*/
112{ double time1 = CoinCpuTime() ;
113  double time2 ;
114/*
115  Try and get all the various i/o to come out in order. Synchronise with C
116  stdio and make stderr and stdout unbuffered.
117*/
118  std::ios::sync_with_stdio() ;
119  setbuf(stderr,0) ;
120  setbuf(stdout,0) ;
121/*
122  The constructor for ctlBlk establishes the default values for cbc-generic
123  parameters. A little more work is required to create the vector of available
124  solvers and set the default.
125*/
126  CbcGenCtlBlk ctlBlk ;
127  OsiSolverInterface *dfltSolver = CbcGenSolvers::setupSolvers() ;
128  ctlBlk.dfltSolver_ = dfltSolver ;
129  assert (ctlBlk.dfltSolver_) ;
130/*
131  Now we can begin to initialise the parameter vector. Create a vector of the
132  proper size, then load up the parameters that are relevant to the main
133  program (specifically, values held in ctlBlk and actions evoked from the
134  main program).
135*/
136  int numParams = 0 ;
137  CoinParamVec paramVec ;
138  paramVec.reserve(CbcOsiParam::CBCOSI_LASTPARAM) ;
139  ctlBlk.paramVec_ = &paramVec ;
140  ctlBlk.genParams_.first_ = numParams ;
141  CbcGenParamUtils::addCbcGenParams(numParams,paramVec,&ctlBlk) ;
142  ctlBlk.genParams_.last_ = numParams-1 ;
143/*
144  Establish a CbcModel object with the default lp solver. Install any defaults
145  that are available from ctlBlk.
146*/
147  CbcModel *model = new CbcModel(*dfltSolver) ;
148  ctlBlk.model_ = model ;
149  model->messageHandler()->setLogLevel(1) ;
150  model->setNumberStrong(ctlBlk.chooseStrong_.numStrong_) ;
151  model->setNumberBeforeTrust(ctlBlk.chooseStrong_.numBeforeTrust_) ;
152  CbcCbcParamUtils::setCbcModelDefaults(model) ;
153  OsiSolverInterface *osi = model->solver() ;
154/*
155  Set up the remaining classes of parameters, taking defaults from the CbcModel
156  and OsiSolverInterface objects we've set up. There are parameters that
157  belong to CbcModel (CbcCbcParam) and to the underlying OsiSolverInterface
158  (CbcOsiParam).
159*/
160  ctlBlk.cbcParams_.first_ = numParams ;
161  CbcCbcParamUtils::addCbcCbcParams(numParams,paramVec,model) ;
162  ctlBlk.cbcParams_.last_ = numParams-1 ;
163  ctlBlk.osiParams_.first_ = numParams ;
164  CbcOsiParamUtils::addCbcOsiParams(numParams,paramVec,osi) ;
165  ctlBlk.osiParams_.last_ = numParams-1 ;
166/*
167  Initialise the vector that tracks parameters that have been changed by user
168  command.
169*/
170  ctlBlk.setByUser_.resize(CbcOsiParam::CBCOSI_LASTPARAM,false) ;
171/*
172  The main command parsing loop. Call getCommand to get the next parameter.
173  (The user will be prompted in interactive mode.) If we find something,
174  proceed to process it.
175
176  If we don't find anything, behaviour depends on what we've seen so far:
177
178  * An empty command/parameter and no history of previous success gets a
179    brief message. If we're in interactive mode, allow the user to try again,
180    otherwise quit.
181
182  * An empty command/parameter in interactive mode with some history of
183    successful commands is ignored. Iterate and try again.
184
185  * An empty command/parameter when we're not interactive is taken
186    as the end of commands. If we have a good model, force branchAndBound.
187    (This is one aspect of giving the expected behaviour for
188    `cbc-generic [parameters] foo.mps'.)
189*/
190  bool keepParsing = true ;
191  bool forceImport = false ;
192  std::string forceImportFile = "" ;
193  std::string prompt = "cbcGen: " ;
194  std::string pfx = "" ;
195  while (keepParsing)
196  { std::string paramName = CoinParamUtils::getCommand(argc,argv,prompt,&pfx);
197    if (paramName.length() == 0)
198    { if (ctlBlk.paramsProcessed_ == 0)
199      { if (CoinParamUtils::isInteractive())
200        { std::cout
201            << "Type `?' or `help' for usage and command keywords."
202            << " Type `quit' to quit." ; }
203        else
204        { std::cout
205            << "Type `cbc-generic -help' for usage and parameter keywords." ;
206          keepParsing = false ; }
207        std::cout << std::endl ; }
208      else
209      if (!CoinParamUtils::isInteractive())
210      { keepParsing = false ;
211        if (ctlBlk.goodModel_ == true &&
212            ctlBlk.bab_.majorStatus_ == CbcGenCtlBlk::BACNotRun)
213        { paramName = "branchAndCut" ;
214          pfx = "-" ; } } }
215    if (paramName == "")
216    { continue ; }
217/*
218  Do we have a parameter we recognise? In command line mode, if there was no
219  prefix (either `-' or `--'), the user didn't intend this as a command
220  keyword.
221*/
222    int matchNdx ;
223    if (!CoinParamUtils::isCommandLine() || pfx == "-" || pfx == "--")
224    { matchNdx = CoinParamUtils::lookupParam(paramName,paramVec) ; }
225    else
226    { matchNdx = -3 ; }
227    std::cout
228      << "Command is `" << paramName
229      << "', pfx `" << pfx
230      << "', match = " << matchNdx << std::endl ;
231/*
232  If matchNdx is positive, we have a unique parameter match and we can get on
233  with processing. If the return value is negative, and we're not
234  interactive, quit. If we're interactive, react as appropriate:
235    -1: There was a `?' in the command string. Prompt again.
236    -2: No `?', and one or more short matches. Prompt again.
237    -3: No `?', but we didn't match anything either. If we're in command line
238        mode, and there was no `-' or `--' prefix, try forcing `import' (but
239        just once, eh). This is the other piece required to get `cbc-generic
240        [parameters] foo.mps' to work as expected.) In interactive mode,
241        we'll require the user to say `import'.  Interactive mode and no
242        history of successful commands gets the help message.
243    -4: Configuration error, offer `report to maintainers' message.
244*/
245    if (matchNdx < 0)
246    { if (matchNdx == -3)
247      { if (CoinParamUtils::isCommandLine() && pfx == "")
248        { if (!forceImport)
249          { forceImportFile = paramName ;
250            paramName = "import" ;
251            matchNdx = CoinParamUtils::lookupParam(paramName,paramVec) ;
252            forceImport = true ; }
253          else
254          { std::cout << "No commands matched `" << paramName << "'."
255                << std::endl ; } }
256        else
257        { std::cout << "No commands matched `" << paramName << "'."
258              << std::endl ; 
259          if (ctlBlk.paramsProcessed_ == 0)
260          { std::cout
261              << "Type `?' or `help' for usage and command keywords."
262              << " Type `quit' to quit." << std::endl ; } } }
263      else
264      if (matchNdx == -4)
265      { std::cout
266          << "Please report this error by filing a ticket at "
267          << "https://projects.coin-or.org/Cbc/wiki."
268          << std::endl ; } }
269    if (matchNdx < 0)
270    { keepParsing = CoinParamUtils::isInteractive() ;
271      continue ; }
272    CoinParam *param = paramVec[matchNdx] ;
273    ctlBlk.paramsProcessed_++ ;
274/*
275  Depending on the type, we may need a parameter. For keyword parameters, check
276  that the keyword is recognised --- setKwdVal will quietly fail on a bad
277  keyword.
278*/
279    CoinParam::CoinParamType type = param->type() ;
280    int valid = 0 ;
281    switch (type)
282    { case CoinParam::coinParamAct:
283      { break ; }
284      case CoinParam::coinParamInt:
285      { int ival = CoinParamUtils::getIntField(argc,argv,&valid) ;
286        if (valid == 0)
287        { param->setIntVal(ival) ; }
288        break ; }
289      case CoinParam::coinParamDbl:
290      { double dval = CoinParamUtils::getDoubleField(argc,argv,&valid) ;
291        if (valid == 0)
292        { param->setDblVal(dval) ; }
293        break ; }
294      case CoinParam::coinParamStr:
295      { if (forceImport)
296        { param->setStrVal(forceImportFile) ; }
297        else
298        { const std::string tmp =
299                CoinParamUtils::getStringField(argc,argv,&valid) ;
300          if (valid == 0)
301          { param->setStrVal(tmp) ; } }
302        break ; }
303      case CoinParam::coinParamKwd:
304      { const std::string tmp =
305                CoinParamUtils::getStringField(argc,argv,&valid) ;
306        if (valid == 0)
307        { param->setKwdVal(tmp) ;
308          if (param->kwdVal() != tmp)
309          { std::cout
310              << "Unrecognised keyword `" << tmp << "' for parameter "
311              << param->name() << std::endl ;
312            param->printKwds() ;
313            std::cout << std::endl ;
314            valid = 1 ; } }
315        break ; }
316      default:
317      { assert (false) ;
318        break ; } }
319/*
320  Deal with missing or incorrect values.
321
322  If valid came back as 2, we're short a parameter. This is interpreted as a
323  request to tell the user the current value.  If valid came back as 1, we
324  had some sort of parse error. Print an error message.
325*/
326    if (valid != 0)
327    { switch (valid)
328      { case 1:
329        { std::cout
330            << "Could not parse the value given for parameter `"
331            << param->name() << "'." << std::endl ;
332          break ; }
333        case 2:
334        { std::cout
335            << "Current value of " << param->name() << " parameter is `"
336            << *param << "'." << std::endl ;
337          break ; }
338        default:
339        { std::cout
340            << "Parse status is " << valid
341            << "; this indicates internal confusion." << std::endl
342            << "Please report this error by filing a ticket at "
343            << "https://projects.coin-or.org/Cbc/wiki."
344            << std::endl ; } }
345      keepParsing = CoinParamUtils::isInteractive() ;
346      continue ; }
347/*
348  Ok, call the parameter's push function to do the heavy lifting. Push and pull
349  functions return 0 for success, 1 for non-fatal error, -1 for fatal error.
350*/
351    if (param->pushFunc() == 0)
352    { std::cout << "Parameter `" << param->name()
353                << "' is not implemented." << std::endl ; }
354    else
355    { int retval = (param->pushFunc())(param) ;
356      markAsSetByUser(ctlBlk,param) ;
357      if (retval < 0)
358      { keepParsing = false ; } } }
359/*
360  End of loop to parse and execute parameter actions. Time to do cleanup.
361  The destructor for CbcGenCtlBlk will delete anything with a non-null pointer,
362  so we need to be careful that the default solver is deleted only once.
363*/
364    ctlBlk.dfltSolver_ = 0 ;
365    CbcGenSolvers::deleteSolvers() ;
366    for (int i = 0 ; i < paramVec.size() ; i++)
367    { if (paramVec[i] != 0) delete paramVec[i] ; }
368  }
369/*
370  End of memory allocation block. There should be no allocated objects at
371  this point.
372*/
373  return (0) ;
374}   
Note: See TracBrowser for help on using the repository browser.