source: trunk/Cbc/src/CbcStrategy.cpp @ 1514

Last change on this file since 1514 was 1393, checked in by lou, 10 years ago

Mark #if 0 with JJF_ZERO and #if 1 with JJF_ONE as a historical reference
point.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.5 KB
Line 
1/* $Id: CbcStrategy.cpp 1393 2009-12-11 00:29:38Z forrest $ */
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#ifdef JJF_ZERO
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        // Limited set that could reduce problem size (drop rows / fix values)
479        CglProbing generator1;
480        generator1.setUsingObjective(true);
481        generator1.setMaxPass(1);
482        generator1.setMaxPassRoot(1);
483        generator1.setMaxProbeRoot(CoinMin(3000, solver->getNumCols()));
484        generator1.setMaxProbeRoot(123);
485        generator1.setMaxElements(100);
486        generator1.setMaxElementsRoot(200);
487        generator1.setMaxLookRoot(50);
488        generator1.setRowCuts(3);
489        //generator1.messageHandler()->setLogLevel(logLevel);
490        // Not needed with pass in process->messageHandler()->setLogLevel(logLevel);
491        // Add in generators
492        process->addCutGenerator(&generator1);
493        int translate[] = {9999, 0, 2, -2, 3, 4, 4, 4};
494        OsiSolverInterface * solver2 =
495            process->preProcessNonDefault(*solver,
496                                          translate[desiredPreProcess_], preProcessPasses_, 6);
497        // Tell solver we are not in Branch and Cut
498        solver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
499        if (solver2)
500            solver2->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
501        bool feasible = true;
502        if (!solver2) {
503            feasible = false;
504            //printf("Pre-processing says infeasible\n");
505            delete process;
506            preProcessState_ = -1;
507            process_ = NULL;
508        } else {
509            // now tighten bounds
510#ifdef COIN_HAS_CLP
511            if (clpSolver) {
512                // model has changed
513                solver = model.solver();
514                OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
515                ClpSimplex * lpSolver = clpSolver->getModelPtr();
516                lpSolver->passInMessageHandler(solver->messageHandler());
517                if (lpSolver->tightenPrimalBounds() == 0) {
518                    lpSolver->dual();
519                } else {
520                    feasible = false;
521                }
522            }
523#endif
524            if (feasible) {
525                preProcessState_ = 1;
526                process_ = process;
527                /* Note that original solver will be kept (with false)
528                   and that final solver will also be kept.
529                   This is for post-processing
530
531                   Keep in mind when examining this that linear presolve does not
532                   understand SOS.
533                */
534                OsiSolverInterface * solver3 = solver2->clone();
535                model.assignSolver(solver3, false);
536                if (process_->numberSOS()) {
537                    int numberSOS = process_->numberSOS();
538                    int numberIntegers = model.numberIntegers();
539                    /* model may not have created objects
540                       If none then create
541                       NOTE - put back to original column numbers as
542                       CbcModel will pack down ALL as it doesn't know where from
543                    */
544                    bool someObjects = model.numberObjects() > 0;
545                    if (!numberIntegers || !model.numberObjects()) {
546                        model.findIntegers(true);
547                        numberIntegers = model.numberIntegers();
548                    }
549                    OsiObject ** oldObjects = model.objects();
550                    // Do sets and priorities
551                    OsiObject ** objects = new OsiObject * [numberSOS];
552                    // set old objects to have low priority
553                    int numberOldObjects = model.numberObjects();
554                    int numberColumns = model.getNumCols();
555                    for (int iObj = 0; iObj < numberOldObjects; iObj++) {
556                        int oldPriority = oldObjects[iObj]->priority();
557                        oldObjects[iObj]->setPriority(numberColumns + oldPriority);
558                    }
559                    const int * starts = process_->startSOS();
560                    const int * which = process_->whichSOS();
561                    const int * type = process_->typeSOS();
562                    const double * weight = process_->weightSOS();
563                    int iSOS;
564                    for (iSOS = 0; iSOS < numberSOS; iSOS++) {
565                        int iStart = starts[iSOS];
566                        int n = starts[iSOS+1] - iStart;
567                        objects[iSOS] = new CbcSOS(&model, n, which + iStart, weight + iStart,
568                                                   iSOS, type[iSOS]);
569                        // branch on long sets first
570                        objects[iSOS]->setPriority(numberColumns - n);
571                    }
572                    model.addObjects(numberSOS, objects);
573                    for (iSOS = 0; iSOS < numberSOS; iSOS++)
574                        delete objects[iSOS];
575                    delete [] objects;
576                    if (!someObjects) {
577                        // put back old column numbers
578                        const int * originalColumns = process_->originalColumns();
579                        // use reverse lookup to fake it
580                        int n = originalColumns[numberColumns-1] + 1;
581                        int * fake = new int[n];
582                        int i;
583                        // This was wrong (now is correct) - so could never have been called
584                        abort();
585                        for ( i = 0; i < n; i++)
586                            fake[i] = -1;
587                        for (i = 0; i < numberColumns; i++)
588                            fake[originalColumns[i]] = i;
589                        for (int iObject = 0; iObject < model.numberObjects(); iObject++) {
590                            // redo ids etc
591                            CbcSimpleInteger * obj =
592                                dynamic_cast <CbcSimpleInteger *>(model.modifiableObject(iObject)) ;
593                            if (obj) {
594                                obj->resetSequenceEtc(n, fake);
595                            } else {
596                                // redo ids etc
597                                CbcObject * obj =
598                                    dynamic_cast <CbcObject *>(model.modifiableObject(iObject)) ;
599                                assert (obj);
600                                obj->redoSequenceEtc(&model, n, fake);
601                            }
602                        }
603                        delete [] fake;
604                    }
605                }
606            } else {
607                //printf("Pre-processing says infeasible\n");
608                delete process;
609                preProcessState_ = -1;
610                process_ = NULL;
611            }
612        }
613    }
614    model.setNumberStrong(numberStrong_);
615    model.setNumberBeforeTrust(numberBeforeTrust_);
616}
617// Create C++ lines to get to current state
618void
619CbcStrategyDefault::generateCpp( FILE * fp)
620{
621    fprintf(fp, "0#include \"CbcStrategy.hpp\"\n");
622    fprintf(fp, "3  CbcStrategyDefault strategy(%s,%d,%d,%d);\n",
623            cutsOnlyAtRoot_ ? "1" : "0",
624            numberStrong_,
625            numberBeforeTrust_,
626            printLevel_);
627    fprintf(fp, "3  strategy.setupPreProcessing(%d,%d);\n",
628            desiredPreProcess_, preProcessPasses_);
629}
630// Default Constructor
631CbcStrategyDefaultSubTree::CbcStrategyDefaultSubTree(CbcModel * parent ,
632        int cutsOnlyAtRoot,
633        int numberStrong,
634        int numberBeforeTrust,
635        int printLevel)
636        : CbcStrategy(),
637        parentModel_(parent),
638        cutsOnlyAtRoot_(cutsOnlyAtRoot),
639        numberStrong_(numberStrong),
640        numberBeforeTrust_(numberBeforeTrust),
641        printLevel_(printLevel)
642{
643}
644
645
646// Destructor
647CbcStrategyDefaultSubTree::~CbcStrategyDefaultSubTree ()
648{
649}
650
651// Clone
652CbcStrategy *
653CbcStrategyDefaultSubTree::clone() const
654{
655    return new CbcStrategyDefaultSubTree(*this);
656}
657
658// Copy constructor
659CbcStrategyDefaultSubTree::CbcStrategyDefaultSubTree(const CbcStrategyDefaultSubTree & rhs)
660        :
661        CbcStrategy(rhs),
662        parentModel_(rhs.parentModel_),
663        cutsOnlyAtRoot_(rhs.cutsOnlyAtRoot_),
664        numberStrong_(rhs.numberStrong_),
665        numberBeforeTrust_(rhs.numberBeforeTrust_),
666        printLevel_(rhs.printLevel_)
667{
668    setNested(rhs.getNested());
669}
670
671// Setup cut generators
672void
673CbcStrategyDefaultSubTree::setupCutGenerators(CbcModel & model)
674{
675    // Set up some cut generators and defaults
676    if (cutsOnlyAtRoot_ < 0)
677        return; // no cuts wanted
678    // Probing first as gets tight bounds on continuous
679
680    CglProbing generator1;
681    generator1.setUsingObjective(true);
682    generator1.setMaxPass(1);
683    // Number of unsatisfied variables to look at
684    generator1.setMaxProbe(10);
685    // How far to follow the consequences
686    generator1.setMaxLook(10);
687    // Only look at rows with fewer than this number of elements
688    generator1.setMaxElements(200);
689    //generator1.setRowCuts(3);
690
691    CglGomory generator2;
692    // try larger limit
693    generator2.setLimit(300);
694
695    CglKnapsackCover generator3;
696
697    //CglOddHole generator4;
698    //generator4.setMinimumViolation(0.005);
699    //generator4.setMinimumViolationPer(0.00002);
700    // try larger limit
701    //generator4.setMaximumEntries(200);
702
703    CglClique generator5;
704    generator5.setStarCliqueReport(false);
705    generator5.setRowCliqueReport(false);
706
707    CglMixedIntegerRounding2 mixedGen;
708    CglFlowCover flowGen;
709
710    // Add in generators
711    int setting = cutsOnlyAtRoot_ ? -99 : -1;
712    int numberGenerators = model.numberCutGenerators();
713    int numberParentGenerators = parentModel_->numberCutGenerators();
714    int iGenerator;
715    bool found;
716    found = false;
717    int howOften = 0;
718    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
719        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
720        CglProbing * cgl = dynamic_cast<CglProbing *>(generator);
721        if (cgl) {
722            found = true;
723            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
724            break;
725        }
726    }
727
728    if (found && (howOften >= -1 || howOften == -98)) {
729        found = false;
730        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
731            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
732            CglProbing * cgl = dynamic_cast<CglProbing *>(generator);
733            if (cgl) {
734                found = true;
735                break;
736            }
737        }
738        if (!found) {
739            if (howOften == -1)
740                howOften = -98;
741            else if (howOften == -98)
742                howOften = -99;
743            model.addCutGenerator(&generator1, setting, "Probing");
744            CbcCutGenerator * generator =
745                model.cutGenerator(numberGenerators);
746            generator->setHowOften(howOften);
747            numberGenerators++;
748        }
749    }
750    found = false;
751    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
752        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
753        CglGomory * cgl = dynamic_cast<CglGomory *>(generator);
754        if (cgl) {
755            found = true;
756            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
757            break;
758        }
759    }
760    if (found && howOften >= 0) {
761        found = false;
762        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
763            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
764            CglGomory * cgl = dynamic_cast<CglGomory *>(generator);
765            if (cgl) {
766                found = true;
767                break;
768            }
769        }
770        if (!found)
771            model.addCutGenerator(&generator2, setting, "Gomory");
772    }
773    found = false;
774    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
775        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
776        CglKnapsackCover * cgl = dynamic_cast<CglKnapsackCover *>(generator);
777        if (cgl) {
778            found = true;
779            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
780            break;
781        }
782    }
783    if (found && howOften >= 0) {
784        found = false;
785        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
786            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
787            CglKnapsackCover * cgl = dynamic_cast<CglKnapsackCover *>(generator);
788            if (cgl) {
789                found = true;
790                break;
791            }
792        }
793        if (!found)
794            model.addCutGenerator(&generator3, setting, "Knapsack");
795    }
796    found = false;
797    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
798        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
799        CglClique * cgl = dynamic_cast<CglClique *>(generator);
800        if (cgl) {
801            found = true;
802            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
803            break;
804        }
805    }
806    if (found && howOften >= 0) {
807        found = false;
808        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
809            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
810            CglClique * cgl = dynamic_cast<CglClique *>(generator);
811            if (cgl) {
812                found = true;
813                break;
814            }
815        }
816        if (!found)
817            model.addCutGenerator(&generator5, setting, "Clique");
818    }
819    found = false;
820    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
821        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
822        CglFlowCover * cgl = dynamic_cast<CglFlowCover *>(generator);
823        if (cgl) {
824            found = true;
825            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
826            break;
827        }
828    }
829    if (found && howOften >= 0) {
830        found = false;
831        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
832            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
833            CglFlowCover * cgl = dynamic_cast<CglFlowCover *>(generator);
834            if (cgl) {
835                found = true;
836                break;
837            }
838        }
839        if (!found)
840            model.addCutGenerator(&flowGen, setting, "FlowCover");
841        found = false;
842    }
843    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
844        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
845        CglMixedIntegerRounding2 * cgl = dynamic_cast<CglMixedIntegerRounding2 *>(generator);
846        if (cgl) {
847            found = true;
848            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
849            break;
850        }
851    }
852    if (found && howOften >= 0) {
853        found = false;
854        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
855            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
856            CglMixedIntegerRounding2 * cgl = dynamic_cast<CglMixedIntegerRounding2 *>(generator);
857            if (cgl) {
858                found = true;
859                break;
860            }
861        }
862        if (!found)
863            model.addCutGenerator(&mixedGen, setting, "MixedIntegerRounding2");
864    }
865#ifdef JJF_ZERO
866    // Say we want timings
867    int newNumberGenerators = model.numberCutGenerators();
868    for (iGenerator = numberGenerators; iGenerator < newNumberGenerators; iGenerator++) {
869        CbcCutGenerator * generator = model.cutGenerator(iGenerator);
870        generator->setTiming(true);
871    }
872#endif
873    if (model.getNumCols() < -500)
874        model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible
875    else if (model.getNumCols() < 5000)
876        model.setMaximumCutPassesAtRoot(100); // use minimum drop
877    else
878        model.setMaximumCutPassesAtRoot(20);
879}
880// Setup heuristics
881void
882CbcStrategyDefaultSubTree::setupHeuristics(CbcModel & model)
883{
884    // Allow rounding heuristic
885
886    CbcRounding heuristic1(model);
887    heuristic1.setHeuristicName("rounding");
888    int numberHeuristics = model.numberHeuristics();
889    int iHeuristic;
890    bool found;
891    found = false;
892    for (iHeuristic = 0; iHeuristic < numberHeuristics; iHeuristic++) {
893        CbcHeuristic * heuristic = model.heuristic(iHeuristic);
894        CbcRounding * cgl = dynamic_cast<CbcRounding *>(heuristic);
895        if (cgl) {
896            found = true;
897            break;
898        }
899    }
900    if (!found)
901        model.addHeuristic(&heuristic1);
902}
903// Do printing stuff
904void
905CbcStrategyDefaultSubTree::setupPrinting(CbcModel & model, int modelLogLevel)
906{
907    if (!modelLogLevel) {
908        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
909        model.messageHandler()->setLogLevel(0);
910        model.solver()->messageHandler()->setLogLevel(0);
911    } else if (modelLogLevel == 1) {
912        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
913        model.messageHandler()->setLogLevel(1);
914        model.solver()->messageHandler()->setLogLevel(0);
915    } else {
916        model.messageHandler()->setLogLevel(2);
917        model.solver()->messageHandler()->setLogLevel(1);
918        model.setPrintFrequency(50);
919    }
920}
921// Other stuff e.g. strong branching
922void
923CbcStrategyDefaultSubTree::setupOther(CbcModel & model)
924{
925    model.setNumberStrong(numberStrong_);
926    model.setNumberBeforeTrust(numberBeforeTrust_);
927}
928// For uniform setting of cut and heuristic options
929void
930setCutAndHeuristicOptions(CbcModel & model)
931{
932    int numberGenerators = model.numberCutGenerators();
933    int iGenerator;
934    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
935        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
936        CglProbing * cglProbing = dynamic_cast<CglProbing *>(generator);
937        if (cglProbing) {
938            cglProbing->setUsingObjective(1);
939            cglProbing->setMaxPass(1);
940            cglProbing->setMaxPassRoot(1);
941            // Number of unsatisfied variables to look at
942            cglProbing->setMaxProbe(10);
943            cglProbing->setMaxProbeRoot(50);
944            //cglProbing->setMaxProbeRoot(123);
945            // How far to follow the consequences
946            cglProbing->setMaxLook(5);
947            cglProbing->setMaxLookRoot(50);
948            cglProbing->setMaxLookRoot(10);
949            // Only look at rows with fewer than this number of elements
950            cglProbing->setMaxElements(200);
951            cglProbing->setMaxElementsRoot(300);
952            cglProbing->setRowCuts(3);
953        }
954#ifdef JJF_ZERO
955        CglGomory * cglGomory = dynamic_cast<CglGomory *>(generator);
956        if (cglGomory) {
957            // try larger limit
958            cglGomory->setLimitAtRoot(1000);
959            cglGomory->setLimit(50);
960        }
961        CglKnapsackCover * cglKnapsackCover = dynamic_cast<CglKnapsackCover *>(generator);
962        if (cglKnapsackCover) {
963        }
964#endif
965    }
966}
967
968
969
Note: See TracBrowser for help on using the repository browser.