source: trunk/CbcBranchLotsize.cpp @ 216

Last change on this file since 216 was 201, checked in by forrest, 15 years ago

mostly NDEBUG

  • 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) 2002, 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 <cassert>
8#include <cmath>
9#include <cfloat>
10
11#include "OsiSolverInterface.hpp"
12#include "CbcModel.hpp"
13#include "CbcMessage.hpp"
14#include "CbcBranchLotsize.hpp"
15#include "CoinSort.hpp"
16#include "CoinError.hpp"
17/*
18  CBC_PRINT 1 just does sanity checks - no printing
19            2
20*/
21//#define CBC_PRINT 1
22// First/last variable to print info on
23#if CBC_PRINT
24// preset does all - change to x,x to just do x
25static int firstPrint=0;
26static int lastPrint=1000000;
27static CbcModel * saveModel=NULL;
28#endif
29// Just for debug (CBC_PRINT defined in CbcBranchLotsize.cpp)
30void 
31CbcLotsize::printLotsize(double value,bool condition,int type) const
32{
33#if CBC_PRINT
34  if (columnNumber_>=firstPrint&&columnNumber_<=lastPrint) {
35    int printIt = CBC_PRINT-1;
36    // Get details
37    OsiSolverInterface * solver = saveModel->solver();
38    double currentLower = solver->getColLower()[columnNumber_];
39    double currentUpper = solver->getColUpper()[columnNumber_];
40    int i;
41    // See if in a valid range (with two tolerances)
42    bool inRange=false;
43    bool inRange2=false;
44    double integerTolerance = 
45      model_->getDblParam(CbcModel::CbcIntegerTolerance);
46    // increase if type 2
47    if (type==2) {
48      integerTolerance *= 100.0;
49      type=0;
50      printIt=2; // always print
51    }
52    // bounds should match some bound
53    int rangeL=-1;
54    int rangeU=-1;
55    if (rangeType_==1) {
56      for (i=0;i<numberRanges_;i++) {
57        if (fabs(currentLower-bound_[i])<1.0e-12)
58          rangeL=i;
59        if (fabs(currentUpper-bound_[i])<1.0e-12)
60          rangeU=i;
61        if (fabs(value-bound_[i])<integerTolerance)
62          inRange=true;
63        if (fabs(value-bound_[i])<1.0e8)
64          inRange2=true;
65      }
66    } else {
67      for (i=0;i<numberRanges_;i++) {
68        if (fabs(currentLower-bound_[2*i])<1.0e-12)
69          rangeL=i;
70        if (fabs(currentUpper-bound_[2*i+1])<1.0e-12)
71          rangeU=i;
72        if (value>bound_[2*i]-integerTolerance&&
73            value<bound_[2*i+1]+integerTolerance)
74          inRange=true;
75        if (value>bound_[2*i]-integerTolerance&&
76            value<bound_[2*i+1]+integerTolerance)
77          inRange=true;
78      }
79    }
80    assert (rangeL>=0&&rangeU>=0);
81    bool abortIt=false;
82    switch (type) {
83      // returning from findRange (fall through to just check)
84    case 0:
85      if (printIt) {
86        printf("findRange returns %s for column %d and value %g",
87               condition ? "true" : "false",columnNumber_,value);
88        if (printIt>1)
89          printf(" LP bounds %g, %g",currentLower,currentUpper);
90        printf("\n");
91      }
92      // Should match
93    case 1:
94      if (inRange!=condition) {
95        printIt=2;
96        abortIt=true;
97      }
98      break;
99      //
100    case 2:
101      break;
102      //
103    case 3:
104      break;
105      //
106    case 4:
107      break;
108    }
109  }
110#endif
111}
112/** Default Constructor
113
114*/
115CbcLotsize::CbcLotsize ()
116  : CbcObject(),
117    columnNumber_(-1),
118    rangeType_(0),
119    numberRanges_(0),
120    largestGap_(0),
121    bound_(NULL),
122    range_(0)
123{
124}
125
126/** Useful constructor
127
128  Loads actual upper & lower bounds for the specified variable.
129*/
130CbcLotsize::CbcLotsize (CbcModel * model, 
131                                    int iColumn, int numberPoints,
132                        const double * points, bool range)
133  : CbcObject(model)
134{
135#if CBC_PRINT
136  if (!saveModel)
137    saveModel=model;
138#endif
139  assert (numberPoints>0);
140  columnNumber_ = iColumn ;
141  // and set id so can be used for branching
142  id_=iColumn;
143  // sort ranges
144  int * sort = new int[numberPoints];
145  double * weight = new double [numberPoints];
146  int i;
147  if (range) {
148    rangeType_=2;
149  } else {
150    rangeType_=1;
151  }
152  for (i=0;i<numberPoints;i++) {
153    sort[i]=i;
154    weight[i]=points[i*rangeType_];
155  }
156  CoinSort_2(weight,weight+numberPoints,sort);
157  numberRanges_=1;
158  largestGap_=0;
159  if (rangeType_==1) {
160    bound_ = new double[numberPoints+1];
161    bound_[0]=weight[0];
162    for (i=1;i<numberPoints;i++) {
163      if (weight[i]!=weight[i-1]) 
164        bound_[numberRanges_++]=weight[i];
165    }
166    // and for safety
167    bound_[numberRanges_]=bound_[numberRanges_-1];
168    for (i=1;i<numberRanges_;i++) {
169      largestGap_ = CoinMax(largestGap_,bound_[i]-bound_[i-1]);
170    }
171  } else {
172    bound_ = new double[2*numberPoints+2];
173    bound_[0]=points[sort[0]*2];
174    bound_[1]=points[sort[0]*2+1];
175    double lo=bound_[0];
176    double hi=bound_[1];
177    assert (hi>=lo);
178    for (i=1;i<numberPoints;i++) {
179      double thisLo =points[sort[i]*2];
180      double thisHi =points[sort[i]*2+1];
181      assert (thisHi>=thisLo);
182      if (thisLo>hi) {
183        bound_[2*numberRanges_]=thisLo;
184        bound_[2*numberRanges_+1]=thisHi;
185        numberRanges_++;
186        lo=thisLo;
187        hi=thisHi;
188      } else {
189        //overlap
190        hi=CoinMax(hi,thisHi);
191        bound_[2*numberRanges_-1]=hi;
192      }
193    }
194    // and for safety
195    bound_[2*numberRanges_]=bound_[2*numberRanges_-2];
196    bound_[2*numberRanges_+1]=bound_[2*numberRanges_-1];
197    for (i=1;i<numberRanges_;i++) {
198      largestGap_ = CoinMax(largestGap_,bound_[2*i]-bound_[2*i-1]);
199    }
200  }
201  delete [] sort;
202  delete [] weight;
203  range_=0;
204}
205
206// Copy constructor
207CbcLotsize::CbcLotsize ( const CbcLotsize & rhs)
208  :CbcObject(rhs)
209
210{
211  columnNumber_ = rhs.columnNumber_;
212  rangeType_ = rhs.rangeType_;
213  numberRanges_ = rhs.numberRanges_;
214  range_ = rhs.range_;
215  largestGap_ = rhs.largestGap_;
216  if (numberRanges_) {
217    assert (rangeType_>0&&rangeType_<3);
218    bound_= new double [(numberRanges_+1)*rangeType_];
219    memcpy(bound_,rhs.bound_,(numberRanges_+1)*rangeType_*sizeof(double));
220  } else {
221    bound_=NULL;
222  }
223}
224
225// Clone
226CbcObject *
227CbcLotsize::clone() const
228{
229  return new CbcLotsize(*this);
230}
231
232// Assignment operator
233CbcLotsize & 
234CbcLotsize::operator=( const CbcLotsize& rhs)
235{
236  if (this!=&rhs) {
237    CbcObject::operator=(rhs);
238    columnNumber_ = rhs.columnNumber_;
239    rangeType_ = rhs.rangeType_;
240    numberRanges_ = rhs.numberRanges_;
241    largestGap_ = rhs.largestGap_;
242    delete [] bound_;
243    range_ = rhs.range_;
244    if (numberRanges_) {
245      assert (rangeType_>0&&rangeType_<3);
246      bound_= new double [(numberRanges_+1)*rangeType_];
247      memcpy(bound_,rhs.bound_,(numberRanges_+1)*rangeType_*sizeof(double));
248    } else {
249      bound_=NULL;
250    }
251  }
252  return *this;
253}
254
255// Destructor
256CbcLotsize::~CbcLotsize ()
257{
258  delete [] bound_;
259}
260/* Finds range of interest so value is feasible in range range_ or infeasible
261   between hi[range_] and lo[range_+1].  Returns true if feasible.
262*/
263bool 
264CbcLotsize::findRange(double value) const
265{
266  assert (range_>=0&&range_<numberRanges_+1);
267  double integerTolerance = 
268    model_->getDblParam(CbcModel::CbcIntegerTolerance);
269  int iLo;
270  int iHi;
271  double infeasibility=0.0;
272  if (rangeType_==1) {
273    if (value<bound_[range_]-integerTolerance) {
274      iLo=0;
275      iHi=range_-1;
276    } else if (value<bound_[range_]+integerTolerance) {
277#if CBC_PRINT
278      printLotsize(value,true,0);
279#endif
280      return true;
281    } else if (value<bound_[range_+1]-integerTolerance) {
282#ifdef CBC_PRINT
283      printLotsize(value,false,0);
284#endif
285      return false;
286    } else {
287      iLo=range_+1;
288      iHi=numberRanges_-1;
289    }
290    // check lo and hi
291    bool found=false;
292    if (value>bound_[iLo]-integerTolerance&&value<bound_[iLo+1]+integerTolerance) {
293      range_=iLo;
294      found=true;
295    } else if (value>bound_[iHi]-integerTolerance&&value<bound_[iHi+1]+integerTolerance) {
296      range_=iHi;
297      found=true;
298    } else {
299      range_ = (iLo+iHi)>>1;
300    }
301    //points
302    while (!found) {
303      if (value<bound_[range_]) {
304        if (value>=bound_[range_-1]) {
305          // found
306          range_--;
307          break;
308        } else {
309          iHi = range_;
310        }
311      } else {
312        if (value<bound_[range_+1]) {
313          // found
314          break;
315        } else {
316          iLo = range_;
317        }
318      }
319      range_ = (iLo+iHi)>>1;
320    }
321    if (value-bound_[range_]<=bound_[range_+1]-value) {
322      infeasibility = value-bound_[range_];
323    } else {
324      infeasibility = bound_[range_+1]-value;
325      if (infeasibility<integerTolerance)
326        range_++;
327    }
328#ifdef CBC_PRINT
329    printLotsize(value,(infeasibility<integerTolerance),0);
330#endif
331    return (infeasibility<integerTolerance);
332  } else {
333    // ranges
334    if (value<bound_[2*range_]-integerTolerance) {
335      iLo=0;
336      iHi=range_-1;
337    } else if (value<bound_[2*range_+1]+integerTolerance) {
338#ifdef CBC_PRINT
339      printLotsize(value,true,0);
340#endif
341      return true;
342    } else if (value<bound_[2*range_+2]-integerTolerance) {
343#ifdef CBC_PRINT
344      printLotsize(value,false,0);
345#endif
346      return false;
347    } else {
348      iLo=range_+1;
349      iHi=numberRanges_-1;
350    }
351    // check lo and hi
352    bool found=false;
353    if (value>bound_[2*iLo]-integerTolerance&&value<bound_[2*iLo+2]-integerTolerance) {
354      range_=iLo;
355      found=true;
356    } else if (value>=bound_[2*iHi]-integerTolerance) {
357      range_=iHi;
358      found=true;
359    } else {
360      range_ = (iLo+iHi)>>1;
361    }
362    //points
363    while (!found) {
364      if (value<bound_[2*range_]) {
365        if (value>=bound_[2*range_-2]) {
366          // found
367          range_--;
368          break;
369        } else {
370          iHi = range_;
371        }
372      } else {
373        if (value<bound_[2*range_+2]) {
374          // found
375          break;
376        } else {
377          iLo = range_;
378        }
379      }
380      range_ = (iLo+iHi)>>1;
381    }
382    if (value>=bound_[2*range_]-integerTolerance&&value<=bound_[2*range_+1]+integerTolerance)
383      infeasibility=0.0;
384    else if (value-bound_[2*range_+1]<bound_[2*range_+2]-value) {
385      infeasibility = value-bound_[2*range_+1];
386    } else {
387      infeasibility = bound_[2*range_+2]-value;
388    }
389#ifdef CBC_PRINT
390    printLotsize(value,(infeasibility<integerTolerance),0);
391#endif
392    return (infeasibility<integerTolerance);
393  }
394}
395/* Returns floor and ceiling
396 */
397void 
398CbcLotsize::floorCeiling(double & floorLotsize, double & ceilingLotsize, double value,
399                         double tolerance) const
400{
401  bool feasible=findRange(value);
402  if (rangeType_==1) {
403    floorLotsize=bound_[range_];
404    ceilingLotsize=bound_[range_+1];
405    // may be able to adjust
406    if (feasible&&fabs(value-floorLotsize)>fabs(value-ceilingLotsize)) {
407      floorLotsize=bound_[range_+1];
408      ceilingLotsize=bound_[range_+2];
409    }
410  } else {
411    // ranges
412    assert (value>=bound_[2*range_+1]);
413    floorLotsize=bound_[2*range_+1];
414    ceilingLotsize=bound_[2*range_+2];
415  }
416}
417
418// Infeasibility - large is 0.5
419double 
420CbcLotsize::infeasibility(int & preferredWay) const
421{
422  OsiSolverInterface * solver = model_->solver();
423  const double * solution = model_->testSolution();
424  const double * lower = solver->getColLower();
425  const double * upper = solver->getColUpper();
426  double value = solution[columnNumber_];
427  value = CoinMax(value, lower[columnNumber_]);
428  value = CoinMin(value, upper[columnNumber_]);
429  double integerTolerance = 
430    model_->getDblParam(CbcModel::CbcIntegerTolerance);
431  /*printf("%d %g %g %g %g\n",columnNumber_,value,lower[columnNumber_],
432    solution[columnNumber_],upper[columnNumber_]);*/
433  assert (value>=bound_[0]-integerTolerance
434          &&value<=bound_[rangeType_*numberRanges_-1]+integerTolerance);
435  double infeasibility=0.0;
436  bool feasible = findRange(value);
437  if (!feasible) {
438    if (rangeType_==1) {
439      if (value-bound_[range_]<bound_[range_+1]-value) {
440        preferredWay=-1;
441        infeasibility = value-bound_[range_];
442      } else {
443        preferredWay=1;
444        infeasibility = bound_[range_+1]-value;
445      }
446    } else {
447      // ranges
448      if (value-bound_[2*range_+1]<bound_[2*range_+2]-value) {
449        preferredWay=-1;
450        infeasibility = value-bound_[2*range_+1];
451      } else {
452        preferredWay=1;
453        infeasibility = bound_[2*range_+2]-value;
454      }
455    }
456  } else {
457    // always satisfied
458    preferredWay=-1;
459  }
460  if (infeasibility<integerTolerance)
461    infeasibility=0.0;
462  else
463    infeasibility /= largestGap_;
464#ifdef CBC_PRINT
465    printLotsize(value,infeasibility,1);
466#endif
467  return infeasibility;
468}
469/* Column number if single column object -1 otherwise,
470   so returns >= 0
471   Used by heuristics
472*/
473int 
474CbcLotsize::columnNumber() const
475{
476  return columnNumber_;
477}
478// This looks at solution and sets bounds to contain solution
479/** More precisely: it first forces the variable within the existing
480    bounds, and then tightens the bounds to make sure the variable is feasible
481*/
482void 
483CbcLotsize::feasibleRegion()
484{
485  OsiSolverInterface * solver = model_->solver();
486  const double * lower = solver->getColLower();
487  const double * upper = solver->getColUpper();
488  const double * solution = model_->testSolution();
489  double value = solution[columnNumber_];
490  value = CoinMax(value, lower[columnNumber_]);
491  value = CoinMin(value, upper[columnNumber_]);
492  findRange(value);
493  double nearest;
494  if (rangeType_==1) {
495    nearest = bound_[range_];
496    solver->setColLower(columnNumber_,nearest);
497    solver->setColUpper(columnNumber_,nearest);
498  } else {
499    // ranges
500    solver->setColLower(columnNumber_,bound_[2*range_]);
501    solver->setColUpper(columnNumber_,bound_[2*range_+1]);
502    if (value>bound_[2*range_+1]) 
503      nearest=bound_[2*range_+1];
504    else if (value<bound_[2*range_]) 
505      nearest = bound_[2*range_];
506    else
507      nearest = value;
508  }
509#ifdef CBC_PRINT
510  // print details
511  printLotsize(value,true,2);
512#endif
513  // Scaling may have moved it a bit
514  // Lotsizing variables could be a lot larger
515#ifndef NDEBUG
516  double integerTolerance = 
517    model_->getDblParam(CbcModel::CbcIntegerTolerance);
518  assert (fabs(value-nearest)<=(100.0+10.0*fabs(nearest))*integerTolerance);
519#endif
520}
521
522// Creates a branching object
523CbcBranchingObject * 
524CbcLotsize::createBranch(int way) 
525{
526  OsiSolverInterface * solver = model_->solver();
527  const double * solution = model_->testSolution();
528  const double * lower = solver->getColLower();
529  const double * upper = solver->getColUpper();
530  double value = solution[columnNumber_];
531  value = CoinMax(value, lower[columnNumber_]);
532  value = CoinMin(value, upper[columnNumber_]);
533  assert (!findRange(value));
534  return new CbcLotsizeBranchingObject(model_,columnNumber_,way,
535                                             value,this);
536}
537
538
539/* Given valid solution (i.e. satisfied) and reduced costs etc
540   returns a branching object which would give a new feasible
541   point in direction reduced cost says would be cheaper.
542   If no feasible point returns null
543*/
544CbcBranchingObject * 
545CbcLotsize::preferredNewFeasible() const
546{
547  OsiSolverInterface * solver = model_->solver();
548  double value = model_->testSolution()[columnNumber_];
549
550  assert (findRange(value));
551  double dj = solver->getObjSense()*solver->getReducedCost()[columnNumber_];
552  CbcLotsizeBranchingObject * object = NULL;
553  double lo,up;
554  if (dj>=0.0) {
555    // can we go down
556    if (range_) {
557      // yes
558      if (rangeType_==1) {
559        lo = bound_[range_-1];
560        up = bound_[range_-1];
561      } else {
562        lo = bound_[2*range_-2];
563        up = bound_[2*range_-1];
564      }
565      object = new CbcLotsizeBranchingObject(model_,columnNumber_,-1,
566                                             lo,up);
567    }
568  } else {
569    // can we go up
570    if (range_<numberRanges_-1) {
571      // yes
572      if (rangeType_==1) {
573        lo = bound_[range_+1];
574        up = bound_[range_+1];
575      } else {
576        lo = bound_[2*range_+2];
577        up = bound_[2*range_+3];
578      }
579      object = new CbcLotsizeBranchingObject(model_,columnNumber_,-1,
580                                             lo,up);
581    }
582  }
583  return object;
584}
585 
586/* Given valid solution (i.e. satisfied) and reduced costs etc
587   returns a branching object which would give a new feasible
588   point in direction opposite to one reduced cost says would be cheaper.
589   If no feasible point returns null
590*/
591CbcBranchingObject * 
592CbcLotsize::notPreferredNewFeasible() const 
593{
594  OsiSolverInterface * solver = model_->solver();
595  double value = model_->testSolution()[columnNumber_];
596
597#ifndef NDEBUG
598  double nearest = floor(value+0.5);
599  double integerTolerance = 
600    model_->getDblParam(CbcModel::CbcIntegerTolerance);
601  // Scaling may have moved it a bit
602  // Lotsizing variables could be a lot larger
603  assert (fabs(value-nearest)<=(10.0+10.0*fabs(nearest))*integerTolerance);
604#endif
605  double dj = solver->getObjSense()*solver->getReducedCost()[columnNumber_];
606  CbcLotsizeBranchingObject * object = NULL;
607  double lo,up;
608  if (dj<=0.0) {
609    // can we go down
610    if (range_) {
611      // yes
612      if (rangeType_==1) {
613        lo = bound_[range_-1];
614        up = bound_[range_-1];
615      } else {
616        lo = bound_[2*range_-2];
617        up = bound_[2*range_-1];
618      }
619      object = new CbcLotsizeBranchingObject(model_,columnNumber_,-1,
620                                             lo,up);
621    }
622  } else {
623    // can we go up
624    if (range_<numberRanges_-1) {
625      // yes
626      if (rangeType_==1) {
627        lo = bound_[range_+1];
628        up = bound_[range_+1];
629      } else {
630        lo = bound_[2*range_+2];
631        up = bound_[2*range_+3];
632      }
633      object = new CbcLotsizeBranchingObject(model_,columnNumber_,-1,
634                                             lo,up);
635    }
636  }
637  return object;
638}
639 
640/*
641  Bounds may be tightened, so it may be good to be able to refresh the local
642  copy of the original bounds.
643 */
644void 
645CbcLotsize::resetBounds()
646{
647  //printf("resetBounds needs coding for CbcLotSize\n");
648}
649
650
651// Default Constructor
652CbcLotsizeBranchingObject::CbcLotsizeBranchingObject()
653  :CbcBranchingObject()
654{
655  down_[0] = 0.0;
656  down_[1] = 0.0;
657  up_[0] = 0.0;
658  up_[1] = 0.0;
659}
660
661// Useful constructor
662CbcLotsizeBranchingObject::CbcLotsizeBranchingObject (CbcModel * model, 
663                                                      int variable, int way , double value,
664                                                      const CbcLotsize * lotsize)
665  :CbcBranchingObject(model,variable,way,value)
666{
667  int iColumn = lotsize->modelSequence();
668  assert (variable==iColumn);
669  down_[0] = model_->solver()->getColLower()[iColumn];
670  double integerTolerance = 
671    model_->getDblParam(CbcModel::CbcIntegerTolerance);
672  lotsize->floorCeiling(down_[1],up_[0],value,integerTolerance);
673  up_[1] = model->getColUpper()[iColumn];
674}
675// Useful constructor for fixing
676CbcLotsizeBranchingObject::CbcLotsizeBranchingObject (CbcModel * model, 
677                                                      int variable, int way,
678                                                      double lowerValue, 
679                                                      double upperValue)
680  :CbcBranchingObject(model,variable,way,lowerValue)
681{
682  numberBranchesLeft_=1;
683  down_[0] = lowerValue;
684  down_[1] = upperValue;
685  up_[0] = lowerValue;
686  up_[1] = upperValue;
687}
688 
689
690// Copy constructor
691CbcLotsizeBranchingObject::CbcLotsizeBranchingObject ( const CbcLotsizeBranchingObject & rhs) :CbcBranchingObject(rhs)
692{
693  down_[0] = rhs.down_[0];
694  down_[1] = rhs.down_[1];
695  up_[0] = rhs.up_[0];
696  up_[1] = rhs.up_[1];
697}
698
699// Assignment operator
700CbcLotsizeBranchingObject & 
701CbcLotsizeBranchingObject::operator=( const CbcLotsizeBranchingObject& rhs)
702{
703  if (this != &rhs) {
704    CbcBranchingObject::operator=(rhs);
705    down_[0] = rhs.down_[0];
706    down_[1] = rhs.down_[1];
707    up_[0] = rhs.up_[0];
708    up_[1] = rhs.up_[1];
709  }
710  return *this;
711}
712CbcBranchingObject * 
713CbcLotsizeBranchingObject::clone() const
714{ 
715  return (new CbcLotsizeBranchingObject(*this));
716}
717
718
719// Destructor
720CbcLotsizeBranchingObject::~CbcLotsizeBranchingObject ()
721{
722}
723
724/*
725  Perform a branch by adjusting the bounds of the specified variable. Note
726  that each arm of the branch advances the object to the next arm by
727  advancing the value of way_.
728
729  Providing new values for the variable's lower and upper bounds for each
730  branching direction gives a little bit of additional flexibility and will
731  be easily extensible to multi-way branching.
732*/
733double
734CbcLotsizeBranchingObject::branch(bool normalBranch)
735{
736  if (model_->messageHandler()->logLevel()>2&&normalBranch)
737    print(normalBranch);
738  numberBranchesLeft_--;
739  int iColumn = variable_;
740  if (way_<0) {
741#ifdef CBC_DEBUG
742  { double olb,oub ;
743    olb = model_->solver()->getColLower()[iColumn] ;
744    oub = model_->solver()->getColUpper()[iColumn] ;
745    printf("branching down on var %d: [%g,%g] => [%g,%g]\n",
746           iColumn,olb,oub,down_[0],down_[1]) ; }
747#endif
748    model_->solver()->setColLower(iColumn,down_[0]);
749    model_->solver()->setColUpper(iColumn,down_[1]);
750    way_=1;
751  } else {
752#ifdef CBC_DEBUG
753  { double olb,oub ;
754    olb = model_->solver()->getColLower()[iColumn] ;
755    oub = model_->solver()->getColUpper()[iColumn] ;
756    printf("branching up on var %d: [%g,%g] => [%g,%g]\n",
757           iColumn,olb,oub,up_[0],up_[1]) ; }
758#endif
759    model_->solver()->setColLower(iColumn,up_[0]);
760    model_->solver()->setColUpper(iColumn,up_[1]);
761    way_=-1;      // Swap direction
762  }
763  return 0.0;
764}
765// Print
766void
767CbcLotsizeBranchingObject::print(bool normalBranch)
768{
769  int iColumn = variable_;
770  if (way_<0) {
771  { double olb,oub ;
772    olb = model_->solver()->getColLower()[iColumn] ;
773    oub = model_->solver()->getColUpper()[iColumn] ;
774    printf("branching down on var %d: [%g,%g] => [%g,%g]\n",
775           iColumn,olb,oub,down_[0],down_[1]) ; }
776  } else {
777  { double olb,oub ;
778    olb = model_->solver()->getColLower()[iColumn] ;
779    oub = model_->solver()->getColUpper()[iColumn] ;
780    printf("branching up on var %d: [%g,%g] => [%g,%g]\n",
781           iColumn,olb,oub,up_[0],up_[1]) ; }
782  }
783}
Note: See TracBrowser for help on using the repository browser.