source: branches/sandbox/Cbc/src/CbcGeneric.cpp @ 1389

Last change on this file since 1389 was 1374, checked in by bjarni, 10 years ago

Renamed all CbcGenXXXX.cpp_lou back to CbcGenXXXX.cpp (same for .hpp) after reorganizing the CbcParam? and CbcSolver? files

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