source: trunk/Cbc/src/CbcGenOsiParamUtils.cpp @ 958

Last change on this file since 958 was 958, checked in by lou, 11 years ago

Bare INT_MAX fails under GCC 4.3. Change to COIN_INT_MAX.

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