source: stable/2.8/Cbc/src/CbcCutGenerator.cpp @ 1902

Last change on this file since 1902 was 1883, checked in by stefan, 6 years ago

sync with trunk rev 1882

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.1 KB
Line 
1/* $Id: CbcCutGenerator.cpp 1883 2013-04-06 13:33:15Z stefan $ */
2// Copyright (C) 2003, 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#include "CbcConfig.h"
11#include <cassert>
12#include <cstdlib>
13#include <cmath>
14#include <cfloat>
15
16#ifdef COIN_HAS_CLP
17#include "OsiClpSolverInterface.hpp"
18#else
19#include "OsiSolverInterface.hpp"
20#endif
21//#define CGL_DEBUG 1
22#ifdef CGL_DEBUG
23#include "OsiRowCutDebugger.hpp"
24#endif
25#include "CbcModel.hpp"
26#include "CbcMessage.hpp"
27#include "CbcCutGenerator.hpp"
28#include "CbcBranchDynamic.hpp"
29#include "CglProbing.hpp"
30#include "CoinTime.hpp"
31
32// Default Constructor
33CbcCutGenerator::CbcCutGenerator ()
34        : timeInCutGenerator_(0.0),
35        model_(NULL),
36        generator_(NULL),
37        generatorName_(NULL),
38        whenCutGenerator_(-1),
39        whenCutGeneratorInSub_(-100),
40        switchOffIfLessThan_(0),
41        depthCutGenerator_(-1),
42        depthCutGeneratorInSub_(-1),
43        inaccuracy_(0),
44        numberTimes_(0),
45        numberCuts_(0),
46        numberElements_(0),
47        numberColumnCuts_(0),
48        numberCutsActive_(0),
49        numberCutsAtRoot_(0),
50        numberActiveCutsAtRoot_(0),
51        numberShortCutsAtRoot_(0),
52        switches_(1),
53        maximumTries_(-1)
54{
55}
56// Normal constructor
57CbcCutGenerator::CbcCutGenerator(CbcModel * model, CglCutGenerator * generator,
58                                 int howOften, const char * name,
59                                 bool normal, bool atSolution,
60                                 bool infeasible, int howOftenInSub,
61                                 int whatDepth, int whatDepthInSub,
62                                 int switchOffIfLessThan)
63        :
64        timeInCutGenerator_(0.0),
65        depthCutGenerator_(whatDepth),
66        depthCutGeneratorInSub_(whatDepthInSub),
67        inaccuracy_(0),
68        numberTimes_(0),
69        numberCuts_(0),
70        numberElements_(0),
71        numberColumnCuts_(0),
72        numberCutsActive_(0),
73        numberCutsAtRoot_(0),
74        numberActiveCutsAtRoot_(0),
75        numberShortCutsAtRoot_(0),
76        switches_(1),
77        maximumTries_(-1)
78{
79    if (howOften < -1900) {
80        setGlobalCuts(true);
81        howOften += 2000;
82    } else if (howOften < -900) {
83        setGlobalCutsAtRoot(true);
84        howOften += 1000;
85    }
86    model_ = model;
87    generator_ = generator->clone();
88    generator_->refreshSolver(model_->solver());
89    setNeedsOptimalBasis(generator_->needsOptimalBasis());
90    whenCutGenerator_ = howOften;
91    whenCutGeneratorInSub_ = howOftenInSub;
92    switchOffIfLessThan_ = switchOffIfLessThan;
93    if (name)
94        generatorName_ = CoinStrdup(name);
95    else
96        generatorName_ = CoinStrdup("Unknown");
97    setNormal(normal);
98    setAtSolution(atSolution);
99    setWhenInfeasible(infeasible);
100}
101
102// Copy constructor
103CbcCutGenerator::CbcCutGenerator ( const CbcCutGenerator & rhs)
104{
105    model_ = rhs.model_;
106    generator_ = rhs.generator_->clone();
107    //generator_->refreshSolver(model_->solver());
108    whenCutGenerator_ = rhs.whenCutGenerator_;
109    whenCutGeneratorInSub_ = rhs.whenCutGeneratorInSub_;
110    switchOffIfLessThan_ = rhs.switchOffIfLessThan_;
111    depthCutGenerator_ = rhs.depthCutGenerator_;
112    depthCutGeneratorInSub_ = rhs.depthCutGeneratorInSub_;
113    generatorName_ = CoinStrdup(rhs.generatorName_);
114    switches_ = rhs.switches_;
115    maximumTries_ = rhs.maximumTries_;
116    timeInCutGenerator_ = rhs.timeInCutGenerator_;
117    savedCuts_ = rhs.savedCuts_;
118    inaccuracy_ = rhs.inaccuracy_;
119    numberTimes_ = rhs.numberTimes_;
120    numberCuts_ = rhs.numberCuts_;
121    numberElements_ = rhs.numberElements_;
122    numberColumnCuts_ = rhs.numberColumnCuts_;
123    numberCutsActive_ = rhs.numberCutsActive_;
124    numberCutsAtRoot_  = rhs.numberCutsAtRoot_;
125    numberActiveCutsAtRoot_ = rhs.numberActiveCutsAtRoot_;
126    numberShortCutsAtRoot_ = rhs.numberShortCutsAtRoot_;
127}
128
129// Assignment operator
130CbcCutGenerator &
131CbcCutGenerator::operator=( const CbcCutGenerator & rhs)
132{
133    if (this != &rhs) {
134        delete generator_;
135        free(generatorName_);
136        model_ = rhs.model_;
137        generator_ = rhs.generator_->clone();
138        generator_->refreshSolver(model_->solver());
139        whenCutGenerator_ = rhs.whenCutGenerator_;
140        whenCutGeneratorInSub_ = rhs.whenCutGeneratorInSub_;
141        switchOffIfLessThan_ = rhs.switchOffIfLessThan_;
142        depthCutGenerator_ = rhs.depthCutGenerator_;
143        depthCutGeneratorInSub_ = rhs.depthCutGeneratorInSub_;
144        generatorName_ = CoinStrdup(rhs.generatorName_);
145        switches_ = rhs.switches_;
146        maximumTries_ = rhs.maximumTries_;
147        timeInCutGenerator_ = rhs.timeInCutGenerator_;
148        savedCuts_ = rhs.savedCuts_;
149        inaccuracy_ = rhs.inaccuracy_;
150        numberTimes_ = rhs.numberTimes_;
151        numberCuts_ = rhs.numberCuts_;
152        numberElements_ = rhs.numberElements_;
153        numberColumnCuts_ = rhs.numberColumnCuts_;
154        numberCutsActive_ = rhs.numberCutsActive_;
155        numberCutsAtRoot_  = rhs.numberCutsAtRoot_;
156        numberActiveCutsAtRoot_ = rhs.numberActiveCutsAtRoot_;
157        numberShortCutsAtRoot_ = rhs.numberShortCutsAtRoot_;
158    }
159    return *this;
160}
161
162// Destructor
163CbcCutGenerator::~CbcCutGenerator ()
164{
165    free(generatorName_);
166    delete generator_;
167}
168
169/* This is used to refresh any inforamtion.
170   It also refreshes the solver in the cut generator
171   in case generator wants to do some work
172*/
173void
174CbcCutGenerator::refreshModel(CbcModel * model)
175{
176    model_ = model;
177    generator_->refreshSolver(model_->solver());
178}
179/* Generate cuts for the model data contained in si.
180   The generated cuts are inserted into and returned in the
181   collection of cuts cs.
182*/
183bool
184CbcCutGenerator::generateCuts( OsiCuts & cs , int fullScan, OsiSolverInterface * solver, CbcNode * node)
185{
186    /*
187          Make some decisions about whether we'll generate cuts. First convert
188          whenCutGenerator_ to a set of canonical values for comparison to the node
189          count.
190
191                 0 <    mod 1000000, with a result of 0 forced to 1
192           -99 <= <= 0  convert to 1
193          -100 =        Off, period
194        */
195        int depth;
196    if (node)
197        depth = node->depth();
198    else
199        depth = 0;
200    int howOften = whenCutGenerator_;
201    if (dynamic_cast<CglProbing*>(generator_)) {
202        if (howOften == -100 && model_->doCutsNow(3)) {
203            howOften = 1; // do anyway
204        }
205    }
206    if (howOften == -100)
207        return false;
208    int pass = model_->getCurrentPassNumber() - 1;
209    if (maximumTries_>0) {
210      // howOften means what it says
211      if ((pass%howOften)!=0||depth)
212        return false;
213      else
214        howOften=1;
215    }
216    if (howOften > 0)
217        howOften = howOften % 1000000;
218    else
219        howOften = 1;
220    if (!howOften)
221        howOften = 1;
222    bool returnCode = false;
223    //OsiSolverInterface * solver = model_->solver();
224    // Reset cuts on first pass
225    if (!pass)
226        savedCuts_ = OsiCuts();
227    /*
228          Determine if we should generate cuts based on node count.
229        */
230        bool doThis = (model_->getNodeCount() % howOften) == 0;
231    /*
232          If the user has provided a depth specification, it will override the node
233          count specification.
234        */
235        if (depthCutGenerator_ > 0) {
236        doThis = (depth % depthCutGenerator_) == 0;
237        if (depth < depthCutGenerator_)
238            doThis = true; // and also at top of tree
239    }
240        /*
241          A few magic numbers ...
242
243          The distinction between -100 and 100 for howOften is that we can override 100
244          with fullScan. -100 means no cuts, period. As does the magic number -200 for
245          whenCutGeneratorInSub_.
246        */
247
248    // But turn off if 100
249    if (howOften == 100)
250        doThis = false;
251    // Switch off if special setting
252    if (whenCutGeneratorInSub_ == -200 && model_->parentModel()) {
253        fullScan = 0;
254        doThis = false;
255    }
256    if (fullScan || doThis) {
257        CoinThreadRandom * randomNumberGenerator = NULL;
258#ifdef COIN_HAS_CLP
259        {
260            OsiClpSolverInterface * clpSolver
261            = dynamic_cast<OsiClpSolverInterface *> (solver);
262            if (clpSolver)
263                randomNumberGenerator =
264                    clpSolver->getModelPtr()->randomNumberGenerator();
265        }
266#endif
267        double time1 = 0.0;
268        if (timing())
269            time1 = CoinCpuTime();
270        //#define CBC_DEBUG
271        int numberRowCutsBefore = cs.sizeRowCuts() ;
272        int numberColumnCutsBefore = cs.sizeColCuts() ;
273#ifdef JJF_ZERO
274        int cutsBefore = cs.sizeCuts();
275#endif
276        CglTreeInfo info;
277        info.level = depth;
278        info.pass = pass;
279        info.formulation_rows = model_->numberRowsAtContinuous();
280        info.inTree = node != NULL;
281        info.randomNumberGenerator = randomNumberGenerator;
282        info.options = (globalCutsAtRoot()) ? 8 : 0;
283        if (ineffectualCuts())
284            info.options |= 32;
285        if (globalCuts())
286            info.options |= 16;
287        if (fullScan < 0)
288            info.options |= 128;
289        if (whetherInMustCallAgainMode())
290          info.options |= 1024;
291        // See if we want alternate set of cuts
292        if ((model_->moreSpecialOptions()&16384) != 0)
293            info.options |= 256;
294        if (model_->parentModel())
295            info.options |= 512;
296        // above had &&!model_->parentModel()&&depth<2)
297        incrementNumberTimesEntered();
298        CglProbing* generator =
299            dynamic_cast<CglProbing*>(generator_);
300        //if (!depth&&!pass)
301        //printf("Cut generator %s when %d\n",generatorName_,whenCutGenerator_);
302        if (!generator) {
303            // Pass across model information in case it could be useful
304            //void * saveData = solver->getApplicationData();
305            //solver->setApplicationData(model_);
306            generator_->generateCuts(*solver, cs, info);
307            //solver->setApplicationData(saveData);
308        } else {
309            // Probing - return tight column bounds
310            CglTreeProbingInfo * info2 = model_->probingInfo();
311            bool doCuts = false;
312            if (info2 && !depth) {
313                info2->options = (globalCutsAtRoot()) ? 8 : 0;
314                info2->level = depth;
315                info2->pass = pass;
316                info2->formulation_rows = model_->numberRowsAtContinuous();
317                info2->inTree = node != NULL;
318                info2->randomNumberGenerator = randomNumberGenerator;
319                generator->generateCutsAndModify(*solver, cs, info2);
320                doCuts = true;
321            } else if (depth) {
322                /* The idea behind this is that probing may work in a different
323                   way deep in tree.  So every now and then try various
324                   combinations to see what works.
325                */
326#define TRY_NOW_AND_THEN
327#ifdef TRY_NOW_AND_THEN
328                if ((numberTimes_ == 200 || (numberTimes_ > 200 && (numberTimes_ % 2000) == 0))
329                        && !model_->parentModel() && info.formulation_rows > 200) {
330                    /* In tree, every now and then try various combinations
331                       maxStack, maxProbe (last 5 digits)
332                       123 is special and means CglProbing will try and
333                       be intelligent.
334                    */
335                    int test[] = {
336                        100123,
337                        199999,
338                        200123,
339                        299999,
340                        500123,
341                        599999,
342                        1000123,
343                        1099999,
344                        2000123,
345                        2099999
346                    };
347                    int n = static_cast<int> (sizeof(test) / sizeof(int));
348                    int saveStack = generator->getMaxLook();
349                    int saveNumber = generator->getMaxProbe();
350                    int kr1 = 0;
351                    int kc1 = 0;
352                    int bestStackTree = -1;
353                    int bestNumberTree = -1;
354                    for (int i = 0; i < n; i++) {
355                        //OsiCuts cs2 = cs;
356                        int stack = test[i] / 100000;
357                        int number = test[i] - 100000 * stack;
358                        generator->setMaxLook(stack);
359                        generator->setMaxProbe(number);
360                        int numberRowCutsBefore = cs.sizeRowCuts() ;
361                        int numberColumnCutsBefore = cs.sizeColCuts() ;
362                        generator_->generateCuts(*solver, cs, info);
363                        int numberRowCuts = cs.sizeRowCuts() - numberRowCutsBefore ;
364                        int numberColumnCuts = cs.sizeColCuts() - numberColumnCutsBefore ;
365#ifdef CLP_INVESTIGATE
366                        if (numberRowCuts < kr1 || numberColumnCuts < kc1)
367                            printf("Odd ");
368#endif
369                        if (numberRowCuts > kr1 || numberColumnCuts > kc1) {
370#ifdef CLP_INVESTIGATE
371                            printf("*** ");
372#endif
373                            kr1 = numberRowCuts;
374                            kc1 = numberColumnCuts;
375                            bestStackTree = stack;
376                            bestNumberTree = number;
377                            doCuts = true;
378                        }
379#ifdef CLP_INVESTIGATE
380                        printf("maxStack %d number %d gives %d row cuts and %d column cuts\n",
381                               stack, number, numberRowCuts, numberColumnCuts);
382#endif
383                    }
384                    generator->setMaxLook(saveStack);
385                    generator->setMaxProbe(saveNumber);
386                    if (bestStackTree > 0) {
387                        generator->setMaxLook(bestStackTree);
388                        generator->setMaxProbe(bestNumberTree);
389#ifdef CLP_INVESTIGATE
390                        printf("RRNumber %d -> %d, stack %d -> %d\n",
391                               saveNumber, bestNumberTree, saveStack, bestStackTree);
392#endif
393                    } else {
394                        // no good
395                        generator->setMaxLook(0);
396#ifdef CLP_INVESTIGATE
397                        printf("RRSwitching off number %d -> %d, stack %d -> %d\n",
398                               saveNumber, saveNumber, saveStack, 1);
399#endif
400                    }
401                }
402#endif
403                if (generator->getMaxLook() > 0 && !doCuts) {
404                    generator->generateCutsAndModify(*solver, cs, &info);
405                    doCuts = true;
406                }
407            } else {
408                // at root - don't always do
409                if (pass < 15 || (pass&1) == 0) {
410                    generator->generateCutsAndModify(*solver, cs, &info);
411                    doCuts = true;
412                }
413            }
414            if (doCuts && generator->tightLower()) {
415                // probing may have tightened bounds - check
416                const double * tightLower = generator->tightLower();
417                const double * lower = solver->getColLower();
418                const double * tightUpper = generator->tightUpper();
419                const double * upper = solver->getColUpper();
420                const double * solution = solver->getColSolution();
421                int j;
422                int numberColumns = solver->getNumCols();
423                double primalTolerance = 1.0e-8;
424                const char * tightenBounds = generator->tightenBounds();
425#ifdef CGL_DEBUG
426                const OsiRowCutDebugger * debugger = solver->getRowCutDebugger();
427                if (debugger && debugger->onOptimalPath(*solver)) {
428                    printf("On optimal path CbcCut\n");
429                    int nCols = solver->getNumCols();
430                    int i;
431                    const double * optimal = debugger->optimalSolution();
432                    const double * objective = solver->getObjCoefficients();
433                    double objval1 = 0.0, objval2 = 0.0;
434                    for (i = 0; i < nCols; i++) {
435#if CGL_DEBUG>1
436                        printf("%d %g %g %g %g\n", i, lower[i], solution[i], upper[i], optimal[i]);
437#endif
438                        objval1 += solution[i] * objective[i];
439                        objval2 += optimal[i] * objective[i];
440                        assert(optimal[i] >= lower[i] - 1.0e-5 && optimal[i] <= upper[i] + 1.0e-5);
441                        assert(optimal[i] >= tightLower[i] - 1.0e-5 && optimal[i] <= tightUpper[i] + 1.0e-5);
442                    }
443                    printf("current obj %g, integer %g\n", objval1, objval2);
444                }
445#endif
446                bool feasible = true;
447                if ((model_->getThreadMode()&2) == 0) {
448                    for (j = 0; j < numberColumns; j++) {
449                        if (solver->isInteger(j)) {
450                            if (tightUpper[j] < upper[j]) {
451                                double nearest = floor(tightUpper[j] + 0.5);
452                                //assert (fabs(tightUpper[j]-nearest)<1.0e-5); may be infeasible
453                                solver->setColUpper(j, nearest);
454                                if (nearest < solution[j] - primalTolerance)
455                                    returnCode = true;
456                            }
457                            if (tightLower[j] > lower[j]) {
458                                double nearest = floor(tightLower[j] + 0.5);
459                                //assert (fabs(tightLower[j]-nearest)<1.0e-5); may be infeasible
460                                solver->setColLower(j, nearest);
461                                if (nearest > solution[j] + primalTolerance)
462                                    returnCode = true;
463                            }
464                        } else {
465                            if (upper[j] > lower[j]) {
466                                if (tightUpper[j] == tightLower[j]) {
467                                    // fix
468                                    //if (tightLower[j]!=lower[j])
469                                    solver->setColLower(j, tightLower[j]);
470                                    //if (tightUpper[j]!=upper[j])
471                                    solver->setColUpper(j, tightUpper[j]);
472                                    if (tightLower[j] > solution[j] + primalTolerance ||
473                                            tightUpper[j] < solution[j] - primalTolerance)
474                                        returnCode = true;
475                                } else if (tightenBounds && tightenBounds[j]) {
476                                    solver->setColLower(j, CoinMax(tightLower[j], lower[j]));
477                                    solver->setColUpper(j, CoinMin(tightUpper[j], upper[j]));
478                                    if (tightLower[j] > solution[j] + primalTolerance ||
479                                            tightUpper[j] < solution[j] - primalTolerance)
480                                        returnCode = true;
481                                }
482                            }
483                        }
484                        if (upper[j] < lower[j] - 1.0e-3) {
485                            feasible = false;
486                            break;
487                        }
488                    }
489                } else {
490                    CoinPackedVector lbs;
491                    CoinPackedVector ubs;
492                    int numberChanged = 0;
493                    bool ifCut = false;
494                    for (j = 0; j < numberColumns; j++) {
495                        if (solver->isInteger(j)) {
496                            if (tightUpper[j] < upper[j]) {
497                                double nearest = floor(tightUpper[j] + 0.5);
498                                //assert (fabs(tightUpper[j]-nearest)<1.0e-5); may be infeasible
499                                ubs.insert(j, nearest);
500                                numberChanged++;
501                                if (nearest < solution[j] - primalTolerance)
502                                    ifCut = true;
503                            }
504                            if (tightLower[j] > lower[j]) {
505                                double nearest = floor(tightLower[j] + 0.5);
506                                //assert (fabs(tightLower[j]-nearest)<1.0e-5); may be infeasible
507                                lbs.insert(j, nearest);
508                                numberChanged++;
509                                if (nearest > solution[j] + primalTolerance)
510                                    ifCut = true;
511                            }
512                        } else {
513                            if (upper[j] > lower[j]) {
514                                if (tightUpper[j] == tightLower[j]) {
515                                    // fix
516                                    lbs.insert(j, tightLower[j]);
517                                    ubs.insert(j, tightUpper[j]);
518                                    if (tightLower[j] > solution[j] + primalTolerance ||
519                                            tightUpper[j] < solution[j] - primalTolerance)
520                                        ifCut = true;
521                                } else if (tightenBounds && tightenBounds[j]) {
522                                    lbs.insert(j, CoinMax(tightLower[j], lower[j]));
523                                    ubs.insert(j, CoinMin(tightUpper[j], upper[j]));
524                                    if (tightLower[j] > solution[j] + primalTolerance ||
525                                            tightUpper[j] < solution[j] - primalTolerance)
526                                        ifCut = true;
527                                }
528                            }
529                        }
530                        if (upper[j] < lower[j] - 1.0e-3) {
531                            feasible = false;
532                            break;
533                        }
534                    }
535                    if (numberChanged) {
536                        OsiColCut cc;
537                        cc.setUbs(ubs);
538                        cc.setLbs(lbs);
539                        if (ifCut) {
540                            cc.setEffectiveness(100.0);
541                        } else {
542                            cc.setEffectiveness(1.0e-5);
543                        }
544                        cs.insert(cc);
545                    }
546                }
547                if (!feasible) {
548                    // not feasible -add infeasible cut
549                    OsiRowCut rc;
550                    rc.setLb(COIN_DBL_MAX);
551                    rc.setUb(0.0);
552                    cs.insert(rc);
553                }
554            }
555            //if (!solver->basisIsAvailable())
556            //returnCode=true;
557            if (!returnCode) {
558              // bounds changed but still optimal
559#ifdef COIN_HAS_CLP
560              OsiClpSolverInterface * clpSolver
561                = dynamic_cast<OsiClpSolverInterface *> (solver);
562              if (clpSolver) {
563                clpSolver->setLastAlgorithm(2);
564              }
565#endif
566            }
567#ifdef JJF_ZERO
568            // Pass across info to pseudocosts
569            char * mark = new char[numberColumns];
570            memset(mark, 0, numberColumns);
571            int nLook = generator->numberThisTime();
572            const int * lookedAt = generator->lookedAt();
573            const int * fixedDown = generator->fixedDown();
574            const int * fixedUp = generator->fixedUp();
575            for (j = 0; j < nLook; j++)
576                mark[lookedAt[j]] = 1;
577            int numberObjects = model_->numberObjects();
578            for (int i = 0; i < numberObjects; i++) {
579                CbcSimpleIntegerDynamicPseudoCost * obj1 =
580                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(model_->modifiableObject(i)) ;
581                if (obj1) {
582                    int iColumn = obj1->columnNumber();
583                    if (mark[iColumn])
584                        obj1->setProbingInformation(fixedDown[iColumn], fixedUp[iColumn]);
585                }
586            }
587            delete [] mark;
588#endif
589        }
590        CbcCutModifier * modifier = model_->cutModifier();
591        if (modifier) {
592            int numberRowCutsAfter = cs.sizeRowCuts() ;
593            int k ;
594            int nOdd = 0;
595            //const OsiSolverInterface * solver = model_->solver();
596            for (k = numberRowCutsAfter - 1; k >= numberRowCutsBefore; k--) {
597                OsiRowCut & thisCut = cs.rowCut(k) ;
598                int returnCode = modifier->modify(solver, thisCut);
599                if (returnCode) {
600                    nOdd++;
601                    if (returnCode == 3)
602                        cs.eraseRowCut(k);
603                }
604            }
605            if (nOdd)
606                COIN_DETAIL_PRINT(printf("Cut generator %s produced %d cuts of which %d were modified\n",
607                                         generatorName_, numberRowCutsAfter - numberRowCutsBefore, nOdd));
608        }
609        {
610            // make all row cuts without test for duplicate
611            int numberRowCutsAfter = cs.sizeRowCuts() ;
612            int k ;
613#ifdef CGL_DEBUG
614            const OsiRowCutDebugger * debugger = solver->getRowCutDebugger();
615#endif
616            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
617                OsiRowCut * thisCut = cs.rowCutPtr(k) ;
618#ifdef CGL_DEBUG
619                if (debugger && debugger->onOptimalPath(*solver))
620                    assert(!debugger->invalidCut(*thisCut));
621#endif
622                thisCut->mutableRow().setTestForDuplicateIndex(false);
623            }
624        }
625        // Add in saved cuts if violated
626        if (false && !depth) {
627            const double * solution = solver->getColSolution();
628            double primalTolerance = 1.0e-7;
629            int numberCuts = savedCuts_.sizeRowCuts() ;
630            for (int k = numberCuts - 1; k >= 0; k--) {
631                const OsiRowCut * thisCut = savedCuts_.rowCutPtr(k) ;
632                double sum = 0.0;
633                int n = thisCut->row().getNumElements();
634                const int * column = thisCut->row().getIndices();
635                const double * element = thisCut->row().getElements();
636                assert (n);
637                for (int i = 0; i < n; i++) {
638                    double value = element[i];
639                    sum += value * solution[column[i]];
640                }
641                if (sum > thisCut->ub() + primalTolerance) {
642                    sum = sum - thisCut->ub();
643                } else if (sum < thisCut->lb() - primalTolerance) {
644                    sum = thisCut->lb() - sum;
645                } else {
646                    sum = 0.0;
647                }
648                if (sum) {
649                    // add to candidates and take out here
650                    cs.insert(*thisCut);
651                    savedCuts_.eraseRowCut(k);
652                }
653            }
654        }
655        if (!atSolution()) {
656            int numberRowCutsAfter = cs.sizeRowCuts() ;
657            int k ;
658            int nEls = 0;
659            int nCuts = numberRowCutsAfter - numberRowCutsBefore;
660            // Remove NULL cuts!
661            int nNull = 0;
662            const double * solution = solver->getColSolution();
663            bool feasible = true;
664            double primalTolerance = 1.0e-7;
665            int shortCut = (depth) ? -1 : generator_->maximumLengthOfCutInTree();
666            for (k = numberRowCutsAfter - 1; k >= numberRowCutsBefore; k--) {
667                const OsiRowCut * thisCut = cs.rowCutPtr(k) ;
668                double sum = 0.0;
669                if (thisCut->lb() <= thisCut->ub()) {
670                    int n = thisCut->row().getNumElements();
671                    if (n <= shortCut)
672                        numberShortCutsAtRoot_++;
673                    const int * column = thisCut->row().getIndices();
674                    const double * element = thisCut->row().getElements();
675                    if (n <= 0) {
676                        // infeasible cut - give up
677                        feasible = false;
678                        break;
679                    }
680                    nEls += n;
681                    for (int i = 0; i < n; i++) {
682                        double value = element[i];
683                        sum += value * solution[column[i]];
684                    }
685                    if (sum > thisCut->ub() + primalTolerance) {
686                        sum = sum - thisCut->ub();
687                    } else if (sum < thisCut->lb() - primalTolerance) {
688                        sum = thisCut->lb() - sum;
689                    } else {
690                        sum = 0.0;
691                        cs.eraseRowCut(k);
692                        nNull++;
693                    }
694                }
695            }
696            //if (nNull)
697            //printf("%s has %d cuts and %d elements - %d null!\n",generatorName_,
698            //       nCuts,nEls,nNull);
699            numberRowCutsAfter = cs.sizeRowCuts() ;
700            nCuts = numberRowCutsAfter - numberRowCutsBefore;
701            nEls = 0;
702            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
703                const OsiRowCut * thisCut = cs.rowCutPtr(k) ;
704                int n = thisCut->row().getNumElements();
705                nEls += n;
706            }
707            //printf("%s has %d cuts and %d elements\n",generatorName_,
708            //     nCuts,nEls);
709            int nElsNow = solver->getMatrixByCol()->getNumElements();
710            int numberColumns = solver->getNumCols();
711            int numberRows = solver->getNumRows();
712            //double averagePerRow = static_cast<double>(nElsNow)/
713            //static_cast<double>(numberRows);
714            int nAdd;
715            int nAdd2;
716            int nReasonable;
717            if (!model_->parentModel() && depth < 2) {
718                if (inaccuracy_ < 3) {
719                    nAdd = 10000;
720                    if (pass > 0 && numberColumns > -500)
721                        nAdd = CoinMin(nAdd, nElsNow + 2 * numberRows);
722                } else {
723                    nAdd = 10000;
724                    if (pass > 0)
725                        nAdd = CoinMin(nAdd, nElsNow + 2 * numberRows);
726                }
727                nAdd2 = 5 * numberColumns;
728                nReasonable = CoinMax(nAdd2, nElsNow / 8 + nAdd);
729                if (!depth && !pass) {
730                    // allow more
731                    nAdd += nElsNow / 2;
732                    nAdd2 += nElsNow / 2;
733                    nReasonable += nElsNow / 2;
734                }
735                //if (!depth&&ineffectualCuts())
736                //nReasonable *= 2;
737            } else {
738                nAdd = 200;
739                nAdd2 = 2 * numberColumns;
740                nReasonable = CoinMax(nAdd2, nElsNow / 8 + nAdd);
741            }
742            //#define UNS_WEIGHT 0.1
743#ifdef UNS_WEIGHT
744            const double * colLower = solver->getColLower();
745            const double * colUpper = solver->getColUpper();
746#endif
747            if (/*nEls>CoinMax(nAdd2,nElsNow/8+nAdd)*/nCuts && feasible) {
748                //printf("need to remove cuts\n");
749                // just add most effective
750#ifndef JJF_ONE
751                int nDelete = nEls - nReasonable;
752
753                nElsNow = nEls;
754                double * sort = new double [nCuts];
755                int * which = new int [nCuts];
756                // For parallel cuts
757                double * element2 = new double [numberColumns];
758                //#define USE_OBJECTIVE 2
759#ifdef USE_OBJECTIVE
760                const double *objective = solver->getObjCoefficients() ;
761#if USE_OBJECTIVE>1
762                double objNorm = 0.0;
763                for (int i = 0; i < numberColumns; i++)
764                    objNorm += objective[i] * objective[i];
765                if (objNorm)
766                    objNorm = 1.0 / sqrt(objNorm);
767                else
768                    objNorm = 1.0;
769                objNorm *= 0.01; // downgrade
770#endif
771#endif
772                CoinZeroN(element2, numberColumns);
773                for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
774                    const OsiRowCut * thisCut = cs.rowCutPtr(k) ;
775                    double sum = 0.0;
776                    if (thisCut->lb() <= thisCut->ub()) {
777                        int n = thisCut->row().getNumElements();
778                        const int * column = thisCut->row().getIndices();
779                        const double * element = thisCut->row().getElements();
780                        assert (n);
781#ifdef UNS_WEIGHT
782                        double normU = 0.0;
783                        double norm = 1.0e-3;
784                        int nU = 0;
785                        for (int i = 0; i < n; i++) {
786                            double value = element[i];
787                            int iColumn = column[i];
788                            double solValue = solution[iColumn];
789                            sum += value * solValue;
790                            value *= value;
791                            norm += value;
792                            if (solValue > colLower[iColumn] + 1.0e-6 &&
793                                    solValue < colUpper[iColumn] - 1.0e-6) {
794                                normU += value;
795                                nU++;
796                            }
797                        }
798#ifdef JJF_ZERO
799                        int nS = n - nU;
800                        if (numberColumns > 20000) {
801                            if (nS > 50) {
802                                double ratio = 50.0 / nS;
803                                normU /= ratio;
804                            }
805                        }
806#endif
807                        norm += UNS_WEIGHT * (normU - norm);
808#else
809                        double norm = 1.0e-3;
810#ifdef USE_OBJECTIVE
811                        double obj = 0.0;
812#endif
813                        for (int i = 0; i < n; i++) {
814                            int iColumn = column[i];
815                            double value = element[i];
816                            sum += value * solution[iColumn];
817                            norm += value * value;
818#ifdef USE_OBJECTIVE
819                            obj += value * objective[iColumn];
820#endif
821                        }
822#endif
823                        if (sum > thisCut->ub()) {
824                            sum = sum - thisCut->ub();
825                        } else if (sum < thisCut->lb()) {
826                            sum = thisCut->lb() - sum;
827                        } else {
828                            sum = 0.0;
829                        }
830#ifdef USE_OBJECTIVE
831                        if (sum) {
832#if USE_OBJECTIVE==1
833                            obj = CoinMax(1.0e-6, fabs(obj));
834                            norm = sqrt(obj * norm);
835                            //sum += fabs(obj)*invObjNorm;
836                            //printf("sum %g norm %g normobj %g invNorm %g mod %g\n",
837                            //     sum,norm,obj,invObjNorm,obj*invObjNorm);
838                            // normalize
839                            sum /= sqrt(norm);
840#else
841                            // normalize
842                            norm = 1.0 / sqrt(norm);
843                            sum = (sum + objNorm * obj) * norm;
844#endif
845                        }
846#else
847                        // normalize
848                        sum /= sqrt(norm);
849#endif
850                        //sum /= pow(norm,0.3);
851                        // adjust for length
852                        //sum /= pow(reinterpret_cast<double>(n),0.2);
853                        //sum /= sqrt((double) n);
854                        // randomize
855                        //double randomNumber =
856                        //model_->randomNumberGenerator()->randomDouble();
857                        //sum *= (0.5+randomNumber);
858                    } else {
859                        // keep
860                        sum = COIN_DBL_MAX;
861                    }
862                    sort[k-numberRowCutsBefore] = sum;
863                    which[k-numberRowCutsBefore] = k;
864                }
865                CoinSort_2(sort, sort + nCuts, which);
866                // Now see which ones are too similar
867                int nParallel = 0;
868                double testValue = (depth > 1) ? 0.99 : 0.999999;
869                for (k = 0; k < nCuts; k++) {
870                    int j = which[k];
871                    const OsiRowCut * thisCut = cs.rowCutPtr(j) ;
872                    if (thisCut->lb() > thisCut->ub())
873                        break; // cut is infeasible
874                    int n = thisCut->row().getNumElements();
875                    const int * column = thisCut->row().getIndices();
876                    const double * element = thisCut->row().getElements();
877                    assert (n);
878                    double norm = 0.0;
879                    double lb = thisCut->lb();
880                    double ub = thisCut->ub();
881                    for (int i = 0; i < n; i++) {
882                        double value = element[i];
883                        element2[column[i]] = value;
884                        norm += value * value;
885                    }
886                    int kkk = CoinMin(nCuts, k + 5);
887                    for (int kk = k + 1; kk < kkk; kk++) {
888                        int jj = which[kk];
889                        const OsiRowCut * thisCut2 = cs.rowCutPtr(jj) ;
890                        if (thisCut2->lb() > thisCut2->ub())
891                            break; // cut is infeasible
892                        int nB = thisCut2->row().getNumElements();
893                        const int * columnB = thisCut2->row().getIndices();
894                        const double * elementB = thisCut2->row().getElements();
895                        assert (nB);
896                        double normB = 0.0;
897                        double product = 0.0;
898                        for (int i = 0; i < nB; i++) {
899                            double value = elementB[i];
900                            normB += value * value;
901                            product += value * element2[columnB[i]];
902                        }
903                        if (product > 0.0 && product*product > testValue*norm*normB) {
904                            bool parallel = true;
905                            double lbB = thisCut2->lb();
906                            double ubB = thisCut2->ub();
907                            if ((lb < -1.0e20 && lbB > -1.0e20) ||
908                                    (lbB < -1.0e20 && lb > -1.0e20))
909                                parallel = false;
910                            double tolerance;
911                            tolerance = CoinMax(fabs(lb), fabs(lbB)) + 1.0e-6;
912                            if (fabs(lb - lbB) > tolerance)
913                                parallel = false;
914                            if ((ub > 1.0e20 && ubB < 1.0e20) ||
915                                    (ubB > 1.0e20 && ub < 1.0e20))
916                                parallel = false;
917                            tolerance = CoinMax(fabs(ub), fabs(ubB)) + 1.0e-6;
918                            if (fabs(ub - ubB) > tolerance)
919                                parallel = false;
920                            if (parallel) {
921                                nParallel++;
922                                sort[k] = 0.0;
923                                break;
924                            }
925                        }
926                    }
927                    for (int i = 0; i < n; i++) {
928                        element2[column[i]] = 0.0;
929                    }
930                }
931                delete [] element2;
932                CoinSort_2(sort, sort + nCuts, which);
933                k = 0;
934                while (nDelete > 0 || !sort[k]) {
935                    int iCut = which[k];
936                    const OsiRowCut * thisCut = cs.rowCutPtr(iCut) ;
937                    int n = thisCut->row().getNumElements();
938                    // may be best, just to save if short
939                    if (false && n && sort[k]) {
940                        // add to saved cuts
941                        savedCuts_.insert(*thisCut);
942                    }
943                    nDelete -= n;
944                    k++;
945                    if (k >= nCuts)
946                        break;
947                }
948                std::sort(which, which + k);
949                k--;
950                for (; k >= 0; k--) {
951                    cs.eraseRowCut(which[k]);
952                }
953                delete [] sort;
954                delete [] which;
955                numberRowCutsAfter = cs.sizeRowCuts() ;
956#else
957                double * norm = new double [nCuts];
958                int * which = new int [2*nCuts];
959                double * score = new double [nCuts];
960                double * ortho = new double [nCuts];
961                int nIn = 0;
962                int nOut = nCuts;
963                // For parallel cuts
964                double * element2 = new double [numberColumns];
965                const double *objective = solver->getObjCoefficients() ;
966                double objNorm = 0.0;
967                for (int i = 0; i < numberColumns; i++)
968                    objNorm += objective[i] * objective[i];
969                if (objNorm)
970                    objNorm = 1.0 / sqrt(objNorm);
971                else
972                    objNorm = 1.0;
973                objNorm *= 0.1; // weight of 0.1
974                CoinZeroN(element2, numberColumns);
975                int numberRowCuts = numberRowCutsAfter - numberRowCutsBefore;
976                int iBest = -1;
977                double best = 0.0;
978                int nPossible = 0;
979                double testValue = (depth > 1) ? 0.7 : 0.5;
980                for (k = 0; k < numberRowCuts; k++) {
981                    const OsiRowCut * thisCut = cs.rowCutPtr(k + numberRowCutsBefore) ;
982                    double sum = 0.0;
983                    if (thisCut->lb() <= thisCut->ub()) {
984                        int n = thisCut->row().getNumElements();
985                        const int * column = thisCut->row().getIndices();
986                        const double * element = thisCut->row().getElements();
987                        assert (n);
988                        double normThis = 1.0e-6;
989                        double obj = 0.0;
990                        for (int i = 0; i < n; i++) {
991                            int iColumn = column[i];
992                            double value = element[i];
993                            sum += value * solution[iColumn];
994                            normThis += value * value;
995                            obj += value * objective[iColumn];
996                        }
997                        if (sum > thisCut->ub()) {
998                            sum = sum - thisCut->ub();
999                        } else if (sum < thisCut->lb()) {
1000                            sum = thisCut->lb() - sum;
1001                        } else {
1002                            sum = 0.0;
1003                        }
1004                        if (sum) {
1005                            normThis = 1.0 / sqrt(normThis);
1006                            norm[k] = normThis;
1007                            sum *= normThis;
1008                            obj *= normThis;
1009                            score[k] = sum + obj * objNorm;
1010                            ortho[k] = 1.0;
1011                        }
1012                    } else {
1013                        // keep and discard others
1014                        nIn = 1;
1015                        which[0] = k;
1016                        for (int j = 0; j < numberRowCuts; j++) {
1017                            if (j != k)
1018                                which[nOut++] = j;
1019                        }
1020                        iBest = -1;
1021                        break;
1022                    }
1023                    if (sum) {
1024                        if (score[k] > best) {
1025                            best = score[k];
1026                            iBest = nPossible;
1027                        }
1028                        which[nPossible++] = k;
1029                    } else {
1030                        which[nOut++] = k;
1031                    }
1032                }
1033                while (iBest >= 0) {
1034                    int kBest = which[iBest];
1035                    int j = which[nIn];
1036                    which[iBest] = j;
1037                    which[nIn++] = kBest;
1038                    const OsiRowCut * thisCut = cs.rowCutPtr(kBest + numberRowCutsBefore) ;
1039                    int n = thisCut->row().getNumElements();
1040                    nReasonable -= n;
1041                    if (nReasonable <= 0) {
1042                        for (k = nIn; k < nPossible; k++)
1043                            which[nOut++] = which[k];
1044                        break;
1045                    }
1046                    // Now see which ones are too similar and choose next
1047                    iBest = -1;
1048                    best = 0.0;
1049                    int nOld = nPossible;
1050                    nPossible = nIn;
1051                    const int * column = thisCut->row().getIndices();
1052                    const double * element = thisCut->row().getElements();
1053                    assert (n);
1054                    double normNew = norm[kBest];
1055                    for (int i = 0; i < n; i++) {
1056                        double value = element[i];
1057                        element2[column[i]] = value;
1058                    }
1059                    for (int j = nIn; j < nOld; j++) {
1060                        k = which[j];
1061                        const OsiRowCut * thisCut2 = cs.rowCutPtr(k + numberRowCutsBefore) ;
1062                        int nB = thisCut2->row().getNumElements();
1063                        const int * columnB = thisCut2->row().getIndices();
1064                        const double * elementB = thisCut2->row().getElements();
1065                        assert (nB);
1066                        double normB = norm[k];
1067                        double product = 0.0;
1068                        for (int i = 0; i < nB; i++) {
1069                            double value = elementB[i];
1070                            product += value * element2[columnB[i]];
1071                        }
1072                        double orthoScore = 1.0 - product * normNew * normB;
1073                        if (orthoScore >= testValue) {
1074                            ortho[k] = CoinMin(orthoScore, ortho[k]);
1075                            double test = score[k] + ortho[k];
1076                            if (test > best) {
1077                                best = score[k];
1078                                iBest = nPossible;
1079                            }
1080                            which[nPossible++] = k;
1081                        } else {
1082                            which[nOut++] = k;
1083                        }
1084                    }
1085                    for (int i = 0; i < n; i++) {
1086                        element2[column[i]] = 0.0;
1087                    }
1088                }
1089                delete [] score;
1090                delete [] ortho;
1091                std::sort(which + nCuts, which + nOut);
1092                k = nOut - 1;
1093                for (; k >= nCuts; k--) {
1094                    cs.eraseRowCut(which[k] + numberRowCutsBefore);
1095                }
1096                delete [] norm;
1097                delete [] which;
1098                numberRowCutsAfter = cs.sizeRowCuts() ;
1099#endif
1100            }
1101        }
1102#ifdef CBC_DEBUG
1103        {
1104            int numberRowCutsAfter = cs.sizeRowCuts() ;
1105            int k ;
1106            int nBad = 0;
1107            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
1108                OsiRowCut thisCut = cs.rowCut(k) ;
1109                if (thisCut.lb() > thisCut.ub() ||
1110                        thisCut.lb() > 1.0e8 ||
1111                        thisCut.ub() < -1.0e8)
1112                    printf("cut from %s has bounds %g and %g!\n",
1113                           generatorName_, thisCut.lb(), thisCut.ub());
1114                if (thisCut.lb() <= thisCut.ub()) {
1115                    /* check size of elements.
1116                       We can allow smaller but this helps debug generators as it
1117                       is unsafe to have small elements */
1118                    int n = thisCut.row().getNumElements();
1119                    const int * column = thisCut.row().getIndices();
1120                    const double * element = thisCut.row().getElements();
1121                    assert (n);
1122                    for (int i = 0; i < n; i++) {
1123                        double value = element[i];
1124                        if (fabs(value) <= 1.0e-12 || fabs(value) >= 1.0e20)
1125                            nBad++;
1126                    }
1127                }
1128                if (nBad)
1129                    printf("Cut generator %s produced %d cuts of which %d had tiny or large elements\n",
1130                           generatorName_, numberRowCutsAfter - numberRowCutsBefore, nBad);
1131            }
1132        }
1133#endif
1134        int numberRowCutsAfter = cs.sizeRowCuts() ;
1135        int numberColumnCutsAfter = cs.sizeColCuts() ;
1136        if (numberRowCutsBefore < numberRowCutsAfter) {
1137            for (int k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
1138                OsiRowCut thisCut = cs.rowCut(k) ;
1139                int n = thisCut.row().getNumElements();
1140                numberElements_ += n;
1141            }
1142#ifdef JJF_ZERO
1143            printf("generator %s generated %d row cuts\n",
1144                   generatorName_, numberRowCutsAfter - numberRowCutsBefore);
1145#endif
1146            numberCuts_ += numberRowCutsAfter - numberRowCutsBefore;
1147        }
1148        if (numberColumnCutsBefore < numberColumnCutsAfter) {
1149#ifdef JJF_ZERO
1150            printf("generator %s generated %d column cuts\n",
1151                   generatorName_, numberColumnCutsAfter - numberColumnCutsBefore);
1152#endif
1153            numberColumnCuts_ += numberColumnCutsAfter - numberColumnCutsBefore;
1154        }
1155        if (timing())
1156            timeInCutGenerator_ += CoinCpuTime() - time1;
1157        // switch off if first time and no good
1158        if (node == NULL && !pass ) {
1159            if (numberRowCutsAfter - numberRowCutsBefore
1160                < switchOffIfLessThan_ /*&& numberCuts_ < switchOffIfLessThan_*/) {
1161              // switch off
1162              maximumTries_ = 0;
1163              whenCutGenerator_=-100;
1164              //whenCutGenerator_ = -100;
1165              //whenCutGeneratorInSub_ = -200;
1166            }
1167        }
1168        if (maximumTries_>0) {
1169          maximumTries_--;
1170          if (!maximumTries_) 
1171            whenCutGenerator_=-100;
1172        }
1173    }
1174    return returnCode;
1175}
1176void
1177CbcCutGenerator::setHowOften(int howOften)
1178{
1179
1180    if (howOften >= 1000000) {
1181        // leave Probing every SCANCUTS_PROBING
1182        howOften = howOften % 1000000;
1183        CglProbing* generator =
1184            dynamic_cast<CglProbing*>(generator_);
1185
1186        if (generator && howOften > SCANCUTS_PROBING)
1187            howOften = SCANCUTS_PROBING + 1000000;
1188        else
1189            howOften += 1000000;
1190    }
1191    whenCutGenerator_ = howOften;
1192}
1193void
1194CbcCutGenerator::setWhatDepth(int value)
1195{
1196    depthCutGenerator_ = value;
1197}
1198void
1199CbcCutGenerator::setWhatDepthInSub(int value)
1200{
1201    depthCutGeneratorInSub_ = value;
1202}
1203// Add in statistics from other
1204void 
1205CbcCutGenerator::addStatistics(const CbcCutGenerator * other)
1206{
1207  // Time in cut generator
1208  timeInCutGenerator_ += other->timeInCutGenerator_;
1209  // Number times cut generator entered
1210  numberTimes_ += other->numberTimes_;
1211  // Total number of cuts added
1212  numberCuts_ += other->numberCuts_;
1213  // Total number of elements added
1214  numberElements_ += other->numberElements_;
1215  // Total number of column cuts added
1216  numberColumnCuts_ += other->numberColumnCuts_;
1217  // Total number of cuts active after (at end of n cut passes at each node)
1218  numberCutsActive_ += other->numberCutsActive_;
1219  // Number of cuts generated at root
1220  numberCutsAtRoot_ += other->numberCutsAtRoot_;
1221  // Number of cuts active at root
1222  numberActiveCutsAtRoot_ += other->numberActiveCutsAtRoot_;
1223  // Number of short cuts at root
1224  numberShortCutsAtRoot_ += other->numberShortCutsAtRoot_;
1225}
1226// Scale back statistics by factor
1227void 
1228CbcCutGenerator::scaleBackStatistics(int factor)
1229{
1230  // leave time
1231  // Number times cut generator entered
1232  numberTimes_ = (numberTimes_+factor-1)/factor;
1233  // Total number of cuts added
1234  numberCuts_ = (numberCuts_+factor-1)/factor;
1235  // Total number of elements added
1236  numberElements_ = (numberElements_+factor-1)/factor;
1237  // Total number of column cuts added
1238  numberColumnCuts_ = (numberColumnCuts_+factor-1)/factor;
1239  // Total number of cuts active after (at end of n cut passes at each node)
1240  numberCutsActive_ = (numberCutsActive_+factor-1)/factor;
1241  // Number of cuts generated at root
1242  numberCutsAtRoot_ = (numberCutsAtRoot_+factor-1)/factor;
1243  // Number of cuts active at root
1244  numberActiveCutsAtRoot_ = (numberActiveCutsAtRoot_+factor-1)/factor;
1245  // Number of short cuts at root
1246  numberShortCutsAtRoot_ = (numberShortCutsAtRoot_+factor-1)/factor;
1247}
1248// Create C++ lines to get to current state
1249void
1250CbcCutGenerator::generateTuning( FILE * fp)
1251{
1252    fprintf(fp, "// Cbc tuning for generator %s\n", generatorName_);
1253    fprintf(fp, "   generator->setHowOften(%d);\n", whenCutGenerator_);
1254    fprintf(fp, "   generator->setSwitchOffIfLessThan(%d);\n", switchOffIfLessThan_);
1255    fprintf(fp, "   generator->setWhatDepth(%d);\n", depthCutGenerator_);
1256    fprintf(fp, "   generator->setInaccuracy(%d);\n", inaccuracy_);
1257    if (timing())
1258        fprintf(fp, "   generator->setTiming(true);\n");
1259    if (normal())
1260        fprintf(fp, "   generator->setNormal(true);\n");
1261    if (atSolution())
1262        fprintf(fp, "   generator->setAtSolution(true);\n");
1263    if (whenInfeasible())
1264        fprintf(fp, "   generator->setWhenInfeasible(true);\n");
1265    if (needsOptimalBasis())
1266        fprintf(fp, "   generator->setNeedsOptimalBasis(true);\n");
1267    if (mustCallAgain())
1268        fprintf(fp, "   generator->setMustCallAgain(true);\n");
1269    if (whetherToUse())
1270        fprintf(fp, "   generator->setWhetherToUse(true);\n");
1271}
1272
1273
1274
Note: See TracBrowser for help on using the repository browser.