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

Last change on this file since 1899 was 1899, checked in by stefan, 5 years ago

fixup svn properties

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.5 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 1899 2013-04-09 18:12:08Z stefan $
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 1899 2013-04-09 18:12:08Z stefan $" ;
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 &&
226                            ctlBlk.bab_.majorStatus_ == CbcGenCtlBlk::BACNotRun) {
227                        paramName = "branchAndCut" ;
228                        pfx = "-" ;
229                    }
230                }
231            }
232            if (paramName == "") {
233                continue ;
234            }
235            /*
236              Do we have a parameter we recognise? In command line mode, if there was no
237              prefix (either `-' or `--'), the user didn't intend this as a command
238              keyword.
239            */
240            int matchNdx ;
241            if (!CoinParamUtils::isCommandLine() || pfx == "-" || pfx == "--") {
242                matchNdx = CoinParamUtils::lookupParam(paramName, paramVec) ;
243            } else {
244                matchNdx = -3 ;
245            }
246            std::cout
247                << "Command is `" << paramName
248                << "', pfx `" << pfx
249                << "', match = " << matchNdx << std::endl ;
250            /*
251              If matchNdx is positive, we have a unique parameter match and we can get on
252              with processing. If the return value is negative, and we're not
253              interactive, quit. If we're interactive, react as appropriate:
254                -1: There was a `?' in the command string. Prompt again.
255                -2: No `?', and one or more short matches. Prompt again.
256                -3: No `?', but we didn't match anything either. If we're in command line
257                mode, and there was no `-' or `--' prefix, try forcing `import' (but
258                just once, eh). This is the other piece required to get `cbc-generic
259                [parameters] foo.mps' to work as expected.) In interactive mode,
260                we'll require the user to say `import'.  Interactive mode and no
261                history of successful commands gets the help message.
262                -4: Configuration error, offer `report to maintainers' message.
263            */
264            if (matchNdx < 0) {
265                if (matchNdx == -3) {
266                    if (CoinParamUtils::isCommandLine() && pfx == "") {
267                        if (!forceImport) {
268                            forceImportFile = paramName ;
269                            paramName = "import" ;
270                            matchNdx = CoinParamUtils::lookupParam(paramName, paramVec) ;
271                            forceImport = true ;
272                        } else {
273                            std::cout << "No commands matched `" << paramName << "'."
274                                      << std::endl ;
275                        }
276                    } else {
277                        std::cout << "No commands matched `" << paramName << "'."
278                                  << std::endl ;
279                        if (ctlBlk.paramsProcessed_ == 0) {
280                            std::cout
281                                << "Type `?' or `help' for usage and command keywords."
282                                << " Type `quit' to quit." << std::endl ;
283                        }
284                    }
285                } else if (matchNdx == -4) {
286                    std::cout
287                        << "Please report this error by filing a ticket at "
288                        << "https://projects.coin-or.org/Cbc/wiki."
289                        << std::endl ;
290                }
291            }
292            if (matchNdx < 0) {
293                keepParsing = CoinParamUtils::isInteractive() ;
294                continue ;
295            }
296            CoinParam *param = paramVec[matchNdx] ;
297            ctlBlk.paramsProcessed_++ ;
298            /*
299              Depending on the type, we may need a parameter. For keyword parameters, check
300              that the keyword is recognised --- setKwdVal will quietly fail on a bad
301              keyword.
302            */
303            CoinParam::CoinParamType type = param->type() ;
304            int valid = 0 ;
305            switch (type) {
306            case CoinParam::coinParamAct: {
307                break ;
308            }
309            case CoinParam::coinParamInt: {
310                int ival = CoinParamUtils::getIntField(argc, argv, &valid) ;
311                if (valid == 0) {
312                    param->setIntVal(ival) ;
313                }
314                break ;
315            }
316            case CoinParam::coinParamDbl: {
317                double dval = CoinParamUtils::getDoubleField(argc, argv, &valid) ;
318                if (valid == 0) {
319                    param->setDblVal(dval) ;
320                }
321                break ;
322            }
323            case CoinParam::coinParamStr: {
324                if (forceImport) {
325                    param->setStrVal(forceImportFile) ;
326                } else {
327                    const std::string tmp =
328                        CoinParamUtils::getStringField(argc, argv, &valid) ;
329                    if (valid == 0) {
330                        param->setStrVal(tmp) ;
331                    }
332                }
333                break ;
334            }
335            case CoinParam::coinParamKwd: {
336                const std::string tmp =
337                    CoinParamUtils::getStringField(argc, argv, &valid) ;
338                if (valid == 0) {
339                    param->setKwdVal(tmp) ;
340                    if (param->kwdVal() != tmp) {
341                        std::cout
342                            << "Unrecognised keyword `" << tmp << "' for parameter "
343                            << param->name() << std::endl ;
344                        param->printKwds() ;
345                        std::cout << std::endl ;
346                        valid = 1 ;
347                    }
348                }
349                break ;
350            }
351            default: {
352                assert (false) ;
353                break ;
354            }
355            }
356            /*
357              Deal with missing or incorrect values.
358
359              If valid came back as 2, we're short a parameter. This is interpreted as a
360              request to tell the user the current value.  If valid came back as 1, we
361              had some sort of parse error. Print an error message.
362            */
363            if (valid != 0) {
364                switch (valid) {
365                case 1: {
366                    std::cout
367                        << "Could not parse the value given for parameter `"
368                        << param->name() << "'." << std::endl ;
369                    break ;
370                }
371                case 2: {
372                    std::cout
373                        << "Current value of " << param->name() << " parameter is `"
374                        << *param << "'." << std::endl ;
375                    break ;
376                }
377                default: {
378                    std::cout
379                        << "Parse status is " << valid
380                        << "; this indicates internal confusion." << std::endl
381                        << "Please report this error by filing a ticket at "
382                        << "https://projects.coin-or.org/Cbc/wiki."
383                        << std::endl ;
384                }
385                }
386                keepParsing = CoinParamUtils::isInteractive() ;
387                continue ;
388            }
389            /*
390              Ok, call the parameter's push function to do the heavy lifting. Push and pull
391              functions return 0 for success, 1 for non-fatal error, -1 for fatal error.
392            */
393            if (param->pushFunc() == 0) {
394                std::cout << "Parameter `" << param->name()
395                          << "' is not implemented." << std::endl ;
396            } else {
397                int retval = (param->pushFunc())(param) ;
398                markAsSetByUser(ctlBlk, param) ;
399                if (retval < 0) {
400                    keepParsing = false ;
401                }
402            }
403        }
404        /*
405          End of loop to parse and execute parameter actions. Time to do cleanup.
406          The destructor for CbcGenCtlBlk will delete anything with a non-null pointer,
407          so we need to be careful that the default solver is deleted only once.
408        */
409        ctlBlk.dfltSolver_ = 0 ;
410        CbcGenSolvers::deleteSolvers() ;
411        for (int i = 0 ; i < paramVec.size() ; i++) {
412            if (paramVec[i] != 0) delete paramVec[i] ;
413        }
414    }
415    /*
416      End of memory allocation block. There should be no allocated objects at
417      this point.
418    */
419    return (0) ;
420}
421
Note: See TracBrowser for help on using the repository browser.