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

Last change on this file since 1361 was 1361, checked in by bjarni, 10 years ago

Added Lou's annotations to Cbc_ampl.cpp, CbcSolver?.cpp, CbcSolver?.hpp, CbcStrategy?.cpp, CbcTreeLocal?.cpp, ClpAmplStuff?.cpp, CoinSolve?.cpp, and unitTestClp.cpp

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.4 KB
Line 
1/* $Id: CbcStrategy.cpp 1361 2009-12-04 22:15:40Z bjarni $ */
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 (BK: lou removed this comment, why??)
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
335/*
336 Aside from setting CbcModel::numberStrong_ and numberBeforeTrust, the big
337 activity is integer preprocessing. Surely this code to do preprocessing
338 duplicates code to do preprocessing up in the solver main routine. Most of the
339 effort goes into manipulating SOS sets.
340*/
341// Other stuff e.g. strong branching
342void
343CbcStrategyDefault::setupOther(CbcModel & model)
344{
345    // See if preprocessing wanted
346    if (desiredPreProcess_) {
347        delete process_;
348        /*
349          Inaccurate as of 080122 --- assignSolver (below) can now be instructed not to
350          delete the existing solver when the preprocessed solver is assigned to the
351          model. 'Course, we do need to hold on to a pointer somewhere, and that must
352          be captured before this call.
353        */
354        // solver_ should have been cloned outside
355        CglPreProcess * process = new CglPreProcess();
356        // Pass in models message handler
357        process->passInMessageHandler(model.messageHandler());
358        OsiSolverInterface * solver = model.solver();
359#ifdef COIN_HAS_CLP
360        OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
361        if (clpSolver && false) {
362            // see if all coefficients multiple of 0.01 (close enough)
363            CoinPackedMatrix * matrix = clpSolver->getModelPtr()->matrix();
364            double * element = matrix->getMutableElements();
365            //const int * row = matrix->getIndices();
366            const CoinBigIndex * columnStart = matrix->getVectorStarts();
367            const int * columnLength = matrix->getVectorLengths();
368            int numberInt = 0;
369            int numberNon = 0;
370            int numberClose = 0;
371            int numberColumns = clpSolver->getNumCols();
372            int iColumn;
373            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
374                for (int j = columnStart[iColumn];
375                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
376                    //int iRow = row[j];
377                    double value1 = element[j];
378                    double value = fabs(value1);
379                    if (value > 1.0e7) {
380                        if (value != floor(value))
381                            numberNon++;
382                        else
383                            numberInt++;
384                    } else {
385                        int iValue = static_cast<int>( 100 * (value + 0.005));
386                        double value2 = iValue;
387                        if (value2 == 100.0*value) {
388                            numberInt++;
389                        } else if (fabs(value2 - 100.0*value) < 1.0e-5) {
390                            numberClose++;
391                        } else {
392                            numberNon++;
393                        }
394                    }
395                }
396            }
397            if (!numberNon && numberClose) {
398                printf("Tidying %d multiples of 0.01, %d close\n",
399                       numberInt, numberClose);
400                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
401                    for (int j = columnStart[iColumn];
402                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
403                        //int iRow = row[j];
404                        double value1 = element[j];
405                        double value = fabs(value1);
406                        if (value < 1.0e7) {
407                            int iValue = static_cast<int>( 100 * (value + 0.005));
408                            double value2 = iValue;
409                            if (value2 != 100.0*value) {
410                                value2 *= 0.01;
411                                if (fabs(value - floor(value + 0.5)) <= 1.0e-7)
412                                    value2 = floor(value + 0.5);
413                                if (value1 < 0.0)
414                                    value2 = -value2;
415                                element[j] = value2;
416                            }
417                        }
418                    }
419                }
420            }
421        }
422#endif
423        {
424            // mark some columns as ineligible for presolve
425            int numberColumns = solver->getNumCols();
426            char * prohibited = new char[numberColumns];
427            memset(prohibited, 0, numberColumns);
428            int numberProhibited = 0;
429            /*
430              Create CbcSimpleInteger objects would be more accurate in the general
431              case.  The `false' parameter says we won't delete existing objects.
432
433              Only Clp will produce SOS objects in findIntegers (080122), and that's
434              where a possible conversion can occur. If clp is holding OsiSOS objects,
435              they'll be converted to CbcSOS objects.
436            */
437            // convert to Cbc integers
438            model.findIntegers(false);
439            int numberObjects = model.numberObjects();
440            if (numberObjects) {
441                OsiObject ** objects = model.objects();
442                for (int iObject = 0; iObject < numberObjects; iObject++) {
443                    CbcSOS * obj =
444                        dynamic_cast <CbcSOS *>(objects[iObject]) ;
445                    if (obj) {
446                        // SOS
447                        int n = obj->numberMembers();
448                        const int * which = obj->members();
449                        for (int i = 0; i < n; i++) {
450                            int iColumn = which[i];
451                            prohibited[iColumn] = 1;
452                            numberProhibited++;
453                        }
454                    }
455                }
456            }
457            if (numberProhibited)
458                process->passInProhibited(prohibited, numberColumns);
459            delete [] prohibited;
460        }
461        int logLevel = model.messageHandler()->logLevel();
462#ifdef COIN_HAS_CLP
463        //OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
464        ClpSimplex * lpSolver = NULL;
465        if (clpSolver) {
466            if (clpSolver->messageHandler()->logLevel())
467                clpSolver->messageHandler()->setLogLevel(1);
468            if (logLevel > -1)
469                clpSolver->messageHandler()->setLogLevel(CoinMin(logLevel, clpSolver->messageHandler()->logLevel()));
470            lpSolver = clpSolver->getModelPtr();
471            /// If user left factorization frequency then compute
472            lpSolver->defaultFactorizationFrequency();
473        }
474#endif
475        // Tell solver we are in Branch and Cut
476        solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo) ;
477        // Default set of cut generators
478        CglProbing generator1;
479        generator1.setUsingObjective(true);
480        generator1.setMaxPass(1);
481        generator1.setMaxPassRoot(1);
482        generator1.setMaxProbeRoot(CoinMin(3000, solver->getNumCols()));
483        generator1.setMaxProbeRoot(123);
484        generator1.setMaxElements(100);
485        generator1.setMaxElementsRoot(200);
486        generator1.setMaxLookRoot(50);
487        generator1.setRowCuts(3);
488        //generator1.messageHandler()->setLogLevel(logLevel);
489        // Not needed with pass in process->messageHandler()->setLogLevel(logLevel);
490        // Add in generators
491        process->addCutGenerator(&generator1);
492        int translate[] = {9999, 0, 2, -2, 3, 4, 4, 4};
493        OsiSolverInterface * solver2 =
494            process->preProcessNonDefault(*solver,
495                                          translate[desiredPreProcess_], preProcessPasses_, 6);
496        // Tell solver we are not in Branch and Cut
497        solver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
498        if (solver2)
499            solver2->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
500        bool feasible = true;
501        if (!solver2) {
502            feasible = false;
503            //printf("Pre-processing says infeasible\n");
504            delete process;
505            preProcessState_ = -1;
506            process_ = NULL;
507        } else {
508            // now tighten bounds
509#ifdef COIN_HAS_CLP
510            if (clpSolver) {
511                // model has changed
512                solver = model.solver();
513                OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
514                ClpSimplex * lpSolver = clpSolver->getModelPtr();
515                lpSolver->passInMessageHandler(solver->messageHandler());
516                if (lpSolver->tightenPrimalBounds() == 0) {
517                    lpSolver->dual();
518                } else {
519                    feasible = false;
520                }
521            }
522#endif
523            if (feasible) {
524                preProcessState_ = 1;
525                process_ = process;
526                /* Note that original solver will be kept (with false)
527                   and that final solver will also be kept.
528                   This is for post-processing
529                */
530                OsiSolverInterface * solver3 = solver2->clone();
531                model.assignSolver(solver3, false);
532                if (process_->numberSOS()) {
533                    int numberSOS = process_->numberSOS();
534                    int numberIntegers = model.numberIntegers();
535                    /* model may not have created objects
536                       If none then create
537                       NOTE - put back to original column numbers as
538                       CbcModel will pack down ALL as it doesn't know where from
539                    */
540                    bool someObjects = model.numberObjects() > 0;
541                    if (!numberIntegers || !model.numberObjects()) {
542                        model.findIntegers(true);
543                        numberIntegers = model.numberIntegers();
544                    }
545                    OsiObject ** oldObjects = model.objects();
546                    // Do sets and priorities
547                    OsiObject ** objects = new OsiObject * [numberSOS];
548                    // set old objects to have low priority
549                    int numberOldObjects = model.numberObjects();
550                    int numberColumns = model.getNumCols();
551                    for (int iObj = 0; iObj < numberOldObjects; iObj++) {
552                        int oldPriority = oldObjects[iObj]->priority();
553                        oldObjects[iObj]->setPriority(numberColumns + oldPriority);
554                    }
555                    const int * starts = process_->startSOS();
556                    const int * which = process_->whichSOS();
557                    const int * type = process_->typeSOS();
558                    const double * weight = process_->weightSOS();
559                    int iSOS;
560                    for (iSOS = 0; iSOS < numberSOS; iSOS++) {
561                        int iStart = starts[iSOS];
562                        int n = starts[iSOS+1] - iStart;
563                        objects[iSOS] = new CbcSOS(&model, n, which + iStart, weight + iStart,
564                                                   iSOS, type[iSOS]);
565                        // branch on long sets first
566                        objects[iSOS]->setPriority(numberColumns - n);
567                    }
568                    model.addObjects(numberSOS, objects);
569                    for (iSOS = 0; iSOS < numberSOS; iSOS++)
570                        delete objects[iSOS];
571                    delete [] objects;
572                    if (!someObjects) {
573                        // put back old column numbers
574                        const int * originalColumns = process_->originalColumns();
575                        // use reverse lookup to fake it
576                        int n = originalColumns[numberColumns-1] + 1;
577                        int * fake = new int[n];
578                        int i;
579                        // This was wrong (now is correct) - so could never have been called
580                        abort();
581                        for ( i = 0; i < n; i++)
582                            fake[i] = -1;
583                        for (i = 0; i < numberColumns; i++)
584                            fake[originalColumns[i]] = i;
585                        for (int iObject = 0; iObject < model.numberObjects(); iObject++) {
586                            // redo ids etc
587                            CbcSimpleInteger * obj =
588                                dynamic_cast <CbcSimpleInteger *>(model.modifiableObject(iObject)) ;
589                            if (obj) {
590                                obj->resetSequenceEtc(n, fake);
591                            } else {
592                                // redo ids etc
593                                CbcObject * obj =
594                                    dynamic_cast <CbcObject *>(model.modifiableObject(iObject)) ;
595                                assert (obj);
596                                obj->redoSequenceEtc(&model, n, fake);
597                            }
598                        }
599                        delete [] fake;
600                    }
601                }
602            } else {
603                //printf("Pre-processing says infeasible\n");
604                delete process;
605                preProcessState_ = -1;
606                process_ = NULL;
607            }
608        }
609    }
610    model.setNumberStrong(numberStrong_);
611    model.setNumberBeforeTrust(numberBeforeTrust_);
612}
613// Create C++ lines to get to current state
614void
615CbcStrategyDefault::generateCpp( FILE * fp)
616{
617    fprintf(fp, "0#include \"CbcStrategy.hpp\"\n");
618    fprintf(fp, "3  CbcStrategyDefault strategy(%s,%d,%d,%d);\n",
619            cutsOnlyAtRoot_ ? "1" : "0",
620            numberStrong_,
621            numberBeforeTrust_,
622            printLevel_);
623    fprintf(fp, "3  strategy.setupPreProcessing(%d,%d);\n",
624            desiredPreProcess_, preProcessPasses_);
625}
626// Default Constructor
627CbcStrategyDefaultSubTree::CbcStrategyDefaultSubTree(CbcModel * parent ,
628        int cutsOnlyAtRoot,
629        int numberStrong,
630        int numberBeforeTrust,
631        int printLevel)
632        : CbcStrategy(),
633        parentModel_(parent),
634        cutsOnlyAtRoot_(cutsOnlyAtRoot),
635        numberStrong_(numberStrong),
636        numberBeforeTrust_(numberBeforeTrust),
637        printLevel_(printLevel)
638{
639}
640
641
642// Destructor
643CbcStrategyDefaultSubTree::~CbcStrategyDefaultSubTree ()
644{
645}
646
647// Clone
648CbcStrategy *
649CbcStrategyDefaultSubTree::clone() const
650{
651    return new CbcStrategyDefaultSubTree(*this);
652}
653
654// Copy constructor
655CbcStrategyDefaultSubTree::CbcStrategyDefaultSubTree(const CbcStrategyDefaultSubTree & rhs)
656        :
657        CbcStrategy(rhs),
658        parentModel_(rhs.parentModel_),
659        cutsOnlyAtRoot_(rhs.cutsOnlyAtRoot_),
660        numberStrong_(rhs.numberStrong_),
661        numberBeforeTrust_(rhs.numberBeforeTrust_),
662        printLevel_(rhs.printLevel_)
663{
664    setNested(rhs.getNested());
665}
666
667// Setup cut generators
668void
669CbcStrategyDefaultSubTree::setupCutGenerators(CbcModel & model)
670{
671    // Set up some cut generators and defaults
672    if (cutsOnlyAtRoot_ < 0)
673        return; // no cuts wanted
674    // Probing first as gets tight bounds on continuous
675
676    CglProbing generator1;
677    generator1.setUsingObjective(true);
678    generator1.setMaxPass(1);
679    // Number of unsatisfied variables to look at
680    generator1.setMaxProbe(10);
681    // How far to follow the consequences
682    generator1.setMaxLook(10);
683    // Only look at rows with fewer than this number of elements
684    generator1.setMaxElements(200);
685    //generator1.setRowCuts(3);
686
687    CglGomory generator2;
688    // try larger limit
689    generator2.setLimit(300);
690
691    CglKnapsackCover generator3;
692
693    //CglOddHole generator4;
694    //generator4.setMinimumViolation(0.005);
695    //generator4.setMinimumViolationPer(0.00002);
696    // try larger limit
697    //generator4.setMaximumEntries(200);
698
699    CglClique generator5;
700    generator5.setStarCliqueReport(false);
701    generator5.setRowCliqueReport(false);
702
703    CglMixedIntegerRounding2 mixedGen;
704    CglFlowCover flowGen;
705
706    // Add in generators
707    int setting = cutsOnlyAtRoot_ ? -99 : -1;
708    int numberGenerators = model.numberCutGenerators();
709    int numberParentGenerators = parentModel_->numberCutGenerators();
710    int iGenerator;
711    bool found;
712    found = false;
713    int howOften = 0;
714    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
715        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
716        CglProbing * cgl = dynamic_cast<CglProbing *>(generator);
717        if (cgl) {
718            found = true;
719            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
720            break;
721        }
722    }
723
724    if (found && (howOften >= -1 || howOften == -98)) {
725        found = false;
726        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
727            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
728            CglProbing * cgl = dynamic_cast<CglProbing *>(generator);
729            if (cgl) {
730                found = true;
731                break;
732            }
733        }
734        if (!found) {
735            if (howOften == -1)
736                howOften = -98;
737            else if (howOften == -98)
738                howOften = -99;
739            model.addCutGenerator(&generator1, setting, "Probing");
740            CbcCutGenerator * generator =
741                model.cutGenerator(numberGenerators);
742            generator->setHowOften(howOften);
743            numberGenerators++;
744        }
745    }
746    found = false;
747    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
748        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
749        CglGomory * cgl = dynamic_cast<CglGomory *>(generator);
750        if (cgl) {
751            found = true;
752            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
753            break;
754        }
755    }
756    if (found && howOften >= 0) {
757        found = false;
758        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
759            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
760            CglGomory * cgl = dynamic_cast<CglGomory *>(generator);
761            if (cgl) {
762                found = true;
763                break;
764            }
765        }
766        if (!found)
767            model.addCutGenerator(&generator2, setting, "Gomory");
768    }
769    found = false;
770    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
771        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
772        CglKnapsackCover * cgl = dynamic_cast<CglKnapsackCover *>(generator);
773        if (cgl) {
774            found = true;
775            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
776            break;
777        }
778    }
779    if (found && howOften >= 0) {
780        found = false;
781        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
782            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
783            CglKnapsackCover * cgl = dynamic_cast<CglKnapsackCover *>(generator);
784            if (cgl) {
785                found = true;
786                break;
787            }
788        }
789        if (!found)
790            model.addCutGenerator(&generator3, setting, "Knapsack");
791    }
792    found = false;
793    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
794        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
795        CglClique * cgl = dynamic_cast<CglClique *>(generator);
796        if (cgl) {
797            found = true;
798            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
799            break;
800        }
801    }
802    if (found && howOften >= 0) {
803        found = false;
804        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
805            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
806            CglClique * cgl = dynamic_cast<CglClique *>(generator);
807            if (cgl) {
808                found = true;
809                break;
810            }
811        }
812        if (!found)
813            model.addCutGenerator(&generator5, setting, "Clique");
814    }
815    found = false;
816    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
817        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
818        CglFlowCover * cgl = dynamic_cast<CglFlowCover *>(generator);
819        if (cgl) {
820            found = true;
821            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
822            break;
823        }
824    }
825    if (found && howOften >= 0) {
826        found = false;
827        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
828            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
829            CglFlowCover * cgl = dynamic_cast<CglFlowCover *>(generator);
830            if (cgl) {
831                found = true;
832                break;
833            }
834        }
835        if (!found)
836            model.addCutGenerator(&flowGen, setting, "FlowCover");
837        found = false;
838    }
839    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
840        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
841        CglMixedIntegerRounding2 * cgl = dynamic_cast<CglMixedIntegerRounding2 *>(generator);
842        if (cgl) {
843            found = true;
844            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
845            break;
846        }
847    }
848    if (found && howOften >= 0) {
849        found = false;
850        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
851            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
852            CglMixedIntegerRounding2 * cgl = dynamic_cast<CglMixedIntegerRounding2 *>(generator);
853            if (cgl) {
854                found = true;
855                break;
856            }
857        }
858        if (!found)
859            model.addCutGenerator(&mixedGen, setting, "MixedIntegerRounding2");
860    }
861#if 0
862    // Say we want timings
863    int newNumberGenerators = model.numberCutGenerators();
864    for (iGenerator = numberGenerators; iGenerator < newNumberGenerators; iGenerator++) {
865        CbcCutGenerator * generator = model.cutGenerator(iGenerator);
866        generator->setTiming(true);
867    }
868#endif
869    if (model.getNumCols() < -500)
870        model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible
871    else if (model.getNumCols() < 5000)
872        model.setMaximumCutPassesAtRoot(100); // use minimum drop
873    else
874        model.setMaximumCutPassesAtRoot(20);
875}
876// Setup heuristics
877void
878CbcStrategyDefaultSubTree::setupHeuristics(CbcModel & model)
879{
880    // Allow rounding heuristic
881
882    CbcRounding heuristic1(model);
883    heuristic1.setHeuristicName("rounding");
884    int numberHeuristics = model.numberHeuristics();
885    int iHeuristic;
886    bool found;
887    found = false;
888    for (iHeuristic = 0; iHeuristic < numberHeuristics; iHeuristic++) {
889        CbcHeuristic * heuristic = model.heuristic(iHeuristic);
890        CbcRounding * cgl = dynamic_cast<CbcRounding *>(heuristic);
891        if (cgl) {
892            found = true;
893            break;
894        }
895    }
896    if (!found)
897        model.addHeuristic(&heuristic1);
898}
899// Do printing stuff
900void
901CbcStrategyDefaultSubTree::setupPrinting(CbcModel & model, int modelLogLevel)
902{
903    if (!modelLogLevel) {
904        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
905        model.messageHandler()->setLogLevel(0);
906        model.solver()->messageHandler()->setLogLevel(0);
907    } else if (modelLogLevel == 1) {
908        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
909        model.messageHandler()->setLogLevel(1);
910        model.solver()->messageHandler()->setLogLevel(0);
911    } else {
912        model.messageHandler()->setLogLevel(2);
913        model.solver()->messageHandler()->setLogLevel(1);
914        model.setPrintFrequency(50);
915    }
916}
917// Other stuff e.g. strong branching
918void
919CbcStrategyDefaultSubTree::setupOther(CbcModel & model)
920{
921    model.setNumberStrong(numberStrong_);
922    model.setNumberBeforeTrust(numberBeforeTrust_);
923}
924// For uniform setting of cut and heuristic options
925void
926setCutAndHeuristicOptions(CbcModel & model)
927{
928    int numberGenerators = model.numberCutGenerators();
929    int iGenerator;
930    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
931        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
932        CglProbing * cglProbing = dynamic_cast<CglProbing *>(generator);
933        if (cglProbing) {
934            cglProbing->setUsingObjective(1);
935            cglProbing->setMaxPass(1);
936            cglProbing->setMaxPassRoot(1);
937            // Number of unsatisfied variables to look at
938            cglProbing->setMaxProbe(10);
939            cglProbing->setMaxProbeRoot(50);
940            //cglProbing->setMaxProbeRoot(123);
941            // How far to follow the consequences
942            cglProbing->setMaxLook(5);
943            cglProbing->setMaxLookRoot(50);
944            cglProbing->setMaxLookRoot(10);
945            // Only look at rows with fewer than this number of elements
946            cglProbing->setMaxElements(200);
947            cglProbing->setMaxElementsRoot(300);
948            cglProbing->setRowCuts(3);
949        }
950#if 0
951        CglGomory * cglGomory = dynamic_cast<CglGomory *>(generator);
952        if (cglGomory) {
953            // try larger limit
954            cglGomory->setLimitAtRoot(1000);
955            cglGomory->setLimit(50);
956        }
957        CglKnapsackCover * cglKnapsackCover = dynamic_cast<CglKnapsackCover *>(generator);
958        if (cglKnapsackCover) {
959        }
960#endif
961    }
962}
963
964
965
Note: See TracBrowser for help on using the repository browser.