source: trunk/Cbc/src/CbcGenCtlBlk.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: 17.7 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: CbcGenCtlBlk.cpp 1899 2013-04-09 18:12:08Z stefan $
8*/
9/*
10  This file is part of cbc-generic.
11*/
12
13#include "CbcConfig.h"
14#include "CoinPragma.hpp"
15
16#include <cassert>
17
18#include "CbcGenCtlBlk.hpp"
19
20namespace {
21
22char svnid[] = "$Id: CbcGenCtlBlk.cpp 1899 2013-04-09 18:12:08Z stefan $" ;
23
24}
25
26/*
27  Constructor for cbc-generic control block.
28
29  Set up defaults for the cbc-generic control block. Note that prototypes for
30  cut generators and heuristics will be created on demand; see the access
31  functions.
32
33  Once this structure settles down, simple intialisation should move up to
34  the standard `:' block. In the meantime, this avoids complaints about
35  ordering.
36*/
37
38CbcGenCtlBlk::CbcGenCtlBlk ()
39
40{
41    version_ = CBC_GENERIC_VERSION ;
42    /*
43      It's unclear to me that this is a good choice for dfltDirectory. Makes
44      sense for commands, but seems unnecessary for data files. Perhaps a null
45      string instead?
46    */
47    char dirsep = CoinFindDirSeparator() ;
48    dfltDirectory_ = (dirsep == '/' ? "./" : ".\\") ;
49    lastMpsIn_ = "" ;
50    allowImportErrors_ = false ;
51    lastSolnOut_ = "stdout" ;
52    printMode_ = 0 ;
53    printMask_ = "" ;
54
55    paramVec_ = 0 ;
56    genParams_.first_ = 0 ;
57    genParams_.last_ = 0 ;
58    cbcParams_.first_ = 0 ;
59    cbcParams_.last_ = 0 ;
60    osiParams_.first_ = 0 ;
61    osiParams_.last_ = 0 ;
62
63    verbose_ = 0 ;
64    paramsProcessed_ = 0 ;
65    defaultSettings_ = true ;
66
67    debugCreate_ = "" ;
68    debugFile_ = "" ;
69    debugSol_.numCols_ = -1 ;
70    debugSol_.values_ = 0 ;
71
72    printOpt_ = 0 ;
73
74    /*
75      Assigning us_en to cur_lang_ is entirely bogus, but CoinMessages::Language
76      does not provide an `unspecified' code.
77    */
78    msgHandler_ = new CoinMessageHandler() ;
79    ourMsgHandler_ = true ;
80    cur_lang_ = CoinMessages::us_en ;
81    msgs_ = 0 ;
82    logLvl_ = 0 ;
83
84    totalTime_ = 0.0 ;
85
86    model_ = 0 ;
87    dfltSolver_ = 0 ;
88    goodModel_ = false ;
89    bab_.majorStatus_ = BACInvalid ;
90    bab_.minorStatus_ = BACmInvalid ;
91    bab_.where_ = BACwInvalid ;
92    bab_.haveAnswer_ = false ;
93    bab_.answerSolver_ = 0 ;
94
95    preProcess_ = CbcGenCtlBlk::IPPSOS ;
96    cutDepth_ = -1 ;
97
98    probing_.action_ = CbcGenCtlBlk::CGIfMove ;
99    probing_.proto_ = 0 ;
100    probing_.usingObjective_ = true ;
101    probing_.maxPass_ = 3 ;
102    probing_.maxPassRoot_ = 3 ;
103    probing_.maxProbe_ = 10 ;
104    probing_.maxProbeRoot_ = 50 ;
105    probing_.maxLook_ = 10 ;
106    probing_.maxLookRoot_ = 50 ;
107    probing_.maxElements_ = 200 ;
108    probing_.rowCuts_ = 3 ;
109
110    clique_.action_ = CbcGenCtlBlk::CGIfMove ;
111    clique_.proto_ = 0 ;
112    clique_.starCliqueReport_ = false ;
113    clique_.rowCliqueReport_ = false ;
114    clique_.minViolation_ = 0.1 ;
115
116    flow_.action_ = CbcGenCtlBlk::CGIfMove ;
117    flow_.proto_ = 0 ;
118
119    gomory_.action_ = CbcGenCtlBlk::CGIfMove ;
120    gomory_.proto_ = 0 ;
121    gomory_.limit_ = 50 ;
122    gomory_.limitAtRoot_ = 512 ;
123
124    knapsack_.action_ = CbcGenCtlBlk::CGIfMove ;
125    knapsack_.proto_ = 0 ;
126
127    // landp_action_ = CbcGenCtlBlk::CGOff ;
128    // landp_.proto_ = 0 ;
129
130    mir_.action_ = CbcGenCtlBlk::CGIfMove ;
131    mir_.proto_ = 0 ;
132
133    oddHole_.action_ = CbcGenCtlBlk::CGOff ;
134    oddHole_.proto_ = 0 ;
135
136    redSplit_.action_ = CbcGenCtlBlk::CGRoot ;
137    redSplit_.proto_ = 0 ;
138
139    twomir_.action_ = CbcGenCtlBlk::CGRoot ;
140    twomir_.proto_ = 0 ;
141    twomir_.maxElements_ = 250 ;
142
143    fpump_.action_ = CbcGenCtlBlk::CGOn ;
144    fpump_.proto_ = 0 ;
145
146    combine_.action_ = CbcGenCtlBlk::CGOn ;
147    combine_.proto_ = 0 ;
148    combine_.trySwap_ = 1 ;
149
150    greedyCover_.action_ = CbcGenCtlBlk::CGOn ;
151    greedyCover_.proto_ = 0 ;
152    greedyEquality_.action_ = CbcGenCtlBlk::CGOn ;
153    greedyEquality_.proto_ = 0 ;
154
155    localTree_.action_ = CbcGenCtlBlk::CGOff ;
156    localTree_.proto_ = 0 ;
157    localTree_.soln_ = 0 ;
158    localTree_.range_ = 10 ;
159    localTree_.typeCuts_ = 0 ;
160    localTree_.maxDiverge_ = 0 ;
161    localTree_.timeLimit_ = 10000 ;
162    localTree_.nodeLimit_ = 2000 ;
163    localTree_.refine_ = true ;
164
165    rounding_.action_ = CbcGenCtlBlk::CGOn ;
166    rounding_.proto_ = 0 ;
167
168    djFix_.action_ = false ;
169    djFix_.threshold_ = 1.0e100 ;
170
171    priorityAction_ = CbcGenCtlBlk::BPOff ;
172    /*
173      The value for numBeforeTrust is as recommended by Achterberg. Cbc's
174      implementation doesn't really have a parameter equivalent to Achterberg's
175      dynamic limit on number of strong branching evaluations, so go with a fairly
176      large default. As of 06.12.16, the magic number for shadow price mode meant
177      `use shadow prices (penalties, I think) if there's no strong branching info'.
178    */
179    chooseStrong_.numBeforeTrust_ = 8 ;
180    chooseStrong_.numStrong_ = 100 ;
181    chooseStrong_.shadowPriceMode_ = 1 ;
182
183    return ;
184}
185
186/*
187  Note that we don't want to delete dfltSolver_ here because it's just a
188  copy of the pointer held in the solvers map over in CbcGenSolvers.cpp.
189*/
190CbcGenCtlBlk::~CbcGenCtlBlk ()
191
192{
193    if (model_) delete model_ ;
194    if (bab_.answerSolver_) delete bab_.answerSolver_ ;
195
196    if (probing_.proto_) delete probing_.proto_ ;
197    if (clique_.proto_) delete clique_.proto_ ;
198    if (flow_.proto_) delete flow_.proto_ ;
199    if (gomory_.proto_) delete gomory_.proto_ ;
200    if (knapsack_.proto_) delete knapsack_.proto_ ;
201    if (mir_.proto_) delete mir_.proto_ ;
202    if (oddHole_.proto_) delete oddHole_.proto_ ;
203    if (redSplit_.proto_) delete redSplit_.proto_ ;
204    if (twomir_.proto_) delete twomir_.proto_ ;
205
206    if (fpump_.proto_) delete fpump_.proto_ ;
207    if (combine_.proto_) delete combine_.proto_ ;
208    if (greedyCover_.proto_) delete greedyCover_.proto_ ;
209    if (greedyEquality_.proto_) delete greedyEquality_.proto_ ;
210    if (rounding_.proto_) delete rounding_.proto_ ;
211
212    if (msgHandler_ && ourMsgHandler_) delete msgHandler_ ;
213    if (msgs_) delete msgs_ ;
214
215    return ;
216}
217
218/*
219  Access functions for cut generators and heuristics. These support lazy
220  creation --- if action_ is other than CGOff, an object is created if
221  necessary and a pointer is stored in proto_. The pointer is returned as
222  a generic CglCutGenerator or CbcHeuristic. The return value of the function
223  is the value of action_.
224
225  Because the model may have changed, the default for heuristics is to delete
226  any existing object and create a new one. This can be suppressed if desired.
227*/
228
229CbcGenCtlBlk::CGControl CbcGenCtlBlk::getProbing (CglCutGenerator *&gen)
230
231{
232    if (probing_.action_ != CbcGenCtlBlk::CGOff && probing_.proto_ == 0) {
233        probing_.proto_ = new CglProbing() ;
234        probing_.proto_->setUsingObjective(probing_.usingObjective_) ;
235        probing_.proto_->setMaxPass(probing_.maxPass_) ;
236        probing_.proto_->setMaxPassRoot(probing_.maxPassRoot_) ;
237        probing_.proto_->setMaxProbe(probing_.maxProbe_) ;
238        probing_.proto_->setMaxProbeRoot(probing_.maxProbeRoot_) ;
239        probing_.proto_->setMaxLook(probing_.maxLook_) ;
240        probing_.proto_->setMaxLookRoot(probing_.maxLookRoot_) ;
241        probing_.proto_->setMaxElements(probing_.maxElements_) ;
242        probing_.proto_->setRowCuts(probing_.rowCuts_) ;
243    }
244    gen = dynamic_cast<CglCutGenerator *>(probing_.proto_) ;
245
246    return (probing_.action_) ;
247}
248
249
250CbcGenCtlBlk::CGControl CbcGenCtlBlk::getClique (CglCutGenerator *&gen)
251
252{
253    if (clique_.action_ != CbcGenCtlBlk::CGOff && clique_.proto_ == 0) {
254        clique_.proto_ = new CglClique() ;
255        clique_.proto_->setStarCliqueReport(clique_.starCliqueReport_) ;
256        clique_.proto_->setRowCliqueReport(clique_.rowCliqueReport_) ;
257        clique_.proto_->setMinViolation(clique_.minViolation_) ;
258    }
259    gen = dynamic_cast<CglCutGenerator *>(clique_.proto_) ;
260
261    return (clique_.action_) ;
262}
263
264
265CbcGenCtlBlk::CGControl CbcGenCtlBlk::getFlow (CglCutGenerator *&gen)
266
267{
268    if (flow_.action_ != CbcGenCtlBlk::CGOff && flow_.proto_ == 0) {
269        flow_.proto_ = new CglFlowCover() ;
270    }
271    gen = dynamic_cast<CglCutGenerator *>(flow_.proto_) ;
272
273    return (flow_.action_) ;
274}
275
276
277CbcGenCtlBlk::CGControl CbcGenCtlBlk::getGomory (CglCutGenerator *&gen)
278
279{
280    if (gomory_.action_ != CbcGenCtlBlk::CGOff && gomory_.proto_ == 0) {
281        gomory_.proto_ = new CglGomory() ;
282        gomory_.proto_->setLimitAtRoot(gomory_.limitAtRoot_) ;
283        gomory_.proto_->setLimit(gomory_.limit_) ;
284    }
285    gen = dynamic_cast<CglCutGenerator *>(gomory_.proto_) ;
286
287    return (gomory_.action_) ;
288}
289
290
291CbcGenCtlBlk::CGControl CbcGenCtlBlk::getKnapsack (CglCutGenerator *&gen)
292
293{
294    if (knapsack_.action_ != CbcGenCtlBlk::CGOff && knapsack_.proto_ == 0) {
295        knapsack_.proto_ = new CglKnapsackCover() ;
296    }
297    gen = dynamic_cast<CglCutGenerator *>(knapsack_.proto_) ;
298
299    return (knapsack_.action_) ;
300}
301
302
303CbcGenCtlBlk::CGControl CbcGenCtlBlk::getMir (CglCutGenerator *&gen)
304
305{
306    if (mir_.action_ != CbcGenCtlBlk::CGOff && mir_.proto_ == 0) {
307        mir_.proto_ = new CglMixedIntegerRounding2() ;
308    }
309    gen = dynamic_cast<CglCutGenerator *>(mir_.proto_) ;
310
311    return (mir_.action_) ;
312}
313
314
315CbcGenCtlBlk::CGControl CbcGenCtlBlk::getRedSplit (CglCutGenerator *&gen)
316
317{
318    if (redSplit_.action_ != CbcGenCtlBlk::CGOff && redSplit_.proto_ == 0) {
319        redSplit_.proto_ = new CglRedSplit() ;
320    }
321    gen = dynamic_cast<CglCutGenerator *>(redSplit_.proto_) ;
322
323    return (redSplit_.action_) ;
324}
325
326
327CbcGenCtlBlk::CGControl CbcGenCtlBlk::getTwomir (CglCutGenerator *&gen)
328
329{
330    if (twomir_.action_ != CbcGenCtlBlk::CGOff && twomir_.proto_ == 0) {
331        twomir_.proto_ = new CglTwomir() ;
332        twomir_.proto_->setMaxElements(twomir_.maxElements_) ;
333    }
334    gen = dynamic_cast<CglCutGenerator *>(twomir_.proto_) ;
335
336    return (twomir_.action_) ;
337}
338
339
340CbcGenCtlBlk::CGControl
341CbcGenCtlBlk::getFPump (CbcHeuristic *&gen, CbcModel *model,
342                        bool alwaysCreate)
343
344{
345    if (fpump_.action_ != CbcGenCtlBlk::CGOff &&
346            (fpump_.proto_ == 0 || alwaysCreate)) {
347        if (fpump_.proto_) {
348            delete fpump_.proto_ ;
349        }
350        fpump_.proto_ = new CbcHeuristicFPump(*model) ;
351        fpump_.proto_->setMaximumPasses(fpump_.iters_) ;
352    }
353    gen = dynamic_cast<CbcHeuristic *>(fpump_.proto_) ;
354
355    return (fpump_.action_) ;
356}
357
358
359CbcGenCtlBlk::CGControl
360CbcGenCtlBlk::getCombine (CbcHeuristic *&gen, CbcModel *model,
361                          bool alwaysCreate)
362
363{
364    if (combine_.action_ != CbcGenCtlBlk::CGOff &&
365            (combine_.proto_ == 0 || alwaysCreate)) {
366        if (combine_.proto_) {
367            delete combine_.proto_ ;
368        }
369        combine_.proto_ = new CbcHeuristicLocal(*model) ;
370        combine_.proto_->setSearchType(combine_.trySwap_) ;
371    }
372    gen = dynamic_cast<CbcHeuristic *>(combine_.proto_) ;
373
374    return (combine_.action_) ;
375}
376
377
378CbcGenCtlBlk::CGControl
379CbcGenCtlBlk::getGreedyCover (CbcHeuristic *&gen, CbcModel *model,
380                              bool alwaysCreate)
381
382{
383    if (greedyCover_.action_ != CbcGenCtlBlk::CGOff &&
384            (greedyCover_.proto_ == 0 || alwaysCreate)) {
385        if (greedyCover_.proto_) {
386            delete greedyCover_.proto_ ;
387        }
388        greedyCover_.proto_ = new CbcHeuristicGreedyCover(*model) ;
389    }
390    gen = dynamic_cast<CbcHeuristic *>(greedyCover_.proto_) ;
391
392    return (greedyCover_.action_) ;
393}
394
395
396CbcGenCtlBlk::CGControl
397CbcGenCtlBlk::getGreedyEquality (CbcHeuristic *&gen, CbcModel *model,
398                                 bool alwaysCreate)
399
400{
401    if (greedyEquality_.action_ != CbcGenCtlBlk::CGOff &&
402            (greedyEquality_.proto_ == 0 || alwaysCreate)) {
403        if (greedyEquality_.proto_) {
404            delete greedyEquality_.proto_ ;
405        }
406        greedyEquality_.proto_ = new CbcHeuristicGreedyEquality(*model) ;
407    }
408    gen = dynamic_cast<CbcHeuristic *>(greedyEquality_.proto_) ;
409
410    return (greedyEquality_.action_) ;
411}
412
413
414CbcGenCtlBlk::CGControl
415CbcGenCtlBlk::getRounding (CbcHeuristic *&gen, CbcModel *model,
416                           bool alwaysCreate)
417
418{
419    if (rounding_.action_ != CbcGenCtlBlk::CGOff &&
420            (rounding_.proto_ == 0 || alwaysCreate)) {
421        if (rounding_.proto_) {
422            delete rounding_.proto_ ;
423        }
424        rounding_.proto_ = new CbcRounding(*model) ;
425    }
426    gen = dynamic_cast<CbcHeuristic *>(rounding_.proto_) ;
427
428    return (rounding_.action_) ;
429}
430
431
432CbcGenCtlBlk::CGControl
433CbcGenCtlBlk::getTreeLocal (CbcTreeLocal *&localTree, CbcModel *model,
434                            bool alwaysCreate)
435
436{
437    if (localTree_.action_ != CbcGenCtlBlk::CGOff &&
438            (localTree_.proto_ == 0 || alwaysCreate)) {
439        if (localTree_.proto_) {
440            delete localTree_.proto_ ;
441        }
442        localTree_.proto_ =
443            new CbcTreeLocal(model, localTree_.soln_, localTree_.range_,
444                             localTree_.typeCuts_, localTree_.maxDiverge_,
445                             localTree_.timeLimit_, localTree_.nodeLimit_,
446                             localTree_.refine_) ;
447    }
448    localTree = localTree_.proto_ ;
449
450    return (localTree_.action_) ;
451}
452
453/*
454  A bunch of little translation helper routines leading up to a version of
455  setBaBStatus that figures it all out given a CbcModel and BACWhere code.
456  This translation needs to be centralised to avoid sprinkling magic numbers
457  all through the code.
458
459  Be a bit careful with the translation routines --- they aren't sensitive to
460  where the search stopped.
461*/
462
463CbcGenCtlBlk::BACMajor CbcGenCtlBlk::translateMajor (int status)
464
465{
466    switch (status) {
467    case -1: {
468        return (BACNotRun) ;
469    }
470    case  0: {
471        return (BACFinish) ;
472    }
473    case  1: {
474        return (BACStop) ;
475    }
476    case  2: {
477        return (BACAbandon) ;
478    }
479    case  5: {
480        return (BACUser) ;
481    }
482    default: {
483        return (BACInvalid) ;
484    }
485    }
486}
487
488
489CbcGenCtlBlk::BACMinor CbcGenCtlBlk::translateMinor (int status)
490
491{
492    switch (status) {
493    case -1: {
494        return (BACmInvalid) ;
495    }
496    case  0: {
497        return (BACmFinish) ;
498    }
499    case  1: {
500        return (BACmInfeas) ;
501    }
502    case  2: {
503        return (BACmGap) ;
504    }
505    case  3: {
506        return (BACmNodeLimit) ;
507    }
508    case  4: {
509        return (BACmTimeLimit) ;
510    }
511    case  5: {
512        return (BACmUser) ;
513    }
514    case  6: {
515        return (BACmSolnLimit) ;
516    }
517    case  7: {
518        return (BACmUbnd) ;
519    }
520    default: {
521        return (BACmOther) ;
522    }
523    }
524}
525
526/*
527  A bit different --- given an OSI, use its interrogation functions to choose
528  an appropriate BACMinor code. Not everything matches up, eh?
529*/
530CbcGenCtlBlk::BACMinor
531CbcGenCtlBlk::translateMinor (const OsiSolverInterface *osi)
532
533{
534    if (osi->isProvenOptimal()) {
535        return (BACmFinish) ;
536    } else if (osi->isProvenPrimalInfeasible()) {
537        return (BACmInfeas) ;
538    } else if (osi->isProvenDualInfeasible()) {
539        return (BACmUbnd) ;
540    } else {
541        return (BACmOther) ;
542    }
543}
544
545
546/*
547  A routine to set the bab_ status block given a CbcModel and an indication
548  of where we're at in the search. Really, this is just a big mapping from
549  CbcModel codes to CbcGeneric codes.
550*/
551
552void CbcGenCtlBlk::setBaBStatus (const CbcModel *model, BACWhere where,
553                                 bool haveAnswer,
554                                 OsiSolverInterface *answerSolver)
555
556{
557    CbcGenCtlBlk::BACMajor major ;
558    CbcGenCtlBlk::BACMinor minor ;
559
560    major = translateMajor(model->status()) ;
561
562    if (where == CbcGenCtlBlk::BACwBareRoot ||
563            where == CbcGenCtlBlk::BACwIPPRelax) {
564        minor = translateMinor(model->solver()) ;
565    } else {
566        minor = translateMinor(model->secondaryStatus()) ;
567    }
568
569    setBaBStatus(major, minor, where, haveAnswer, answerSolver) ;
570
571    return ;
572}
573
574
575/*
576  Last, but not least, a routine to print the result.
577*/
578
579void CbcGenCtlBlk::printBaBStatus ()
580
581{
582    std::cout << "BAC result: stopped " ;
583
584    switch (bab_.where_) {
585    case BACwNotStarted: {
586        std::cout << "before root relaxation" ;
587        break ;
588    }
589    case BACwBareRoot: {
590        std::cout << "after root relaxation" ;
591        break ;
592    }
593    case BACwIPP: {
594        std::cout << "after integer preprocessing" ;
595        break ;
596    }
597    case BACwIPPRelax: {
598        std::cout << "after solving preprocessed relaxation" ;
599        break ;
600    }
601    case BACwBAC: {
602        std::cout << "after branch-and-cut" ;
603        break ;
604    }
605    default: {
606        std::cout << "!!invalid phase code!!" ;
607        break ;
608    }
609    }
610
611    std::cout << std::endl << "    Branch-and-cut " ;
612
613    switch (bab_.majorStatus_) {
614    case BACNotRun: {
615        std::cout << "never got started" ;
616        break ;
617    }
618    case BACFinish: {
619        std::cout << "finished" ;
620        break ;
621    }
622    case BACStop: {
623        std::cout << "stopped on a limit" ;
624        break ;
625    }
626    case BACAbandon: {
627        std::cout << "was abandoned" ;
628        break ;
629    }
630    case BACUser: {
631        std::cout << "stopped due to a user event" ;
632        break ;
633    }
634    default: {
635        std::cout << "!!invalid major status code!!" ;
636        break ;
637    }
638    }
639
640    std::cout << "; minor status is " ;
641
642    switch (bab_.minorStatus_) {
643    case BACmFinish: {
644        std::cout << "optimal" ;
645        break ;
646    }
647    case BACmInfeas: {
648        std::cout << "infeasible" ;
649        break ;
650    }
651    case BACmUbnd: {
652        std::cout << "unbounded" ;
653        break ;
654    }
655    case BACmGap: {
656        std::cout << "reached specified integrality gap." ;
657        break ;
658    }
659    case BACmNodeLimit: {
660        std::cout << "reached node limit" ;
661        break ;
662    }
663    case BACmTimeLimit: {
664        std::cout << "reached time limit" ;
665        break ;
666    }
667    case BACmSolnLimit: {
668        std::cout << "reached limit on number of solutions" ;
669        break ;
670    }
671    case BACmUser: {
672        std::cout << "stopped due to a user event" ;
673        break ;
674    }
675    case BACmOther: {
676        std::cout << "other" ;
677        break ;
678    }
679    default: {
680        std::cout << "!!invalid minor status code!!" ;
681        break ;
682    }
683    }
684
685    std::cout << "." << std::endl ;
686}
687
Note: See TracBrowser for help on using the repository browser.