source: branches/sandbox/Cbc/src/CbcStrategy.cpp @ 1357

Last change on this file since 1357 was 1357, checked in by coin, 10 years ago

run 'astyle -A4 -p' and dos2unix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.3 KB
Line 
1/* $Id: CbcStrategy.cpp 1357 2009-12-04 20:02:04Z coin $ */
2// Copyright (C) 2005, International Business Machines
3// Corporation and others.  All Rights Reserved.
4#if defined(_MSC_VER)
5// Turn off compiler warning about long names
6#  pragma warning(disable:4786)
7#endif
8
9#include "CbcConfig.h"
10
11#include <cassert>
12#include <cstdlib>
13#include <cmath>
14#include <cfloat>
15
16#include "OsiSolverInterface.hpp"
17#ifdef COIN_HAS_CLP
18#include "OsiClpSolverInterface.hpp"
19#endif
20#include "CbcModel.hpp"
21#include "CbcMessage.hpp"
22#include "CbcStrategy.hpp"
23#include "CbcCutGenerator.hpp"
24#include "CbcBranchActual.hpp"
25#include "CbcNode.hpp"
26#include "CoinWarmStart.hpp"
27#include "CglPreProcess.hpp"
28// Cuts
29
30#include "CglGomory.hpp"
31#include "CglProbing.hpp"
32#include "CglKnapsackCover.hpp"
33#include "CglOddHole.hpp"
34#include "CglClique.hpp"
35#include "CglFlowCover.hpp"
36#include "CglMixedIntegerRounding2.hpp"
37
38// Heuristics
39
40#include "CbcHeuristic.hpp"
41#include "CbcHeuristicLocal.hpp"
42
43// Default Constructor
44CbcStrategy::CbcStrategy()
45        : depth_(0),
46        preProcessState_(0),
47        process_(NULL)
48{
49}
50
51// Destructor
52CbcStrategy::~CbcStrategy ()
53{
54    delete process_;
55}
56// Delete pre-processing object to save memory
57void
58CbcStrategy::deletePreProcess()
59{
60    delete process_;
61    process_ = NULL;
62}
63// Return a new Full node information pointer (descendant of CbcFullNodeInfo)
64CbcNodeInfo *
65CbcStrategy::fullNodeInfo(CbcModel * model, int numberRowsAtContinuous) const
66{
67    return new CbcFullNodeInfo(model, numberRowsAtContinuous);
68}
69// Return a new Partial node information pointer (descendant of CbcPartialNodeInfo)
70CbcNodeInfo *
71CbcStrategy::partialNodeInfo(CbcModel * /*model*/,
72                             CbcNodeInfo * parent, CbcNode * owner,
73                             int numberChangedBounds, const int * variables,
74                             const double * boundChanges,
75                             const CoinWarmStartDiff *basisDiff) const
76{
77    return new CbcPartialNodeInfo(parent, owner, numberChangedBounds, variables,
78                                  boundChanges, basisDiff);
79}
80/* After a CbcModel::resolve this can return a status
81   -1 no effect
82   0 treat as optimal
83   1 as 0 but do not do any more resolves (i.e. no more cuts)
84   2 treat as infeasible
85*/
86int
87CbcStrategy::status(CbcModel * /*model*/, CbcNodeInfo * /*parent*/,
88                    int /*whereFrom*/)
89{
90    return -1;
91}
92
93// Default Constructor
94CbcStrategyDefault::CbcStrategyDefault(int cutsOnlyAtRoot,
95                                       int numberStrong,
96                                       int numberBeforeTrust,
97                                       int printLevel)
98        : CbcStrategy(),
99        cutsOnlyAtRoot_(cutsOnlyAtRoot),
100        numberStrong_(numberStrong),
101        numberBeforeTrust_(numberBeforeTrust),
102        printLevel_(printLevel),
103        desiredPreProcess_(0),
104        preProcessPasses_(0)
105{
106}
107
108
109// Destructor
110CbcStrategyDefault::~CbcStrategyDefault ()
111{
112}
113
114// Clone
115CbcStrategy *
116CbcStrategyDefault::clone() const
117{
118    return new CbcStrategyDefault(*this);
119}
120
121// Copy constructor
122CbcStrategyDefault::CbcStrategyDefault(const CbcStrategyDefault & rhs)
123        :
124        CbcStrategy(rhs),
125        cutsOnlyAtRoot_(rhs.cutsOnlyAtRoot_),
126        numberStrong_(rhs.numberStrong_),
127        numberBeforeTrust_(rhs.numberBeforeTrust_),
128        printLevel_(rhs.printLevel_),
129        desiredPreProcess_(rhs.desiredPreProcess_),
130        preProcessPasses_(rhs.preProcessPasses_)
131{
132    setNested(rhs.getNested());
133}
134
135// Setup cut generators
136void
137CbcStrategyDefault::setupCutGenerators(CbcModel & model)
138{
139    if (cutsOnlyAtRoot_ < 0)
140        return; // no cuts wanted
141    // Set up some cut generators and defaults
142    // Probing first as gets tight bounds on continuous
143    // See flags for Probing, Gomory, Knapsack, Clique, FlowCover, MixedIntegerRounding2 below
144    int genFlags = 63;
145    //#define CBC_GENERATE_TEST
146#ifdef CBC_GENERATE_TEST
147    int nNodes = model.getMaximumNodes();
148    if (nNodes >= 190000 && nNodes < 190064)
149        genFlags = nNodes - 190000;
150#endif
151
152    CglProbing generator1;
153    generator1.setUsingObjective(true);
154    generator1.setMaxPass(1);
155    generator1.setMaxPassRoot(1);
156    // Number of unsatisfied variables to look at
157    generator1.setMaxProbe(10);
158    // How far to follow the consequences
159    generator1.setMaxLook(10);
160    // Only look at rows with fewer than this number of elements
161    generator1.setMaxElements(200);
162    generator1.setMaxElementsRoot(300);
163    //generator1.setRowCuts(3);
164
165    CglGomory generator2;
166    // try larger limit
167    generator2.setLimit(300);
168
169    CglKnapsackCover generator3;
170
171    //CglOddHole generator4;
172    //generator4.setMinimumViolation(0.005);
173    //generator4.setMinimumViolationPer(0.00002);
174    // try larger limit
175    //generator4.setMaximumEntries(200);
176
177    CglClique generator5;
178    generator5.setStarCliqueReport(false);
179    generator5.setRowCliqueReport(false);
180
181    CglMixedIntegerRounding2 mixedGen;
182    CglFlowCover flowGen;
183
184    // Add in generators
185    int setting = cutsOnlyAtRoot_ ? -99 : -1;
186    int numberGenerators = model.numberCutGenerators();
187    int iGenerator;
188    bool found;
189    found = false;
190    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
191        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
192        CglProbing * cgl = dynamic_cast<CglProbing *>(generator);
193        if (cgl) {
194            found = true;
195            break;
196        }
197    }
198    if (!found && (genFlags&1) != 0)
199        model.addCutGenerator(&generator1, setting, "Probing");
200    found = false;
201    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
202        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
203        CglGomory * cgl = dynamic_cast<CglGomory *>(generator);
204        if (cgl) {
205            found = true;
206            break;
207        }
208    }
209    if (!found && (genFlags&2) != 0)
210        model.addCutGenerator(&generator2, setting, "Gomory");
211    found = false;
212    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
213        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
214        CglKnapsackCover * cgl = dynamic_cast<CglKnapsackCover *>(generator);
215        if (cgl) {
216            found = true;
217            break;
218        }
219    }
220    if (!found && (genFlags&4) != 0)
221        model.addCutGenerator(&generator3, setting, "Knapsack");
222    //model.addCutGenerator(&generator4,setting,"OddHole");
223    found = false;
224    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
225        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
226        CglClique * cgl = dynamic_cast<CglClique *>(generator);
227        if (cgl) {
228            found = true;
229            break;
230        }
231    }
232    if (!found && (genFlags&8) != 0)
233        model.addCutGenerator(&generator5, setting, "Clique");
234    found = false;
235    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
236        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
237        CglFlowCover * cgl = dynamic_cast<CglFlowCover *>(generator);
238        if (cgl) {
239            found = true;
240            break;
241        }
242    }
243    if (!found && (genFlags&16) != 0)
244        model.addCutGenerator(&flowGen, setting, "FlowCover");
245    found = false;
246    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
247        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
248        CglMixedIntegerRounding2 * cgl = dynamic_cast<CglMixedIntegerRounding2 *>(generator);
249        if (cgl) {
250            found = true;
251            break;
252        }
253    }
254    if (!found && (genFlags&32) != 0)
255        model.addCutGenerator(&mixedGen, setting, "MixedIntegerRounding2");
256    // Say we want timings
257    int newNumberGenerators = model.numberCutGenerators();
258    for (iGenerator = numberGenerators; iGenerator < newNumberGenerators; iGenerator++) {
259        CbcCutGenerator * generator = model.cutGenerator(iGenerator);
260        generator->setTiming(true);
261    }
262    int currentPasses = model.getMaximumCutPassesAtRoot();
263    if (currentPasses >= 0) {
264        if (model.getNumCols() < 5000)
265            model.setMaximumCutPassesAtRoot(CoinMax(50, currentPasses)); // use minimum drop
266        else
267            model.setMaximumCutPassesAtRoot(CoinMax(20, currentPasses));
268    } else {
269        currentPasses = -currentPasses;
270        if (model.getNumCols() < 500)
271            model.setMaximumCutPassesAtRoot(-CoinMax(100, currentPasses)); // always do 100 if possible
272        else
273            model.setMaximumCutPassesAtRoot(-CoinMax(20, currentPasses));
274    }
275}
276// Setup heuristics
277void
278CbcStrategyDefault::setupHeuristics(CbcModel & model)
279{
280    // Allow rounding heuristic
281
282    CbcRounding heuristic1(model);
283    heuristic1.setHeuristicName("rounding");
284    int numberHeuristics = model.numberHeuristics();
285    int iHeuristic;
286    bool found;
287    found = false;
288    for (iHeuristic = 0; iHeuristic < numberHeuristics; iHeuristic++) {
289        CbcHeuristic * heuristic = model.heuristic(iHeuristic);
290        CbcRounding * cgl = dynamic_cast<CbcRounding *>(heuristic);
291        if (cgl) {
292            found = true;
293            break;
294        }
295    }
296    if (!found)
297        model.addHeuristic(&heuristic1);
298#if 0
299    // Allow join solutions
300    CbcHeuristicLocal heuristic2(model);
301    heuristic2.setHeuristicName("join solutions");
302    heuristic2.setSearchType(1);
303    found = false;
304    for (iHeuristic = 0; iHeuristic < numberHeuristics; iHeuristic++) {
305        CbcHeuristic * heuristic = model.heuristic(iHeuristic);
306        CbcHeuristicLocal * cgl = dynamic_cast<CbcHeuristicLocal *>(heuristic);
307        if (cgl) {
308            found = true;
309            break;
310        }
311    }
312    if (!found)
313        model.addHeuristic(&heuristic2);
314#endif
315}
316// Do printing stuff
317void
318CbcStrategyDefault::setupPrinting(CbcModel & model, int modelLogLevel)
319{
320    if (!modelLogLevel) {
321        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
322        model.messageHandler()->setLogLevel(0);
323        model.solver()->messageHandler()->setLogLevel(0);
324    } else if (modelLogLevel == 1) {
325        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
326        model.messageHandler()->setLogLevel(1);
327        model.solver()->messageHandler()->setLogLevel(0);
328    } else {
329        model.messageHandler()->setLogLevel(CoinMax(2, model.messageHandler()->logLevel()));
330        model.solver()->messageHandler()->setLogLevel(CoinMax(1, model.solver()->messageHandler()->logLevel()));
331        model.setPrintFrequency(CoinMin(50, model.printFrequency()));
332    }
333}
334// Other stuff e.g. strong branching
335void
336CbcStrategyDefault::setupOther(CbcModel & model)
337{
338    // See if preprocessing wanted
339    if (desiredPreProcess_) {
340        delete process_;
341        // solver_ should have been cloned outside
342        CglPreProcess * process = new CglPreProcess();
343        // Pass in models message handler
344        process->passInMessageHandler(model.messageHandler());
345        OsiSolverInterface * solver = model.solver();
346#ifdef COIN_HAS_CLP
347        OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
348        if (clpSolver && false) {
349            // see if all coefficients multiple of 0.01 (close enough)
350            CoinPackedMatrix * matrix = clpSolver->getModelPtr()->matrix();
351            double * element = matrix->getMutableElements();
352            //const int * row = matrix->getIndices();
353            const CoinBigIndex * columnStart = matrix->getVectorStarts();
354            const int * columnLength = matrix->getVectorLengths();
355            int numberInt = 0;
356            int numberNon = 0;
357            int numberClose = 0;
358            int numberColumns = clpSolver->getNumCols();
359            int iColumn;
360            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
361                for (int j = columnStart[iColumn];
362                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
363                    //int iRow = row[j];
364                    double value1 = element[j];
365                    double value = fabs(value1);
366                    if (value > 1.0e7) {
367                        if (value != floor(value))
368                            numberNon++;
369                        else
370                            numberInt++;
371                    } else {
372                        int iValue = static_cast<int>( 100 * (value + 0.005));
373                        double value2 = iValue;
374                        if (value2 == 100.0*value) {
375                            numberInt++;
376                        } else if (fabs(value2 - 100.0*value) < 1.0e-5) {
377                            numberClose++;
378                        } else {
379                            numberNon++;
380                        }
381                    }
382                }
383            }
384            if (!numberNon && numberClose) {
385                printf("Tidying %d multiples of 0.01, %d close\n",
386                       numberInt, numberClose);
387                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
388                    for (int j = columnStart[iColumn];
389                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
390                        //int iRow = row[j];
391                        double value1 = element[j];
392                        double value = fabs(value1);
393                        if (value < 1.0e7) {
394                            int iValue = static_cast<int>( 100 * (value + 0.005));
395                            double value2 = iValue;
396                            if (value2 != 100.0*value) {
397                                value2 *= 0.01;
398                                if (fabs(value - floor(value + 0.5)) <= 1.0e-7)
399                                    value2 = floor(value + 0.5);
400                                if (value1 < 0.0)
401                                    value2 = -value2;
402                                element[j] = value2;
403                            }
404                        }
405                    }
406                }
407            }
408        }
409#endif
410        {
411            // mark some columns as ineligible for presolve
412            int numberColumns = solver->getNumCols();
413            char * prohibited = new char[numberColumns];
414            memset(prohibited, 0, numberColumns);
415            int numberProhibited = 0;
416            // convert to Cbc integers
417            model.findIntegers(false);
418            int numberObjects = model.numberObjects();
419            if (numberObjects) {
420                OsiObject ** objects = model.objects();
421                for (int iObject = 0; iObject < numberObjects; iObject++) {
422                    CbcSOS * obj =
423                        dynamic_cast <CbcSOS *>(objects[iObject]) ;
424                    if (obj) {
425                        // SOS
426                        int n = obj->numberMembers();
427                        const int * which = obj->members();
428                        for (int i = 0; i < n; i++) {
429                            int iColumn = which[i];
430                            prohibited[iColumn] = 1;
431                            numberProhibited++;
432                        }
433                    }
434                }
435            }
436            if (numberProhibited)
437                process->passInProhibited(prohibited, numberColumns);
438            delete [] prohibited;
439        }
440        int logLevel = model.messageHandler()->logLevel();
441#ifdef COIN_HAS_CLP
442        //OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
443        ClpSimplex * lpSolver = NULL;
444        if (clpSolver) {
445            if (clpSolver->messageHandler()->logLevel())
446                clpSolver->messageHandler()->setLogLevel(1);
447            if (logLevel > -1)
448                clpSolver->messageHandler()->setLogLevel(CoinMin(logLevel, clpSolver->messageHandler()->logLevel()));
449            lpSolver = clpSolver->getModelPtr();
450            /// If user left factorization frequency then compute
451            lpSolver->defaultFactorizationFrequency();
452        }
453#endif
454        // Tell solver we are in Branch and Cut
455        solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo) ;
456        // Default set of cut generators
457        CglProbing generator1;
458        generator1.setUsingObjective(true);
459        generator1.setMaxPass(1);
460        generator1.setMaxPassRoot(1);
461        generator1.setMaxProbeRoot(CoinMin(3000, solver->getNumCols()));
462        generator1.setMaxProbeRoot(123);
463        generator1.setMaxElements(100);
464        generator1.setMaxElementsRoot(200);
465        generator1.setMaxLookRoot(50);
466        generator1.setRowCuts(3);
467        //generator1.messageHandler()->setLogLevel(logLevel);
468        // Not needed with pass in process->messageHandler()->setLogLevel(logLevel);
469        // Add in generators
470        process->addCutGenerator(&generator1);
471        int translate[] = {9999, 0, 2, -2, 3, 4, 4, 4};
472        OsiSolverInterface * solver2 =
473            process->preProcessNonDefault(*solver,
474                                          translate[desiredPreProcess_], preProcessPasses_, 6);
475        // Tell solver we are not in Branch and Cut
476        solver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
477        if (solver2)
478            solver2->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
479        bool feasible = true;
480        if (!solver2) {
481            feasible = false;
482            //printf("Pre-processing says infeasible\n");
483            delete process;
484            preProcessState_ = -1;
485            process_ = NULL;
486        } else {
487            // now tighten bounds
488#ifdef COIN_HAS_CLP
489            if (clpSolver) {
490                // model has changed
491                solver = model.solver();
492                OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
493                ClpSimplex * lpSolver = clpSolver->getModelPtr();
494                lpSolver->passInMessageHandler(solver->messageHandler());
495                if (lpSolver->tightenPrimalBounds() == 0) {
496                    lpSolver->dual();
497                } else {
498                    feasible = false;
499                }
500            }
501#endif
502            if (feasible) {
503                preProcessState_ = 1;
504                process_ = process;
505                /* Note that original solver will be kept (with false)
506                   and that final solver will also be kept.
507                   This is for post-processing
508                */
509                OsiSolverInterface * solver3 = solver2->clone();
510                model.assignSolver(solver3, false);
511                if (process_->numberSOS()) {
512                    int numberSOS = process_->numberSOS();
513                    int numberIntegers = model.numberIntegers();
514                    /* model may not have created objects
515                       If none then create
516                       NOTE - put back to original column numbers as
517                       CbcModel will pack down ALL as it doesn't know where from
518                    */
519                    bool someObjects = model.numberObjects() > 0;
520                    if (!numberIntegers || !model.numberObjects()) {
521                        model.findIntegers(true);
522                        numberIntegers = model.numberIntegers();
523                    }
524                    OsiObject ** oldObjects = model.objects();
525                    // Do sets and priorities
526                    OsiObject ** objects = new OsiObject * [numberSOS];
527                    // set old objects to have low priority
528                    int numberOldObjects = model.numberObjects();
529                    int numberColumns = model.getNumCols();
530                    for (int iObj = 0; iObj < numberOldObjects; iObj++) {
531                        int oldPriority = oldObjects[iObj]->priority();
532                        oldObjects[iObj]->setPriority(numberColumns + oldPriority);
533                    }
534                    const int * starts = process_->startSOS();
535                    const int * which = process_->whichSOS();
536                    const int * type = process_->typeSOS();
537                    const double * weight = process_->weightSOS();
538                    int iSOS;
539                    for (iSOS = 0; iSOS < numberSOS; iSOS++) {
540                        int iStart = starts[iSOS];
541                        int n = starts[iSOS+1] - iStart;
542                        objects[iSOS] = new CbcSOS(&model, n, which + iStart, weight + iStart,
543                                                   iSOS, type[iSOS]);
544                        // branch on long sets first
545                        objects[iSOS]->setPriority(numberColumns - n);
546                    }
547                    model.addObjects(numberSOS, objects);
548                    for (iSOS = 0; iSOS < numberSOS; iSOS++)
549                        delete objects[iSOS];
550                    delete [] objects;
551                    if (!someObjects) {
552                        // put back old column numbers
553                        const int * originalColumns = process_->originalColumns();
554                        // use reverse lookup to fake it
555                        int n = originalColumns[numberColumns-1] + 1;
556                        int * fake = new int[n];
557                        int i;
558                        // This was wrong (now is correct) - so could never have been called
559                        abort();
560                        for ( i = 0; i < n; i++)
561                            fake[i] = -1;
562                        for (i = 0; i < numberColumns; i++)
563                            fake[originalColumns[i]] = i;
564                        for (int iObject = 0; iObject < model.numberObjects(); iObject++) {
565                            // redo ids etc
566                            CbcSimpleInteger * obj =
567                                dynamic_cast <CbcSimpleInteger *>(model.modifiableObject(iObject)) ;
568                            if (obj) {
569                                obj->resetSequenceEtc(n, fake);
570                            } else {
571                                // redo ids etc
572                                CbcObject * obj =
573                                    dynamic_cast <CbcObject *>(model.modifiableObject(iObject)) ;
574                                assert (obj);
575                                obj->redoSequenceEtc(&model, n, fake);
576                            }
577                        }
578                        delete [] fake;
579                    }
580                }
581            } else {
582                //printf("Pre-processing says infeasible\n");
583                delete process;
584                preProcessState_ = -1;
585                process_ = NULL;
586            }
587        }
588    }
589    model.setNumberStrong(numberStrong_);
590    model.setNumberBeforeTrust(numberBeforeTrust_);
591}
592// Create C++ lines to get to current state
593void
594CbcStrategyDefault::generateCpp( FILE * fp)
595{
596    fprintf(fp, "0#include \"CbcStrategy.hpp\"\n");
597    fprintf(fp, "3  CbcStrategyDefault strategy(%s,%d,%d,%d);\n",
598            cutsOnlyAtRoot_ ? "1" : "0",
599            numberStrong_,
600            numberBeforeTrust_,
601            printLevel_);
602    fprintf(fp, "3  strategy.setupPreProcessing(%d,%d);\n",
603            desiredPreProcess_, preProcessPasses_);
604}
605// Default Constructor
606CbcStrategyDefaultSubTree::CbcStrategyDefaultSubTree(CbcModel * parent ,
607        int cutsOnlyAtRoot,
608        int numberStrong,
609        int numberBeforeTrust,
610        int printLevel)
611        : CbcStrategy(),
612        parentModel_(parent),
613        cutsOnlyAtRoot_(cutsOnlyAtRoot),
614        numberStrong_(numberStrong),
615        numberBeforeTrust_(numberBeforeTrust),
616        printLevel_(printLevel)
617{
618}
619
620
621// Destructor
622CbcStrategyDefaultSubTree::~CbcStrategyDefaultSubTree ()
623{
624}
625
626// Clone
627CbcStrategy *
628CbcStrategyDefaultSubTree::clone() const
629{
630    return new CbcStrategyDefaultSubTree(*this);
631}
632
633// Copy constructor
634CbcStrategyDefaultSubTree::CbcStrategyDefaultSubTree(const CbcStrategyDefaultSubTree & rhs)
635        :
636        CbcStrategy(rhs),
637        parentModel_(rhs.parentModel_),
638        cutsOnlyAtRoot_(rhs.cutsOnlyAtRoot_),
639        numberStrong_(rhs.numberStrong_),
640        numberBeforeTrust_(rhs.numberBeforeTrust_),
641        printLevel_(rhs.printLevel_)
642{
643    setNested(rhs.getNested());
644}
645
646// Setup cut generators
647void
648CbcStrategyDefaultSubTree::setupCutGenerators(CbcModel & model)
649{
650    // Set up some cut generators and defaults
651    if (cutsOnlyAtRoot_ < 0)
652        return; // no cuts wanted
653    // Probing first as gets tight bounds on continuous
654
655    CglProbing generator1;
656    generator1.setUsingObjective(true);
657    generator1.setMaxPass(1);
658    // Number of unsatisfied variables to look at
659    generator1.setMaxProbe(10);
660    // How far to follow the consequences
661    generator1.setMaxLook(10);
662    // Only look at rows with fewer than this number of elements
663    generator1.setMaxElements(200);
664    //generator1.setRowCuts(3);
665
666    CglGomory generator2;
667    // try larger limit
668    generator2.setLimit(300);
669
670    CglKnapsackCover generator3;
671
672    //CglOddHole generator4;
673    //generator4.setMinimumViolation(0.005);
674    //generator4.setMinimumViolationPer(0.00002);
675    // try larger limit
676    //generator4.setMaximumEntries(200);
677
678    CglClique generator5;
679    generator5.setStarCliqueReport(false);
680    generator5.setRowCliqueReport(false);
681
682    CglMixedIntegerRounding2 mixedGen;
683    CglFlowCover flowGen;
684
685    // Add in generators
686    int setting = cutsOnlyAtRoot_ ? -99 : -1;
687    int numberGenerators = model.numberCutGenerators();
688    int numberParentGenerators = parentModel_->numberCutGenerators();
689    int iGenerator;
690    bool found;
691    found = false;
692    int howOften = 0;
693    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
694        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
695        CglProbing * cgl = dynamic_cast<CglProbing *>(generator);
696        if (cgl) {
697            found = true;
698            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
699            break;
700        }
701    }
702
703    if (found && (howOften >= -1 || howOften == -98)) {
704        found = false;
705        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
706            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
707            CglProbing * cgl = dynamic_cast<CglProbing *>(generator);
708            if (cgl) {
709                found = true;
710                break;
711            }
712        }
713        if (!found) {
714            if (howOften == -1)
715                howOften = -98;
716            else if (howOften == -98)
717                howOften = -99;
718            model.addCutGenerator(&generator1, setting, "Probing");
719            CbcCutGenerator * generator =
720                model.cutGenerator(numberGenerators);
721            generator->setHowOften(howOften);
722            numberGenerators++;
723        }
724    }
725    found = false;
726    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
727        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
728        CglGomory * cgl = dynamic_cast<CglGomory *>(generator);
729        if (cgl) {
730            found = true;
731            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
732            break;
733        }
734    }
735    if (found && howOften >= 0) {
736        found = false;
737        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
738            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
739            CglGomory * cgl = dynamic_cast<CglGomory *>(generator);
740            if (cgl) {
741                found = true;
742                break;
743            }
744        }
745        if (!found)
746            model.addCutGenerator(&generator2, setting, "Gomory");
747    }
748    found = false;
749    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
750        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
751        CglKnapsackCover * cgl = dynamic_cast<CglKnapsackCover *>(generator);
752        if (cgl) {
753            found = true;
754            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
755            break;
756        }
757    }
758    if (found && howOften >= 0) {
759        found = false;
760        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
761            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
762            CglKnapsackCover * cgl = dynamic_cast<CglKnapsackCover *>(generator);
763            if (cgl) {
764                found = true;
765                break;
766            }
767        }
768        if (!found)
769            model.addCutGenerator(&generator3, setting, "Knapsack");
770    }
771    found = false;
772    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
773        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
774        CglClique * cgl = dynamic_cast<CglClique *>(generator);
775        if (cgl) {
776            found = true;
777            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
778            break;
779        }
780    }
781    if (found && howOften >= 0) {
782        found = false;
783        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
784            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
785            CglClique * cgl = dynamic_cast<CglClique *>(generator);
786            if (cgl) {
787                found = true;
788                break;
789            }
790        }
791        if (!found)
792            model.addCutGenerator(&generator5, setting, "Clique");
793    }
794    found = false;
795    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
796        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
797        CglFlowCover * cgl = dynamic_cast<CglFlowCover *>(generator);
798        if (cgl) {
799            found = true;
800            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
801            break;
802        }
803    }
804    if (found && howOften >= 0) {
805        found = false;
806        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
807            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
808            CglFlowCover * cgl = dynamic_cast<CglFlowCover *>(generator);
809            if (cgl) {
810                found = true;
811                break;
812            }
813        }
814        if (!found)
815            model.addCutGenerator(&flowGen, setting, "FlowCover");
816        found = false;
817    }
818    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
819        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
820        CglMixedIntegerRounding2 * cgl = dynamic_cast<CglMixedIntegerRounding2 *>(generator);
821        if (cgl) {
822            found = true;
823            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
824            break;
825        }
826    }
827    if (found && howOften >= 0) {
828        found = false;
829        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
830            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
831            CglMixedIntegerRounding2 * cgl = dynamic_cast<CglMixedIntegerRounding2 *>(generator);
832            if (cgl) {
833                found = true;
834                break;
835            }
836        }
837        if (!found)
838            model.addCutGenerator(&mixedGen, setting, "MixedIntegerRounding2");
839    }
840#if 0
841    // Say we want timings
842    int newNumberGenerators = model.numberCutGenerators();
843    for (iGenerator = numberGenerators; iGenerator < newNumberGenerators; iGenerator++) {
844        CbcCutGenerator * generator = model.cutGenerator(iGenerator);
845        generator->setTiming(true);
846    }
847#endif
848    if (model.getNumCols() < -500)
849        model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible
850    else if (model.getNumCols() < 5000)
851        model.setMaximumCutPassesAtRoot(100); // use minimum drop
852    else
853        model.setMaximumCutPassesAtRoot(20);
854}
855// Setup heuristics
856void
857CbcStrategyDefaultSubTree::setupHeuristics(CbcModel & model)
858{
859    // Allow rounding heuristic
860
861    CbcRounding heuristic1(model);
862    heuristic1.setHeuristicName("rounding");
863    int numberHeuristics = model.numberHeuristics();
864    int iHeuristic;
865    bool found;
866    found = false;
867    for (iHeuristic = 0; iHeuristic < numberHeuristics; iHeuristic++) {
868        CbcHeuristic * heuristic = model.heuristic(iHeuristic);
869        CbcRounding * cgl = dynamic_cast<CbcRounding *>(heuristic);
870        if (cgl) {
871            found = true;
872            break;
873        }
874    }
875    if (!found)
876        model.addHeuristic(&heuristic1);
877}
878// Do printing stuff
879void
880CbcStrategyDefaultSubTree::setupPrinting(CbcModel & model, int modelLogLevel)
881{
882    if (!modelLogLevel) {
883        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
884        model.messageHandler()->setLogLevel(0);
885        model.solver()->messageHandler()->setLogLevel(0);
886    } else if (modelLogLevel == 1) {
887        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
888        model.messageHandler()->setLogLevel(1);
889        model.solver()->messageHandler()->setLogLevel(0);
890    } else {
891        model.messageHandler()->setLogLevel(2);
892        model.solver()->messageHandler()->setLogLevel(1);
893        model.setPrintFrequency(50);
894    }
895}
896// Other stuff e.g. strong branching
897void
898CbcStrategyDefaultSubTree::setupOther(CbcModel & model)
899{
900    model.setNumberStrong(numberStrong_);
901    model.setNumberBeforeTrust(numberBeforeTrust_);
902}
903// For uniform setting of cut and heuristic options
904void
905setCutAndHeuristicOptions(CbcModel & model)
906{
907    int numberGenerators = model.numberCutGenerators();
908    int iGenerator;
909    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
910        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
911        CglProbing * cglProbing = dynamic_cast<CglProbing *>(generator);
912        if (cglProbing) {
913            cglProbing->setUsingObjective(1);
914            cglProbing->setMaxPass(1);
915            cglProbing->setMaxPassRoot(1);
916            // Number of unsatisfied variables to look at
917            cglProbing->setMaxProbe(10);
918            cglProbing->setMaxProbeRoot(50);
919            //cglProbing->setMaxProbeRoot(123);
920            // How far to follow the consequences
921            cglProbing->setMaxLook(5);
922            cglProbing->setMaxLookRoot(50);
923            cglProbing->setMaxLookRoot(10);
924            // Only look at rows with fewer than this number of elements
925            cglProbing->setMaxElements(200);
926            cglProbing->setMaxElementsRoot(300);
927            cglProbing->setRowCuts(3);
928        }
929#if 0
930        CglGomory * cglGomory = dynamic_cast<CglGomory *>(generator);
931        if (cglGomory) {
932            // try larger limit
933            cglGomory->setLimitAtRoot(1000);
934            cglGomory->setLimit(50);
935        }
936        CglKnapsackCover * cglKnapsackCover = dynamic_cast<CglKnapsackCover *>(generator);
937        if (cglKnapsackCover) {
938        }
939#endif
940    }
941}
942
943
944
Note: See TracBrowser for help on using the repository browser.