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

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

Revised main program for cbc-generic. (Testing commit.)

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