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

Last change on this file since 1899 was 1899, checked in by stefan, 6 years ago

fixup svn properties

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