source: trunk/Cbc/src/CbcGeneric.cpp @ 862

Last change on this file since 862 was 765, checked in by andreasw, 12 years ago

merging changes from Bug Squashing Party Aug 2007 to regular trunk

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