source: branches/devel/Cbc/src/CbcGenParamUtils.cpp @ 648

Last change on this file since 648 was 608, checked in by lou, 12 years ago

Cbc-generic: Add message handler, separate libCbc and cbc-generic main log
level parameters.

  • Property svn:eol-style set to native
File size: 48.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 "CoinParam.hpp"
19
20#include "CbcModel.hpp"
21
22#include "CbcGenParam.hpp"
23#include "CbcGenCtlBlk.hpp"
24
25/*! \file CbcGenParamUtils
26    \brief Implementation functions for CbcGenParam parameters.
27*/
28
29namespace {
30
31  char svnid[] = "$Id$" ;
32
33}
34
35namespace CbcGenSolvers
36{
37  void setupSolverParam(CbcGenParam &solverParam) ;
38}
39
40namespace CbcGenParamUtils
41{
42
43/*
44  Function to add cbc-generic control parameters to the cbc-generic parameter
45  vector. Were needed, defaults are drawn from ctlBlk-> This function is a
46  friend of CbcGenCtlBlk.
47*/
48
49void addCbcGenParams (int &numberParameters, CoinParamVec &parameters,
50                      CbcGenCtlBlk *ctlBlk)
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,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,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
640void loadGenParamObj (const CoinParamVec paramVec, int first, int last,
641                      CbcGenCtlBlk *ctlBlk)
642
643{ int i ;
644/*
645  Load the cbc-generic object into the parameters
646*/
647  for (i = first ; i <= last ; i++)
648  { CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(paramVec[i]) ;
649    assert (genParam != 0) ;
650    genParam->setObj(ctlBlk) ; }
651
652  return ; }
653
654
655/* Functions to implement  cbc-generic (CbcGenParam) parameters */
656
657/*
658  Maintainer's utility, scan the parameters and report the ones that are
659  unimplemented (i.e., have no pushFunc).
660*/
661
662int doUnimplementedParam (CoinParam *param)
663
664{ assert (param != 0) ;
665
666  CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
667  assert (genParam != 0) ;
668
669  CbcGenCtlBlk *ctlBlk = genParam->obj() ;
670  assert (ctlBlk != 0) ;
671
672  assert (ctlBlk->paramVec_ != 0) ;
673  CoinParamVec &paramVec = *ctlBlk->paramVec_ ;
674
675  int unimpCnt = 0 ;
676  int maxAcross = 5 ;
677  for (unsigned i = 0 ; i < paramVec.size() ; i++)
678  { CoinParam *param = paramVec[i] ;
679    if (param->pushFunc() == 0)
680    { if (unimpCnt%maxAcross == 0)
681      { std::cout << std::endl ; }
682      else
683      { std::cout << " " ; }
684      std::cout << param->name() ;
685      unimpCnt++ ; } }
686  if (unimpCnt%maxAcross != 1)
687  { std::cout << std::endl ; }
688  std::cout << unimpCnt << " unimplemented parameters." << std::endl ;
689
690  return (0) ; }
691
692
693/*
694  Noop function. Mainly to eliminate commands from the list returned by
695  doUnimplmentedParam.
696*/
697
698int doNothingParam (CoinParam *param)
699{
700  return (0) ;
701}
702
703/*
704  Function to terminate command parsing by returning -1.
705*/
706
707int doExitParam (CoinParam *param)
708
709{
710  return (-1) ;
711}
712
713/*
714  Function to print the current version.
715*/
716
717int doVersionParam (CoinParam *param)
718
719{ assert (param != 0) ;
720  CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
721  assert (genParam != 0) ;
722  CbcGenCtlBlk *ctlBlk = genParam->obj() ;
723  assert (ctlBlk != 0) ;
724
725  std::cout << "cbc-generic version " << ctlBlk->version_ << std::endl ;
726  std::cout
727    << "cbc-generic is experimental software. If you want a stable MIP "
728    << "solver, please" << std::endl
729    << "use cbc. If you discover bugs while using cbc-generic "
730    << "please specify" << std::endl
731    << "cbc-generic in the ticket description or email subject line."
732    << std::endl ;
733
734  return (0) ; }
735
736/*
737  Function to handle help (HELP), `?' (GENERALQUERY), and `???'
738  (FULLGENERALQUERY).
739*/
740
741int doHelpParam (CoinParam *param)
742
743{ assert (param != 0) ;
744  CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
745  assert (genParam != 0) ;
746  CbcGenCtlBlk *ctlBlk = genParam->obj() ;
747  assert (ctlBlk != 0) ;
748
749  CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
750
751  int verbose = ctlBlk->verbose_ ;
752  bool shortHelp = ((verbose&0x01)?true:false) ;
753  bool longHelp = ((verbose&0x02)?true:false) ;
754  bool hidden = ((verbose&0x08)?true:false) ;
755
756  CoinParamVec *paramVec = ctlBlk->paramVec_ ;
757  assert (paramVec != 0) ;
758/*
759  Tune up the initial settings. FULLGENERALQUERY will print normally hidden
760  params, and a request for long help overrules a request for short help.
761*/
762  if (code == CbcGenParam::FULLGENERALQUERY)
763  { hidden = true ; }
764  if (longHelp)
765  { shortHelp = false ; }
766
767  CoinParamUtils::printGenericHelp() ;
768
769  std::cout << "\nAvailable commands are:" ;
770  std::string pfx("  ") ;
771  CoinParamUtils::printHelp(*paramVec,0,paramVec->size()-1,pfx,
772                            shortHelp,longHelp,hidden) ;
773 
774  return (0) ; }
775
776/*
777  Function to push a double-valued parameter.
778*/
779
780int pushCbcGenDblParam (CoinParam *param)
781
782{ assert (param != 0) ;
783  CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
784  assert (genParam != 0) ;
785  CbcGenCtlBlk *ctlBlk = genParam->obj() ;
786  assert (ctlBlk != 0) ;
787
788  double val = genParam->dblVal() ;
789  CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
790
791  int retval = 0 ;
792/*
793  Figure out what we're doing and set the relevant field.
794*/
795  switch (code)
796  { case CbcGenParam::DJFIX:
797    { ctlBlk->djFix_.action_ = true ;
798      ctlBlk->djFix_.threshold_ = val ;
799      break ; }
800    default:
801    { std::cerr << "pushCbcGenDbl: no equivalent CbcGenCtlBlk field for "
802                << "parameter code `" << code << "'." << std::endl ;
803      retval = -1 ;
804      break ; } }
805
806  return (retval) ; }
807
808/*
809  Function to push an integer-valued parameter.
810*/
811
812int pushCbcGenIntParam (CoinParam *param)
813
814{ assert (param != 0) ;
815  CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
816  assert (genParam != 0) ;
817  CbcGenCtlBlk *ctlBlk = genParam->obj() ;
818  assert (ctlBlk != 0) ;
819
820  int val = genParam->intVal() ;
821  CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
822
823  int retval = 0 ;
824/*
825  Figure out what we're doing and set the relevant field.
826*/
827  switch (code)
828  { case CbcGenParam::CUTDEPTH:
829    { ctlBlk->setCutDepth(val) ;
830      break ; }
831    case CbcGenParam::LOGLEVEL:
832    { ctlBlk->setLogLevel(val) ;
833      break ; }
834    case CbcGenParam::PRINTOPTIONS:
835    { ctlBlk->printOpt_ = val ;
836      break ; }
837    case CbcGenParam::VERBOSE:
838    { ctlBlk->verbose_ = val ;
839      break ; }
840    default:
841    { std::cerr << "pushCbcGenInt: no equivalent CbcGenCtlBlk field for "
842                << "parameter code `" << code << "'." << std::endl ;
843      retval = -1 ;
844      break ; } }
845
846  return (retval) ; }
847
848
849/*
850  Function to push a keyword-valued parameter. This is the catch-all function
851  for keyword parameters that don't belong to any other useful grouping.
852*/
853
854int pushCbcGenKwdParam (CoinParam *param)
855
856{ assert (param != 0) ;
857  CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
858  assert (genParam != 0) ;
859  CbcGenCtlBlk *ctlBlk = genParam->obj() ;
860  assert (ctlBlk != 0) ;
861
862  std::string str = genParam->kwdVal() ;
863  CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
864
865  int retval = 0 ;
866/*
867  Figure out what we're doing and set the relevant field.
868*/
869  switch (code)
870  { case CbcGenParam::PREPROCESS:
871    { if (str == "off")
872      { ctlBlk->setIPPAction(CbcGenCtlBlk::IPPOff) ; }
873      else
874      if (str == "on")
875      { ctlBlk->setIPPAction(CbcGenCtlBlk::IPPOn) ; }
876      else
877      if (str == "save")
878      { ctlBlk->setIPPAction(CbcGenCtlBlk::IPPSave) ; }
879      else
880      if (str == "equal")
881      { ctlBlk->setIPPAction(CbcGenCtlBlk::IPPEqual) ; }
882      else
883      if (str == "sos")
884      { ctlBlk->setIPPAction(CbcGenCtlBlk::IPPSOS) ; }
885      else
886      if (str == "trysos")
887      { ctlBlk->setIPPAction(CbcGenCtlBlk::IPPTrySOS) ; }
888      else
889      if (str == "equalall")
890      { ctlBlk->setIPPAction(CbcGenCtlBlk::IPPEqualAll) ; }
891      else
892      if (str == "strategy")
893      { ctlBlk->setIPPAction(CbcGenCtlBlk::IPPStrategy) ; }
894      else
895      { std::cerr
896          << "pushCbcGenKwdParam(PREPROCESS): unrecognised keyword `"
897          << str << "'." << std::endl ;
898        retval = -1 ; }
899      break ; }
900    case CbcGenParam::COSTSTRATEGY:
901    { if (str == "off")
902      { ctlBlk->priorityAction_ = CbcGenCtlBlk::BPOff ; }
903      else
904      if (str == "priorities")
905      { ctlBlk->priorityAction_ = CbcGenCtlBlk::BPCost ; }
906      if (str == "columnOrder")
907      { ctlBlk->priorityAction_ = CbcGenCtlBlk::BPOrder ; }
908      else
909      { std::cerr
910          << "pushCbcGenKwdParam(COSTSTRATEGY): unrecognised keyword `"
911          << str << "'." << std::endl ;
912        retval = -1 ; }
913      break ; }
914    case CbcGenParam::INTPRINT:
915    { if (str == "normal")
916      { ctlBlk->printMode_ = 0 ; }
917      else
918      if (str == "integer")
919      { ctlBlk->printMode_ = 1 ; }
920      else
921      if (str == "special")
922      { ctlBlk->printMode_ = 2 ; }
923      else
924      if (str == "rows")
925      { ctlBlk->printMode_ = 3 ; }
926      else
927      if (str == "all")
928      { ctlBlk->printMode_ = 4 ; }
929      else
930      { std::cerr
931          << "pushCbcGenKwdParam(INTPRINT): unrecognised keyword `"
932          << str << "'." << std::endl ;
933        retval = -1 ; }
934      break ; }
935    default:
936    { std::cerr
937        << "pushCbcGenKwdParam: unrecognised parameter code `"
938        << code << "'." << std::endl ;
939      retval = -1 ;
940      break ; } }
941
942  return (retval) ; }
943
944/*
945  Function to push a string-valued parameter
946*/
947
948int pushCbcGenStrParam (CoinParam *param)
949
950{ assert (param != 0) ;
951  CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
952  assert (genParam != 0) ;
953  CbcGenCtlBlk *ctlBlk = genParam->obj() ;
954  assert (ctlBlk != 0) ;
955
956  std::string str = genParam->strVal() ;
957  CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
958
959  int retval = 0 ;
960/*
961  Figure out what we're doing and set the relevant field.
962*/
963  switch (code)
964  { case CbcGenParam::DIRECTORY:
965    { char dirSep = CoinFindDirSeparator() ;
966      if (str[str.length()-1] != dirSep)
967      { str += dirSep ; }
968      ctlBlk->dfltDirectory_ = str ;
969      break ; }
970    default:
971    { std::cerr << "pushCbcGenStr: no equivalent CbcGenCtlBlk field for "
972                << "parameter code `" << code << "'." << std::endl ;
973      retval = -1 ;
974      break ; } }
975
976  return (retval) ; }
977
978/*
979  The various parameters to control cut generators can be
980  grouped, as they all use the same set of keywords.
981*/
982int pushCbcGenCutParam (CoinParam *param)
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->kwdVal() ;
991  CbcGenParam::CbcGenParamCode code = genParam->paramCode() ;
992/*
993  Setup to return nonfatal/fatal error (1/-1) by default, so that all we need
994  to do is correct to 0 (no error) if we're successful.
995*/
996  int retval ;
997  if (CoinParamUtils::isInteractive())
998  { retval = 1 ; }
999  else
1000  { retval = -1 ; }
1001/*
1002  First translate the keyword into the correct CGControl enum value.
1003*/
1004  CbcGenCtlBlk::CGControl action ;
1005  if (str == "off")
1006  { action = CbcGenCtlBlk::CGOff ; }
1007  else
1008  if (str == "on")
1009  { action = CbcGenCtlBlk::CGOn ; }
1010  else
1011  if (str == "root")
1012  { action = CbcGenCtlBlk::CGRoot ; }
1013  else
1014  if (str == "ifmove")
1015  { action = CbcGenCtlBlk::CGIfMove ; }
1016  else
1017  if (str == "forceOn")
1018  { action = CbcGenCtlBlk::CGForceOn ; }
1019  else
1020  if (str == "forceOnBut")
1021  { action = CbcGenCtlBlk::CGForceBut ; }
1022  else
1023  { std::cerr
1024      << "pushCbcGenCutParam: unrecognised keyword `"
1025      << str << "'." << std::endl ;
1026    return (retval) ; }
1027/*
1028  Validate the parameter code and set a variable to separate cuts from
1029  heuristics.
1030*/
1031  bool isCut = false ;
1032  bool isHeuristic = false ;
1033  switch (code)
1034  { case CbcGenParam::CLIQUECUTS:
1035    case CbcGenParam::FLOWCUTS:
1036    case CbcGenParam::GOMORYCUTS:
1037    case CbcGenParam::KNAPSACKCUTS:
1038    case CbcGenParam::MIXEDCUTS:
1039    case CbcGenParam::PROBINGCUTS:
1040    case CbcGenParam::REDSPLITCUTS:
1041    case CbcGenParam::TWOMIRCUTS:
1042    case CbcGenParam::CUTSTRATEGY:
1043    { isCut = true ; 
1044      break ; }
1045    case CbcGenParam::COMBINE:
1046    case CbcGenParam::FPUMP:
1047    case CbcGenParam::ROUNDING:
1048    case CbcGenParam::LOCALTREE:
1049    case CbcGenParam::HEURISTICSTRATEGY:
1050    { isHeuristic = true ; 
1051      break ; }
1052    default:
1053    { std::cerr
1054        << "pushCbcGenCutParam: unrecognised parameter code `"
1055        << code << "'." << std::endl ;
1056      return (retval) ; } }
1057/*
1058  See if the action is valid for the specified type. Heuristics are on or
1059  off; cuts can be any of the other codes. Only probing can use forceOnBut.
1060*/
1061  if (isHeuristic)
1062  { if (!(action == CbcGenCtlBlk::CGOff || action == CbcGenCtlBlk::CGOn))
1063    { std::cerr
1064        << "pushCbcGenCutParam: only on or off is valid for a heuristic."
1065        << std::endl ;
1066      return (retval) ; } }
1067  else
1068  if (isCut)
1069  { if (action == CbcGenCtlBlk::CGForceBut &&
1070        code != CbcGenParam::PROBINGCUTS)
1071    { std::cerr
1072        << "pushCbcGenCutParam: forceOnBut is valid only for probing."
1073        << std::endl ;
1074      return (retval) ; } }
1075/*
1076  We've done the basic checks; go ahead and set the relevant field in the
1077  control block. We shouldn't need the default case, but some compilers will
1078  complain if it's missing.
1079*/
1080  switch (code)
1081  { case CbcGenParam::CLIQUECUTS:
1082    { ctlBlk->setCliqueAction(action) ;
1083      break ; }
1084    case CbcGenParam::FLOWCUTS:
1085    { ctlBlk->setFlowAction(action) ;
1086      break ; }
1087    case CbcGenParam::GOMORYCUTS:
1088    { ctlBlk->setGomoryAction(action) ;
1089      break ; }
1090    case CbcGenParam::KNAPSACKCUTS:
1091    { ctlBlk->setKnapsackAction(action) ;
1092      break ; }
1093    case CbcGenParam::MIXEDCUTS:
1094    { ctlBlk->setMirAction(action) ;
1095      break ; }
1096    case CbcGenParam::PROBINGCUTS:
1097    { ctlBlk->setProbingAction(action) ;
1098      break ; }
1099    case CbcGenParam::REDSPLITCUTS:
1100    { ctlBlk->setRedSplitAction(action) ;
1101      break ; }
1102    case CbcGenParam::TWOMIRCUTS:
1103    { ctlBlk->setTwomirAction(action) ;
1104      break ; }
1105    case CbcGenParam::CUTSTRATEGY:
1106    { ctlBlk->setCliqueAction(action) ;
1107      ctlBlk->setFlowAction(action) ;
1108      ctlBlk->setGomoryAction(action) ;
1109      ctlBlk->setKnapsackAction(action) ;
1110      ctlBlk->setMirAction(action) ;
1111      ctlBlk->setProbingAction(action) ;
1112      ctlBlk->setRedSplitAction(action) ;
1113      ctlBlk->setTwomirAction(action) ;
1114      break ; }
1115    case CbcGenParam::COMBINE:
1116    { ctlBlk->setCombineAction(action) ;
1117      break ; }
1118    case CbcGenParam::FPUMP:
1119    { ctlBlk->setFPumpAction(action) ;
1120      break ; }
1121    case CbcGenParam::GREEDY:
1122    { ctlBlk->setGreedyCoverAction(action) ;
1123      ctlBlk->setGreedyEqualityAction(action) ;
1124      break ; }
1125    case CbcGenParam::LOCALTREE:
1126    { ctlBlk->setTreeLocalAction(action) ;
1127      break ; }
1128    case CbcGenParam::ROUNDING:
1129    { ctlBlk->setRoundingAction(action) ;
1130      break ; }
1131    case CbcGenParam::HEURISTICSTRATEGY:
1132    { ctlBlk->setCombineAction(action) ;
1133      ctlBlk->setFPumpAction(action) ;
1134      ctlBlk->setGreedyCoverAction(action) ;
1135      ctlBlk->setRoundingAction(action) ;
1136      ctlBlk->setTreeLocalAction(action) ;
1137      break ; }
1138    default:
1139    { std::cerr
1140        << "pushCbcGenCutParam: internal confusion!" << std::endl ;
1141      return (-1) ; } }
1142
1143  return (0) ; }
1144
1145/*
1146  This routine imports a new constraint system into the solver.
1147*/
1148
1149int doImportParam (CoinParam *param)
1150
1151{ assert (param != 0) ;
1152  CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
1153  assert (genParam != 0) ;
1154  CbcGenCtlBlk *ctlBlk = genParam->obj() ;
1155  assert (ctlBlk != 0) ;
1156/*
1157  Setup to return nonfatal/fatal error (1/-1) by default, so that all we need
1158  to do is correct to 0 (no error) if we're successful.
1159*/
1160  int retval ;
1161  if (CoinParamUtils::isInteractive())
1162  { retval = 1 ; }
1163  else
1164  { retval = -1 ; }
1165/*
1166  Figure out where we're going to acquire this new model. As special cases,
1167  `$' says `use the previous input source' and `-' says `use stdin'.
1168*/
1169  std::string field = genParam->strVal() ;
1170  std::string fileName ;
1171  if (field == "$")
1172  { fileName = ctlBlk->lastMpsIn_ ;
1173    field = fileName ; }
1174  else
1175  if (field == "-")
1176  { fileName = "stdin" ;
1177    field = fileName ; }
1178  else
1179  { fileName = field ; }
1180/*
1181  See if we can open a file. fileCoinReadable understands a fair bit about
1182  platforms and compressed files and will try variations of the file name
1183  (see the doxygen doc'n for details). The file name returned in field wil
1184  be the one that actually worked.
1185*/
1186  bool canOpen = fileCoinReadable(fileName,ctlBlk->dfltDirectory_) ;
1187  if (canOpen == false)
1188  { std::cout
1189      << "Unable to open file `" << fileName
1190      << "', original name '" << genParam->strVal() <<"'." << std::endl ;
1191    return (retval) ; }
1192/*
1193  We can find the file. Record the name. This requires a little finesse: what
1194  we want is the base file name (and extension(s), if present) but not the
1195  prefix, unless it's an absolute path.
1196*/
1197  if (!fileAbsPath(fileName))
1198  { std::string::size_type pos = fileName.rfind(field) ;
1199    ctlBlk->lastMpsIn_ = fileName.substr(pos) ; }
1200  else
1201  { ctlBlk->lastMpsIn_ = fileName ; }
1202/*
1203  Try to read the file. Standard OSI doesn't support the Clp extensions for
1204  keepImportNames and allowImportErrors. It should at least support
1205  keepImportNames. Status will be zero for a successful read.
1206*/
1207  OsiSolverInterface *lpSolver = ctlBlk->model_->solver() ;
1208  int status = lpSolver->readMps(fileName.c_str(),"") ;
1209  if (status)
1210  { std::cout
1211      << "There were "<< status << " errors on input." << std::endl ;
1212    return (retval) ; }
1213/*
1214  We have a model! Return success.
1215*/
1216  ctlBlk->goodModel_ = true ;
1217
1218  return (0) ; }
1219
1220
1221/*
1222  This routine imports a debug file into the solver, or arranges for its
1223  creation. Import works in the standard way, using the file name provided
1224  with the command.
1225
1226  As special cases, if the file name is `create' or `createAfterPre', the
1227  action here sets up to cause a debug file containing the solution to be
1228  dumped after branch-and-cut is completed.  `createAfterPre' will dump the
1229  solution before undoing the presolve transforms.  `create' will dump the
1230  solution after integer presolve is backed out.
1231*/
1232
1233int doDebugParam (CoinParam *param)
1234
1235{ assert (param != 0) ;
1236  CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
1237  assert (genParam != 0) ;
1238  CbcGenCtlBlk *ctlBlk = genParam->obj() ;
1239  assert (ctlBlk != 0) ;
1240/*
1241  Setup to return nonfatal/fatal error (1/-1) by default, so that all we need
1242  to do is correct to 0 (no error) if we're successful.
1243*/
1244  int retval ;
1245  if (CoinParamUtils::isInteractive())
1246  { retval = 1 ; }
1247  else
1248  { retval = -1 ; }
1249/*
1250   If the file name is `create' or `createAfterPre', we're just setting up to
1251   make a debug file the next time we do branch-and-cut.
1252*/
1253  std::string field = genParam->strVal() ;
1254  if (field == "create" || field == "createAfterPre")
1255  { ctlBlk->debugCreate_ = field ;
1256    return (0) ; }
1257/*
1258  Figure out where we're going to acquire the debug file. As special cases,
1259  `$' says `use the previous input source' and `-' says `use stdin'.
1260*/
1261  std::string fileName ;
1262  if (field == "$")
1263  { fileName = ctlBlk->debugFile_ ;
1264    field = fileName ; }
1265  else
1266  if (field == "-")
1267  { fileName = "stdin" ;
1268    field = fileName ; }
1269  else
1270  { fileName = field ; }
1271/*
1272  See if we can open a file. fileCoinReadable understands a fair bit about
1273  platforms and compressed files and will try variations of the file name
1274  (see the doxygen doc'n for details). The file name returned in field wil be
1275  the one that actually worked. No default prefix --- a debug file is assumed
1276  to always be in the current directory.
1277*/
1278  bool canOpen = fileCoinReadable(fileName,ctlBlk->dfltDirectory_) ;
1279  if (canOpen == false)
1280  { std::cout
1281      << "Unable to open file `" << fileName
1282      << "', original name '" << genParam->strVal() <<"'." << std::endl ;
1283    return (retval) ; }
1284/*
1285  We can find the file. Record the name. This requires a little finesse: what
1286  we want is the base file name (and extension(s), if present) but not the
1287  prefix, unless it's an absolute path.
1288*/
1289  if (!fileAbsPath(fileName))
1290  { std::string::size_type pos = fileName.rfind(field) ;
1291    ctlBlk->lastMpsIn_ = fileName.substr(pos) ; }
1292  else
1293  { ctlBlk->lastMpsIn_ = fileName ; }
1294/*
1295  Load the primal variable values into the debug solution vector.
1296*/
1297  int intUnused,numCols ;
1298  double dblUnused ;
1299  double *primals ;
1300
1301  bool readOK = readSolution(fileName,
1302                             intUnused,numCols,dblUnused,0,0,&primals,0) ;
1303 
1304  if (readOK)
1305  { if (ctlBlk->debugSol_.values_)
1306    { delete[] ctlBlk->debugSol_.values_ ; }
1307    ctlBlk->debugSol_.numCols_ = numCols ;
1308    ctlBlk->debugSol_.values_ = primals ;
1309    retval = 0 ; }
1310  else
1311  { if (primals)
1312    { delete[] primals ; } }
1313
1314  return (retval) ; }
1315
1316
1317/*
1318  Utility routine to save the current solution to a file. No formatting, and
1319  not intended to be portable in any way, shape, or form.
1320*/
1321
1322void saveSolution (const OsiSolverInterface *osi, std::string fileName)
1323
1324{ FILE *fp = fopen(fileName.c_str(),"wb") ;
1325
1326  if (fp)
1327  { int numberRows = osi->getNumRows() ;
1328    int numberColumns = osi->getNumCols() ;
1329    double objectiveValue = osi->getObjValue() ;
1330
1331    fwrite(&numberRows,sizeof(int),1,fp) ;
1332    fwrite(&numberColumns,sizeof(int),1,fp) ;
1333    fwrite(&objectiveValue,sizeof(double),1,fp) ;
1334
1335    const double *primalRowSolution = osi->getRowActivity() ;
1336    const double *dualRowSolution = osi->getRowPrice() ;
1337    const double *primalColumnSolution = osi->getColSolution() ;
1338    const double *dualColumnSolution = osi->getReducedCost() ;
1339
1340    fwrite(primalRowSolution,sizeof(double),numberRows,fp) ;
1341    fwrite(dualRowSolution,sizeof(double),numberRows,fp) ;
1342    fwrite(primalColumnSolution,sizeof(double),numberColumns,fp) ;
1343    fwrite(dualColumnSolution,sizeof(double),numberColumns,fp) ;
1344
1345    fclose(fp) ; }
1346  else
1347  { std::cout
1348      << "saveSolution: Unable to open file `"
1349      << fileName << "'." << std::endl ; }
1350 
1351  return ; }
1352
1353/*
1354  Utility routine to read in a solution dump created by saveSolution. Generally
1355  we don't need all the info in this file, so the routine accepts a bunch of
1356  reference/pointer paramaters and fills in any that are non-null. It's the
1357  client's responsibility to dispose of space allocated for solution vectors.
1358  The parameters fileName, numRows, numCols, and objVal are mandatory. The rest
1359  can be null.
1360*/
1361bool readSolution (std::string fileName,
1362                   int &numRows, int &numCols, double &objVal,
1363                   double **rowActivity, double **dualVars,
1364                   double **primalVars, double **reducedCosts)
1365
1366{ FILE *fp = fopen(fileName.c_str(),"rb") ;
1367  bool retval = true ;
1368
1369  numRows = -1 ;
1370  numCols = -1 ;
1371  objVal = 0 ;
1372  *rowActivity = 0 ;
1373  *dualVars = 0 ;
1374  *primalVars = 0 ;
1375  *reducedCosts = 0 ;
1376
1377  if (fp)
1378  { fread(&numRows,sizeof(int),1,fp) ;
1379    fread(&numCols,sizeof(int),1,fp) ;
1380    fread(&objVal,sizeof(double),1,fp) ;
1381
1382    if (rowActivity != NULL)
1383    { *rowActivity = new double [numRows] ;
1384      fread(*rowActivity,sizeof(double),numRows,fp) ; }
1385    else
1386    { fseek(fp,numRows*sizeof(double),SEEK_CUR) ; }
1387
1388    if (dualVars != NULL)
1389    { *dualVars = new double [numRows] ;
1390      fread(*dualVars,sizeof(double),numRows,fp) ; }
1391    else
1392    { fseek(fp,numRows*sizeof(double),SEEK_CUR) ; }
1393
1394    if (primalVars != NULL)
1395    { *primalVars = new double [numCols] ;
1396      fread(*primalVars,sizeof(double),numCols,fp) ; }
1397    else
1398    { fseek(fp,numCols*sizeof(double),SEEK_CUR) ; }
1399
1400    if (reducedCosts != NULL)
1401    { *reducedCosts = new double [numCols] ;
1402      fread(*reducedCosts,sizeof(double),numCols,fp) ; }
1403    else
1404    { fseek(fp,numCols*sizeof(double),SEEK_CUR) ; }
1405
1406    fclose(fp) ; }
1407  else
1408  { std::cout
1409      << "readSolution: Unable to open file `"
1410      << fileName << "'." << std::endl ;
1411    retval = false ; }
1412
1413  return (retval) ; }
1414       
1415
1416} // end namespace CbcGenParamUtils
1417
1418
Note: See TracBrowser for help on using the repository browser.