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

Last change on this file since 591 was 591, checked in by lou, 13 years ago

Initial commit of cbc-generic source.

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