source: trunk/Cbc/src/CbcCutGenerator.cpp @ 983

Last change on this file since 983 was 983, checked in by forrest, 11 years ago

random number generator to CbcModel? and allow cut pruning on size

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.4 KB
Line 
1// Copyright (C) 2003, International Business Machines
2// Corporation and others.  All Rights Reserved.
3#if defined(_MSC_VER)
4// Turn off compiler warning about long names
5#  pragma warning(disable:4786)
6#endif
7#include "CbcConfig.h"
8#include <cassert>
9#include <cstdlib>
10#include <cmath>
11#include <cfloat>
12
13#ifdef COIN_HAS_CLP
14#include "OsiClpSolverInterface.hpp"
15#else
16#include "OsiSolverInterface.hpp"
17#endif
18#include "CbcModel.hpp"
19#include "CbcMessage.hpp"
20#include "CbcCutGenerator.hpp"
21#include "CbcBranchDynamic.hpp"
22#include "CglProbing.hpp"
23#include "CoinTime.hpp"
24
25// Default Constructor
26CbcCutGenerator::CbcCutGenerator ()
27  : model_(NULL),
28    generator_(NULL),
29    whenCutGenerator_(-1),
30    whenCutGeneratorInSub_(-100),
31    switchOffIfLessThan_(0),
32    depthCutGenerator_(-1),
33    depthCutGeneratorInSub_(-1),
34    generatorName_(NULL),
35    normal_(true),
36    atSolution_(false),
37    whenInfeasible_(false),
38    mustCallAgain_(false),
39    switchedOff_(false),
40    timing_(false),
41    timeInCutGenerator_(0.0),
42    numberTimes_(0),
43    numberCuts_(0),
44    numberColumnCuts_(0),
45    numberCutsActive_(0),
46    numberCutsAtRoot_(0),
47    numberActiveCutsAtRoot_(0)
48{
49}
50// Normal constructor
51CbcCutGenerator::CbcCutGenerator(CbcModel * model,CglCutGenerator * generator,
52                                 int howOften, const char * name,
53                                 bool normal, bool atSolution, 
54                                 bool infeasible, int howOftenInSub,
55                                 int whatDepth, int whatDepthInSub,
56                                 int switchOffIfLessThan)
57  : 
58    depthCutGenerator_(whatDepth),
59    depthCutGeneratorInSub_(whatDepthInSub),
60    mustCallAgain_(false),
61    switchedOff_(false),
62    timing_(false),
63    timeInCutGenerator_(0.0),
64    numberTimes_(0),
65    numberCuts_(0),
66    numberColumnCuts_(0),
67    numberCutsActive_(0),
68    numberCutsAtRoot_(0),
69    numberActiveCutsAtRoot_(0)
70{
71  model_ = model;
72  generator_=generator->clone();
73  generator_->refreshSolver(model_->solver());
74  whenCutGenerator_=howOften;
75  whenCutGeneratorInSub_ = howOftenInSub;
76  switchOffIfLessThan_=switchOffIfLessThan;
77  if (name)
78    generatorName_=strdup(name);
79  else
80    generatorName_ = strdup("Unknown");
81  normal_=normal;
82  atSolution_=atSolution;
83  whenInfeasible_=infeasible;
84}
85
86// Copy constructor
87CbcCutGenerator::CbcCutGenerator ( const CbcCutGenerator & rhs)
88{
89  model_ = rhs.model_;
90  generator_=rhs.generator_->clone();
91  //generator_->refreshSolver(model_->solver());
92  whenCutGenerator_=rhs.whenCutGenerator_;
93  whenCutGeneratorInSub_ = rhs.whenCutGeneratorInSub_;
94  switchOffIfLessThan_ = rhs.switchOffIfLessThan_;
95  depthCutGenerator_=rhs.depthCutGenerator_;
96  depthCutGeneratorInSub_ = rhs.depthCutGeneratorInSub_;
97  generatorName_=strdup(rhs.generatorName_);
98  normal_=rhs.normal_;
99  atSolution_=rhs.atSolution_;
100  whenInfeasible_=rhs.whenInfeasible_;
101  mustCallAgain_ = rhs.mustCallAgain_;
102  switchedOff_ = rhs.switchedOff_;
103  timing_ = rhs.timing_;
104  timeInCutGenerator_ = rhs.timeInCutGenerator_;
105  numberTimes_ = rhs.numberTimes_;
106  numberCuts_ = rhs.numberCuts_;
107  numberColumnCuts_ = rhs.numberColumnCuts_;
108  numberCutsActive_ = rhs.numberCutsActive_;
109  numberCutsAtRoot_  = rhs.numberCutsAtRoot_;
110  numberActiveCutsAtRoot_ = rhs.numberActiveCutsAtRoot_;
111}
112
113// Assignment operator
114CbcCutGenerator & 
115CbcCutGenerator::operator=( const CbcCutGenerator& rhs)
116{
117  if (this!=&rhs) {
118    delete generator_;
119    free(generatorName_);
120    model_ = rhs.model_;
121    generator_=rhs.generator_->clone();
122    generator_->refreshSolver(model_->solver());
123    whenCutGenerator_=rhs.whenCutGenerator_;
124    whenCutGeneratorInSub_ = rhs.whenCutGeneratorInSub_;
125    switchOffIfLessThan_ = rhs.switchOffIfLessThan_;
126    depthCutGenerator_=rhs.depthCutGenerator_;
127    depthCutGeneratorInSub_ = rhs.depthCutGeneratorInSub_;
128    generatorName_=strdup(rhs.generatorName_);
129    normal_=rhs.normal_;
130    atSolution_=rhs.atSolution_;
131    whenInfeasible_=rhs.whenInfeasible_;
132    mustCallAgain_ = rhs.mustCallAgain_;
133    switchedOff_ = rhs.switchedOff_;
134    timing_ = rhs.timing_;
135    timeInCutGenerator_ = rhs.timeInCutGenerator_;
136    numberTimes_ = rhs.numberTimes_;
137    numberCuts_ = rhs.numberCuts_;
138    numberColumnCuts_ = rhs.numberColumnCuts_;
139    numberCutsActive_ = rhs.numberCutsActive_;
140    numberCutsAtRoot_  = rhs.numberCutsAtRoot_;
141    numberActiveCutsAtRoot_ = rhs.numberActiveCutsAtRoot_;
142  }
143  return *this;
144}
145
146// Destructor
147CbcCutGenerator::~CbcCutGenerator ()
148{
149  free(generatorName_);
150  delete generator_;
151}
152
153/* This is used to refresh any inforamtion.
154   It also refreshes the solver in the cut generator
155   in case generator wants to do some work
156*/
157void 
158CbcCutGenerator::refreshModel(CbcModel * model)
159{
160  model_=model;
161  generator_->refreshSolver(model_->solver());
162}
163/* Generate cuts for the model data contained in si.
164   The generated cuts are inserted into and returned in the
165   collection of cuts cs.
166*/
167bool
168CbcCutGenerator::generateCuts( OsiCuts & cs , int fullScan, OsiSolverInterface * solver, CbcNode * node)
169{
170  int howOften = whenCutGenerator_;
171  if (howOften==-100)
172    return false;
173  if (howOften>0)
174    howOften = howOften % 1000000;
175  else 
176    howOften=1;
177  if (!howOften)
178    howOften=1;
179  bool returnCode=false;
180  //OsiSolverInterface * solver = model_->solver();
181  int depth;
182  if (node)
183    depth=node->depth();
184  else
185    depth=0;
186  int pass=model_->getCurrentPassNumber()-1;
187  bool doThis=(model_->getNodeCount()%howOften)==0;
188  CoinThreadRandom * randomNumberGenerator=NULL;
189#ifdef COIN_HAS_CLP
190  {
191    OsiClpSolverInterface * clpSolver
192      = dynamic_cast<OsiClpSolverInterface *> (solver);
193    if (clpSolver) 
194      randomNumberGenerator = clpSolver->getModelPtr()->randomNumberGenerator();
195  }
196#endif
197  if (depthCutGenerator_>0) {
198    doThis = (depth % depthCutGenerator_) ==0;
199    if (depth<depthCutGenerator_)
200      doThis=true; // and also at top of tree
201  }
202  // But turn off if 100
203  if (howOften==100)
204    doThis=false;
205  // Switch off if special setting
206  if (whenCutGeneratorInSub_==-200) {
207    fullScan=0;
208    doThis=false;
209  }
210  if (fullScan||doThis) {
211    double time1=0.0;
212    if (timing_)
213      time1 = CoinCpuTime();
214    //#define CBC_DEBUG
215    int numberRowCutsBefore = cs.sizeRowCuts() ;
216    int numberColumnCutsBefore = cs.sizeColCuts() ;
217#if 0
218    int cutsBefore = cs.sizeCuts();
219#endif
220    CglTreeInfo info;
221    info.level = depth;
222    info.pass = pass;
223    info.formulation_rows = model_->numberRowsAtContinuous();
224    info.inTree = node!=NULL;
225    info.randomNumberGenerator=randomNumberGenerator;
226    incrementNumberTimesEntered();
227    CglProbing* generator =
228      dynamic_cast<CglProbing*>(generator_);
229    if (!generator) {
230      // Pass across model information in case it could be useful
231      //void * saveData = solver->getApplicationData();
232      //solver->setApplicationData(model_);
233      generator_->generateCuts(*solver,cs,info);
234      //solver->setApplicationData(saveData);
235    } else {
236      // Probing - return tight column bounds
237      CglTreeProbingInfo * info2 = model_->probingInfo();
238      if (info2&&!depth) {
239        info2->level = depth;
240        info2->pass = pass;
241        info2->formulation_rows = model_->numberRowsAtContinuous();
242        info2->inTree = node!=NULL;
243        info2->randomNumberGenerator=randomNumberGenerator;
244        generator->generateCutsAndModify(*solver,cs,info2);
245      } else {
246        if ((numberTimes_==200||(numberTimes_>200&&(numberTimes_%2000)==0))
247             &&!model_->parentModel()&&false) {
248          // in tree, maxStack, maxProbe
249          int test[]= {
250            100123,
251            199999,
252            200123,
253            299999,
254            500123,
255            599999,
256            1000123,
257            1099999,
258            2000123,
259            2099999};
260          int n = (int) (sizeof(test)/sizeof(int));
261          int saveStack = generator->getMaxLook();
262          int saveNumber = generator->getMaxProbe();
263          int kr1=0;
264          int kc1=0;
265          int bestStackTree=-1;
266          int bestNumberTree=-1;
267          for (int i=0;i<n;i++) {
268            OsiCuts cs2 = cs;
269            int stack = test[i]/100000;
270            int number = test[i] - 100000*stack;
271            generator->setMaxLook(stack);
272            generator->setMaxProbe(number);
273            generator_->generateCuts(*solver,cs2,info);
274            int numberRowCuts = cs2.sizeRowCuts()-numberRowCutsBefore ;
275            int numberColumnCuts= cs2.sizeColCuts()-numberColumnCutsBefore ;
276            if (numberRowCuts<kr1||numberColumnCuts<kc1)
277              printf("Odd ");
278            if (numberRowCuts>kr1||numberColumnCuts>kc1) {
279              printf("*** ");
280              kr1=numberRowCuts;
281              kc1=numberColumnCuts;
282              bestStackTree=stack;
283              bestNumberTree=number;
284            }
285            printf("maxStack %d number %d gives %d row cuts and %d column cuts\n",
286                   stack,number,numberRowCuts,numberColumnCuts);
287          }
288          generator->setMaxLook(saveStack);
289          generator->setMaxProbe(saveNumber);
290          if (bestStackTree>0) {
291            generator->setMaxLook(bestStackTree);
292            generator->setMaxProbe(bestNumberTree);
293            printf("RRNumber %d -> %d, stack %d -> %d\n",
294                   saveNumber,bestNumberTree,saveStack,bestStackTree);
295          } else {
296            // no good
297            generator->setMaxLook(1);
298            printf("RRSwitching off number %d -> %d, stack %d -> %d\n",
299                   saveNumber,saveNumber,saveStack,1);
300          }
301        }
302        if (generator->getMaxLook()>0)
303          generator->generateCutsAndModify(*solver,cs,&info);
304      }
305      const double * tightLower = generator->tightLower();
306      const double * lower = solver->getColLower();
307      const double * tightUpper = generator->tightUpper();
308      const double * upper = solver->getColUpper();
309      const double * solution = solver->getColSolution();
310      int j;
311      int numberColumns = solver->getNumCols();
312      double primalTolerance = 1.0e-8;
313      const char * tightenBounds = generator->tightenBounds();
314      if ((model_->getThreadMode()&2)==0) {
315        for (j=0;j<numberColumns;j++) {
316          if (solver->isInteger(j)) {
317            if (tightUpper[j]<upper[j]) {
318              double nearest = floor(tightUpper[j]+0.5);
319              //assert (fabs(tightUpper[j]-nearest)<1.0e-5); may be infeasible
320              solver->setColUpper(j,nearest);
321              if (nearest<solution[j]-primalTolerance)
322                returnCode=true;
323            }
324            if (tightLower[j]>lower[j]) {
325              double nearest = floor(tightLower[j]+0.5);
326              //assert (fabs(tightLower[j]-nearest)<1.0e-5); may be infeasible
327              solver->setColLower(j,nearest);
328              if (nearest>solution[j]+primalTolerance)
329                returnCode=true;
330            }
331          } else {
332            if (upper[j]>lower[j]) {
333              if (tightUpper[j]==tightLower[j]) {
334                // fix
335                solver->setColLower(j,tightLower[j]);
336                solver->setColUpper(j,tightUpper[j]);
337                if (tightLower[j]>solution[j]+primalTolerance||
338                    tightUpper[j]<solution[j]-primalTolerance)
339                  returnCode=true;
340              } else if (tightenBounds&&tightenBounds[j]) {
341                solver->setColLower(j,CoinMax(tightLower[j],lower[j]));
342                solver->setColUpper(j,CoinMin(tightUpper[j],upper[j]));
343                if (tightLower[j]>solution[j]+primalTolerance||
344                    tightUpper[j]<solution[j]-primalTolerance)
345                  returnCode=true;
346              }
347            }
348          }
349        }
350      } else {
351        CoinPackedVector lbs;
352        CoinPackedVector ubs;
353        int numberChanged=0;
354        bool ifCut=false;
355        for (j=0;j<numberColumns;j++) {
356          if (solver->isInteger(j)) {
357            if (tightUpper[j]<upper[j]) {
358              double nearest = floor(tightUpper[j]+0.5);
359              //assert (fabs(tightUpper[j]-nearest)<1.0e-5); may be infeasible
360              ubs.insert(j,nearest);
361              numberChanged++;
362              if (nearest<solution[j]-primalTolerance)
363                ifCut=true;
364            }
365            if (tightLower[j]>lower[j]) {
366              double nearest = floor(tightLower[j]+0.5);
367              //assert (fabs(tightLower[j]-nearest)<1.0e-5); may be infeasible
368              lbs.insert(j,nearest);
369              numberChanged++;
370              if (nearest>solution[j]+primalTolerance)
371                ifCut=true;
372            }
373          } else {
374            if (upper[j]>lower[j]) {
375              if (tightUpper[j]==tightLower[j]) {
376                // fix
377                lbs.insert(j,tightLower[j]);
378                ubs.insert(j,tightUpper[j]);
379                if (tightLower[j]>solution[j]+primalTolerance||
380                    tightUpper[j]<solution[j]-primalTolerance)
381                  ifCut=true;
382              } else if (tightenBounds&&tightenBounds[j]) {
383                lbs.insert(j,CoinMax(tightLower[j],lower[j]));
384                ubs.insert(j,CoinMin(tightUpper[j],upper[j]));
385                if (tightLower[j]>solution[j]+primalTolerance||
386                    tightUpper[j]<solution[j]-primalTolerance)
387                  ifCut=true;
388              }
389            }
390          }
391        }
392        if (numberChanged) {
393          OsiColCut cc;
394          cc.setUbs(ubs);
395          cc.setLbs(lbs);
396          if (ifCut) {
397            cc.setEffectiveness(100.0);
398          } else {
399            cc.setEffectiveness(1.0e-5);
400          }
401          cs.insert(cc);
402        }
403      }
404      //if (!solver->basisIsAvailable())
405      //returnCode=true;
406#if 0
407      // Pass across info to pseudocosts
408      char * mark = new char[numberColumns];
409      memset(mark,0,numberColumns);
410      int nLook = generator->numberThisTime();
411      const int * lookedAt = generator->lookedAt();
412      const int * fixedDown = generator->fixedDown();
413      const int * fixedUp = generator->fixedUp();
414      for (j=0;j<nLook;j++)
415        mark[lookedAt[j]]=1;
416      int numberObjects = model_->numberObjects();
417      for (int i=0;i<numberObjects;i++) {
418        CbcSimpleIntegerDynamicPseudoCost * obj1 =
419          dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(model_->modifiableObject(i)) ;
420        if (obj1) {
421          int iColumn = obj1->columnNumber();
422          if (mark[iColumn])
423            obj1->setProbingInformation(fixedDown[iColumn],fixedUp[iColumn]);
424        }
425      }
426      delete [] mark;
427#endif
428    }
429    CbcCutModifier * modifier = model_->cutModifier();
430    if (modifier) {
431      int numberRowCutsAfter = cs.sizeRowCuts() ;
432      int k ;
433      int nOdd=0;
434      //const OsiSolverInterface * solver = model_->solver();
435      for (k = numberRowCutsAfter-1;k>=numberRowCutsBefore;k--) {
436        OsiRowCut & thisCut = cs.rowCut(k) ;
437        int returnCode = modifier->modify(solver,thisCut);
438        if (returnCode) {
439          nOdd++;
440          if (returnCode==3)
441            cs.eraseRowCut(k);
442        }
443      }
444      if (nOdd) 
445        printf("Cut generator %s produced %d cuts of which %d were modified\n",
446                 generatorName_,numberRowCutsAfter-numberRowCutsBefore,nOdd);
447    }
448    { 
449      // make all row cuts without test for duplicate
450      int numberRowCutsAfter = cs.sizeRowCuts() ;
451      int k ;
452      for (k = numberRowCutsBefore;k<numberRowCutsAfter;k++) {
453        OsiRowCut * thisCut = cs.rowCutPtr(k) ;
454        thisCut->mutableRow().setTestForDuplicateIndex(false);
455      }
456    }
457    {
458      int numberRowCutsAfter = cs.sizeRowCuts() ;
459      if (numberRowCutsBefore<numberRowCutsAfter) {
460#if 0
461        printf("generator %s generated %d row cuts\n",
462               generatorName_,numberRowCutsAfter-numberRowCutsBefore);
463#endif
464        numberCuts_ += numberRowCutsAfter-numberRowCutsBefore;
465      }
466      int numberColumnCutsAfter = cs.sizeColCuts() ;
467      if (numberColumnCutsBefore<numberColumnCutsAfter) {
468#if 0
469        printf("generator %s generated %d column cuts\n",
470               generatorName_,numberColumnCutsAfter-numberColumnCutsBefore);
471#endif
472        numberColumnCuts_ += numberColumnCutsAfter-numberColumnCutsBefore;
473      }
474    }
475    {
476      int numberRowCutsAfter = cs.sizeRowCuts() ;
477      int k ;
478      int nEls=0;
479      int nCuts= numberRowCutsAfter-numberRowCutsBefore;
480      for (k = numberRowCutsBefore;k<numberRowCutsAfter;k++) {
481        OsiRowCut thisCut = cs.rowCut(k) ;
482        int n=thisCut.row().getNumElements();
483        nEls+= n;
484      }
485      //printf("%s has %d cuts and %d elements\n",generatorName_,
486      //     nCuts,nEls);
487      int nElsNow = solver->getMatrixByCol()->getNumElements();
488      if (nEls*8>nElsNow+8000+10000000) {
489        //printf("need to remove cuts\n");
490        // just add most effective
491        int numberColumns = solver->getNumCols();
492        int nReasonable = CoinMax(5*numberColumns,nElsNow/8);
493        int nDelete = nEls - nReasonable;
494        nElsNow = nEls;
495        const double * solution = solver->getColSolution();
496        double * sort = new double [nCuts];
497        int * which = new int [nCuts];
498        for (k = numberRowCutsBefore;k<numberRowCutsAfter;k++) {
499          OsiRowCut thisCut = cs.rowCut(k) ;
500          double sum=0.0;
501          if (thisCut.lb()<=thisCut.ub()) {
502            int n=thisCut.row().getNumElements();
503            const int * column = thisCut.row().getIndices();
504            const double * element = thisCut.row().getElements();
505            assert (n);
506            for (int i=0;i<n;i++) {
507              double value = element[i];
508              sum += value*solution[column[i]];
509            }
510            if (sum>thisCut.ub()) {
511              sum= sum-thisCut.ub();
512            } else if (sum<thisCut.lb()) {
513              sum= thisCut.lb()-sum;
514            } else {
515              printf("ffffffffffffffff odd\n");
516              sum=0.0;
517            }
518          } else {
519            // keep
520            sum=COIN_DBL_MAX;
521          }
522          sort[k-numberRowCutsBefore]=sum;
523          which[k-numberRowCutsBefore]=k;
524        }
525        CoinSort_2(sort,sort+nCuts,which);
526        k=0;
527        while (nDelete>0) {
528          int iCut=which[k];
529          OsiRowCut thisCut = cs.rowCut(iCut) ;
530          int n=thisCut.row().getNumElements();
531          nDelete-=n; 
532          k++;
533        }
534        std::sort(which,which+k);
535        k--;
536        for (;k>=0;k--) {
537          cs.eraseRowCut(which[k]);
538        }
539        delete [] sort;
540        delete [] which;
541        int numberRowCutsAfter = cs.sizeRowCuts() ;
542        nEls=0;
543        nCuts= numberRowCutsAfter-numberRowCutsBefore;
544        for (k = numberRowCutsBefore;k<numberRowCutsAfter;k++) {
545          OsiRowCut thisCut = cs.rowCut(k) ;
546          int n=thisCut.row().getNumElements();
547          nEls+= n;
548        }
549        printf("%s NOW has %d cuts and %d elements( down from %d els)\n",
550               generatorName_,
551               nCuts,nEls,nElsNow);
552      }
553    }
554#ifdef CBC_DEBUG
555    {
556      int numberRowCutsAfter = cs.sizeRowCuts() ;
557      int k ;
558      int nBad=0;
559      for (k = numberRowCutsBefore;k<numberRowCutsAfter;k++) {
560        OsiRowCut thisCut = cs.rowCut(k) ;
561        if (thisCut.lb()>thisCut.ub()||
562            thisCut.lb()>1.0e8||
563            thisCut.ub()<-1.0e8)
564          printf("cut from %s has bounds %g and %g!\n",
565                 generatorName_,thisCut.lb(),thisCut.ub());
566        if (thisCut.lb()<=thisCut.ub()) {
567          /* check size of elements.
568             We can allow smaller but this helps debug generators as it
569             is unsafe to have small elements */
570          int n=thisCut.row().getNumElements();
571          const int * column = thisCut.row().getIndices();
572          const double * element = thisCut.row().getElements();
573          assert (n);
574          for (int i=0;i<n;i++) {
575            double value = element[i];
576            if (fabs(value)<=1.0e-12||fabs(value)>=1.0e20)
577              nBad++;
578          }
579        }
580        if (nBad) 
581          printf("Cut generator %s produced %d cuts of which %d had tiny or large elements\n",
582                 generatorName_,numberRowCutsAfter-numberRowCutsBefore,nBad);
583      }
584    }
585#endif
586    if (timing_)
587      timeInCutGenerator_ += CoinCpuTime()-time1;
588#if 0
589    // switch off if first time and no good
590    if (node==NULL&&!pass) {
591      if (cs.sizeCuts()-cutsBefore<CoinAbs(switchOffIfLessThan_)) {
592        whenCutGenerator_=-99;
593        whenCutGeneratorInSub_ = -200;
594      }
595    }
596#endif
597  }
598  return returnCode;
599}
600void 
601CbcCutGenerator::setHowOften(int howOften) 
602{
603 
604  if (howOften>=1000000) {
605    // leave Probing every SCANCUTS_PROBING
606    howOften = howOften % 1000000;
607    CglProbing* generator =
608      dynamic_cast<CglProbing*>(generator_);
609   
610    if (generator&&howOften>SCANCUTS_PROBING) 
611      howOften=SCANCUTS_PROBING+1000000;
612    else
613      howOften += 1000000;
614  }
615  whenCutGenerator_ = howOften;
616}
617void 
618CbcCutGenerator::setWhatDepth(int value) 
619{
620  depthCutGenerator_ = value;
621}
622void 
623CbcCutGenerator::setWhatDepthInSub(int value) 
624{
625  depthCutGeneratorInSub_ = value;
626}
627
628
629// Default Constructor
630CbcCutModifier::CbcCutModifier() 
631{
632}
633
634
635// Destructor
636CbcCutModifier::~CbcCutModifier ()
637{
638}
639
640// Copy constructor
641CbcCutModifier::CbcCutModifier ( const CbcCutModifier & rhs)
642{
643}
644
645// Assignment operator
646CbcCutModifier & 
647CbcCutModifier::operator=( const CbcCutModifier& rhs)
648{
649  if (this!=&rhs) {
650  }
651  return *this;
652}
653
654// Default Constructor
655CbcCutSubsetModifier::CbcCutSubsetModifier ()
656  : CbcCutModifier(),
657    firstOdd_(COIN_INT_MAX)
658{
659}
660
661// Useful constructor
662CbcCutSubsetModifier::CbcCutSubsetModifier (int firstOdd)
663  : CbcCutModifier()
664{
665  firstOdd_=firstOdd;
666}
667
668// Copy constructor
669CbcCutSubsetModifier::CbcCutSubsetModifier ( const CbcCutSubsetModifier & rhs)
670  :CbcCutModifier(rhs)
671{
672  firstOdd_ = rhs.firstOdd_;
673}
674
675// Clone
676CbcCutModifier *
677CbcCutSubsetModifier::clone() const
678{
679  return new CbcCutSubsetModifier(*this);
680}
681
682// Assignment operator
683CbcCutSubsetModifier & 
684CbcCutSubsetModifier::operator=( const CbcCutSubsetModifier& rhs)
685{
686  if (this!=&rhs) {
687    CbcCutModifier::operator=(rhs);
688    firstOdd_ = rhs.firstOdd_;
689  }
690  return *this;
691}
692
693// Destructor
694CbcCutSubsetModifier::~CbcCutSubsetModifier ()
695{
696}
697/* Returns
698   0 unchanged
699   1 strengthened
700   2 weakened
701   3 deleted
702*/
703int 
704CbcCutSubsetModifier::modify(const OsiSolverInterface * solver, OsiRowCut & cut) 
705{
706  int n=cut.row().getNumElements();
707  if (!n)
708    return 0;
709  const int * column = cut.row().getIndices();
710  //const double * element = cut.row().getElements();
711  int returnCode=0;
712  for (int i=0;i<n;i++) {
713    if (column[i]>=firstOdd_) {
714      returnCode=3;
715      break;
716    }
717  }
718  if (!returnCode) {
719    const double * element = cut.row().getElements();
720    printf("%g <= ",cut.lb());
721    for (int i=0;i<n;i++) {
722      printf("%g*x%d ",element[i],column[i]);
723    }
724    printf("<= %g\n",cut.ub());
725  }
726  //return 3;
727  return returnCode;
728}
729
Note: See TracBrowser for help on using the repository browser.