source: trunk/Cbc/src/CbcGenParamUtils.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: 54.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: CbcGenParamUtils.cpp 1899 2013-04-09 18:12:08Z stefan $
8*/
9/*
10  This file is part of cbc-generic.
11*/
12
13#if defined(_MSC_VER)
14// Turn off compiler warning about long names
15#  pragma warning(disable:4786)
16#endif
17
18#include <string>
19#include <cassert>
20
21#include "CoinFileIO.hpp"
22
23#include "CoinFinite.hpp"
24#include "CoinParam.hpp"
25
26#include "CbcModel.hpp"
27
28#include "CbcGenParam.hpp"
29#include "CbcGenCtlBlk.hpp"
30
31/*! \file CbcGenParamUtils
32    \brief Implementation functions for CbcGenParam parameters.
33*/
34
35namespace {
36
37char svnid[] = "$Id: CbcGenParamUtils.cpp 1899 2013-04-09 18:12:08Z stefan $" ;
38
39}
40
41namespace CbcGenSolvers {
42void setupSolverParam(CbcGenParam &solverParam) ;
43}
44
45namespace CbcGenParamUtils {
46
47/*
48  Function to add cbc-generic control parameters to the cbc-generic parameter
49  vector. Were needed, defaults are drawn from ctlBlk-> This function is a
50  friend of CbcGenCtlBlk.
51*/
52
53void addCbcGenParams (int &numberParameters, CoinParamVec &parameters,
54                      CbcGenCtlBlk *ctlBlk)
55
56{
57    CbcGenParam *param ;
58    std::string empty = "" ;
59
60    param = new CbcGenParam(CbcGenParam::GENERALQUERY, "?",
61                            "Print a list of commands", false) ;
62    param->setPushFunc(doHelpParam) ;
63    param->setObj(ctlBlk) ;
64    parameters.push_back(param) ;
65
66    param = new CbcGenParam(CbcGenParam::FULLGENERALQUERY, "???",
67                            "Print a list with *all* commands, even those hidden with `?'", false) ;
68    param->setPushFunc(doHelpParam) ;
69    param->setObj(ctlBlk) ;
70    parameters.push_back(param) ;
71
72    param = new CbcGenParam(CbcGenParam::PRINTVERSION,
73                            "version", "Print version") ;
74    param->setPushFunc(doVersionParam) ;
75    param->setObj(ctlBlk) ;
76    parameters.push_back(param) ;
77
78    /*
79      Built into CoinParam parsing. No additional actions required. doNothingParam
80      simply prevents them from being reported as unimplemented.
81    */
82    param = new CbcGenParam(CbcGenParam::STDIN, "-",
83                            "Switch to interactive command line mode", false) ;
84    param->setPushFunc(doNothingParam) ;
85    parameters.push_back(param) ;
86    param = new CbcGenParam(CbcGenParam::STDIN, "stdin",
87                            "Switch to interactive command line mode", false) ;
88    param->setPushFunc(doNothingParam) ;
89    param->setObj(ctlBlk) ;
90    parameters.push_back(param) ;
91
92    param = new CbcGenParam(CbcGenParam::BAB,
93                            "branch!AndCut", "Do Branch and Cut") ;
94    param->setPushFunc(doBaCParam) ;
95    param->setObj(ctlBlk) ;
96    param->setLongHelp(
97        "This does branch and cut. There are many parameters which can affect the performance.  First just try with default settings and look carefully at the log file.  Did cuts help?  Did they take too long?  Look at output to see which cuts were effective and then do some tuning.  You will see that the options for cuts are off, on, root and ifmove.  Off is obvious, on means that this cut generator will be tried in the branch and cut tree (you can fine tune using 'depth').  Root means just at the root node while 'ifmove' means that cuts will be used in the tree if they look as if they are doing some good and moving the objective value.  If pre-processing reduced the size of the problem or strengthened many coefficients then it is probably wise to leave it on.  Switch off heuristics which did not provide solutions.  The other major area to look at is the search.  Hopefully good solutions were obtained fairly early in the search so the important point is to select the best variable to branch on.  See whether strong branching did a good job - or did it just take a lot of iterations.  Adjust the strongBranching and trustPseudoCosts parameters."
98    ) ;
99    parameters.push_back(param) ;
100
101    param = new CbcGenParam(CbcGenParam::CPP,
102                            "cpp!Generate", "Generates C++ code", -1, 50000) ;
103    param->setObj(ctlBlk) ;
104    param->setLongHelp(
105        "Once you like what the stand-alone solver does then this allows you to generate user_driver.cpp which approximates the code.  0 gives simplest driver, 1 generates saves and restores, 2 generates saves and restores even for variables at default value. 4 bit in cbc generates size dependent code rather than computed values."
106    ) ;
107    parameters.push_back(param) ;
108
109    param = new CbcGenParam(CbcGenParam::CLIQUECUTS,
110                            "clique!Cuts", "Whether to use clique cuts", "off",
111                            ctlBlk->clique_.action_) ;
112    param->appendKwd("on") ;
113    param->appendKwd("root") ;
114    param->appendKwd("ifmove") ;
115    param->appendKwd("forceOn") ;
116    param->setObj(ctlBlk) ;
117    param->setPushFunc(pushCbcGenCutParam) ;
118    param->setLongHelp(
119        "This switches on clique cuts (either at root or in entire tree). See branchAndCut for information on options."
120    ) ;
121    parameters.push_back(param) ;
122
123    param = new CbcGenParam(CbcGenParam::CUTDEPTH,
124                            "cutD!epth", "Depth in tree at which to do cuts",
125                            -1, 999999, ctlBlk->cutDepth_) ;
126    param->setObj(ctlBlk) ;
127    param->setPushFunc(pushCbcGenIntParam) ;
128    param->setLongHelp(
129        "Cut generators may be off, on only at the root, on if they look useful, and on at some interval.  If they are done every node then that is that, but it may be worth doing them every so often.  The original method was every so many nodes but it is more logical to do it whenever depth in tree is a multiple of K.  This option does that and defaults to -1 (off)."
130    ) ;
131    parameters.push_back(param) ;
132
133
134    param = new CbcGenParam(CbcGenParam::CUTSTRATEGY,
135                            "cuts!OnOff", "Switches all cuts on or off", "off", 0) ;
136    param->appendKwd("on") ;
137    param->appendKwd("root") ;
138    param->appendKwd("ifmove") ;
139    param->appendKwd("forceOn") ;
140    param->setObj(ctlBlk) ;
141    param->setLongHelp(
142        "This can be used to switch on or off all cuts (apart from Reduce and Split).  Then you can set individual ones off or on.  See branchAndCut for information on options."
143    ) ;
144    parameters.push_back(param) ;
145
146    param = new CbcGenParam(CbcGenParam::COMBINE,
147                            "combine!Solutions",
148                            "Whether to use combine solution heuristic", "off",
149                            ctlBlk->combine_.action_) ;
150    param->appendKwd("on") ;
151    param->setObj(ctlBlk) ;
152    param->setLongHelp(
153        "This switches on a heuristic which does branch and cut on the problem given by just using variables which have appeared in one or more solutions. It is obviously only tried after two or more solutions."
154    ) ;
155    parameters.push_back(param) ;
156
157    param = new CbcGenParam(CbcGenParam::COSTSTRATEGY,
158                            "cost!Strategy", "Whether to use costs or column order as priorities",
159                            "off", 0) ;
160    param->appendKwd("pri!orities") ;
161    param->appendKwd("column!Order") ;
162    param->setObj(ctlBlk) ;
163    param->setLongHelp(
164        "This orders the variables in order of their absolute costs - with largest cost ones being branched on first.  This primitive strategy can be surprisingly effective.  The column order option is obviously not on costs but it's easy to implement."
165    ) ;
166    parameters.push_back(param) ;
167
168    param = new CbcGenParam(CbcGenParam::DEBUG,
169                            "debug!In", "Read/write valid solution from/to file", "", false) ;
170    param->setObj(ctlBlk) ;
171    param->setPushFunc(doDebugParam) ;
172    param->setLongHelp(
173        "This will read a solution file from the given file name.  It will use the default directory given by 'directory'.  A name of '$' will use the previous value for the name.  This is initialized to '', i.e. it must be set.\n\nIf set to create it will create a file called debug.file after B&C search; if set to createAfterPre it will create the file before undoing preprocessing.\n\nThe idea is that if you suspect a bad cut generator and you did not use preprocessing you can do a good run with debug set to 'create' and then switch on the cuts you suspect and re-run with debug set to 'debug.file'  Similarly if you do use preprocessing, but use createAfterPre.  The create case has the same effect as saveSolution."
174    ) ;
175    parameters.push_back(param) ;
176
177    param = new CbcGenParam(CbcGenParam::DIRECTORY,
178                            "directory", "Set Default directory for import etc.",
179                            ctlBlk->dfltDirectory_) ;
180    param->setObj(ctlBlk) ;
181    param->setLongHelp(
182        "This sets the directory which import, export, saveModel, restoreModel etc. will use. It is initialized to the current directory."
183    ) ;
184    param->setPushFunc(pushCbcGenStrParam) ;
185    parameters.push_back(param) ;
186
187    param = new CbcGenParam(CbcGenParam::EXIT, "end", "Stops execution") ;
188    param->setPushFunc(doExitParam) ;
189    param->setObj(ctlBlk) ;
190    param->setLongHelp(
191        "This stops execution; end, exit, quit and stop are synonyms."
192    ) ;
193    parameters.push_back(param) ;
194
195    param = new CbcGenParam(CbcGenParam::ERRORSALLOWED,
196                            "error!sAllowed", "Whether to allow import errors", "off", 0) ;
197    param->appendKwd("on") ;
198    param->setObj(ctlBlk) ;
199    param->setLongHelp(
200        "The default is not to use any model which had errors when reading the mps file.  Setting this to 'on' will allow all errors from which the code can recover simply by ignoring the error.  There are some errors from which the code can not recover, e.g., no ENDATA.  This has to be set before import, i.e., -errorsAllowed on -import xxxxxx.mps."
201    ) ;
202    parameters.push_back(param) ;
203
204    param = new CbcGenParam(CbcGenParam::EXIT, "exit", "Stops execution") ;
205    param->setPushFunc(doExitParam) ;
206    param->setObj(ctlBlk) ;
207    param->setLongHelp(
208        "This stops execution; end, exit, quit and stop are synonyms."
209    ) ;
210    parameters.push_back(param) ;
211
212    param = new CbcGenParam(CbcGenParam::EXPORT,
213                            "export", "Export model as mps file",
214                            std::string("default.mps")) ;
215    param->setObj(ctlBlk) ;
216    param->setLongHelp(
217        "This will write an MPS format file to the given file name.  It will use the default directory given by 'directory'.  A name of '$' will use the previous value for the name.  This is initialized to 'default.mps'."
218    ) ;
219    parameters.push_back(param) ;
220
221    param = new CbcGenParam(CbcGenParam::DJFIX, "fix!OnDj",
222                            "Try heuristic that fixes variables based on reduced costs",
223                            -1.0e20, 1.0e20, ctlBlk->djFix_.threshold_) ;
224    param->setPushFunc(pushCbcGenDblParam) ;
225    param->setObj(ctlBlk) ;
226    param->setLongHelp(
227        "If set, integer variables with reduced costs greater than the specified value will be fixed before branch and bound - use with extreme caution!"
228    ) ;
229    parameters.push_back(param) ;
230
231    param = new CbcGenParam(CbcGenParam::FPUMP,
232                            "feas!ibilityPump", "Whether to try Feasibility Pump", "off",
233                            ctlBlk->fpump_.action_) ;
234    param->appendKwd("on") ;
235    param->setObj(ctlBlk) ;
236    param->setLongHelp(
237        "This switches on feasibility pump heuristic at root. This is due to Fischetti and Lodi and uses a sequence of LPs to try and get an integer feasible solution.  Some fine tuning is available by passFeasibilityPump."
238    ) ;
239    parameters.push_back(param) ;
240
241    param = new CbcGenParam(CbcGenParam::FPUMPITS,
242                            "passF!easibilityPump", "How many passes in feasibility pump",
243                            0, 10000, ctlBlk->fpump_.iters_) ;
244    param->setObj(ctlBlk) ;
245    param->setLongHelp(
246        "This fine tunes the Feasibility Pump heuristic by doing more or fewer passes."
247    ) ;
248    parameters.push_back(param) ;
249
250    param = new CbcGenParam(CbcGenParam::FLOWCUTS,
251                            "flow!CoverCuts", "Whether to use Flow Cover cuts", "off",
252                            ctlBlk->flow_.action_) ;
253    param->appendKwd("on") ;
254    param->appendKwd("root") ;
255    param->appendKwd("ifmove") ;
256    param->appendKwd("forceOn") ;
257    param->setObj(ctlBlk) ;
258    param->setPushFunc(pushCbcGenCutParam) ;
259    param->setLongHelp(
260        "This switches on flow cover cuts (either at root or in entire tree).  See branchAndCut for information on options."
261    ) ;
262    parameters.push_back(param) ;
263
264    param = new CbcGenParam(CbcGenParam::GOMORYCUTS, "gomory!Cuts",
265                            "Whether to use Gomory cuts", "off",
266                            ctlBlk->gomory_.action_) ;
267    param->appendKwd("on") ;
268    param->appendKwd("root") ;
269    param->appendKwd("ifmove") ;
270    param->appendKwd("forceOn") ;
271    param->setObj(ctlBlk) ;
272    param->setPushFunc(pushCbcGenCutParam) ;
273    param->setLongHelp(
274        "The original cuts - beware of imitations!  Having gone out of favor, they are now more fashionable as LP solvers are more robust and they interact well with other cuts.  They will almost always give cuts (although in this executable they are limited as to number of variables in cut).  However the cuts may be dense so it is worth experimenting. See branchAndCut for information on options."
275    ) ;
276    parameters.push_back(param) ;
277
278    param = new CbcGenParam(CbcGenParam::GREEDY,
279                            "greedy!Heuristic", "Whether to use a greedy heuristic", "off",
280                            ctlBlk->greedyCover_.action_) ;
281    param->appendKwd("on") ;
282    param->appendKwd("root") ;
283    param->setObj(ctlBlk) ;
284    param->setLongHelp(
285        "Switches on a pair of greedy heuristic which will try and obtain a solution.  It may just fix a percentage of variables and then try a small branch and cut run."
286    ) ;
287    parameters.push_back(param) ;
288
289    param = new CbcGenParam(CbcGenParam::HEURISTICSTRATEGY,
290                            "heur!isticsOnOff", "Switches most heuristics on or off", "off", 0) ;
291    param->appendKwd("on") ;
292    param->setObj(ctlBlk) ;
293    param->setLongHelp(
294        "This can be used to switch on or off all heuristics.  Then you can set individual ones off or on.  CbcTreeLocal is not included as it dramatically alters search."
295    ) ;
296    parameters.push_back(param) ;
297
298    param = new CbcGenParam(CbcGenParam::KNAPSACKCUTS,
299                            "knapsack!Cuts", "Whether to use Knapsack cuts", "off",
300                            ctlBlk->knapsack_.action_) ;
301    param->appendKwd("on") ;
302    param->appendKwd("root") ;
303    param->appendKwd("ifmove") ;
304    param->appendKwd("forceOn") ;
305    param->setObj(ctlBlk) ;
306    param->setPushFunc(pushCbcGenCutParam) ;
307    param->setLongHelp(
308        "This switches on knapsack cuts (either at root or in entire tree). See branchAndCut for information on options."
309    ) ;
310    parameters.push_back(param) ;
311
312    /*
313      param = new CbcGenParam(CbcGenParam::LANDPCUTS,
314        "lift!AndProjectCuts","Whether to use lift-and-project cuts","off",
315        ctlBlk->landp_.action_) ;
316      param->appendKwd("on") ;
317      param->appendKwd("root") ;
318      param->appendKwd("ifmove") ;
319      param->appendKwd("forceOn") ;
320      param->setObj(ctlBlk) ;
321      param->setLongHelp(
322        "This switches on lift-and-project cuts (either at root or in entire tree). See branchAndCut for information on options."
323        ) ;
324      parameters.push_back(param) ;
325    */
326
327    param = new CbcGenParam(CbcGenParam::LOCALTREE,
328                            "local!TreeSearch", "Whether to use local tree search", "off",
329                            ctlBlk->localTree_.action_) ;
330    param->appendKwd("on") ;
331    param->setObj(ctlBlk) ;
332    param->setLongHelp(
333        "This switches on a local search algorithm when a solution is found.  This is from Fischetti and Lodi and is not really a heuristic although it can be used as one. When used from this program it has limited functionality.  It is not controlled by heuristicsOnOff."
334    ) ;
335    parameters.push_back(param) ;
336
337    param = new CbcGenParam(CbcGenParam::LOGLEVEL,
338                            "log!Level", "Level of detail in cbc-generic output.",
339                            -1, 999999, ctlBlk->logLvl_) ;
340    param->setObj(ctlBlk) ;
341    param->setPushFunc(pushCbcGenIntParam) ;
342    param->setLongHelp(
343        "If set to 0 then there should be no output in normal circumstances. A value of 1 is probably the best value for most uses, while 2 and 3 give more information."
344    ) ;
345    parameters.push_back(param) ;
346
347    param = new CbcGenParam(CbcGenParam::MIXEDCUTS,
348                            "mixed!IntegerRoundingCuts",
349                            "Whether to use Mixed Integer Rounding cuts", "off",
350                            ctlBlk->mir_.action_) ;
351    param->appendKwd("on") ;
352    param->appendKwd("root") ;
353    param->appendKwd("ifmove") ;
354    param->appendKwd("forceOn") ;
355    param->setObj(ctlBlk) ;
356    param->setPushFunc(pushCbcGenCutParam) ;
357    param->setLongHelp(
358        "This switches on mixed integer rounding cuts (either at root or in entire tree).  See branchAndCut for information on options."
359    ) ;
360    parameters.push_back(param) ;
361
362    param = new CbcGenParam(CbcGenParam::USESOLUTION,
363                            "force!Solution",
364                            "Whether to use given solution as crash for BAB", "off", 0) ;
365    param->appendKwd("on") ;
366    param->setObj(ctlBlk) ;
367    param->setLongHelp(
368        "If on then tries to branch to solution given by AMPL or priorities file."
369    ) ;
370    parameters.push_back(param) ;
371
372    param = new CbcGenParam(CbcGenParam::HELP, "help",
373                            "Print out version, non-standard options and some help") ;
374    param->setPushFunc(doHelpParam) ;
375    param->setObj(ctlBlk) ;
376    param->setLongHelp(
377        "This prints out some help to get a user started. If you're seeing this message, you should be past that stage."
378    ) ;
379    parameters.push_back(param) ;
380
381    param = new CbcGenParam(CbcGenParam::IMPORT,
382                            "import", "Import model from mps file",
383                            ctlBlk->lastMpsIn_) ;
384    param->setPushFunc(doImportParam) ;
385    param->setObj(ctlBlk) ;
386    param->setLongHelp(
387        "This will read an MPS format file from the given file name.  It will use the default directory given by 'directory'.  A name of '$' will use the previous value for the name.  This is initialized to '', i.e., it must be set.  If you have libgz then it can read compressed files 'xxxxxxxx.gz'."
388    ) ;
389    parameters.push_back(param) ;
390
391    param = new CbcGenParam(CbcGenParam::SOLVECONTINUOUS, "initialS!olve",
392                            "Solve to continuous optimum") ;
393    param->setObj(ctlBlk) ;
394    param->setLongHelp(
395        "This just solves the problem to the continuous optimum, without adding any cuts."
396    ) ;
397    parameters.push_back(param) ;
398
399    param = new CbcGenParam(CbcGenParam::MESSAGES, "mess!ages",
400                            "Controls whether standardised message prefix is printed", "off", 0) ;
401    param->appendKwd("on") ;
402    param->setObj(ctlBlk) ;
403    param->setLongHelp(
404        "By default, messages have a standard prefix, such as:\n   Clp0005 2261  Objective 109.024 Primal infeas 944413 (758)\nbut this program turns this off to make it look more friendly.  It can be useful to turn them back on if you want to be able to 'grep' for particular messages or if you intend to override the behavior of a particular message."
405    ) ;
406    parameters.push_back(param) ;
407
408    param = new CbcGenParam(CbcGenParam::MIPLIB,
409                            "miplib", "Do some of miplib test set") ;
410    parameters.push_back(param) ;
411
412
413    param = new CbcGenParam(CbcGenParam::OUTDUPROWS,
414                            "outDup!licates",
415                            "Takes duplicate rows, etc., out of the integer model", false) ;
416    parameters.push_back(param) ;
417
418    param = new CbcGenParam(CbcGenParam::OUTPUTFORMAT,
419                            "output!Format", "Which output format to use", 1, 6, 2) ;
420    param->setObj(ctlBlk) ;
421    param->setLongHelp(
422        "Normally export will be done using normal representation for numbers and two values per line.  You may want to do just one per line (for grep or suchlike) and you may wish to save with absolute accuracy using a coded version of the IEEE value. A value of 2 is normal. Otherwise, odd values give one value per line, even values two.  Values of 1 and 2 give normal format, 3 and 4 give greater precision, 5 and 6 give IEEE values.  When exporting a basis, 1 does not save values, 2 saves values, 3 saves with greater accuracy and 4 saves in IEEE format."
423    ) ;
424    parameters.push_back(param) ;
425
426    /*
427      In order for initialisation to work properly, the order of the keywords here
428      must match the order of the enum IPPControl in CbcGenCtlBlk.hpp.
429    */
430    param = new CbcGenParam(CbcGenParam::PREPROCESS,
431                            "preprocess", "Whether to use integer preprocessing", "off",
432                            ctlBlk->preProcess_) ;
433    param->appendKwd("on") ;
434    param->appendKwd("save") ;
435    param->appendKwd("equal") ;
436    param->appendKwd("sos") ;
437    param->appendKwd("trysos") ;
438    param->appendKwd("equalall") ;
439    param->appendKwd("strategy") ;
440    param->setObj(ctlBlk) ;
441    param->setPushFunc(pushCbcGenKwdParam) ;
442    param->setLongHelp(
443        "This tries to reduce size of the model in a similar way to presolve and it also tries to strengthen the model. This can be very useful and is worth trying.  save option saves on file presolved.mps.  equal will turn <= cliques into ==.  sos will create sos sets if all 0-1 in sets (well one extra is allowed) and no overlaps.  trysos is same but allows any number extra. equalall will turn all valid inequalities into equalities with integer slacks. strategy is as on but uses CbcStrategy."
444    ) ;
445    parameters.push_back(param) ;
446
447    param = new CbcGenParam(CbcGenParam::PRINTOPTIONS,
448                            "pO!ptions", "Dubious print options", 0, COIN_INT_MAX, 0, false) ;
449    param->setObj(ctlBlk) ;
450    param->setPushFunc(pushCbcGenIntParam) ;
451    param->setLongHelp(
452        "If this is greater than 0 then presolve will give more information and branch and cut will give statistics"
453    ) ;
454    parameters.push_back(param) ;
455
456    param = new CbcGenParam(CbcGenParam::PROBINGCUTS,
457                            "probing!Cuts", "Whether to use Probing cuts", "off",
458                            ctlBlk->probing_.action_) ;
459    param->appendKwd("on") ;
460    param->appendKwd("root") ;
461    param->appendKwd("ifmove") ;
462    param->appendKwd("forceOn") ;
463    param->appendKwd("forceOnBut") ;
464    param->setObj(ctlBlk) ;
465    param->setPushFunc(pushCbcGenCutParam) ;
466    param->setLongHelp(
467        "This switches on probing cuts (either at root or in entire tree). See branchAndCut for information on options."
468    ) ;
469    parameters.push_back(param) ;
470
471    param = new CbcGenParam(CbcGenParam::INTPRINT,
472                            "printi!ngOptions", "Print options", "normal", 0) ;
473    param->appendKwd("integer") ;
474    param->appendKwd("special") ;
475    param->appendKwd("rows") ;
476    param->appendKwd("all") ;
477    param->setPushFunc(pushCbcGenKwdParam) ;
478    param->setObj(ctlBlk) ;
479    param->setLongHelp(
480        "This changes the amount and format of printing a solution:\nnormal - nonzero column variables \ninteger - nonzero integer column variables\nspecial - in format suitable for OsiRowCutDebugger\nrows - nonzero column variables and row activities\nall - all column variables and row activities.\n\nFor non-integer problems 'integer' and 'special' act like 'normal'.  Also see printMask for controlling output."
481    ) ;
482    parameters.push_back(param) ;
483
484    param = new CbcGenParam(CbcGenParam::PRINTMASK,
485                            "printM!ask",
486                            "Control printing of solution with a regular expression", empty) ;
487    param->setPushFunc(doPrintMaskParam) ;
488    param->setObj(ctlBlk) ;
489    param->setLongHelp(
490        "If set then only those names which match mask are printed in a solution. '?' matches any character and '*' matches any set of characters.  The default is '' (unset) so all variables are printed. This is only active if model has names."
491    ) ;
492    parameters.push_back(param) ;
493
494    param = new CbcGenParam(CbcGenParam::PRIORITYIN,
495                            "prio!rityIn", "Import priorities etc from file", empty) ;
496    param->setObj(ctlBlk) ;
497    param->setLongHelp(
498        "This will read a file with priorities from the given file name.  It will use the default directory given by 'directory'.  A name of '$' will use the previous value for the name.  This is initialized to '', i.e. it must be set.  This can not read from compressed files. File is in csv format with allowed headings - name, number, priority, direction, up, down, solution.  Exactly one of name and number must be given."
499    ) ;
500    parameters.push_back(param) ;
501
502    param = new CbcGenParam(CbcGenParam::REDSPLITCUTS,
503                            "reduce!AndSplitCuts",
504                            "Whether to use Reduce-and-Split cuts", "off",
505                            ctlBlk->redSplit_.action_) ;
506    param->appendKwd("on") ;
507    param->appendKwd("root") ;
508    param->appendKwd("ifmove") ;
509    param->appendKwd("forceOn") ;
510    param->setObj(ctlBlk) ;
511    param->setPushFunc(pushCbcGenCutParam) ;
512    param->setLongHelp(
513        "This switches on reduce and split cuts (either at root or in entire tree). See branchAndCut for information on options."
514    ) ;
515    parameters.push_back(param) ;
516
517    param = new CbcGenParam(CbcGenParam::ROUNDING,
518                            "round!ingHeuristic", "Whether to use Rounding heuristic", "off",
519                            ctlBlk->rounding_.action_) ;
520    param->appendKwd("on") ;
521    param->setObj(ctlBlk) ;
522    param->setLongHelp(
523        "This switches on a simple (but effective) rounding heuristic at each node of tree."
524    ) ;
525    parameters.push_back(param) ;
526
527
528    param = new CbcGenParam(CbcGenParam::EXIT, "quit", "Stops execution") ;
529    param->setPushFunc(doExitParam) ;
530    param->setObj(ctlBlk) ;
531    param->setLongHelp(
532        "This stops execution; end, exit, quit and stop are synonyms."
533    ) ;
534    parameters.push_back(param) ;
535
536    param = new CbcGenParam(CbcGenParam::DUMMY,
537                            "sleep", "for debug", 0, 9999, 0, false) ;
538    param->setObj(ctlBlk) ;
539    param->setLongHelp(
540        "If passed to solver from ampl, then ampl will wait so that you can copy .nl file for debug."
541    ) ;
542    parameters.push_back(param) ;
543
544    param = new CbcGenParam(CbcGenParam::SOLUTION,
545                            "solu!tion", "Prints solution to file",
546                            std::string("stdout")) ;
547    param->setPushFunc(doSolutionParam) ;
548    param->setObj(ctlBlk) ;
549    param->setLongHelp(
550        "This will write a primitive solution file to the given file name.  It will use the default directory given by 'directory'.  A name of '$' will use the previous value for the name.  This is initialized to 'stdout'.  The amount of output can be varied using printi!ngOptions or printMask."
551    ) ;
552    parameters.push_back(param) ;
553
554    param = new CbcGenParam ;
555    CbcGenSolvers::setupSolverParam(*param) ;
556    param->setObj(ctlBlk) ;
557    parameters.push_back(param) ;
558
559    param = new CbcGenParam(CbcGenParam::SOS,
560                            "sos!Options", "Whether to use SOS from AMPL", "off", 0) ;
561    param->appendKwd("on") ;
562    param->setObj(ctlBlk) ;
563    param->setLongHelp(
564        "Normally if AMPL says there are SOS variables they should be used, but sometimes they should be turned off - this does so."
565    ) ;
566    parameters.push_back(param) ;
567
568    param = new CbcGenParam(CbcGenParam::EXIT, "stop", "Stops execution") ;
569    param->setPushFunc(doExitParam) ;
570    param->setObj(ctlBlk) ;
571    param->setLongHelp(
572        "This stops execution; end, exit, quit and stop are synonyms."
573    ) ;
574    parameters.push_back(param) ;
575
576    param = new CbcGenParam(CbcGenParam::STRENGTHEN,
577                            "strengthen", "Create strengthened problem") ;
578    param->setObj(ctlBlk) ;
579    param->setLongHelp(
580        "This creates a new problem by applying the root node cuts. All tight constraints will be in resulting problem."
581    ) ;
582    parameters.push_back(param) ;
583
584    param = new CbcGenParam(CbcGenParam::TIGHTENFACTOR, "tighten!Factor",
585                            "Tighten bounds using value times largest activity at continuous solution",
586                            1.0, 1.0e20) ;
587    param->setObj(ctlBlk) ;
588    param->setLongHelp(
589        "This sleazy trick can help on some problems."
590    ) ;
591    parameters.push_back(param) ;
592
593    param = new CbcGenParam(CbcGenParam::TWOMIRCUTS,
594                            "two!MirCuts",
595                            "Whether to use Two phase Mixed Integer Rounding cuts", "off",
596                            ctlBlk->twomir_.action_) ;
597    param->appendKwd("on") ;
598    param->appendKwd("root") ;
599    param->appendKwd("ifmove") ;
600    param->appendKwd("forceOn") ;
601    param->setObj(ctlBlk) ;
602    param->setPushFunc(pushCbcGenCutParam) ;
603    param->setLongHelp(
604        "This switches on two phase mixed integer rounding cuts (either at root or in entire tree). See branchAndCut for information on options."
605    ) ;
606    parameters.push_back(param) ;
607
608    param = new CbcGenParam(CbcGenParam::UNITTEST, "unitTest", "Do unit test") ;
609    param->setObj(ctlBlk) ;
610    param->setLongHelp(
611        "This exercises the unit test."
612    ) ;
613    parameters.push_back(param) ;
614
615    param = new CbcGenParam(CbcGenParam::USERCBC,
616                            "userCbc", "Hand coded Cbc stuff", 0, COIN_INT_MAX, 0, false) ;
617    param->setObj(ctlBlk) ;
618    param->setLongHelp(
619        "There are times (e.g., when using AMPL interface) when you may wish to do something unusual.  Look for USERCBC in main driver and modify sample code."
620    ) ;
621    parameters.push_back(param) ;
622
623    param = new CbcGenParam(CbcGenParam::VERBOSE,
624                            "verbose", "Switches on longer help on single ?",
625                            0, 15, ctlBlk->verbose_, false) ;
626    param->setPushFunc(pushCbcGenIntParam) ;
627    param->setObj(ctlBlk) ;
628    param->setLongHelp(
629        "Set to 1 to get short help with ? list, 2 to get long help."
630    ) ;
631    parameters.push_back(param) ;
632
633    param = new CbcGenParam(CbcGenParam::SHOWUNIMP,
634                            "unimp!lemented", "Report unimplemented commands.", false) ;
635    param->setPushFunc(doUnimplementedParam) ;
636    param->setObj(ctlBlk) ;
637    parameters.push_back(param) ;
638
639    numberParameters = parameters.size() ;
640    assert (((unsigned) numberParameters) <= parameters.capacity()) ;
641
642    return ;
643}
644
645
646void loadGenParamObj (const CoinParamVec paramVec, int first, int last,
647                      CbcGenCtlBlk *ctlBlk)
648
649{
650    int i ;
651    /*
652      Load the cbc-generic object into the parameters
653    */
654    for (i = first ; i <= last ; i++) {
655        CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(paramVec[i]) ;
656        assert (genParam != 0) ;
657        genParam->setObj(ctlBlk) ;
658    }
659
660    return ;
661}
662
663
664/* Functions to implement  cbc-generic (CbcGenParam) parameters */
665
666/*
667  Maintainer's utility, scan the parameters and report the ones that are
668  unimplemented (i.e., have no pushFunc).
669*/
670
671int doUnimplementedParam (CoinParam *param)
672
673{
674    assert (param != 0) ;
675
676    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
677    assert (genParam != 0) ;
678
679    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
680    assert (ctlBlk != 0) ;
681
682    assert (ctlBlk->paramVec_ != 0) ;
683    CoinParamVec &paramVec = *ctlBlk->paramVec_ ;
684
685    int unimpCnt = 0 ;
686    int maxAcross = 5 ;
687    for (unsigned i = 0 ; i < paramVec.size() ; i++) {
688        CoinParam *param = paramVec[i] ;
689        if (param->pushFunc() == 0) {
690            if (unimpCnt % maxAcross == 0) {
691                std::cout << std::endl ;
692            } else {
693                std::cout << " " ;
694            }
695            std::cout << param->name() ;
696            unimpCnt++ ;
697        }
698    }
699    if (unimpCnt % maxAcross != 1) {
700        std::cout << std::endl ;
701    }
702    std::cout << unimpCnt << " unimplemented parameters." << std::endl ;
703
704    return (0) ;
705}
706
707
708/*
709  Noop function. Mainly to eliminate commands from the list returned by
710  doUnimplmentedParam.
711*/
712
713int doNothingParam (CoinParam *param)
714{
715    return (0) ;
716}
717
718/*
719  Function to terminate command parsing by returning -1.
720*/
721
722int doExitParam (CoinParam *param)
723
724{
725    return (-1) ;
726}
727
728/*
729  Function to print the current version.
730*/
731
732int doVersionParam (CoinParam *param)
733
734{
735    assert (param != 0) ;
736    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
737    assert (genParam != 0) ;
738    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
739    assert (ctlBlk != 0) ;
740
741    std::cout << "cbc-generic version " << ctlBlk->version_ << std::endl ;
742    std::cout
743        << "cbc-generic is experimental software. If you want a stable MIP "
744        << "solver, please" << std::endl
745        << "use cbc. If you discover bugs while using cbc-generic "
746        << "please specify" << std::endl
747        << "cbc-generic in the ticket description or email subject line."
748        << std::endl ;
749
750    return (0) ;
751}
752
753/*
754  Function to handle help (HELP), `?' (GENERALQUERY), and `???'
755  (FULLGENERALQUERY).
756*/
757
758int doHelpParam (CoinParam *param)
759
760{
761    assert (param != 0) ;
762    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
763    assert (genParam != 0) ;
764    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
765    assert (ctlBlk != 0) ;
766
767    CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
768
769    int verbose = ctlBlk->verbose_ ;
770    bool shortHelp = ((verbose & 0x01) ? true : false) ;
771    bool longHelp = ((verbose & 0x02) ? true : false) ;
772    bool hidden = ((verbose & 0x08) ? true : false) ;
773
774    CoinParamVec *paramVec = ctlBlk->paramVec_ ;
775    assert (paramVec != 0) ;
776    /*
777      Tune up the initial settings. FULLGENERALQUERY will print normally hidden
778      params, and a request for long help overrules a request for short help.
779    */
780    if (code == CbcGenParam::FULLGENERALQUERY) {
781        hidden = true ;
782    }
783    if (longHelp) {
784        shortHelp = false ;
785    }
786
787    CoinParamUtils::printGenericHelp() ;
788
789    std::cout << "\nAvailable commands are:" ;
790    std::string pfx("  ") ;
791    CoinParamUtils::printHelp(*paramVec, 0, paramVec->size() - 1, pfx,
792                              shortHelp, longHelp, hidden) ;
793
794    return (0) ;
795}
796
797/*
798  Function to push a double-valued parameter.
799*/
800
801int pushCbcGenDblParam (CoinParam *param)
802
803{
804    assert (param != 0) ;
805    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
806    assert (genParam != 0) ;
807    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
808    assert (ctlBlk != 0) ;
809
810    double val = genParam->dblVal() ;
811    CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
812
813    int retval = 0 ;
814    /*
815      Figure out what we're doing and set the relevant field.
816    */
817    switch (code) {
818    case CbcGenParam::DJFIX: {
819        ctlBlk->djFix_.action_ = true ;
820        ctlBlk->djFix_.threshold_ = val ;
821        break ;
822    }
823    default: {
824        std::cerr << "pushCbcGenDbl: no equivalent CbcGenCtlBlk field for "
825                  << "parameter code `" << code << "'." << std::endl ;
826        retval = -1 ;
827        break ;
828    }
829    }
830
831    return (retval) ;
832}
833
834/*
835  Function to push an integer-valued parameter.
836*/
837
838int pushCbcGenIntParam (CoinParam *param)
839
840{
841    assert (param != 0) ;
842    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
843    assert (genParam != 0) ;
844    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
845    assert (ctlBlk != 0) ;
846
847    int val = genParam->intVal() ;
848    CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
849
850    int retval = 0 ;
851    /*
852      Figure out what we're doing and set the relevant field.
853    */
854    switch (code) {
855    case CbcGenParam::CUTDEPTH: {
856        ctlBlk->setCutDepth(val) ;
857        break ;
858    }
859    case CbcGenParam::LOGLEVEL: {
860        ctlBlk->setLogLevel(val) ;
861        break ;
862    }
863    case CbcGenParam::PRINTOPTIONS: {
864        ctlBlk->printOpt_ = val ;
865        break ;
866    }
867    case CbcGenParam::VERBOSE: {
868        ctlBlk->verbose_ = val ;
869        break ;
870    }
871    default: {
872        std::cerr << "pushCbcGenInt: no equivalent CbcGenCtlBlk field for "
873                  << "parameter code `" << code << "'." << std::endl ;
874        retval = -1 ;
875        break ;
876    }
877    }
878
879    return (retval) ;
880}
881
882
883/*
884  Function to push a keyword-valued parameter. This is the catch-all function
885  for keyword parameters that don't belong to any other useful grouping.
886*/
887
888int pushCbcGenKwdParam (CoinParam *param)
889
890{
891    assert (param != 0) ;
892    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
893    assert (genParam != 0) ;
894    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
895    assert (ctlBlk != 0) ;
896
897    std::string str = genParam->kwdVal() ;
898    CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
899
900    int retval = 0 ;
901    /*
902      Figure out what we're doing and set the relevant field.
903    */
904    switch (code) {
905    case CbcGenParam::PREPROCESS: {
906        if (str == "off") {
907            ctlBlk->setIPPAction(CbcGenCtlBlk::IPPOff) ;
908        } else if (str == "on") {
909            ctlBlk->setIPPAction(CbcGenCtlBlk::IPPOn) ;
910        } else if (str == "save") {
911            ctlBlk->setIPPAction(CbcGenCtlBlk::IPPSave) ;
912        } else if (str == "equal") {
913            ctlBlk->setIPPAction(CbcGenCtlBlk::IPPEqual) ;
914        } else if (str == "sos") {
915            ctlBlk->setIPPAction(CbcGenCtlBlk::IPPSOS) ;
916        } else if (str == "trysos") {
917            ctlBlk->setIPPAction(CbcGenCtlBlk::IPPTrySOS) ;
918        } else if (str == "equalall") {
919            ctlBlk->setIPPAction(CbcGenCtlBlk::IPPEqualAll) ;
920        } else if (str == "strategy") {
921            ctlBlk->setIPPAction(CbcGenCtlBlk::IPPStrategy) ;
922        } else {
923            std::cerr
924                << "pushCbcGenKwdParam(PREPROCESS): unrecognised keyword `"
925                << str << "'." << std::endl ;
926            retval = -1 ;
927        }
928        break ;
929    }
930    case CbcGenParam::COSTSTRATEGY: {
931        if (str == "off") {
932            ctlBlk->priorityAction_ = CbcGenCtlBlk::BPOff ;
933        } else if (str == "priorities") {
934            ctlBlk->priorityAction_ = CbcGenCtlBlk::BPCost ;
935        }
936        if (str == "columnOrder") {
937            ctlBlk->priorityAction_ = CbcGenCtlBlk::BPOrder ;
938        } else {
939            std::cerr
940                << "pushCbcGenKwdParam(COSTSTRATEGY): unrecognised keyword `"
941                << str << "'." << std::endl ;
942            retval = -1 ;
943        }
944        break ;
945    }
946    case CbcGenParam::INTPRINT: {
947        if (str == "normal") {
948            ctlBlk->printMode_ = 0 ;
949        } else if (str == "integer") {
950            ctlBlk->printMode_ = 1 ;
951        } else if (str == "special") {
952            ctlBlk->printMode_ = 2 ;
953        } else if (str == "rows") {
954            ctlBlk->printMode_ = 3 ;
955        } else if (str == "all") {
956            ctlBlk->printMode_ = 4 ;
957        } else {
958            std::cerr
959                << "pushCbcGenKwdParam(INTPRINT): unrecognised keyword `"
960                << str << "'." << std::endl ;
961            retval = -1 ;
962        }
963        break ;
964    }
965    default: {
966        std::cerr
967            << "pushCbcGenKwdParam: unrecognised parameter code `"
968            << code << "'." << std::endl ;
969        retval = -1 ;
970        break ;
971    }
972    }
973
974    return (retval) ;
975}
976
977/*
978  Function to push a string-valued parameter
979*/
980
981int pushCbcGenStrParam (CoinParam *param)
982
983{
984    assert (param != 0) ;
985    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
986    assert (genParam != 0) ;
987    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
988    assert (ctlBlk != 0) ;
989
990    std::string str = genParam->strVal() ;
991    CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
992
993    int retval = 0 ;
994    /*
995      Figure out what we're doing and set the relevant field.
996    */
997    switch (code) {
998    case CbcGenParam::DIRECTORY: {
999        char dirSep = CoinFindDirSeparator() ;
1000        if (str[str.length()-1] != dirSep) {
1001            str += dirSep ;
1002        }
1003        ctlBlk->dfltDirectory_ = str ;
1004        break ;
1005    }
1006    default: {
1007        std::cerr << "pushCbcGenStr: no equivalent CbcGenCtlBlk field for "
1008                  << "parameter code `" << code << "'." << std::endl ;
1009        retval = -1 ;
1010        break ;
1011    }
1012    }
1013
1014    return (retval) ;
1015}
1016
1017/*
1018  The various parameters to control cut generators can be
1019  grouped, as they all use the same set of keywords.
1020*/
1021int pushCbcGenCutParam (CoinParam *param)
1022
1023{
1024    assert (param != 0) ;
1025    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
1026    assert (genParam != 0) ;
1027    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
1028    assert (ctlBlk != 0) ;
1029
1030    std::string str = genParam->kwdVal() ;
1031    CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
1032    /*
1033      Setup to return nonfatal/fatal error (1/-1) by default, so that all we need
1034      to do is correct to 0 (no error) if we're successful.
1035    */
1036    int retval ;
1037    if (CoinParamUtils::isInteractive()) {
1038        retval = 1 ;
1039    } else {
1040        retval = -1 ;
1041    }
1042    /*
1043      First translate the keyword into the correct CGControl enum value.
1044    */
1045    CbcGenCtlBlk::CGControl action ;
1046    if (str == "off") {
1047        action = CbcGenCtlBlk::CGOff ;
1048    } else if (str == "on") {
1049        action = CbcGenCtlBlk::CGOn ;
1050    } else if (str == "root") {
1051        action = CbcGenCtlBlk::CGRoot ;
1052    } else if (str == "ifmove") {
1053        action = CbcGenCtlBlk::CGIfMove ;
1054    } else if (str == "forceOn") {
1055        action = CbcGenCtlBlk::CGForceOn ;
1056    } else if (str == "forceOnBut") {
1057        action = CbcGenCtlBlk::CGForceBut ;
1058    } else {
1059        std::cerr
1060            << "pushCbcGenCutParam: unrecognised keyword `"
1061            << str << "'." << std::endl ;
1062        return (retval) ;
1063    }
1064    /*
1065      Validate the parameter code and set a variable to separate cuts from
1066      heuristics.
1067    */
1068    bool isCut = false ;
1069    bool isHeuristic = false ;
1070    switch (code) {
1071    case CbcGenParam::CLIQUECUTS:
1072    case CbcGenParam::FLOWCUTS:
1073    case CbcGenParam::GOMORYCUTS:
1074    case CbcGenParam::KNAPSACKCUTS:
1075    case CbcGenParam::MIXEDCUTS:
1076    case CbcGenParam::PROBINGCUTS:
1077    case CbcGenParam::REDSPLITCUTS:
1078    case CbcGenParam::TWOMIRCUTS:
1079    case CbcGenParam::CUTSTRATEGY: {
1080        isCut = true ;
1081        break ;
1082    }
1083    case CbcGenParam::COMBINE:
1084    case CbcGenParam::FPUMP:
1085    case CbcGenParam::ROUNDING:
1086    case CbcGenParam::LOCALTREE:
1087    case CbcGenParam::HEURISTICSTRATEGY: {
1088        isHeuristic = true ;
1089        break ;
1090    }
1091    default: {
1092        std::cerr
1093            << "pushCbcGenCutParam: unrecognised parameter code `"
1094            << code << "'." << std::endl ;
1095        return (retval) ;
1096    }
1097    }
1098    /*
1099      See if the action is valid for the specified type. Heuristics are on or
1100      off; cuts can be any of the other codes. Only probing can use forceOnBut.
1101    */
1102    if (isHeuristic) {
1103        if (!(action == CbcGenCtlBlk::CGOff || action == CbcGenCtlBlk::CGOn)) {
1104            std::cerr
1105                << "pushCbcGenCutParam: only on or off is valid for a heuristic."
1106                << std::endl ;
1107            return (retval) ;
1108        }
1109    } else if (isCut) {
1110        if (action == CbcGenCtlBlk::CGForceBut &&
1111                code != CbcGenParam::PROBINGCUTS) {
1112            std::cerr
1113                << "pushCbcGenCutParam: forceOnBut is valid only for probing."
1114                << std::endl ;
1115            return (retval) ;
1116        }
1117    }
1118    /*
1119      We've done the basic checks; go ahead and set the relevant field in the
1120      control block. We shouldn't need the default case, but some compilers will
1121      complain if it's missing.
1122    */
1123    switch (code) {
1124    case CbcGenParam::CLIQUECUTS: {
1125        ctlBlk->setCliqueAction(action) ;
1126        break ;
1127    }
1128    case CbcGenParam::FLOWCUTS: {
1129        ctlBlk->setFlowAction(action) ;
1130        break ;
1131    }
1132    case CbcGenParam::GOMORYCUTS: {
1133        ctlBlk->setGomoryAction(action) ;
1134        break ;
1135    }
1136    case CbcGenParam::KNAPSACKCUTS: {
1137        ctlBlk->setKnapsackAction(action) ;
1138        break ;
1139    }
1140    case CbcGenParam::MIXEDCUTS: {
1141        ctlBlk->setMirAction(action) ;
1142        break ;
1143    }
1144    case CbcGenParam::PROBINGCUTS: {
1145        ctlBlk->setProbingAction(action) ;
1146        break ;
1147    }
1148    case CbcGenParam::REDSPLITCUTS: {
1149        ctlBlk->setRedSplitAction(action) ;
1150        break ;
1151    }
1152    case CbcGenParam::TWOMIRCUTS: {
1153        ctlBlk->setTwomirAction(action) ;
1154        break ;
1155    }
1156    case CbcGenParam::CUTSTRATEGY: {
1157        ctlBlk->setCliqueAction(action) ;
1158        ctlBlk->setFlowAction(action) ;
1159        ctlBlk->setGomoryAction(action) ;
1160        ctlBlk->setKnapsackAction(action) ;
1161        ctlBlk->setMirAction(action) ;
1162        ctlBlk->setProbingAction(action) ;
1163        ctlBlk->setRedSplitAction(action) ;
1164        ctlBlk->setTwomirAction(action) ;
1165        break ;
1166    }
1167    case CbcGenParam::COMBINE: {
1168        ctlBlk->setCombineAction(action) ;
1169        break ;
1170    }
1171    case CbcGenParam::FPUMP: {
1172        ctlBlk->setFPumpAction(action) ;
1173        break ;
1174    }
1175    case CbcGenParam::GREEDY: {
1176        ctlBlk->setGreedyCoverAction(action) ;
1177        ctlBlk->setGreedyEqualityAction(action) ;
1178        break ;
1179    }
1180    case CbcGenParam::LOCALTREE: {
1181        ctlBlk->setTreeLocalAction(action) ;
1182        break ;
1183    }
1184    case CbcGenParam::ROUNDING: {
1185        ctlBlk->setRoundingAction(action) ;
1186        break ;
1187    }
1188    case CbcGenParam::HEURISTICSTRATEGY: {
1189        ctlBlk->setCombineAction(action) ;
1190        ctlBlk->setFPumpAction(action) ;
1191        ctlBlk->setGreedyCoverAction(action) ;
1192        ctlBlk->setRoundingAction(action) ;
1193        ctlBlk->setTreeLocalAction(action) ;
1194        break ;
1195    }
1196    default: {
1197        std::cerr
1198            << "pushCbcGenCutParam: internal confusion!" << std::endl ;
1199        return (-1) ;
1200    }
1201    }
1202
1203    return (0) ;
1204}
1205
1206/*
1207  This routine imports a new constraint system into the solver.
1208*/
1209
1210int doImportParam (CoinParam *param)
1211
1212{
1213    assert (param != 0) ;
1214    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
1215    assert (genParam != 0) ;
1216    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
1217    assert (ctlBlk != 0) ;
1218    /*
1219      Setup to return nonfatal/fatal error (1/-1) by default, so that all we need
1220      to do is correct to 0 (no error) if we're successful.
1221    */
1222    int retval ;
1223    if (CoinParamUtils::isInteractive()) {
1224        retval = 1 ;
1225    } else {
1226        retval = -1 ;
1227    }
1228    /*
1229      Figure out where we're going to acquire this new model. As special cases,
1230      `$' says `use the previous input source' and `-' says `use stdin'.
1231    */
1232    std::string field = genParam->strVal() ;
1233    std::string fileName ;
1234    if (field == "$") {
1235        fileName = ctlBlk->lastMpsIn_ ;
1236        field = fileName ;
1237    } else if (field == "-") {
1238        fileName = "stdin" ;
1239        field = fileName ;
1240    } else {
1241        fileName = field ;
1242    }
1243    /*
1244      See if we can open a file. fileCoinReadable understands a fair bit about
1245      platforms and compressed files and will try variations of the file name
1246      (see the doxygen doc'n for details). The file name returned in field wil
1247      be the one that actually worked.
1248    */
1249    bool canOpen = fileCoinReadable(fileName, ctlBlk->dfltDirectory_) ;
1250    if (canOpen == false) {
1251        std::cout
1252            << "Unable to open file `" << fileName
1253            << "', original name '" << genParam->strVal() << "'." << std::endl ;
1254        return (retval) ;
1255    }
1256    /*
1257      We can find the file. Record the name. This requires a little finesse: what
1258      we want is the base file name (and extension(s), if present) but not the
1259      prefix, unless it's an absolute path.
1260    */
1261    if (!fileAbsPath(fileName)) {
1262        std::string::size_type pos = fileName.rfind(field) ;
1263        ctlBlk->lastMpsIn_ = fileName.substr(pos) ;
1264    } else {
1265        ctlBlk->lastMpsIn_ = fileName ;
1266    }
1267    /*
1268      Try to read the file. Standard OSI doesn't support the Clp extensions for
1269      keepImportNames and allowImportErrors. It should at least support
1270      keepImportNames. Status will be zero for a successful read.
1271    */
1272    OsiSolverInterface *lpSolver = ctlBlk->model_->solver() ;
1273    int status = lpSolver->readMps(fileName.c_str(), "") ;
1274    if (status) {
1275        std::cout
1276            << "There were " << status << " errors on input." << std::endl ;
1277        return (retval) ;
1278    }
1279    /*
1280      We have a model! Return success.
1281    */
1282    ctlBlk->goodModel_ = true ;
1283
1284    return (0) ;
1285}
1286
1287
1288/*
1289  This routine imports a debug file into the solver, or arranges for its
1290  creation. Import works in the standard way, using the file name provided
1291  with the command.
1292
1293  As special cases, if the file name is `create' or `createAfterPre', the
1294  action here sets up to cause a debug file containing the solution to be
1295  dumped after branch-and-cut is completed.  `createAfterPre' will dump the
1296  solution before undoing the presolve transforms.  `create' will dump the
1297  solution after integer presolve is backed out.
1298*/
1299
1300int doDebugParam (CoinParam *param)
1301
1302{
1303    assert (param != 0) ;
1304    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
1305    assert (genParam != 0) ;
1306    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
1307    assert (ctlBlk != 0) ;
1308    /*
1309      Setup to return nonfatal/fatal error (1/-1) by default, so that all we need
1310      to do is correct to 0 (no error) if we're successful.
1311    */
1312    int retval ;
1313    if (CoinParamUtils::isInteractive()) {
1314        retval = 1 ;
1315    } else {
1316        retval = -1 ;
1317    }
1318    /*
1319       If the file name is `create' or `createAfterPre', we're just setting up to
1320       make a debug file the next time we do branch-and-cut.
1321    */
1322    std::string field = genParam->strVal() ;
1323    if (field == "create" || field == "createAfterPre") {
1324        ctlBlk->debugCreate_ = field ;
1325        return (0) ;
1326    }
1327    /*
1328      Figure out where we're going to acquire the debug file. As special cases,
1329      `$' says `use the previous input source' and `-' says `use stdin'.
1330    */
1331    std::string fileName ;
1332    if (field == "$") {
1333        fileName = ctlBlk->debugFile_ ;
1334        field = fileName ;
1335    } else if (field == "-") {
1336        fileName = "stdin" ;
1337        field = fileName ;
1338    } else {
1339        fileName = field ;
1340    }
1341    /*
1342      See if we can open a file. fileCoinReadable understands a fair bit about
1343      platforms and compressed files and will try variations of the file name
1344      (see the doxygen doc'n for details). The file name returned in field wil be
1345      the one that actually worked. No default prefix --- a debug file is assumed
1346      to always be in the current directory.
1347    */
1348    bool canOpen = fileCoinReadable(fileName, ctlBlk->dfltDirectory_) ;
1349    if (canOpen == false) {
1350        std::cout
1351            << "Unable to open file `" << fileName
1352            << "', original name '" << genParam->strVal() << "'." << std::endl ;
1353        return (retval) ;
1354    }
1355    /*
1356      We can find the file. Record the name. This requires a little finesse: what
1357      we want is the base file name (and extension(s), if present) but not the
1358      prefix, unless it's an absolute path.
1359    */
1360    if (!fileAbsPath(fileName)) {
1361        std::string::size_type pos = fileName.rfind(field) ;
1362        ctlBlk->lastMpsIn_ = fileName.substr(pos) ;
1363    } else {
1364        ctlBlk->lastMpsIn_ = fileName ;
1365    }
1366    /*
1367      Load the primal variable values into the debug solution vector.
1368    */
1369    int intUnused, numCols ;
1370    double dblUnused ;
1371    double *primals ;
1372
1373    bool readOK = readSolution(fileName,
1374                               intUnused, numCols, dblUnused, 0, 0, &primals, 0) ;
1375
1376    if (readOK) {
1377        if (ctlBlk->debugSol_.values_) {
1378            delete[] ctlBlk->debugSol_.values_ ;
1379        }
1380        ctlBlk->debugSol_.numCols_ = numCols ;
1381        ctlBlk->debugSol_.values_ = primals ;
1382        retval = 0 ;
1383    } else {
1384        if (primals) {
1385            delete[] primals ;
1386        }
1387    }
1388
1389    return (retval) ;
1390}
1391
1392
1393/*
1394  Utility routine to save the current solution to a file. No formatting, and
1395  not intended to be portable in any way, shape, or form.
1396*/
1397
1398void saveSolution (const OsiSolverInterface *osi, std::string fileName)
1399
1400{
1401    FILE *fp = fopen(fileName.c_str(), "wb") ;
1402
1403    if (fp) {
1404        int numberRows = osi->getNumRows() ;
1405        int numberColumns = osi->getNumCols() ;
1406        double objectiveValue = osi->getObjValue() ;
1407
1408        fwrite(&numberRows, sizeof(int), 1, fp) ;
1409        fwrite(&numberColumns, sizeof(int), 1, fp) ;
1410        fwrite(&objectiveValue, sizeof(double), 1, fp) ;
1411
1412        const double *primalRowSolution = osi->getRowActivity() ;
1413        const double *dualRowSolution = osi->getRowPrice() ;
1414        const double *primalColumnSolution = osi->getColSolution() ;
1415        const double *dualColumnSolution = osi->getReducedCost() ;
1416
1417        fwrite(primalRowSolution, sizeof(double), numberRows, fp) ;
1418        fwrite(dualRowSolution, sizeof(double), numberRows, fp) ;
1419        fwrite(primalColumnSolution, sizeof(double), numberColumns, fp) ;
1420        fwrite(dualColumnSolution, sizeof(double), numberColumns, fp) ;
1421
1422        fclose(fp) ;
1423    } else {
1424        std::cout
1425            << "saveSolution: Unable to open file `"
1426            << fileName << "'." << std::endl ;
1427    }
1428
1429    return ;
1430}
1431
1432/*
1433  Utility routine to read in a solution dump created by saveSolution. Generally
1434  we don't need all the info in this file, so the routine accepts a bunch of
1435  reference/pointer paramaters and fills in any that are non-null. It's the
1436  client's responsibility to dispose of space allocated for solution vectors.
1437  The parameters fileName, numRows, numCols, and objVal are mandatory. The rest
1438  can be null.
1439*/
1440bool readSolution (std::string fileName,
1441                   int &numRows, int &numCols, double &objVal,
1442                   double **rowActivity, double **dualVars,
1443                   double **primalVars, double **reducedCosts)
1444
1445{
1446    FILE *fp = fopen(fileName.c_str(), "rb") ;
1447    bool retval = true ;
1448
1449    numRows = -1 ;
1450    numCols = -1 ;
1451    objVal = 0 ;
1452    *rowActivity = 0 ;
1453    *dualVars = 0 ;
1454    *primalVars = 0 ;
1455    *reducedCosts = 0 ;
1456
1457    if (fp) {
1458        fread(&numRows, sizeof(int), 1, fp) ;
1459        fread(&numCols, sizeof(int), 1, fp) ;
1460        fread(&objVal, sizeof(double), 1, fp) ;
1461
1462        if (rowActivity != NULL) {
1463            *rowActivity = new double [numRows] ;
1464            fread(*rowActivity, sizeof(double), numRows, fp) ;
1465        } else {
1466            fseek(fp, numRows*sizeof(double), SEEK_CUR) ;
1467        }
1468
1469        if (dualVars != NULL) {
1470            *dualVars = new double [numRows] ;
1471            fread(*dualVars, sizeof(double), numRows, fp) ;
1472        } else {
1473            fseek(fp, numRows*sizeof(double), SEEK_CUR) ;
1474        }
1475
1476        if (primalVars != NULL) {
1477            *primalVars = new double [numCols] ;
1478            fread(*primalVars, sizeof(double), numCols, fp) ;
1479        } else {
1480            fseek(fp, numCols*sizeof(double), SEEK_CUR) ;
1481        }
1482
1483        if (reducedCosts != NULL) {
1484            *reducedCosts = new double [numCols] ;
1485            fread(*reducedCosts, sizeof(double), numCols, fp) ;
1486        } else {
1487            fseek(fp, numCols*sizeof(double), SEEK_CUR) ;
1488        }
1489
1490        fclose(fp) ;
1491    } else {
1492        std::cout
1493            << "readSolution: Unable to open file `"
1494            << fileName << "'." << std::endl ;
1495        retval = false ;
1496    }
1497
1498    return (retval) ;
1499}
1500
1501
1502} // end namespace CbcGenParamUtils
1503
1504
Note: See TracBrowser for help on using the repository browser.