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

Last change on this file since 2464 was 2464, checked in by unxusr, 8 months ago

.clang-format with proposal for formatting code

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