source: trunk/Cbc/src/CbcBranchLotsize.cpp

Last change on this file was 2467, checked in by unxusr, 5 months ago

spaces after angles

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