source: branches/devel/Cbc/src/CbcGenOsiParamUtils.cpp @ 604

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

Initial commit of cbc-generic source.

  • Property svn:eol-style set to native
File size: 12.9 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 "CoinParam.hpp"
17
18#include "OsiSolverInterface.hpp"
19
20#include "CbcModel.hpp"
21#include "CbcGenCtlBlk.hpp"
22
23#include "CbcGenParam.hpp"
24#include "CbcGenCbcParam.hpp"
25#include "CbcGenOsiParam.hpp"
26
27/*! \file CbcOsiParamUtils
28    \brief Implementation functions for CbcOsiParam parameters.
29*/
30
31namespace CbcOsiParamUtils
32{
33
34
35
36/*
37  Function to set up OSI parameters. Does not include solver-specific
38  parameters.
39
40  ALGORITHM is commented out in CoinSolve.
41*/
42
43void addCbcOsiParams (int &numberParameters, CoinParamVec &parameters,
44                      OsiSolverInterface *osi)
45{ CbcOsiParam *param ;
46  OsiHintParam key ;
47  bool sense ;
48  OsiHintStrength strength ;
49  int ival ;
50  double dval ;
51
52  param = new CbcOsiParam(CbcOsiParam::KEEPNAMES,
53        "keepN!ames","Whether to keep row and column names on import.",
54        "off",1) ;
55  param->appendKwd("on") ;
56  param->setPushFunc(pushCbcOsiKwd) ;
57  param->setObj(osi) ;
58  param->setLongHelp(
59        "Row and column names are human-friendly, but maintaining names takes up space and time. Specifying -keepnames off >before< importing a problem will discard any name information."
60        ) ;
61  parameters.push_back(param) ;
62
63
64  (void) osi->getIntParam(OsiMaxNumIteration,ival) ;
65  param = new CbcOsiParam(CbcOsiParam::MAXITERATION,
66        "maxIt!erations","Iteration limit for OSI solver.",
67                  0,INT_MAX,ival) ;
68  param->setPushFunc(pushCbcOsiInt) ;
69  param->setObj(osi) ;
70  param->setLongHelp(
71        "Limits the number of iterations the OSI solver can perform when solving a problem."
72        ) ;
73  parameters.push_back(param) ;
74
75
76  (void) osi->getIntParam(OsiMaxNumIterationHotStart,ival) ;
77  param = new CbcOsiParam(CbcOsiParam::MAXHOTITS,
78        "hot!StartMaxIts","Iteration limit for OSI solver hot start.",
79                  0,INT_MAX,ival) ;
80  param->setPushFunc(pushCbcOsiInt) ;
81  param->setObj(osi) ;
82  param->setLongHelp(
83        "Limits the number of iterations the OSI solver can perform when solving a problem from a hot start. In the context of cbc, this limits the number of iterations expended on each LP during strong branching."
84        ) ;
85  parameters.push_back(param) ;
86
87/*
88  Simplified to on/off for OsiSolverInterface, where it goes in as a hint.
89*/
90  (void) osi->getHintParam(OsiDoPresolveInInitial,sense,strength) ;
91  if (sense == true)
92  { ival = 1 ; }
93  else
94  { ival = 0 ; }
95  param = new CbcOsiParam(CbcOsiParam::PRESOLVE,
96        "presolve","Whether to presolve problem","off",ival) ;
97  param->appendKwd("on") ;
98  param->setPushFunc(pushCbcOsiHint) ;
99  param->setObj(osi) ;
100  param->setLongHelp(
101        "Presolve analyzes the model to find such things as redundant constraints, constraints which fix some variables, constraints which can be transformed into bounds, etc.  For the initial solve of any problem this is worth doing unless you know that it will have no effect."
102        ) ;
103  parameters.push_back(param) ;
104
105
106  param = new CbcOsiParam(CbcOsiParam::PRIMALTOLERANCE,
107        "primalT!olerance",
108        "For an optimal solution no primal infeasibility may exceed this value",
109        1.0e-20,1.0e12) ;
110  param->setPushFunc(pushCbcOsiDbl) ;
111  param->setObj(osi) ;
112  param ->setLongHelp(
113        "Normally the default tolerance is fine, but you may want to increase it a bit if a primal run seems to be having a hard time"
114        ) ;
115  parameters.push_back(param) ;
116
117/*
118  Simplified for OsiSolverInterface, which just takes a hint.
119*/
120  (void) osi->getHintParam(OsiDoScale,sense,strength) ;
121  if (sense == true)
122  { ival = 1 ; }
123  else
124  { ival = 0 ; }
125  param = new CbcOsiParam(CbcOsiParam::SCALING,
126                      "scal!ing","Whether to scale problem","off",ival) ;
127  param ->appendKwd("on") ;
128  param->setPushFunc(pushCbcOsiHint) ;
129  param->setObj(osi) ;
130  param ->setLongHelp(
131        "Scaling can help in solving problems which might otherwise fail because of lack of accuracy.  It can also reduce the number of iterations.  It is not applied if the range of elements is small.  When unscaled it is possible that there may be small primal and/or infeasibilities."
132        ) ;
133  parameters.push_back(param) ;
134
135  ival = osi->messageHandler()->logLevel() ;
136  param = new CbcOsiParam(CbcOsiParam::SOLVERLOGLEVEL,
137        "slog!Level","Level of detail in Solver output",-1,63,ival) ;
138  param->setPushFunc(pushCbcOsiLogLevel) ;
139  param->setObj(osi) ;
140  param ->setLongHelp(
141        "If 0 then there should be no output in normal circumstances. 1 is probably the best value for most uses, while 2 and 3 give more information."
142        ) ;
143  parameters.push_back(param) ;
144
145  numberParameters = parameters.size() ;
146  assert (numberParameters <= parameters.capacity()) ;
147
148}
149
150void loadOsiParamObj (const CoinParamVec paramVec, int first, int last,
151                      OsiSolverInterface *obj)
152
153{ int i ;
154/*
155  Load the OsiSolverInterface object into the parameters
156*/
157  for (i = first ; i <= last ; i++)
158  { CbcOsiParam *osiParam = dynamic_cast<CbcOsiParam *>(paramVec[i]) ;
159    assert (osiParam != 0) ;
160    osiParam->setObj(obj) ; }
161
162  return ; }
163
164
165/*
166  Function to set default values for solver appropriate for cbc-generic.
167*/
168
169void setOsiSolverInterfaceDefaults (OsiSolverInterface *osi)
170
171{ 
172
173  osi->setIntParam(OsiMaxNumIteration,1000000) ;
174  osi->setIntParam(OsiMaxNumIterationHotStart,1000) ;
175  osi->setIntParam(OsiNameDiscipline,1) ;
176/*
177  Primal and dual feasibility tolerances (OsiPrimalTolerance and
178  OsiDualTolerance, respectively)  are left to the discretion of the solver.
179*/
180  osi->setDblParam(OsiDualObjectiveLimit,1.0e100) ;
181  osi->setDblParam(OsiPrimalObjectiveLimit,1.0e100) ;
182  osi->setDblParam(OsiObjOffset,0.0) ;
183
184  (void) osi->setHintParam(OsiDoPresolveInInitial,true,OsiHintDo) ;
185  (void) osi->setHintParam(OsiDoDualInInitial,true,OsiHintIgnore) ;
186  (void) osi->setHintParam(OsiDoPresolveInResolve,false,OsiHintTry) ;
187  (void) osi->setHintParam(OsiDoDualInInitial,true,OsiHintTry) ;
188  (void) osi->setHintParam(OsiDoScale,true,OsiHintDo) ;
189  (void) osi->setHintParam(OsiDoCrash,true,OsiHintIgnore) ;
190  (void) osi->setHintParam(OsiDoReducePrint,true,OsiHintDo) ;
191  (void) osi->setHintParam(OsiDoInBranchAndCut,true,OsiHintTry) ;
192
193  return ; }
194
195
196/*
197  Function to push an integer parameter.
198*/
199
200int pushCbcOsiInt (CoinParam *param)
201
202{ assert (param != 0) ;
203
204  CbcOsiParam *osiParam = dynamic_cast<CbcOsiParam *>(param) ;
205  assert (osiParam != 0) ;
206
207  OsiSolverInterface *osi = osiParam->obj() ;
208  assert (osi != 0) ;
209  int val = osiParam->intVal() ;
210  CbcOsiParam::CbcOsiParamCode code = osiParam->paramCode() ;
211
212  assert (osi != 0) ;
213/*
214  Setup to return nonfatal/fatal error (1/-1) by default, so that all we need
215  to do is correct to 0 (no error) if we're successful.
216*/
217  int retval ;
218  if (CoinParamUtils::isInteractive())
219  { retval = 1 ; }
220  else
221  { retval = -1 ; }
222/*
223  Translate the parameter code from CbcOsiParamCode into the correct key for
224  CbcIntParam.
225*/
226  OsiIntParam key ;
227  switch (code)
228  { case CbcOsiParam::MAXITERATION:
229    { key = OsiMaxNumIteration ;
230      break ; }
231    case CbcOsiParam::MAXHOTITS:
232    { key = OsiMaxNumIterationHotStart ;
233      break ; }
234    default:
235    { std::cerr << "pushCbcOsiIntParam: no equivalent OsiIntParam for "
236                << "parameter code `" << code << "'." << std::endl ;
237      retval = -1 ;
238      break ; } }
239
240  bool setOK = osi->setIntParam(key,val) ;
241  if (setOK == false)
242  { retval = -1 ; }
243
244  return (retval) ; }
245/*
246  Function to push a double parameter.
247*/
248
249int pushCbcOsiDbl (CoinParam *param)
250
251{ assert (param != 0) ;
252
253  CbcOsiParam *osiParam = dynamic_cast<CbcOsiParam *>(param) ;
254  assert (osiParam != 0) ;
255
256  OsiSolverInterface *osi = osiParam->obj() ;
257  assert (osi != 0) ;
258  double val = osiParam->dblVal() ;
259  CbcOsiParam::CbcOsiParamCode code = osiParam->paramCode() ;
260
261  assert (osi != 0) ;
262/*
263  Setup to return nonfatal/fatal error (1/-1) by default, so that all we need
264  to do is correct to 0 (no error) if we're successful.
265*/
266  int retval ;
267  if (CoinParamUtils::isInteractive())
268  { retval = 1 ; }
269  else
270  { retval = -1 ; }
271/*
272  Translate the parameter code from CbcOsiParamCode into the correct key for
273  CbcDblParam.
274*/
275  OsiDblParam key ;
276  switch (code)
277  { case CbcOsiParam::PRIMALTOLERANCE:
278    { key = OsiPrimalTolerance ;
279      break ; }
280    case CbcOsiParam::DUALTOLERANCE:
281    { key = OsiDualTolerance ; ;
282      break ; }
283    case CbcOsiParam::DUALBOUND:
284    { key = OsiDualObjectiveLimit ;
285      break ; }
286    default:
287    { std::cerr << "pushCbcOsiDblParam: no equivalent OsiDblParam for "
288                << "parameter code `" << code << "'." << std::endl ;
289      retval = -1 ;
290      break ; } }
291
292  bool setOK = osi->setDblParam(key,val) ;
293  if (setOK == false)
294  { retval = -1 ; }
295
296  return (retval) ; }
297
298
299/*
300  Function to push a keyword-valued parameter. This can translate into integer
301  as well as string-valued parameters.
302*/
303
304int pushCbcOsiKwd (CoinParam *param)
305
306{ assert (param != 0) ;
307  CbcOsiParam *osiParam = dynamic_cast<CbcOsiParam *>(param) ;
308  assert (osiParam != 0) ;
309  OsiSolverInterface *osi = osiParam->obj() ;
310  assert (osi != 0) ;
311
312  std::string str = osiParam->kwdVal() ;
313  CbcOsiParam::CbcOsiParamCode code = osiParam->paramCode() ;
314
315  int retval = 0 ;
316/*
317  Figure out what we're doing and set the relevant field.
318*/
319  OsiIntParam key ;
320
321  switch (code)
322  { case CbcOsiParam::KEEPNAMES:
323    { if (str == "on" || str == "off")
324      { int discipline ;
325        if (str == "on")
326        { discipline = 1 ; }
327        else
328        { discipline = 0 ; }
329        bool recog = osi->setIntParam(OsiNameDiscipline,discipline) ;
330        if (recog == false)
331        { std::cerr
332            << "pushCbcOsiKwdParam(KEEPNAMES): underlying solver does not "
333            << "recognise name discipline " << discipline << "."
334            << std::endl ;
335          retval = +1 ; } }
336      else
337      { std::cerr
338          << "pushCbcOsiKwdParam(KEEPNAMES): unrecognised keyword `"
339          << str << "'." << std::endl ;
340        retval = -1 ; }
341      break ; }
342    default:
343    { std::cerr
344        << "pushCbcGenKwdParam: unrecognised parameter code `"
345        << code << "'." << std::endl ;
346      retval = -1 ;
347      break ; } }
348
349  return (retval) ; }
350
351
352/*
353  Function to set the solver's output level. To cover all the bases, adjust
354  the message handler and set the hint. Nothing can go fatally wrong here,
355  but we'll return non-fatal error if the solver rejects the hint. The
356  implementor of an OSI has wide latitude with hints, and may elect to set a
357  log level as part of handling the hint. Do that first and then explicitly
358  set the message handler log level to be sure the new value isn't
359  overridden.
360*/
361
362int pushCbcOsiLogLevel (CoinParam *param)
363
364{ assert (param != 0) ;
365  CbcOsiParam *osiParam = dynamic_cast<CbcOsiParam *>(param) ;
366  assert (osiParam != 0) ;
367  OsiSolverInterface *osi = osiParam->obj() ;
368  assert(osi != 0) ;
369
370  int lvl = param->intVal() ;
371/*
372  Setup to return nonfatal/fatal error (1/-1) by default, so that all we need
373  to do is correct to 0 (no error) if we're successful.
374*/
375  int retval ;
376  if (CoinParamUtils::isInteractive())
377  { retval = 1 ; }
378  else
379  { retval = -1 ; }
380/*
381  Now try to do the right thing with a hint. Harder to say -- assume that log
382  level 1 is `normal'.
383*/
384  OsiHintStrength strength ;
385  bool sense ;
386  if (lvl < 1)
387  { strength = OsiHintDo ;
388    sense = true ; }
389  else
390  if (lvl == 1)
391  { strength = OsiHintIgnore ;
392    sense = true ; }
393  else
394  if (lvl == 2)
395  { strength = OsiHintTry ;
396    sense = false ; }
397  else
398  { strength = OsiHintDo ;
399    sense = false ; }
400
401  bool setOK = osi->setHintParam(OsiDoReducePrint,sense,strength) ;
402
403/*
404  Recover the message handler and set the log level directly.
405*/
406  CoinMessageHandler *hndl = osi->messageHandler() ;
407  assert (hndl != 0) ;
408  hndl->setLogLevel(lvl) ;
409
410  if (setOK)
411  { return (0) ; }
412  else
413  { return (retval) ; } }
414
415
416/*
417  Function for parameters that are enabled/disabled with a hint.
418*/
419int pushCbcOsiHint (CoinParam *param)
420
421{ assert (param != 0) ;
422  CbcOsiParam *osiParam = dynamic_cast<CbcOsiParam *>(param) ;
423  assert (osiParam != 0) ;
424  OsiSolverInterface *osi = osiParam->obj() ;
425  assert(osi != 0) ;
426/*
427  Setup to return nonfatal/fatal error (1/-1) by default, so that all we need
428  to do is correct to 0 (no error) if we're successful.
429*/
430  int retval ;
431  if (CoinParamUtils::isInteractive())
432  { retval = 1 ; }
433  else
434  { retval = -1 ; }
435/*
436  Set the sense for the hint.
437*/
438  std::string kwd = param->kwdVal() ;
439  bool sense ;
440  if (kwd == "off")
441  { sense = false ; }
442  else
443  { sense = true ; }
444/*
445  Grab the parameter code and translate to an OSI parameter key.
446*/
447  CbcOsiParam::CbcOsiParamCode code = osiParam->paramCode() ;
448  OsiHintParam key ;
449  switch (code)
450  { case CbcOsiParam::PRESOLVE:
451    { key = OsiDoPresolveInInitial ;
452      break ; }
453    case CbcOsiParam::SCALING:
454    { key = OsiDoScale ;
455      break ; }
456    default:
457    { std::cerr << "pushCbcOsiHint: no equivalent OsiHintParam for "
458                << "parameter code `" << code << "'." << std::endl ;
459      retval = -1 ;
460      break ; } }
461
462  bool setOK = osi->setHintParam(key,sense,OsiHintDo) ;
463
464  if (setOK)
465  { return (0) ; }
466  else
467  { return (retval) ; } }
468
469} // end namespace CbcOsiParamUtils
470
Note: See TracBrowser for help on using the repository browser.