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

Last change on this file since 1464 was 1464, checked in by stefan, 9 years ago

merge split branch into trunk; fix some examples

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