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

Last change on this file since 862 was 691, checked in by forrest, 12 years ago

set result

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