source: trunk/Cbc/src/CbcGenParamUtils.cpp @ 1514

Last change on this file since 1514 was 1464, checked in by stefan, 9 years ago

merge split branch into trunk; fix some examples

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