source: branches/devel/Cbc/src/CbcBranchDynamic.cpp @ 648

Last change on this file since 648 was 439, checked in by forrest, 13 years ago

towards common use with other solvers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.9 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//#define CBC_DEBUG
11
12#include "OsiSolverInterface.hpp"
13#include "OsiSolverBranch.hpp"
14#include "CbcModel.hpp"
15#include "CbcMessage.hpp"
16#include "CbcBranchDynamic.hpp"
17#include "CoinSort.hpp"
18#include "CoinError.hpp"
19
20/** Default Constructor
21
22  Equivalent to an unspecified binary variable.
23*/
24CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost ()
25  : CbcSimpleInteger(),
26    downDynamicPseudoCost_(1.0e-5),
27    upDynamicPseudoCost_(1.0e-5),
28    upDownSeparator_(-1.0),
29    sumDownCost_(0.0),
30    sumUpCost_(0.0),
31    sumDownChange_(0.0),
32    sumUpChange_(0.0),
33    sumDownCostSquared_(0.0),
34    sumUpCostSquared_(0.0),
35    sumDownDecrease_(0.0),
36    sumUpDecrease_(0.0),
37    lastDownCost_(0.0),
38    lastUpCost_(0.0),
39    lastDownDecrease_(0),
40    lastUpDecrease_(0),
41    numberTimesDown_(0),
42    numberTimesUp_(0),
43    numberTimesDownInfeasible_(0),
44    numberTimesUpInfeasible_(0),
45    numberBeforeTrust_(0),
46    numberTimesDownLocalFixed_(0),
47    numberTimesUpLocalFixed_(0),
48    numberTimesDownTotalFixed_(0.0),
49    numberTimesUpTotalFixed_(0.0),
50    numberTimesProbingTotal_(0),
51    method_(0)
52{
53}
54
55/** Useful constructor
56
57  Loads dynamic upper & lower bounds for the specified variable.
58*/
59CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost (CbcModel * model,
60                                    int iColumn, double breakEven)
61  : CbcSimpleInteger(model,iColumn,breakEven),
62    upDownSeparator_(-1.0),
63    sumDownCost_(0.0),
64    sumUpCost_(0.0),
65    sumDownChange_(0.0),
66    sumUpChange_(0.0),
67    sumDownCostSquared_(0.0),
68    sumUpCostSquared_(0.0),
69    sumDownDecrease_(0.0),
70    sumUpDecrease_(0.0),
71    lastDownCost_(0.0),
72    lastUpCost_(0.0),
73    lastDownDecrease_(0),
74    lastUpDecrease_(0),
75    numberTimesDown_(0),
76    numberTimesUp_(0),
77    numberTimesDownInfeasible_(0),
78    numberTimesUpInfeasible_(0),
79    numberBeforeTrust_(0),
80    numberTimesDownLocalFixed_(0),
81    numberTimesUpLocalFixed_(0),
82    numberTimesDownTotalFixed_(0.0),
83    numberTimesUpTotalFixed_(0.0),
84    numberTimesProbingTotal_(0),
85    method_(0)
86{
87  const double * cost = model->getObjCoefficients();
88  double costValue = CoinMax(1.0e-5,fabs(cost[iColumn]));
89  // treat as if will cost what it says up
90  upDynamicPseudoCost_=costValue;
91  // and balance at breakeven
92  downDynamicPseudoCost_=((1.0-breakEven_)*upDynamicPseudoCost_)/breakEven_;
93  // so initial will have some effect
94  sumUpCost_ = 2.0*upDynamicPseudoCost_;
95  sumUpChange_ = 2.0;
96  numberTimesUp_ = 2;
97  sumDownCost_ = 2.0*downDynamicPseudoCost_;
98  sumDownChange_ = 2.0;
99  numberTimesDown_ = 2;
100#if 0
101  // No
102  sumUpCost_ = 0.0;
103  sumUpChange_ = 0.0;
104  numberTimesUp_ = 0;
105  sumDownCost_ = 0.0;
106  sumDownChange_ = 0.0;
107  numberTimesDown_ = 0;
108#else
109  sumUpCost_ = 1.0*upDynamicPseudoCost_;
110  sumUpChange_ = 1.0;
111  numberTimesUp_ = 1;
112  sumDownCost_ = 1.0*downDynamicPseudoCost_;
113  sumDownChange_ = 1.0;
114  numberTimesDown_ = 1;
115#endif
116}
117
118/** Useful constructor
119
120  Loads dynamic upper & lower bounds for the specified variable.
121*/
122CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost (CbcModel * model,
123                                    int iColumn, double downDynamicPseudoCost,
124                                                        double upDynamicPseudoCost)
125  : CbcSimpleInteger(model,iColumn),
126    upDownSeparator_(-1.0),
127    sumDownCost_(0.0),
128    sumUpCost_(0.0),
129    sumDownChange_(0.0),
130    sumUpChange_(0.0),
131    sumDownCostSquared_(0.0),
132    sumUpCostSquared_(0.0),
133    sumDownDecrease_(0.0),
134    sumUpDecrease_(0.0),
135    lastDownCost_(0.0),
136    lastUpCost_(0.0),
137    lastDownDecrease_(0),
138    lastUpDecrease_(0),
139    numberTimesDown_(0),
140    numberTimesUp_(0),
141    numberTimesDownInfeasible_(0),
142    numberTimesUpInfeasible_(0),
143    numberBeforeTrust_(0),
144    numberTimesDownLocalFixed_(0),
145    numberTimesUpLocalFixed_(0),
146    numberTimesDownTotalFixed_(0.0),
147    numberTimesUpTotalFixed_(0.0),
148    numberTimesProbingTotal_(0),
149    method_(0)
150{
151  downDynamicPseudoCost_ = downDynamicPseudoCost;
152  upDynamicPseudoCost_ = upDynamicPseudoCost;
153  breakEven_ = upDynamicPseudoCost_/(upDynamicPseudoCost_+downDynamicPseudoCost_);
154  // so initial will have some effect
155  sumUpCost_ = 2.0*upDynamicPseudoCost_;
156  sumUpChange_ = 2.0;
157  numberTimesUp_ = 2;
158  sumDownCost_ = 2.0*downDynamicPseudoCost_;
159  sumDownChange_ = 2.0;
160  numberTimesDown_ = 2;
161#if 0
162  // No
163  sumUpCost_ = 0.0;
164  sumUpChange_ = 0.0;
165  numberTimesUp_ = 0;
166  sumDownCost_ = 0.0;
167  sumDownChange_ = 0.0;
168  numberTimesDown_ = 0;
169#else
170  sumUpCost_ = 1.0*upDynamicPseudoCost_;
171  sumUpChange_ = 1.0;
172  numberTimesUp_ = 1;
173  sumDownCost_ = 1.0*downDynamicPseudoCost_;
174  sumDownChange_ = 1.0;
175  numberTimesDown_ = 1;
176#endif
177}
178/** Useful constructor
179
180  Loads dynamic upper & lower bounds for the specified variable.
181*/
182CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost (CbcModel * model,
183                                    int dummy, int iColumn, double downDynamicPseudoCost,
184                                                        double upDynamicPseudoCost)
185{
186  CbcSimpleIntegerDynamicPseudoCost(model,iColumn,downDynamicPseudoCost,upDynamicPseudoCost);
187}
188
189// Copy constructor
190CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost ( const CbcSimpleIntegerDynamicPseudoCost & rhs)
191  :CbcSimpleInteger(rhs),
192   downDynamicPseudoCost_(rhs.downDynamicPseudoCost_),
193   upDynamicPseudoCost_(rhs.upDynamicPseudoCost_),
194   upDownSeparator_(rhs.upDownSeparator_),
195   sumDownCost_(rhs.sumDownCost_),
196   sumUpCost_(rhs.sumUpCost_),
197   sumDownChange_(rhs.sumDownChange_),
198   sumUpChange_(rhs.sumUpChange_),
199   sumDownCostSquared_(rhs.sumDownCostSquared_),
200   sumUpCostSquared_(rhs.sumUpCostSquared_),
201   sumDownDecrease_(rhs.sumDownDecrease_),
202   sumUpDecrease_(rhs.sumUpDecrease_),
203   lastDownCost_(rhs.lastDownCost_),
204   lastUpCost_(rhs.lastUpCost_),
205   lastDownDecrease_(rhs.lastDownDecrease_),
206   lastUpDecrease_(rhs.lastUpDecrease_),
207   numberTimesDown_(rhs.numberTimesDown_),
208   numberTimesUp_(rhs.numberTimesUp_),
209   numberTimesDownInfeasible_(rhs.numberTimesDownInfeasible_),
210   numberTimesUpInfeasible_(rhs.numberTimesUpInfeasible_),
211   numberBeforeTrust_(rhs.numberBeforeTrust_),
212   numberTimesDownLocalFixed_(rhs.numberTimesDownLocalFixed_),
213   numberTimesUpLocalFixed_(rhs.numberTimesUpLocalFixed_),
214   numberTimesDownTotalFixed_(rhs.numberTimesDownTotalFixed_),
215   numberTimesUpTotalFixed_(rhs.numberTimesUpTotalFixed_),
216   numberTimesProbingTotal_(rhs.numberTimesProbingTotal_),
217   method_(rhs.method_)
218
219{
220}
221
222// Clone
223CbcObject *
224CbcSimpleIntegerDynamicPseudoCost::clone() const
225{
226  return new CbcSimpleIntegerDynamicPseudoCost(*this);
227}
228
229// Assignment operator
230CbcSimpleIntegerDynamicPseudoCost & 
231CbcSimpleIntegerDynamicPseudoCost::operator=( const CbcSimpleIntegerDynamicPseudoCost& rhs)
232{
233  if (this!=&rhs) {
234    CbcSimpleInteger::operator=(rhs);
235    downDynamicPseudoCost_=rhs.downDynamicPseudoCost_;
236    upDynamicPseudoCost_=rhs.upDynamicPseudoCost_;
237    upDownSeparator_=rhs.upDownSeparator_;
238    sumDownCost_ = rhs.sumDownCost_;
239    sumUpCost_ = rhs.sumUpCost_;
240    sumDownChange_ = rhs.sumDownChange_;
241    sumUpChange_ = rhs.sumUpChange_;
242    sumDownCostSquared_ = rhs.sumDownCostSquared_;
243    sumUpCostSquared_ = rhs.sumUpCostSquared_;
244    sumDownDecrease_ = rhs.sumDownDecrease_;
245    sumUpDecrease_ = rhs.sumUpDecrease_;
246    lastDownCost_ = rhs.lastDownCost_;
247    lastUpCost_ = rhs.lastUpCost_;
248    lastDownDecrease_ = rhs.lastDownDecrease_;
249    lastUpDecrease_ = rhs.lastUpDecrease_;
250    numberTimesDown_ = rhs.numberTimesDown_;
251    numberTimesUp_ = rhs.numberTimesUp_;
252    numberTimesDownInfeasible_ = rhs.numberTimesDownInfeasible_;
253    numberTimesUpInfeasible_ = rhs.numberTimesUpInfeasible_;
254    numberBeforeTrust_ = rhs.numberBeforeTrust_;
255    numberTimesDownLocalFixed_ = rhs.numberTimesDownLocalFixed_;
256    numberTimesUpLocalFixed_ = rhs.numberTimesUpLocalFixed_;
257    numberTimesDownTotalFixed_ = rhs.numberTimesDownTotalFixed_;
258    numberTimesUpTotalFixed_ = rhs.numberTimesUpTotalFixed_;
259    numberTimesProbingTotal_ = rhs.numberTimesProbingTotal_;
260    method_=rhs.method_;
261  }
262  return *this;
263}
264
265// Destructor
266CbcSimpleIntegerDynamicPseudoCost::~CbcSimpleIntegerDynamicPseudoCost ()
267{
268}
269// Creates a branching object
270CbcBranchingObject * 
271CbcSimpleIntegerDynamicPseudoCost::createBranch(int way) 
272{
273  const double * solution = model_->testSolution();
274  const double * lower = model_->getCbcColLower();
275  const double * upper = model_->getCbcColUpper();
276  double value = solution[columnNumber_];
277  value = CoinMax(value, lower[columnNumber_]);
278  value = CoinMin(value, upper[columnNumber_]);
279#ifndef NDEBUG
280  double nearest = floor(value+0.5);
281  double integerTolerance = 
282    model_->getDblParam(CbcModel::CbcIntegerTolerance);
283  assert (upper[columnNumber_]>lower[columnNumber_]);
284#endif
285  if (!model_->hotstartSolution()) {
286    assert (fabs(value-nearest)>integerTolerance);
287  } else {
288    const double * hotstartSolution = model_->hotstartSolution();
289    double targetValue = hotstartSolution[columnNumber_];
290    if (way>0)
291      value = targetValue-0.1;
292    else
293      value = targetValue+0.1;
294  }
295  CbcDynamicPseudoCostBranchingObject * newObject = 
296    new CbcDynamicPseudoCostBranchingObject(model_,columnNumber_,way,
297                                            value,this);
298  double up =  upDynamicPseudoCost_*(ceil(value)-value);
299  double down =  downDynamicPseudoCost_*(value-floor(value));
300  double changeInGuessed=up-down;
301  if (way>0)
302    changeInGuessed = - changeInGuessed;
303  changeInGuessed=CoinMax(0.0,changeInGuessed);
304  //if (way>0)
305  //changeInGuessed += 1.0e8; // bias to stay up
306  newObject->setChangeInGuessed(changeInGuessed);
307  newObject->setOriginalObject(this);
308  return newObject;
309}
310/* Create an OsiSolverBranch object
311   
312This returns NULL if branch not represented by bound changes
313*/
314OsiSolverBranch * 
315CbcSimpleIntegerDynamicPseudoCost::solverBranch() const
316{
317  OsiSolverInterface * solver = model_->solver();
318  const double * solution = model_->testSolution();
319  const double * lower = solver->getColLower();
320  const double * upper = solver->getColUpper();
321  double value = solution[columnNumber_];
322  value = CoinMax(value, lower[columnNumber_]);
323  value = CoinMin(value, upper[columnNumber_]);
324  assert (upper[columnNumber_]>lower[columnNumber_]);
325#ifndef NDEBUG
326  double nearest = floor(value+0.5);
327  double integerTolerance = 
328    model_->getDblParam(CbcModel::CbcIntegerTolerance);
329  assert (fabs(value-nearest)>integerTolerance);
330#endif
331  OsiSolverBranch * branch = new OsiSolverBranch();
332  branch->addBranch(columnNumber_,value);
333  return branch;
334}
335 
336// Infeasibility - large is 0.5
337double 
338CbcSimpleIntegerDynamicPseudoCost::infeasibility(int & preferredWay) const
339{
340  const double * solution = model_->testSolution();
341  const double * lower = model_->getCbcColLower();
342  const double * upper = model_->getCbcColUpper();
343  if (upper[columnNumber_]==lower[columnNumber_]) {
344    // fixed
345    preferredWay=1;
346    return 0.0;
347  }
348  assert (breakEven_>0.0&&breakEven_<1.0);
349  double value = solution[columnNumber_];
350  value = CoinMax(value, lower[columnNumber_]);
351  value = CoinMin(value, upper[columnNumber_]);
352  /*printf("%d %g %g %g %g\n",columnNumber_,value,lower[columnNumber_],
353    solution[columnNumber_],upper[columnNumber_]);*/
354  double nearest = floor(value+0.5);
355  double integerTolerance = 
356    model_->getDblParam(CbcModel::CbcIntegerTolerance);
357  double below = floor(value+integerTolerance);
358  double above = below+1.0;
359  if (above>upper[columnNumber_]) {
360    above=below;
361    below = above -1;
362  }
363#define INFEAS 1
364#if INFEAS==1
365  double distanceToCutoff=0.0;
366  double objectiveValue = model_->getCurrentMinimizationObjValue();
367  distanceToCutoff =  model_->getCutoff()  - objectiveValue;
368  if (distanceToCutoff<1.0e20) 
369    distanceToCutoff *= 10.0;
370  else 
371    distanceToCutoff = 1.0e2 + fabs(objectiveValue);
372#endif
373  double sum;
374  int number;
375  double downCost = CoinMax(value-below,0.0);
376  sum = sumDownCost_;
377  number = numberTimesDown_;
378#if INFEAS==1
379  sum += numberTimesDownInfeasible_*(distanceToCutoff/(downCost+1.0e-12));
380  number += numberTimesDownInfeasible_;
381#endif
382  if (number>0)
383    downCost *= sum / (double) number;
384  else
385    downCost  *=  downDynamicPseudoCost_;
386  double upCost = CoinMax((above-value),0.0);
387  sum = sumUpCost_;
388  number = numberTimesUp_;
389#if INFEAS==1
390  sum += numberTimesUpInfeasible_*(distanceToCutoff/(upCost+1.0e-12));
391  number += numberTimesUpInfeasible_;
392#endif
393  if (number>0)
394    upCost *= sum / (double) number;
395  else
396    upCost  *=  upDynamicPseudoCost_;
397  if (downCost>=upCost)
398    preferredWay=1;
399  else
400    preferredWay=-1;
401  // See if up down choice set
402  if (upDownSeparator_>0.0) {
403    preferredWay = (value-below>=upDownSeparator_) ? 1 : -1;
404  }
405  if (preferredWay_)
406    preferredWay=preferredWay_;
407  // weight at 1.0 is max min
408#define WEIGHT_AFTER 0.9
409#define WEIGHT_BEFORE 0.3
410  if (fabs(value-nearest)<=integerTolerance) {
411    return 0.0;
412  } else {
413    int stateOfSearch = model_->stateOfSearch();
414    double returnValue=0.0;
415    double minValue = CoinMin(downCost,upCost);
416    double maxValue = CoinMax(downCost,upCost);
417    if (stateOfSearch<=1||model_->currentNode()->depth()<=10/* was ||maxValue>0.2*distanceToCutoff*/) {
418      // no solution
419      returnValue = WEIGHT_BEFORE*minValue + (1.0-WEIGHT_BEFORE)*maxValue;
420    } else {
421      // some solution
422      returnValue = WEIGHT_AFTER*minValue + (1.0-WEIGHT_AFTER)*maxValue;
423    }
424    if (numberTimesUp_<numberBeforeTrust_||
425        numberTimesDown_<numberBeforeTrust_) {
426      //if (returnValue<1.0e10)
427      //returnValue += 1.0e12;
428      //else
429      returnValue *= 1.0e3;
430      if (!numberTimesUp_&&!numberTimesDown_)
431        returnValue=1.0e50;
432    }
433    //if (fabs(value-0.5)<1.0e-5) {
434    //returnValue = 3.0*returnValue + 0.2;
435    //} else if (value>0.9) {
436    //returnValue = 2.0*returnValue + 0.1;
437    //}
438    if (method_==1) {
439      // probing
440      // average
441      double up=1.0e-15;
442      double down=1.0e-15;
443      if (numberTimesProbingTotal_) {
444        up += numberTimesUpTotalFixed_/((double) numberTimesProbingTotal_);
445        down += numberTimesDownTotalFixed_/((double) numberTimesProbingTotal_);
446      }
447      returnValue = 1 + 10.0*CoinMin(numberTimesDownLocalFixed_,numberTimesUpLocalFixed_) +
448        CoinMin(down,up);
449      returnValue *= 1.0e-3;
450    }
451    return CoinMax(returnValue,1.0e-15);
452  }
453}
454
455double
456CbcSimpleIntegerDynamicPseudoCost::infeasibility(const OsiSolverInterface * solver, const OsiBranchingInformation * info,
457                         int & preferredWay) const
458{
459  double value = info->solution_[columnNumber_];
460  value = CoinMax(value, info->lower_[columnNumber_]);
461  value = CoinMin(value, info->upper_[columnNumber_]);
462  if (info->upper_[columnNumber_]==info->lower_[columnNumber_]) {
463    // fixed
464    preferredWay=1;
465    return 0.0;
466  }
467  assert (breakEven_>0.0&&breakEven_<1.0);
468  double nearest = floor(value+0.5);
469  double integerTolerance = info->integerTolerance_; 
470  double below = floor(value+integerTolerance);
471  double above = below+1.0;
472  if (above>info->upper_[columnNumber_]) {
473    above=below;
474    below = above -1;
475  }
476#if INFEAS==1
477  double objectiveValue = info->objectiveValue_;
478  double distanceToCutoff =  info->cutoff_  - objectiveValue;
479  if (distanceToCutoff<1.0e20) 
480    distanceToCutoff *= 10.0;
481  else 
482    distanceToCutoff = 1.0e2 + fabs(objectiveValue);
483#endif
484  double sum;
485  int number;
486  double downCost = CoinMax(value-below,0.0);
487  sum = sumDownCost_;
488  number = numberTimesDown_;
489#if INFEAS==1
490  sum += numberTimesDownInfeasible_*(distanceToCutoff/(downCost+1.0e-12));
491  number += numberTimesDownInfeasible_;
492#endif
493  if (number>0)
494    downCost *= sum / (double) number;
495  else
496    downCost  *=  downDynamicPseudoCost_;
497  double upCost = CoinMax((above-value),0.0);
498  sum = sumUpCost_;
499  number = numberTimesUp_;
500#if INFEAS==1
501  sum += numberTimesUpInfeasible_*(distanceToCutoff/(upCost+1.0e-12));
502  number += numberTimesUpInfeasible_;
503#endif
504  if (number>0)
505    upCost *= sum / (double) number;
506  else
507    upCost  *=  upDynamicPseudoCost_;
508  if (downCost>=upCost)
509    preferredWay=1;
510  else
511    preferredWay=-1;
512  // See if up down choice set
513  if (upDownSeparator_>0.0) {
514    preferredWay = (value-below>=upDownSeparator_) ? 1 : -1;
515  }
516  if (preferredWay_)
517    preferredWay=preferredWay_;
518  // weight at 1.0 is max min
519#define WEIGHT_BEFORE 0.3
520  if (fabs(value-nearest)<=integerTolerance) {
521    return 0.0;
522  } else {
523    double returnValue=0.0;
524    double minValue = CoinMin(downCost,upCost);
525    double maxValue = CoinMax(downCost,upCost);
526    if (!info->numberBranchingSolutions_||info->depth_<=10/* was ||maxValue>0.2*distanceToCutoff*/) {
527      // no solution
528      returnValue = WEIGHT_BEFORE*minValue + (1.0-WEIGHT_BEFORE)*maxValue;
529    } else {
530      // some solution
531      returnValue = WEIGHT_AFTER*minValue + (1.0-WEIGHT_AFTER)*maxValue;
532    }
533    if (numberTimesUp_<numberBeforeTrust_||
534        numberTimesDown_<numberBeforeTrust_) {
535      //if (returnValue<1.0e10)
536      //returnValue += 1.0e12;
537      //else
538      returnValue *= 1.0e3;
539      if (!numberTimesUp_&&!numberTimesDown_)
540        returnValue=1.0e50;
541    }
542    //if (fabs(value-0.5)<1.0e-5) {
543    //returnValue = 3.0*returnValue + 0.2;
544    //} else if (value>0.9) {
545    //returnValue = 2.0*returnValue + 0.1;
546    //}
547    if (method_==1) {
548      // probing
549      // average
550      double up=1.0e-15;
551      double down=1.0e-15;
552      if (numberTimesProbingTotal_) {
553        up += numberTimesUpTotalFixed_/((double) numberTimesProbingTotal_);
554        down += numberTimesDownTotalFixed_/((double) numberTimesProbingTotal_);
555      }
556      returnValue = 1 + 10.0*CoinMin(numberTimesDownLocalFixed_,numberTimesUpLocalFixed_) +
557        CoinMin(down,up);
558      returnValue *= 1.0e-3;
559    }
560    return CoinMax(returnValue,1.0e-15);
561  }
562}
563// Creates a branching object
564CbcBranchingObject * 
565CbcSimpleIntegerDynamicPseudoCost::createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) 
566{
567  double value = info->solution_[columnNumber_];
568  value = CoinMax(value, info->lower_[columnNumber_]);
569  value = CoinMin(value, info->upper_[columnNumber_]);
570  assert (info->upper_[columnNumber_]>info->lower_[columnNumber_]);
571  if (!info->hotstartSolution_) {
572#ifndef NDEBUG
573    double nearest = floor(value+0.5);
574    assert (fabs(value-nearest)>info->integerTolerance_);
575#endif
576  } else {
577    double targetValue = info->hotstartSolution_[columnNumber_];
578    if (way>0)
579      value = targetValue-0.1;
580    else
581      value = targetValue+0.1;
582  }
583  CbcDynamicPseudoCostBranchingObject * newObject = 
584    new CbcDynamicPseudoCostBranchingObject(model_,columnNumber_,way,
585                                            value,this);
586  double up =  upDynamicPseudoCost_*(ceil(value)-value);
587  double down =  downDynamicPseudoCost_*(value-floor(value));
588  double changeInGuessed=up-down;
589  if (way>0)
590    changeInGuessed = - changeInGuessed;
591  changeInGuessed=CoinMax(0.0,changeInGuessed);
592  //if (way>0)
593  //changeInGuessed += 1.0e8; // bias to stay up
594  newObject->setChangeInGuessed(changeInGuessed);
595  newObject->setOriginalObject(this);
596  return newObject;
597}
598
599// Return "up" estimate
600double 
601CbcSimpleIntegerDynamicPseudoCost::upEstimate() const
602{
603  const double * solution = model_->testSolution();
604  const double * lower = model_->getCbcColLower();
605  const double * upper = model_->getCbcColUpper();
606  double value = solution[columnNumber_];
607  value = CoinMax(value, lower[columnNumber_]);
608  value = CoinMin(value, upper[columnNumber_]);
609  if (upper[columnNumber_]==lower[columnNumber_]) {
610    // fixed
611    return 0.0;
612  }
613  double integerTolerance = 
614    model_->getDblParam(CbcModel::CbcIntegerTolerance);
615  double below = floor(value+integerTolerance);
616  double above = below+1.0;
617  if (above>upper[columnNumber_]) {
618    above=below;
619    below = above -1;
620  }
621  double upCost = CoinMax((above-value)*upDynamicPseudoCost_,0.0);
622  return upCost;
623}
624// Return "down" estimate
625double 
626CbcSimpleIntegerDynamicPseudoCost::downEstimate() const
627{
628  const double * solution = model_->testSolution();
629  const double * lower = model_->getCbcColLower();
630  const double * upper = model_->getCbcColUpper();
631  double value = solution[columnNumber_];
632  value = CoinMax(value, lower[columnNumber_]);
633  value = CoinMin(value, upper[columnNumber_]);
634  if (upper[columnNumber_]==lower[columnNumber_]) {
635    // fixed
636    return 0.0;
637  }
638  double integerTolerance = 
639    model_->getDblParam(CbcModel::CbcIntegerTolerance);
640  double below = floor(value+integerTolerance);
641  double above = below+1.0;
642  if (above>upper[columnNumber_]) {
643    above=below;
644    below = above -1;
645  }
646  double downCost = CoinMax((value-below)*downDynamicPseudoCost_,0.0);
647  return downCost;
648}
649// Pass in probing information
650void 
651CbcSimpleIntegerDynamicPseudoCost::setProbingInformation(int fixedDown, int fixedUp)
652{
653  numberTimesProbingTotal_++;
654  numberTimesDownLocalFixed_ = fixedDown;
655  numberTimesDownTotalFixed_ += fixedDown;
656  numberTimesUpLocalFixed_ = fixedUp;
657  numberTimesUpTotalFixed_ += fixedUp;
658}
659// Print
660void 
661CbcSimpleIntegerDynamicPseudoCost::print(int type,double value) const
662{
663  if (!type) {
664    double meanDown =0.0;
665    double devDown =0.0;
666    if (numberTimesDown_) {
667      meanDown = sumDownCost_/(double) numberTimesDown_;
668      devDown = meanDown*meanDown + sumDownCostSquared_ - 
669        2.0*meanDown*sumDownCost_;
670      if (devDown>=0.0)
671        devDown = sqrt(devDown);
672    }
673    double meanUp =0.0;
674    double devUp =0.0;
675    if (numberTimesUp_) {
676      meanUp = sumUpCost_/(double) numberTimesUp_;
677      devUp = meanUp*meanUp + sumUpCostSquared_ - 
678        2.0*meanUp*sumUpCost_;
679      if (devUp>=0.0)
680        devUp = sqrt(devUp);
681    }
682#if 0
683    printf("%d down %d times (%d inf) mean %g (dev %g) up %d times (%d inf) mean %g (dev %g)\n",
684           columnNumber_,
685           numberTimesDown_,numberTimesDownInfeasible_,meanDown,devDown,
686           numberTimesUp_,numberTimesUpInfeasible_,meanUp,devUp);
687#else
688    printf("%d down %d times (%d inf) mean %g  up %d times (%d inf) mean %g\n",
689           columnNumber_,
690           numberTimesDown_,numberTimesDownInfeasible_,meanDown,
691           numberTimesUp_,numberTimesUpInfeasible_,meanUp);
692#endif
693  } else {
694    const double * upper = model_->getCbcColUpper();
695    double integerTolerance = 
696      model_->getDblParam(CbcModel::CbcIntegerTolerance);
697    double below = floor(value+integerTolerance);
698    double above = below+1.0;
699    if (above>upper[columnNumber_]) {
700      above=below;
701      below = above -1;
702    }
703    double objectiveValue = model_->getCurrentMinimizationObjValue();
704    double distanceToCutoff =  model_->getCutoff() - objectiveValue;
705    if (distanceToCutoff<1.0e20) 
706      distanceToCutoff *= 10.0;
707    else 
708      distanceToCutoff = 1.0e2 + fabs(objectiveValue);
709    double sum;
710    int number;
711    double downCost = CoinMax(value-below,0.0);
712    double downCost0 = downCost*downDynamicPseudoCost_;
713    sum = sumDownCost();
714    number = numberTimesDown();
715    sum += numberTimesDownInfeasible()*(distanceToCutoff/(downCost+1.0e-12));
716    if (number>0)
717      downCost *= sum / (double) number;
718    else
719      downCost  *=  downDynamicPseudoCost_;
720    double upCost = CoinMax((above-value),0.0);
721    double upCost0 = upCost*upDynamicPseudoCost_;
722    sum = sumUpCost();
723    number = numberTimesUp();
724    sum += numberTimesUpInfeasible()*(distanceToCutoff/(upCost+1.0e-12));
725    if (number>0)
726      upCost *= sum / (double) number;
727    else
728      upCost  *=  upDynamicPseudoCost_;
729    printf("%d down %d times %g (est %g)  up %d times %g (est %g)\n",
730           columnNumber_,
731           numberTimesDown_,downCost,downCost0,
732           numberTimesUp_,upCost,upCost0);
733  }
734}
735
736// Default Constructor
737CbcDynamicPseudoCostBranchingObject::CbcDynamicPseudoCostBranchingObject()
738  :CbcIntegerBranchingObject()
739{
740  changeInGuessed_=1.0e-5;
741  object_=NULL;
742}
743
744// Useful constructor
745CbcDynamicPseudoCostBranchingObject::CbcDynamicPseudoCostBranchingObject (CbcModel * model, 
746                                                                          int variable, 
747                                                                          int way , double value,
748                                       CbcSimpleIntegerDynamicPseudoCost * object) 
749  :CbcIntegerBranchingObject(model,variable,way,value)
750{
751  changeInGuessed_=1.0e-5;
752  object_=object;
753}
754// Useful constructor for fixing
755CbcDynamicPseudoCostBranchingObject::CbcDynamicPseudoCostBranchingObject (CbcModel * model, 
756                                                      int variable, int way,
757                                                      double lowerValue, 
758                                                      double upperValue)
759  :CbcIntegerBranchingObject(model,variable,way,lowerValue)
760{
761  changeInGuessed_=1.0e100;
762  object_=NULL;
763}
764 
765
766// Copy constructor
767CbcDynamicPseudoCostBranchingObject::CbcDynamicPseudoCostBranchingObject ( 
768                                 const CbcDynamicPseudoCostBranchingObject & rhs)
769  :CbcIntegerBranchingObject(rhs)
770{
771  changeInGuessed_ = rhs.changeInGuessed_;
772  object_=rhs.object_;
773}
774
775// Assignment operator
776CbcDynamicPseudoCostBranchingObject & 
777CbcDynamicPseudoCostBranchingObject::operator=( const CbcDynamicPseudoCostBranchingObject& rhs)
778{
779  if (this != &rhs) {
780    CbcIntegerBranchingObject::operator=(rhs);
781    changeInGuessed_ = rhs.changeInGuessed_;
782    object_=rhs.object_;
783  }
784  return *this;
785}
786CbcBranchingObject * 
787CbcDynamicPseudoCostBranchingObject::clone() const
788{ 
789  return (new CbcDynamicPseudoCostBranchingObject(*this));
790}
791
792
793// Destructor
794CbcDynamicPseudoCostBranchingObject::~CbcDynamicPseudoCostBranchingObject ()
795{
796}
797
798/*
799  Perform a branch by adjusting the bounds of the specified variable. Note
800  that each arm of the branch advances the object to the next arm by
801  advancing the value of way_.
802
803  Providing new values for the variable's lower and upper bounds for each
804  branching direction gives a little bit of additional flexibility and will
805  be easily extensible to multi-way branching.
806  Returns change in guessed objective on next branch
807*/
808double
809CbcDynamicPseudoCostBranchingObject::branch()
810{
811  CbcIntegerBranchingObject::branch();
812  return changeInGuessed_;
813}
814/* Some branchingObjects may claim to be able to skip
815   strong branching.  If so they have to fill in CbcStrongInfo.
816   The object mention in incoming CbcStrongInfo must match.
817   Returns nonzero if skip is wanted */
818int 
819CbcDynamicPseudoCostBranchingObject::fillStrongInfo( CbcStrongInfo & info)
820{
821  assert (object_);
822  assert (info.possibleBranch==this);
823  if (object_->numberTimesUp()<object_->numberBeforeTrust()||
824      object_->numberTimesDown()<object_->numberBeforeTrust()) {
825    return 0;
826  } else {
827    info.upMovement = object_->upDynamicPseudoCost()*(ceil(value_)-value_);
828    info.downMovement = object_->downDynamicPseudoCost()*(value_-floor(value_));
829    info.numIntInfeasUp  -= (int) (object_->sumUpDecrease()/
830                                   ((double) object_->numberTimesUp()));
831    info.numObjInfeasUp = 0;
832    info.finishedUp = false;
833    info.numItersUp = 0;
834    info.numIntInfeasDown  -= (int) (object_->sumDownDecrease()/
835                                   ((double) object_->numberTimesDown()));
836    info.numObjInfeasDown = 0;
837    info.finishedDown = false;
838    info.numItersDown = 0;
839    info.fix =0;
840    return 1;
841  }
842}
843 
844// Default Constructor
845CbcBranchDynamicDecision::CbcBranchDynamicDecision()
846  :CbcBranchDecision()
847{
848  bestCriterion_ = 0.0;
849  bestChangeUp_ = 0.0;
850  bestNumberUp_ = 0;
851  bestChangeDown_ = 0.0;
852  bestNumberDown_ = 0;
853  bestObject_ = NULL;
854}
855
856// Copy constructor
857CbcBranchDynamicDecision::CbcBranchDynamicDecision (
858                                    const CbcBranchDynamicDecision & rhs)
859  :CbcBranchDecision()
860{
861  bestCriterion_ = rhs.bestCriterion_;
862  bestChangeUp_ = rhs.bestChangeUp_;
863  bestNumberUp_ = rhs.bestNumberUp_;
864  bestChangeDown_ = rhs.bestChangeDown_;
865  bestNumberDown_ = rhs.bestNumberDown_;
866  bestObject_ = rhs.bestObject_;
867}
868
869CbcBranchDynamicDecision::~CbcBranchDynamicDecision()
870{
871}
872
873// Clone
874CbcBranchDecision * 
875CbcBranchDynamicDecision::clone() const
876{
877  return new CbcBranchDynamicDecision(*this);
878}
879
880// Initialize i.e. before start of choosing at a node
881void 
882CbcBranchDynamicDecision::initialize(CbcModel * model)
883{
884  bestCriterion_ = 0.0;
885  bestChangeUp_ = 0.0;
886  bestNumberUp_ = 0;
887  bestChangeDown_ = 0.0;
888  bestNumberDown_ = 0;
889  bestObject_ = NULL;
890}
891
892/* Saves a clone of current branching object.  Can be used to update
893      information on object causing branch - after branch */
894void 
895CbcBranchDynamicDecision::saveBranchingObject(OsiBranchingObject * object) 
896{
897  OsiBranchingObject * obj = object->clone();
898  CbcDynamicPseudoCostBranchingObject * branchingObject =
899    dynamic_cast<CbcDynamicPseudoCostBranchingObject *>(obj);
900  assert (branchingObject);
901  object_=branchingObject;
902}
903/* Pass in information on branch just done.
904   assumes object can get information from solver */
905void 
906CbcBranchDynamicDecision::updateInformation(OsiSolverInterface * solver,
907                                            const CbcNode * node)
908{
909  assert (object_);
910  const CbcModel * model = object_->model();
911  double originalValue=node->objectiveValue();
912  int originalUnsatisfied = node->numberUnsatisfied();
913  double objectiveValue = solver->getObjValue()*model->getObjSense();
914  int unsatisfied=0;
915  int i;
916  int numberIntegers = model->numberIntegers();;
917  const double * solution = solver->getColSolution();
918  //const double * lower = solver->getColLower();
919  //const double * upper = solver->getColUpper();
920  CbcDynamicPseudoCostBranchingObject * branchingObject =
921    dynamic_cast<CbcDynamicPseudoCostBranchingObject *>(object_);
922  if (!branchingObject) {
923    delete object_;
924    object_=NULL;
925    return;
926  }
927  CbcSimpleIntegerDynamicPseudoCost *  object = branchingObject->object();
928  double change = CoinMax(0.0,objectiveValue-originalValue);
929  // probably should also ignore if stopped
930  int iStatus;
931  if (solver->isProvenOptimal())
932    iStatus=0; // optimal
933  else if (solver->isIterationLimitReached()
934           &&!solver->isDualObjectiveLimitReached())
935    iStatus=2; // unknown
936  else
937    iStatus=1; // infeasible
938
939  bool feasible = iStatus!=1;
940  if (feasible) {
941    double integerTolerance = 
942      model->getDblParam(CbcModel::CbcIntegerTolerance);
943    const int * integerVariable = model->integerVariable();
944    for (i=0;i<numberIntegers;i++) {
945      int j=integerVariable[i];
946      double value = solution[j];
947      double nearest = floor(value+0.5);
948      if (fabs(value-nearest)>integerTolerance) 
949        unsatisfied++;
950    }
951  }
952  int way = object_->way();
953  double value = object_->value();
954#define TYPE2 1
955#define TYPERATIO 0.9
956  if (way<0) {
957    // down
958    if (feasible) {
959      //printf("(down change %g value down %g ",change,value-floor(value));
960      object->incrementNumberTimesDown();
961      object->addToSumDownChange(1.0e-30+value-floor(value));
962      object->addToSumDownDecrease(originalUnsatisfied-unsatisfied);
963#if TYPE2==0
964      object->addToSumDownCost(change/(1.0e-30+(value-floor(value))));
965      object->setDownDynamicPseudoCost(object->sumDownCost()/(double) object->numberTimesDown());
966#elif TYPE2==1
967      object->addToSumDownCost(change);
968      object->setDownDynamicPseudoCost(object->sumDownCost()/object->sumDownChange());
969#elif TYPE2==2
970      object->addToSumDownCost(change*TYPERATIO+(1.0-TYPERATIO)*change/(1.0e-30+(value-floor(value))));
971      object->setDownDynamicPseudoCost(object->sumDownCost()*(TYPERATIO/object->sumDownChange()+(1.0-TYPERATIO)/(double) object->numberTimesDown()));
972#endif
973    } else {
974      //printf("(down infeasible value down %g ",change,value-floor(value));
975      object->incrementNumberTimesDownInfeasible();
976#if INFEAS==2
977      double distanceToCutoff=0.0;
978      double objectiveValue = model->getCurrentMinimizationObjValue();
979      distanceToCutoff =  model->getCutoff()  - originalValue;
980      if (distanceToCutoff<1.0e20) 
981        change = distanceToCutoff*2.0;
982      else 
983        change = object->downDynamicPseudoCost()*(value-floor(value))*10.0; 
984      change = CoinMax(1.0e-12*(1.0+fabs(originalValue)),change);
985      object->incrementNumberTimesDown();
986      object->addToSumDownChange(1.0e-30+value-floor(value));
987      object->addToSumDownDecrease(originalUnsatisfied-unsatisfied);
988#if TYPE2==0
989      object->addToSumDownCost(change/(1.0e-30+(value-floor(value))));
990      object->setDownDynamicPseudoCost(object->sumDownCost()/(double) object->numberTimesDown());
991#elif TYPE2==1
992      object->addToSumDownCost(change);
993      object->setDownDynamicPseudoCost(object->sumDownCost()/object->sumDownChange());
994#elif TYPE2==2
995      object->addToSumDownCost(change*TYPERATIO+(1.0-TYPERATIO)*change/(1.0e-30+(value-floor(value))));
996      object->setDownDynamicPseudoCost(object->sumDownCost()*(TYPERATIO/object->sumDownChange()+(1.0-TYPERATIO)/(double) object->numberTimesDown()));
997#endif
998#endif
999    }
1000  } else {
1001    // up
1002    if (feasible) {
1003      //printf("(up change %g value down %g ",change,ceil(value)-value);
1004      object->incrementNumberTimesUp();
1005      object->addToSumUpChange(1.0e-30+ceil(value)-value);
1006      object->addToSumUpDecrease(unsatisfied-originalUnsatisfied);
1007#if TYPE2==0
1008      object->addToSumUpCost(change/(1.0e-30+(ceil(value)-value)));
1009      object->setUpDynamicPseudoCost(object->sumUpCost()/(double) object->numberTimesUp());
1010#elif TYPE2==1
1011      object->addToSumUpCost(change);
1012      object->setUpDynamicPseudoCost(object->sumUpCost()/object->sumUpChange());
1013#elif TYPE2==2
1014      object->addToSumUpCost(change*TYPERATIO+(1.0-TYPERATIO)*change/(1.0e-30+(ceil(value)-value)));
1015      object->setUpDynamicPseudoCost(object->sumUpCost()*(TYPERATIO/object->sumUpChange()+(1.0-TYPERATIO)/(double) object->numberTimesUp()));
1016#endif
1017    } else {
1018      //printf("(up infeasible value down %g ",change,ceil(value)-value);
1019      object->incrementNumberTimesUpInfeasible();
1020#if INFEAS==2
1021      double distanceToCutoff=0.0;
1022      double objectiveValue = model->getCurrentMinimizationObjValue();
1023      distanceToCutoff =  model->getCutoff()  - originalValue;
1024      if (distanceToCutoff<1.0e20) 
1025        change = distanceToCutoff*2.0;
1026      else 
1027        change = object->upDynamicPseudoCost()*(ceil(value)-value)*10.0; 
1028      change = CoinMax(1.0e-12*(1.0+fabs(originalValue)),change);
1029      object->incrementNumberTimesUp();
1030      object->addToSumUpChange(1.0e-30+ceil(value)-value);
1031      object->addToSumUpDecrease(unsatisfied-originalUnsatisfied);
1032#if TYPE2==0
1033      object->addToSumUpCost(change/(1.0e-30+(ceil(value)-value)));
1034      object->setUpDynamicPseudoCost(object->sumUpCost()/(double) object->numberTimesUp());
1035#elif TYPE2==1
1036      object->addToSumUpCost(change);
1037      object->setUpDynamicPseudoCost(object->sumUpCost()/object->sumUpChange());
1038#elif TYPE2==2
1039      object->addToSumUpCost(change*TYPERATIO+(1.0-TYPERATIO)*change/(1.0e-30+(ceil(value)-value)));
1040      object->setUpDynamicPseudoCost(object->sumUpCost()*(TYPERATIO/object->sumUpChange()+(1.0-TYPERATIO)/(double) object->numberTimesUp()));
1041#endif
1042#endif
1043    }
1044  }
1045  //object->print();
1046  delete object_;
1047  object_=NULL;
1048}
1049
1050/*
1051  Simple dynamic decision algorithm. Compare based on infeasibility (numInfUp,
1052  numInfDown) until a solution is found by search, then switch to change in
1053  objective (changeUp, changeDown). Note that bestSoFar is remembered in
1054  bestObject_, so the parameter bestSoFar is unused.
1055*/
1056
1057int
1058CbcBranchDynamicDecision::betterBranch(CbcBranchingObject * thisOne,
1059                            CbcBranchingObject * bestSoFar,
1060                            double changeUp, int numInfUp,
1061                            double changeDown, int numInfDown)
1062{
1063  int stateOfSearch = thisOne->model()->stateOfSearch();
1064  int betterWay=0;
1065  double value=0.0;
1066  if (stateOfSearch<=1&&thisOne->model()->currentNode()->depth()>10) {
1067#if 0
1068    if (!bestObject_) {
1069      bestNumberUp_=INT_MAX;
1070      bestNumberDown_=INT_MAX;
1071    }
1072    // before solution - choose smallest number
1073    // could add in depth as well
1074    int bestNumber = CoinMin(bestNumberUp_,bestNumberDown_);
1075    if (numInfUp<numInfDown) {
1076      if (numInfUp<bestNumber) {
1077        betterWay = 1;
1078      } else if (numInfUp==bestNumber) {
1079        if (changeUp<bestChangeUp_)
1080          betterWay=1;
1081      }
1082    } else if (numInfUp>numInfDown) {
1083      if (numInfDown<bestNumber) {
1084        betterWay = -1;
1085      } else if (numInfDown==bestNumber) {
1086        if (changeDown<bestChangeDown_)
1087          betterWay=-1;
1088      }
1089    } else {
1090      // up and down have same number
1091      bool better=false;
1092      if (numInfUp<bestNumber) {
1093        better=true;
1094      } else if (numInfUp==bestNumber) {
1095        if (CoinMin(changeUp,changeDown)<CoinMin(bestChangeUp_,bestChangeDown_)-1.0e-5)
1096          better=true;;
1097      }
1098      if (better) {
1099        // see which way
1100        if (changeUp<=changeDown)
1101          betterWay=1;
1102        else
1103          betterWay=-1;
1104      }
1105    }
1106    if (betterWay) {
1107      value = CoinMin(numInfUp,numInfDown);
1108    }
1109#else
1110    if (!bestObject_) {
1111      bestCriterion_=-1.0;
1112    }
1113    // got a solution
1114    double minValue = CoinMin(changeDown,changeUp);
1115    double maxValue = CoinMax(changeDown,changeUp);
1116    value = WEIGHT_BEFORE*minValue + (1.0-WEIGHT_BEFORE)*maxValue;
1117    if (value>bestCriterion_+1.0e-8) {
1118      if (changeUp<=changeDown) {
1119        betterWay=1;
1120      } else {
1121        betterWay=-1;
1122      }
1123    }
1124#endif
1125  } else {
1126    if (!bestObject_) {
1127      bestCriterion_=-1.0;
1128    }
1129    // got a solution
1130    double minValue = CoinMin(changeDown,changeUp);
1131    double maxValue = CoinMax(changeDown,changeUp);
1132    // Reduce
1133    maxValue = CoinMin(maxValue,minValue*2.0);
1134    value = WEIGHT_AFTER*minValue + (1.0-WEIGHT_AFTER)*maxValue;
1135    if (value>bestCriterion_+1.0e-8) {
1136      if (changeUp<=changeDown) {
1137        betterWay=1;
1138      } else {
1139        betterWay=-1;
1140      }
1141    }
1142  }
1143  if (betterWay) {
1144    // maybe change better way
1145    CbcDynamicPseudoCostBranchingObject * branchingObject =
1146      dynamic_cast<CbcDynamicPseudoCostBranchingObject *>(thisOne);
1147    if (branchingObject) {
1148      CbcSimpleIntegerDynamicPseudoCost *  object = branchingObject->object();
1149      double separator = object->upDownSeparator();
1150      if (separator>0.0) {
1151        const double * solution = thisOne->model()->testSolution();
1152        double valueVariable = solution[object->columnNumber()];
1153        betterWay = (valueVariable-floor(valueVariable)>=separator) ? 1 : -1;
1154      }
1155    }
1156    bestCriterion_ = value;
1157    bestChangeUp_ = changeUp;
1158    bestNumberUp_ = numInfUp;
1159    bestChangeDown_ = changeDown;
1160    bestNumberDown_ = numInfDown;
1161    bestObject_=thisOne;
1162    // See if user is overriding way
1163    if (thisOne->object()&&thisOne->object()->preferredWay())
1164      betterWay = thisOne->object()->preferredWay();
1165  }
1166  return betterWay;
1167}
1168/* Sets or gets best criterion so far */
1169void 
1170CbcBranchDynamicDecision::setBestCriterion(double value)
1171{ 
1172  bestCriterion_ = value;
1173}
1174double 
1175CbcBranchDynamicDecision::getBestCriterion() const
1176{ 
1177  return bestCriterion_;
1178}
Note: See TracBrowser for help on using the repository browser.