source: stable/2.7/Cbc/src/CbcStrategy.cpp @ 1577

Last change on this file since 1577 was 1573, checked in by lou, 9 years ago

Change to EPL license notice.

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