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

Last change on this file since 2014 was 1641, checked in by forrest, 9 years ago

out some printf statements

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