// $Id: CbcSimpleIntegerDynamicPseudoCost.cpp 1943 2013-07-21 09:05:45Z forrest $
// Copyright (C) 2002, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

// Edwin 11/17/2009 - carved out of CbcBranchDynamic

#if defined(_MSC_VER)
// Turn off compiler warning about long names
#  pragma warning(disable:4786)
#endif
#include <cassert>
#include <cstdlib>
#include <cmath>
#include <cfloat>
//#define CBC_DEBUG
//#define TRACE_ONE 19
#include "OsiSolverInterface.hpp"
#include "OsiSolverBranch.hpp"
#include "CbcModel.hpp"
#include "CbcMessage.hpp"
#include "CbcBranchDynamic.hpp"
#include "CoinSort.hpp"
#include "CoinError.hpp"
#include "CbcSimpleIntegerDynamicPseudoCost.hpp"
#ifdef COIN_HAS_CLP
#include "OsiClpSolverInterface.hpp"
#endif
#ifdef COIN_DEVELOP
typedef struct {
    double sumUp_;
    double upEst_; // or change in obj in update
    double sumDown_;
    double downEst_; // or movement in value in update
    int sequence_;
    int numberUp_;
    int numberUpInf_;
    int numberDown_;
    int numberDownInf_;
    char where_;
    char status_;
} History;
History * history = NULL;
int numberHistory = 0;
int maxHistory = 0;
bool getHistoryStatistics_ = true;
static void increaseHistory()
{
    if (numberHistory == maxHistory) {
        maxHistory = 100 + (3 * maxHistory) / 2;
        History * temp = new History [maxHistory];
        memcpy(temp, history, numberHistory*sizeof(History));
        delete [] history;
        history = temp;
    }
}
static bool addRecord(History newOne)
{
    //if (!getHistoryStatistics_)
    return false;
    bool fromCompare = false;
    int i;
    for ( i = numberHistory - 1; i >= 0; i--) {
        if (newOne.sequence_ != history[i].sequence_)
            continue;
        if (newOne.where_ != history[i].where_)
            continue;
        if (newOne.numberUp_ != history[i].numberUp_)
            continue;
        if (newOne.sumUp_ != history[i].sumUp_)
            continue;
        if (newOne.numberUpInf_ != history[i].numberUpInf_)
            continue;
        if (newOne.upEst_ != history[i].upEst_)
            continue;
        if (newOne.numberDown_ != history[i].numberDown_)
            continue;
        if (newOne.sumDown_ != history[i].sumDown_)
            continue;
        if (newOne.numberDownInf_ != history[i].numberDownInf_)
            continue;
        if (newOne.downEst_ != history[i].downEst_)
            continue;
        // If B knock out previous B
        if (newOne.where_ == 'C') {
            fromCompare = true;
            if (newOne.status_ == 'B') {
                int j;
                for (j = i - 1; j >= 0; j--) {
                    if (history[j].where_ == 'C') {
                        if (history[j].status_ == 'I') {
                            break;
                        } else if (history[j].status_ == 'B') {
                            history[j].status_ = ' ';
                            break;
                        }
                    }
                }
            }
            break;
        }
    }
    if (i == -1 || fromCompare) {
        //add
        increaseHistory();
        history[numberHistory++] = newOne;
        return true;
    } else {
        return false;
    }
}
#endif

/** Default Constructor

  Equivalent to an unspecified binary variable.
*/
CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost ()
        : CbcSimpleInteger(),
        downDynamicPseudoCost_(1.0e-5),
        upDynamicPseudoCost_(1.0e-5),
        upDownSeparator_(-1.0),
        sumDownCost_(0.0),
        sumUpCost_(0.0),
        sumDownChange_(0.0),
        sumUpChange_(0.0),
        downShadowPrice_(0.0),
        upShadowPrice_(0.0),
        sumDownDecrease_(0.0),
        sumUpDecrease_(0.0),
        lastDownCost_(0.0),
        lastUpCost_(0.0),
        lastDownDecrease_(0),
        lastUpDecrease_(0),
        numberTimesDown_(0),
        numberTimesUp_(0),
        numberTimesDownInfeasible_(0),
        numberTimesUpInfeasible_(0),
        numberBeforeTrust_(0),
        numberTimesDownLocalFixed_(0),
        numberTimesUpLocalFixed_(0),
        numberTimesDownTotalFixed_(0.0),
        numberTimesUpTotalFixed_(0.0),
        numberTimesProbingTotal_(0),
        method_(0)
{
}

/** Useful constructor

  Loads dynamic upper & lower bounds for the specified variable.
*/
CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost (CbcModel * model,
        int iColumn, double breakEven)
        : CbcSimpleInteger(model, iColumn, breakEven),
        upDownSeparator_(-1.0),
        sumDownCost_(0.0),
        sumUpCost_(0.0),
        sumDownChange_(0.0),
        sumUpChange_(0.0),
        downShadowPrice_(0.0),
        upShadowPrice_(0.0),
        sumDownDecrease_(0.0),
        sumUpDecrease_(0.0),
        lastDownCost_(0.0),
        lastUpCost_(0.0),
        lastDownDecrease_(0),
        lastUpDecrease_(0),
        numberTimesDown_(0),
        numberTimesUp_(0),
        numberTimesDownInfeasible_(0),
        numberTimesUpInfeasible_(0),
        numberBeforeTrust_(0),
        numberTimesDownLocalFixed_(0),
        numberTimesUpLocalFixed_(0),
        numberTimesDownTotalFixed_(0.0),
        numberTimesUpTotalFixed_(0.0),
        numberTimesProbingTotal_(0),
        method_(0)
{
    const double * cost = model->getObjCoefficients();
    double costValue = CoinMax(1.0e-5, fabs(cost[iColumn]));
    // treat as if will cost what it says up
    upDynamicPseudoCost_ = costValue;
    // and balance at breakeven
    downDynamicPseudoCost_ = ((1.0 - breakEven_) * upDynamicPseudoCost_) / breakEven_;
    // so initial will have some effect
    sumUpCost_ = 2.0 * upDynamicPseudoCost_;
    sumUpChange_ = 2.0;
    numberTimesUp_ = 2;
    sumDownCost_ = 2.0 * downDynamicPseudoCost_;
    sumDownChange_ = 2.0;
    numberTimesDown_ = 2;
#if TYPE2==0
    // No
    sumUpCost_ = 0.0;
    sumUpChange_ = 0.0;
    numberTimesUp_ = 0;
    sumDownCost_ = 0.0;
    sumDownChange_ = 0.0;
    numberTimesDown_ = 0;
#else
    sumUpCost_ = 1.0 * upDynamicPseudoCost_;
    sumUpChange_ = 1.0;
    numberTimesUp_ = 1;
    sumDownCost_ = 1.0 * downDynamicPseudoCost_;
    sumDownChange_ = 1.0;
    numberTimesDown_ = 1;
#endif
}

/** Useful constructor

  Loads dynamic upper & lower bounds for the specified variable.
*/
CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost (CbcModel * model,
        int iColumn, double downDynamicPseudoCost,
        double upDynamicPseudoCost)
        : CbcSimpleInteger(model, iColumn),
        upDownSeparator_(-1.0),
        sumDownCost_(0.0),
        sumUpCost_(0.0),
        sumDownChange_(0.0),
        sumUpChange_(0.0),
        downShadowPrice_(0.0),
        upShadowPrice_(0.0),
        sumDownDecrease_(0.0),
        sumUpDecrease_(0.0),
        lastDownCost_(0.0),
        lastUpCost_(0.0),
        lastDownDecrease_(0),
        lastUpDecrease_(0),
        numberTimesDown_(0),
        numberTimesUp_(0),
        numberTimesDownInfeasible_(0),
        numberTimesUpInfeasible_(0),
        numberBeforeTrust_(0),
        numberTimesDownLocalFixed_(0),
        numberTimesUpLocalFixed_(0),
        numberTimesDownTotalFixed_(0.0),
        numberTimesUpTotalFixed_(0.0),
        numberTimesProbingTotal_(0),
        method_(0)
{
    downDynamicPseudoCost_ = downDynamicPseudoCost;
    upDynamicPseudoCost_ = upDynamicPseudoCost;
    breakEven_ = upDynamicPseudoCost_ / (upDynamicPseudoCost_ + downDynamicPseudoCost_);
    // so initial will have some effect
    sumUpCost_ = 2.0 * upDynamicPseudoCost_;
    sumUpChange_ = 2.0;
    numberTimesUp_ = 2;
    sumDownCost_ = 2.0 * downDynamicPseudoCost_;
    sumDownChange_ = 2.0;
    numberTimesDown_ = 2;
#if TYPE2==0
    // No
    sumUpCost_ = 0.0;
    sumUpChange_ = 0.0;
    numberTimesUp_ = 0;
    sumDownCost_ = 0.0;
    sumDownChange_ = 0.0;
    numberTimesDown_ = 0;
    sumUpCost_ = 1.0e-4 * upDynamicPseudoCost_;
    sumDownCost_ = 1.0e-4 * downDynamicPseudoCost_;
#else
    sumUpCost_ = 1.0 * upDynamicPseudoCost_;
    sumUpChange_ = 1.0;
    numberTimesUp_ = 1;
    sumDownCost_ = 1.0 * downDynamicPseudoCost_;
    sumDownChange_ = 1.0;
    numberTimesDown_ = 1;
#endif
}
/** Useful constructor

  Loads dynamic upper & lower bounds for the specified variable.
*/
CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost (CbcModel * model,
        int /*dummy*/,
        int iColumn, double downDynamicPseudoCost,
        double upDynamicPseudoCost)
{
    CbcSimpleIntegerDynamicPseudoCost(model, iColumn, downDynamicPseudoCost, upDynamicPseudoCost);
}

// Copy constructor
CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost ( const CbcSimpleIntegerDynamicPseudoCost & rhs)
        : CbcSimpleInteger(rhs),
        downDynamicPseudoCost_(rhs.downDynamicPseudoCost_),
        upDynamicPseudoCost_(rhs.upDynamicPseudoCost_),
        upDownSeparator_(rhs.upDownSeparator_),
        sumDownCost_(rhs.sumDownCost_),
        sumUpCost_(rhs.sumUpCost_),
        sumDownChange_(rhs.sumDownChange_),
        sumUpChange_(rhs.sumUpChange_),
        downShadowPrice_(rhs.downShadowPrice_),
        upShadowPrice_(rhs.upShadowPrice_),
        sumDownDecrease_(rhs.sumDownDecrease_),
        sumUpDecrease_(rhs.sumUpDecrease_),
        lastDownCost_(rhs.lastDownCost_),
        lastUpCost_(rhs.lastUpCost_),
        lastDownDecrease_(rhs.lastDownDecrease_),
        lastUpDecrease_(rhs.lastUpDecrease_),
        numberTimesDown_(rhs.numberTimesDown_),
        numberTimesUp_(rhs.numberTimesUp_),
        numberTimesDownInfeasible_(rhs.numberTimesDownInfeasible_),
        numberTimesUpInfeasible_(rhs.numberTimesUpInfeasible_),
        numberBeforeTrust_(rhs.numberBeforeTrust_),
        numberTimesDownLocalFixed_(rhs.numberTimesDownLocalFixed_),
        numberTimesUpLocalFixed_(rhs.numberTimesUpLocalFixed_),
        numberTimesDownTotalFixed_(rhs.numberTimesDownTotalFixed_),
        numberTimesUpTotalFixed_(rhs.numberTimesUpTotalFixed_),
        numberTimesProbingTotal_(rhs.numberTimesProbingTotal_),
        method_(rhs.method_)

{
}

// Clone
CbcObject *
CbcSimpleIntegerDynamicPseudoCost::clone() const
{
    return new CbcSimpleIntegerDynamicPseudoCost(*this);
}

// Assignment operator
CbcSimpleIntegerDynamicPseudoCost &
CbcSimpleIntegerDynamicPseudoCost::operator=( const CbcSimpleIntegerDynamicPseudoCost & rhs)
{
    if (this != &rhs) {
        CbcSimpleInteger::operator=(rhs);
        downDynamicPseudoCost_ = rhs.downDynamicPseudoCost_;
        upDynamicPseudoCost_ = rhs.upDynamicPseudoCost_;
        upDownSeparator_ = rhs.upDownSeparator_;
        sumDownCost_ = rhs.sumDownCost_;
        sumUpCost_ = rhs.sumUpCost_;
        sumDownChange_ = rhs.sumDownChange_;
        sumUpChange_ = rhs.sumUpChange_;
        downShadowPrice_ = rhs.downShadowPrice_;
        upShadowPrice_ = rhs.upShadowPrice_;
        sumDownDecrease_ = rhs.sumDownDecrease_;
        sumUpDecrease_ = rhs.sumUpDecrease_;
        lastDownCost_ = rhs.lastDownCost_;
        lastUpCost_ = rhs.lastUpCost_;
        lastDownDecrease_ = rhs.lastDownDecrease_;
        lastUpDecrease_ = rhs.lastUpDecrease_;
        numberTimesDown_ = rhs.numberTimesDown_;
        numberTimesUp_ = rhs.numberTimesUp_;
        numberTimesDownInfeasible_ = rhs.numberTimesDownInfeasible_;
        numberTimesUpInfeasible_ = rhs.numberTimesUpInfeasible_;
        numberBeforeTrust_ = rhs.numberBeforeTrust_;
        numberTimesDownLocalFixed_ = rhs.numberTimesDownLocalFixed_;
        numberTimesUpLocalFixed_ = rhs.numberTimesUpLocalFixed_;
        numberTimesDownTotalFixed_ = rhs.numberTimesDownTotalFixed_;
        numberTimesUpTotalFixed_ = rhs.numberTimesUpTotalFixed_;
        numberTimesProbingTotal_ = rhs.numberTimesProbingTotal_;
        method_ = rhs.method_;
    }
    return *this;
}

// Destructor
CbcSimpleIntegerDynamicPseudoCost::~CbcSimpleIntegerDynamicPseudoCost ()
{
}
// Copy some information i.e. just variable stuff
void
CbcSimpleIntegerDynamicPseudoCost::copySome(const CbcSimpleIntegerDynamicPseudoCost * otherObject)
{
    downDynamicPseudoCost_ = otherObject->downDynamicPseudoCost_;
    upDynamicPseudoCost_ = otherObject->upDynamicPseudoCost_;
    sumDownCost_ = otherObject->sumDownCost_;
    sumUpCost_ = otherObject->sumUpCost_;
    sumDownChange_ = otherObject->sumDownChange_;
    sumUpChange_ = otherObject->sumUpChange_;
    downShadowPrice_ = otherObject->downShadowPrice_;
    upShadowPrice_ = otherObject->upShadowPrice_;
    sumDownDecrease_ = otherObject->sumDownDecrease_;
    sumUpDecrease_ = otherObject->sumUpDecrease_;
    lastDownCost_ = otherObject->lastDownCost_;
    lastUpCost_ = otherObject->lastUpCost_;
    lastDownDecrease_ = otherObject->lastDownDecrease_;
    lastUpDecrease_ = otherObject->lastUpDecrease_;
    numberTimesDown_ = otherObject->numberTimesDown_;
    numberTimesUp_ = otherObject->numberTimesUp_;
    numberTimesDownInfeasible_ = otherObject->numberTimesDownInfeasible_;
    numberTimesUpInfeasible_ = otherObject->numberTimesUpInfeasible_;
    numberTimesDownLocalFixed_ = otherObject->numberTimesDownLocalFixed_;
    numberTimesUpLocalFixed_ = otherObject->numberTimesUpLocalFixed_;
    numberTimesDownTotalFixed_ = otherObject->numberTimesDownTotalFixed_;
    numberTimesUpTotalFixed_ = otherObject->numberTimesUpTotalFixed_;
    numberTimesProbingTotal_ = otherObject->numberTimesProbingTotal_;
}
// Updates stuff like pseudocosts before threads
void
CbcSimpleIntegerDynamicPseudoCost::updateBefore(const OsiObject * rhs)
{
#ifndef NDEBUG
    const CbcSimpleIntegerDynamicPseudoCost * rhsObject =
        dynamic_cast <const CbcSimpleIntegerDynamicPseudoCost *>(rhs) ;
    assert (rhsObject);
#else
    const CbcSimpleIntegerDynamicPseudoCost * rhsObject =
        static_cast <const CbcSimpleIntegerDynamicPseudoCost *>(rhs) ;
#endif
    copySome(rhsObject);
}
// Updates stuff like pseudocosts after threads finished
void
CbcSimpleIntegerDynamicPseudoCost::updateAfter(const OsiObject * rhs, const OsiObject * baseObjectX)
{
#ifndef NDEBUG
    const CbcSimpleIntegerDynamicPseudoCost * rhsObject =
        dynamic_cast <const CbcSimpleIntegerDynamicPseudoCost *>(rhs) ;
    assert (rhsObject);
    const CbcSimpleIntegerDynamicPseudoCost * baseObject =
        dynamic_cast <const CbcSimpleIntegerDynamicPseudoCost *>(baseObjectX) ;
    assert (baseObject);
#else
    const CbcSimpleIntegerDynamicPseudoCost * rhsObject =
        static_cast <const CbcSimpleIntegerDynamicPseudoCost *>(rhs) ;
    const CbcSimpleIntegerDynamicPseudoCost * baseObject =
        static_cast <const CbcSimpleIntegerDynamicPseudoCost *>(baseObjectX) ;
#endif
    // compute current
    double sumDown = downDynamicPseudoCost_ * numberTimesDown_;
    sumDown -= baseObject->downDynamicPseudoCost_ * baseObject->numberTimesDown_;
    sumDown = CoinMax(sumDown, 0.0);
    sumDown += rhsObject->downDynamicPseudoCost_ * rhsObject->numberTimesDown_;
    assert (rhsObject->numberTimesDown_ >= baseObject->numberTimesDown_);
    assert (rhsObject->numberTimesDownInfeasible_ >= baseObject->numberTimesDownInfeasible_);
    assert( rhsObject->sumDownCost_ >= baseObject->sumDownCost_);
    double sumUp = upDynamicPseudoCost_ * numberTimesUp_;
    sumUp -= baseObject->upDynamicPseudoCost_ * baseObject->numberTimesUp_;
    sumUp = CoinMax(sumUp, 0.0);
    sumUp += rhsObject->upDynamicPseudoCost_ * rhsObject->numberTimesUp_;
    assert (rhsObject->numberTimesUp_ >= baseObject->numberTimesUp_);
    assert (rhsObject->numberTimesUpInfeasible_ >= baseObject->numberTimesUpInfeasible_);
    assert( rhsObject->sumUpCost_ >= baseObject->sumUpCost_);
    sumDownCost_ += rhsObject->sumDownCost_ - baseObject->sumDownCost_;
    sumUpCost_ += rhsObject->sumUpCost_ - baseObject->sumUpCost_;
    sumDownChange_ += rhsObject->sumDownChange_ - baseObject->sumDownChange_;
    sumUpChange_ += rhsObject->sumUpChange_ - baseObject->sumUpChange_;
    downShadowPrice_ = 0.0;
    upShadowPrice_ = 0.0;
    sumDownDecrease_ += rhsObject->sumDownDecrease_ - baseObject->sumDownDecrease_;
    sumUpDecrease_ += rhsObject->sumUpDecrease_ - baseObject->sumUpDecrease_;
    lastDownCost_ += rhsObject->lastDownCost_ - baseObject->lastDownCost_;
    lastUpCost_ += rhsObject->lastUpCost_ - baseObject->lastUpCost_;
    lastDownDecrease_ += rhsObject->lastDownDecrease_ - baseObject->lastDownDecrease_;
    lastUpDecrease_ += rhsObject->lastUpDecrease_ - baseObject->lastUpDecrease_;
    numberTimesDown_ += rhsObject->numberTimesDown_ - baseObject->numberTimesDown_;
    numberTimesUp_ += rhsObject->numberTimesUp_ - baseObject->numberTimesUp_;
    numberTimesDownInfeasible_ += rhsObject->numberTimesDownInfeasible_ - baseObject->numberTimesDownInfeasible_;
    numberTimesUpInfeasible_ += rhsObject->numberTimesUpInfeasible_ - baseObject->numberTimesUpInfeasible_;
    numberTimesDownLocalFixed_ += rhsObject->numberTimesDownLocalFixed_ - baseObject->numberTimesDownLocalFixed_;
    numberTimesUpLocalFixed_ += rhsObject->numberTimesUpLocalFixed_ - baseObject->numberTimesUpLocalFixed_;
    numberTimesDownTotalFixed_ += rhsObject->numberTimesDownTotalFixed_ - baseObject->numberTimesDownTotalFixed_;
    numberTimesUpTotalFixed_ += rhsObject->numberTimesUpTotalFixed_ - baseObject->numberTimesUpTotalFixed_;
    numberTimesProbingTotal_ += rhsObject->numberTimesProbingTotal_ - baseObject->numberTimesProbingTotal_;
    if (numberTimesDown_ > 0) {
        setDownDynamicPseudoCost(sumDown / static_cast<double> (numberTimesDown_));
    }
    if (numberTimesUp_ > 0) {
        setUpDynamicPseudoCost(sumUp / static_cast<double> (numberTimesUp_));
    }
    //printf("XX %d down %d %d %g up %d %d %g\n",columnNumber_,numberTimesDown_,numberTimesDownInfeasible_,downDynamicPseudoCost_,
    // numberTimesUp_,numberTimesUpInfeasible_,upDynamicPseudoCost_);
    assert (downDynamicPseudoCost_ > 1.0e-40 && upDynamicPseudoCost_ > 1.0e-40);
}
// Same - returns true if contents match(ish)
bool
CbcSimpleIntegerDynamicPseudoCost::same(const CbcSimpleIntegerDynamicPseudoCost * otherObject) const
{
    bool okay = true;
    if (downDynamicPseudoCost_ != otherObject->downDynamicPseudoCost_)
        okay = false;
    if (upDynamicPseudoCost_ != otherObject->upDynamicPseudoCost_)
        okay = false;
    if (sumDownCost_ != otherObject->sumDownCost_)
        okay = false;
    if (sumUpCost_ != otherObject->sumUpCost_)
        okay = false;
    if (sumDownChange_ != otherObject->sumDownChange_)
        okay = false;
    if (sumUpChange_ != otherObject->sumUpChange_)
        okay = false;
    if (downShadowPrice_ != otherObject->downShadowPrice_)
        okay = false;
    if (upShadowPrice_ != otherObject->upShadowPrice_)
        okay = false;
    if (sumDownDecrease_ != otherObject->sumDownDecrease_)
        okay = false;
    if (sumUpDecrease_ != otherObject->sumUpDecrease_)
        okay = false;
    if (lastDownCost_ != otherObject->lastDownCost_)
        okay = false;
    if (lastUpCost_ != otherObject->lastUpCost_)
        okay = false;
    if (lastDownDecrease_ != otherObject->lastDownDecrease_)
        okay = false;
    if (lastUpDecrease_ != otherObject->lastUpDecrease_)
        okay = false;
    if (numberTimesDown_ != otherObject->numberTimesDown_)
        okay = false;
    if (numberTimesUp_ != otherObject->numberTimesUp_)
        okay = false;
    if (numberTimesDownInfeasible_ != otherObject->numberTimesDownInfeasible_)
        okay = false;
    if (numberTimesUpInfeasible_ != otherObject->numberTimesUpInfeasible_)
        okay = false;
    if (numberTimesDownLocalFixed_ != otherObject->numberTimesDownLocalFixed_)
        okay = false;
    if (numberTimesUpLocalFixed_ != otherObject->numberTimesUpLocalFixed_)
        okay = false;
    if (numberTimesDownTotalFixed_ != otherObject->numberTimesDownTotalFixed_)
        okay = false;
    if (numberTimesUpTotalFixed_ != otherObject->numberTimesUpTotalFixed_)
        okay = false;
    if (numberTimesProbingTotal_ != otherObject->numberTimesProbingTotal_)
        okay = false;
    return okay;
}
/* Create an OsiSolverBranch object

This returns NULL if branch not represented by bound changes
*/
OsiSolverBranch *
CbcSimpleIntegerDynamicPseudoCost::solverBranch() const
{
    OsiSolverInterface * solver = model_->solver();
    const double * solution = model_->testSolution();
    const double * lower = solver->getColLower();
    const double * upper = solver->getColUpper();
    double value = solution[columnNumber_];
    value = CoinMax(value, lower[columnNumber_]);
    value = CoinMin(value, upper[columnNumber_]);
    assert (upper[columnNumber_] > lower[columnNumber_]);
#ifndef NDEBUG
    double nearest = floor(value + 0.5);
    double integerTolerance =
        model_->getDblParam(CbcModel::CbcIntegerTolerance);
    assert (fabs(value - nearest) > integerTolerance);
#endif
    OsiSolverBranch * branch = new OsiSolverBranch();
    branch->addBranch(columnNumber_, value);
    return branch;
}
//#define FUNNY_BRANCHING
double
CbcSimpleIntegerDynamicPseudoCost::infeasibility(const OsiBranchingInformation * info,
        int &preferredWay) const
{
    assert (downDynamicPseudoCost_ > 1.0e-40 && upDynamicPseudoCost_ > 1.0e-40);
    const double * solution = model_->testSolution();
    const double * lower = model_->getCbcColLower();
    const double * upper = model_->getCbcColUpper();
#ifdef FUNNY_BRANCHING2
    const double * dj = model_->getCbcReducedCost();
    double djValue = dj[columnNumber_];
    lastDownDecrease_++;
    if (djValue > 1.0e-6) {
        // wants to go down
        if (true || lower[columnNumber_] > originalLower_) {
            // Lower bound active
            lastUpDecrease_++;
        }
    } else if (djValue < -1.0e-6) {
        // wants to go up
        if (true || upper[columnNumber_] < originalUpper_) {
            // Upper bound active
            lastUpDecrease_++;
        }
    }
#endif
    if (upper[columnNumber_] == lower[columnNumber_]) {
        // fixed
        preferredWay = 1;
        return 0.0;
    }
    assert (breakEven_ > 0.0 && breakEven_ < 1.0);
	/*
	  Find nearest integer, and integers above and below current value.

	  Given that we've already forced value within bounds, if
	  (current value)+(integer tolerance) > (upper bound)
	  shouldn't we declare this variable integer?
	*/

    double value = solution[columnNumber_];
    value = CoinMax(value, lower[columnNumber_]);
    value = CoinMin(value, upper[columnNumber_]);
    /*printf("%d %g %g %g %g\n",columnNumber_,value,lower[columnNumber_],
      solution[columnNumber_],upper[columnNumber_]);*/
    double nearest = floor(value + 0.5);
    double integerTolerance =
        model_->getDblParam(CbcModel::CbcIntegerTolerance);
    double below = floor(value + integerTolerance);
    double above = below + 1.0;
    if (above > upper[columnNumber_]) {
        above = below;
        below = above - 1;
    }
#if INFEAS==1
/*
  Why do we inflate the distance to the cutoff by a factor of 10 for
  values that could be considered reachable? Why do we add 100 for values
  larger than 1e20?
*/
    double distanceToCutoff = 0.0;
    double objectiveValue = model_->getCurrentMinimizationObjValue();
    distanceToCutoff =  model_->getCutoff()  - objectiveValue;
    if (distanceToCutoff < 1.0e20)
        distanceToCutoff *= 10.0;
    else
        distanceToCutoff = 1.0e2 + fabs(objectiveValue);
    distanceToCutoff = CoinMax(distanceToCutoff, 1.0e-12 * (1.0 + fabs(objectiveValue)));
#endif
    double sum;
#ifndef INFEAS_MULTIPLIER 
#define INFEAS_MULTIPLIER 1.0
#endif
    double number;
    double downCost = CoinMax(value - below, 0.0);
#if TYPE2==0
    sum = sumDownCost_;
    number = numberTimesDown_;
#if INFEAS==1
    sum += INFEAS_MULTIPLIER*numberTimesDownInfeasible_ * CoinMax(distanceToCutoff / (downCost + 1.0e-12), sumDownCost_);
#endif
#elif TYPE2==1
    sum = sumDownCost_;
    number = sumDownChange_;
#if INFEAS==1
    sum += INFEAS_MULTIPLIER*numberTimesDownInfeasible_ * CoinMax(distanceToCutoff / (downCost + 1.0e-12), sumDownCost_);
#endif
#elif TYPE2==2
    abort();
#if INFEAS==1
    sum += INFEAS_MULTIPLIER*numberTimesDownInfeasible_ * (distanceToCutoff / (downCost + 1.0e-12));
#endif
#endif
#if MOD_SHADOW>0
    if (!downShadowPrice_) {
        if (number > 0.0)
            downCost *= sum / number;
        else
            downCost  *=  downDynamicPseudoCost_;
    } else if (downShadowPrice_ > 0.0) {
        downCost *= downShadowPrice_;
    } else {
        downCost *= (downDynamicPseudoCost_ - downShadowPrice_);
    }
#else
    if (downShadowPrice_ <= 0.0) {
        if (number > 0.0)
            downCost *= sum / number;
        else
            downCost  *=  downDynamicPseudoCost_;
    } else {
        downCost *= downShadowPrice_;
    }
#endif
    double upCost = CoinMax((above - value), 0.0);
#if TYPE2==0
    sum = sumUpCost_;
    number = numberTimesUp_;
#if INFEAS==1
    sum += INFEAS_MULTIPLIER*numberTimesUpInfeasible_ * CoinMax(distanceToCutoff / (upCost + 1.0e-12), sumUpCost_);
#endif
#elif TYPE2==1
    sum = sumUpCost_;
    number = sumUpChange_;
#if INFEAS==1
    sum += INFEAS_MULTIPLIER*numberTimesUpInfeasible_ * CoinMax(distanceToCutoff / (upCost + 1.0e-12), sumUpCost_);
#endif
#elif TYPE2==1
    abort();
#if INFEAS==1
    sum += INFEAS_MULTIPLIER*numberTimesUpInfeasible_ * (distanceToCutoff / (upCost + 1.0e-12));
#endif
#endif
#if MOD_SHADOW>0
    if (!upShadowPrice_) {
        if (number > 0.0)
            upCost *= sum / number;
        else
            upCost  *=  upDynamicPseudoCost_;
    } else if (upShadowPrice_ > 0.0) {
        upCost *= upShadowPrice_;
    } else {
        upCost *= (upDynamicPseudoCost_ - upShadowPrice_);
    }
#else
    if (upShadowPrice_ <= 0.0) {
        if (number > 0.0)
            upCost *= sum / number;
        else
            upCost  *=  upDynamicPseudoCost_;
    } else {
        upCost *= upShadowPrice_;
    }
#endif
    if (downCost >= upCost)
        preferredWay = 1;
    else
        preferredWay = -1;
    // See if up down choice set
    if (upDownSeparator_ > 0.0) {
        preferredWay = (value - below >= upDownSeparator_) ? 1 : -1;
    }
#ifdef FUNNY_BRANCHING2
    if (fabs(value - nearest) > integerTolerance) {
        double ratio = (100.0 + lastUpDecrease_) / (100.0 + lastDownDecrease_);
        downCost *= ratio;
        upCost *= ratio;
        if ((lastUpDecrease_ % 100) == -1)
            printf("col %d total %d djtimes %d\n",
                   columnNumber_, lastDownDecrease_, lastUpDecrease_);
    }
#endif
    if (preferredWay_)
        preferredWay = preferredWay_;
    if (info->hotstartSolution_) {
        double targetValue = info->hotstartSolution_[columnNumber_];
        if (value > targetValue)
            preferredWay = -1;
        else
            preferredWay = 1;
    }
    if (fabs(value - nearest) <= integerTolerance) {
        if (priority_ != -999)
            return 0.0;
        else
            return 1.0e-13;
    } else {
        int stateOfSearch = model_->stateOfSearch() % 10;
        double returnValue = 0.0;
        double minValue = CoinMin(downCost, upCost);
        double maxValue = CoinMax(downCost, upCost);
#ifdef COIN_DEVELOP
        char where;
#endif
        // was <= 10
        //if (stateOfSearch<=1||model_->currentNode()->depth()<=-10 /* was ||maxValue>0.2*distanceToCutoff*/) {
        if (stateOfSearch <= 2) {
            // no branching solution
#ifdef COIN_DEVELOP
            where = 'i';
#endif
            returnValue = WEIGHT_BEFORE * minValue + (1.0 - WEIGHT_BEFORE) * maxValue;
            if (0) {
                double sum;
                int number;
                double downCost2 = CoinMax(value - below, 0.0);
                sum = sumDownCost_;
                number = numberTimesDown_;
                if (number > 0)
                    downCost2 *= sum / static_cast<double> (number);
                else
                    downCost2  *=  downDynamicPseudoCost_;
                double upCost2 = CoinMax((above - value), 0.0);
                sum = sumUpCost_;
                number = numberTimesUp_;
                if (number > 0)
                    upCost2 *= sum / static_cast<double> (number);
                else
                    upCost2  *=  upDynamicPseudoCost_;
                double minValue2 = CoinMin(downCost2, upCost2);
                double maxValue2 = CoinMax(downCost2, upCost2);
                printf("%d value %g downC %g upC %g minV %g maxV %g downC2 %g upC2 %g minV2 %g maxV2 %g\n",
                       columnNumber_, value, downCost, upCost, minValue, maxValue,
                       downCost2, upCost2, minValue2, maxValue2);
            }
        } else {
            // some solution
#ifdef COIN_DEVELOP
            where = 'I';
#endif
#ifndef WEIGHT_PRODUCT
            returnValue = WEIGHT_AFTER * minValue + (1.0 - WEIGHT_AFTER) * maxValue;
#else
            double minProductWeight = model_->getDblParam(CbcModel::CbcSmallChange);
            returnValue = CoinMax(minValue, minProductWeight) * CoinMax(maxValue, minProductWeight);
            //returnValue += minProductWeight*minValue;
#endif
        }
        if (numberTimesUp_ < numberBeforeTrust_ ||
                numberTimesDown_ < numberBeforeTrust_) {
            //if (returnValue<1.0e10)
            //returnValue += 1.0e12;
            //else
            returnValue *= 1.0e3;
            if (!numberTimesUp_ && !numberTimesDown_)
                returnValue *= 1.0e10;
        }
        //if (fabs(value-0.5)<1.0e-5) {
        //returnValue = 3.0*returnValue + 0.2;
        //} else if (value>0.9) {
        //returnValue = 2.0*returnValue + 0.1;
        //}
        if (method_ == 1) {
            // probing
            // average
            double up = 1.0e-15;
            double down = 1.0e-15;
            if (numberTimesProbingTotal_) {
                up += numberTimesUpTotalFixed_ / static_cast<double> (numberTimesProbingTotal_);
                down += numberTimesDownTotalFixed_ / static_cast<double> (numberTimesProbingTotal_);
            }
            returnValue = 1 + 10.0 * CoinMin(numberTimesDownLocalFixed_, numberTimesUpLocalFixed_) +
                          CoinMin(down, up);
            returnValue *= 1.0e-3;
        }
#ifdef COIN_DEVELOP
        History hist;
        hist.where_ = where;
        hist.status_ = ' ';
        hist.sequence_ = columnNumber_;
        hist.numberUp_ = numberTimesUp_;
        hist.numberUpInf_ = numberTimesUpInfeasible_;
        hist.sumUp_ = sumUpCost_;
        hist.upEst_ = upCost;
        hist.numberDown_ = numberTimesDown_;
        hist.numberDownInf_ = numberTimesDownInfeasible_;
        hist.sumDown_ = sumDownCost_;
        hist.downEst_ = downCost;
        if (stateOfSearch)
            addRecord(hist);
#endif
        return CoinMax(returnValue, 1.0e-15);
    }
}
// Creates a branching object
CbcBranchingObject *
CbcSimpleIntegerDynamicPseudoCost::createCbcBranch(OsiSolverInterface * /*solver*/,
        const OsiBranchingInformation * info, int way)
{
    double value = info->solution_[columnNumber_];
    value = CoinMax(value, info->lower_[columnNumber_]);
    value = CoinMin(value, info->upper_[columnNumber_]);
    assert (info->upper_[columnNumber_] > info->lower_[columnNumber_]);
    if (!info->hotstartSolution_ && priority_ != -999) {
#ifndef NDEBUG
#ifndef SWITCH_VARIABLES
        double nearest = floor(value + 0.5);
        assert (fabs(value - nearest) > info->integerTolerance_);
#endif
#endif
    } else if (info->hotstartSolution_) {
        double targetValue = info->hotstartSolution_[columnNumber_];
        if (way > 0)
            value = targetValue - 0.1;
        else
            value = targetValue + 0.1;
    } else {
        if (value <= info->lower_[columnNumber_])
            value += 0.1;
        else if (value >= info->upper_[columnNumber_])
            value -= 0.1;
    }
    assert (value >= info->lower_[columnNumber_] &&
            value <= info->upper_[columnNumber_]);
    CbcDynamicPseudoCostBranchingObject * newObject =
        new CbcDynamicPseudoCostBranchingObject(model_, columnNumber_, way,
                                                value, this);
    double up =  upDynamicPseudoCost_ * (ceil(value) - value);
    double down =  downDynamicPseudoCost_ * (value - floor(value));
    double changeInGuessed = up - down;
    if (way > 0)
        changeInGuessed = - changeInGuessed;
    changeInGuessed = CoinMax(0.0, changeInGuessed);
    //if (way>0)
    //changeInGuessed += 1.0e8; // bias to stay up
    newObject->setChangeInGuessed(changeInGuessed);
    newObject->setOriginalObject(this);
    return newObject;
}

// Return "up" estimate
double
CbcSimpleIntegerDynamicPseudoCost::upEstimate() const
{
    const double * solution = model_->testSolution();
    const double * lower = model_->getCbcColLower();
    const double * upper = model_->getCbcColUpper();
    double value = solution[columnNumber_];
    value = CoinMax(value, lower[columnNumber_]);
    value = CoinMin(value, upper[columnNumber_]);
    if (upper[columnNumber_] == lower[columnNumber_]) {
        // fixed
        return 0.0;
    }
    double integerTolerance =
        model_->getDblParam(CbcModel::CbcIntegerTolerance);
    double below = floor(value + integerTolerance);
    double above = below + 1.0;
    if (above > upper[columnNumber_]) {
        above = below;
        below = above - 1;
    }
    double upCost = CoinMax((above - value) * upDynamicPseudoCost_, 0.0);
    return upCost;
}
// Return "down" estimate
double
CbcSimpleIntegerDynamicPseudoCost::downEstimate() const
{
    const double * solution = model_->testSolution();
    const double * lower = model_->getCbcColLower();
    const double * upper = model_->getCbcColUpper();
    double value = solution[columnNumber_];
    value = CoinMax(value, lower[columnNumber_]);
    value = CoinMin(value, upper[columnNumber_]);
    if (upper[columnNumber_] == lower[columnNumber_]) {
        // fixed
        return 0.0;
    }
    double integerTolerance =
        model_->getDblParam(CbcModel::CbcIntegerTolerance);
    double below = floor(value + integerTolerance);
    double above = below + 1.0;
    if (above > upper[columnNumber_]) {
        above = below;
        below = above - 1;
    }
    double downCost = CoinMax((value - below) * downDynamicPseudoCost_, 0.0);
    return downCost;
}
// Set down pseudo cost
void
CbcSimpleIntegerDynamicPseudoCost::setDownDynamicPseudoCost(double value)
{
#ifdef TRACE_ONE
    double oldDown = sumDownCost_;
#endif
    downDynamicPseudoCost_ = value;
    sumDownCost_ = CoinMax(sumDownCost_, value * numberTimesDown_);
#ifdef TRACE_ONE
    if (columnNumber_ == TRACE_ONE) {
        double down = downDynamicPseudoCost_ * numberTimesDown_;
        printf("For %d sumDown %g (%d), inf (%d) - pseudo %g - sumDown was %g -> %g\n",
               TRACE_ONE, down, numberTimesDown_,
               numberTimesDownInfeasible_, downDynamicPseudoCost_,
               oldDown, sumDownCost_);
    }
#endif
}
// Modify down pseudo cost in a slightly different way
void
CbcSimpleIntegerDynamicPseudoCost::updateDownDynamicPseudoCost(double value)
{
    sumDownCost_ += value;
    numberTimesDown_++;
    downDynamicPseudoCost_ = sumDownCost_ / static_cast<double>(numberTimesDown_);
}
// Set up pseudo cost
void
CbcSimpleIntegerDynamicPseudoCost::setUpDynamicPseudoCost(double value)
{
#ifdef TRACE_ONE
    double oldUp = sumUpCost_;
#endif
    upDynamicPseudoCost_ = value;
    sumUpCost_ = CoinMax(sumUpCost_, value * numberTimesUp_);
#ifdef TRACE_ONE
    if (columnNumber_ == TRACE_ONE) {
        double up = upDynamicPseudoCost_ * numberTimesUp_;
        printf("For %d sumUp %g (%d), inf (%d) - pseudo %g - sumUp was %g -> %g\n",
               TRACE_ONE, up, numberTimesUp_,
               numberTimesUpInfeasible_, upDynamicPseudoCost_,
               oldUp, sumUpCost_);
    }
#endif
}
// Modify up pseudo cost in a slightly different way
void
CbcSimpleIntegerDynamicPseudoCost::updateUpDynamicPseudoCost(double value)
{
    sumUpCost_ += value;
    numberTimesUp_++;
    upDynamicPseudoCost_ = sumUpCost_ / static_cast<double>(numberTimesUp_);
}
/* Pass in information on branch just done and create CbcObjectUpdateData instance.
   If object does not need data then backward pointer will be NULL.
   Assumes can get information from solver */
CbcObjectUpdateData
CbcSimpleIntegerDynamicPseudoCost::createUpdateInformation(const OsiSolverInterface * solver,
        const CbcNode * node,
        const CbcBranchingObject * branchingObject)
{
    double originalValue = node->objectiveValue();
    int originalUnsatisfied = node->numberUnsatisfied();
    double objectiveValue = solver->getObjValue() * solver->getObjSense();
    int unsatisfied = 0;
    int i;
    //might be base model - doesn't matter
    int numberIntegers = model_->numberIntegers();;
    const double * solution = solver->getColSolution();
    //const double * lower = solver->getColLower();
    //const double * upper = solver->getColUpper();
    double change = CoinMax(0.0, objectiveValue - originalValue);
    int iStatus;
    if (solver->isProvenOptimal())
        iStatus = 0; // optimal
    else if (solver->isIterationLimitReached()
             && !solver->isDualObjectiveLimitReached())
        iStatus = 2; // unknown
    else
        iStatus = 1; // infeasible

    bool feasible = iStatus != 1;
    if (feasible) {
        double integerTolerance =
            model_->getDblParam(CbcModel::CbcIntegerTolerance);
        const int * integerVariable = model_->integerVariable();
        for (i = 0; i < numberIntegers; i++) {
            int j = integerVariable[i];
            double value = solution[j];
            double nearest = floor(value + 0.5);
            if (fabs(value - nearest) > integerTolerance)
                unsatisfied++;
#ifdef SWITCH_VARIABLES
	    const CbcSwitchingBinary * sObject = dynamic_cast<const CbcSwitchingBinary *> (this);
	    if (sObject) {
	      int state[3],nBadFixed;
	      unsatisfied +=
		sObject->checkAssociatedBounds(solver,solution,0,
					       state,nBadFixed);
	    }
#endif
        }
    }
    int way = branchingObject->way();
    way = - way; // because after branch so moved on
    double value = branchingObject->value();
    CbcObjectUpdateData newData (this, way,
                                 change, iStatus,
                                 originalUnsatisfied - unsatisfied, value);
    newData.originalObjective_ = originalValue;
    // Solvers know about direction
    double direction = solver->getObjSense();
    solver->getDblParam(OsiDualObjectiveLimit, newData.cutoff_);
    newData.cutoff_ *= direction;
    return newData;
}
// Just update using feasible branches and keep count of infeasible
#undef INFEAS
// Update object by CbcObjectUpdateData
void
CbcSimpleIntegerDynamicPseudoCost::updateInformation(const CbcObjectUpdateData & data)
{
    bool feasible = data.status_ != 1;
    int way = data.way_;
    double value = data.branchingValue_;
    double change = data.change_;
#ifdef COIN_DEVELOP
    History hist;
    hist.where_ = 'U'; // need to tell if hot
#endif
    double movement = 0.0;
    if (way < 0) {
        // down
        movement = value - floor(value);
        if (feasible) {
#ifdef COIN_DEVELOP
            hist.status_ = 'D';
#endif
            movement = CoinMax(movement, MINIMUM_MOVEMENT);
            //printf("(down change %g value down %g ",change,movement);
            incrementNumberTimesDown();
            addToSumDownChange(1.0e-30 + movement);
            addToSumDownDecrease(data.intDecrease_);
#if TYPE2==0
            addToSumDownCost(change / (1.0e-30 + movement));
            setDownDynamicPseudoCost(sumDownCost() / static_cast<double>( numberTimesDown()));
#elif TYPE2==1
            addToSumDownCost(change);
            setDownDynamicPseudoCost(sumDownCost() / sumDownChange());
#elif TYPE2==2
            addToSumDownCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (1.0e-30 + movement));
            setDownDynamicPseudoCost(sumDownCost()*(TYPERATIO / sumDownChange() + (1.0 - TYPERATIO) / (double) numberTimesDown()));
#endif
        } else {
#ifdef COIN_DEVELOP
            hist.status_ = 'd';
#endif
            //printf("(down infeasible value down %g ",change,movement);
            incrementNumberTimesDown();
            incrementNumberTimesDownInfeasible();
#if INFEAS==2
            double distanceToCutoff = 0.0;
            double objectiveValue = model->getCurrentMinimizationObjValue();
            distanceToCutoff =  model->getCutoff()  - originalValue;
            if (distanceToCutoff < 1.0e20)
                change = distanceToCutoff * 2.0;
            else
                change = downDynamicPseudoCost() * movement * 10.0;
            change = CoinMax(1.0e-12 * (1.0 + fabs(originalValue)), change);
            addToSumDownChange(1.0e-30 + movement);
            addToSumDownDecrease(data.intDecrease_);
#if TYPE2==0
            addToSumDownCost(change / (1.0e-30 + movement));
            setDownDynamicPseudoCost(sumDownCost() / (double) numberTimesDown());
#elif TYPE2==1
            addToSumDownCost(change);
            setDownDynamicPseudoCost(sumDownCost() / sumDownChange());
#elif TYPE2==2
            addToSumDownCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (1.0e-30 + movement));
            setDownDynamicPseudoCost(sumDownCost()*(TYPERATIO / sumDownChange() + (1.0 - TYPERATIO) / (double) numberTimesDown()));
#endif
#endif
        }
#if INFEAS==1
        double sum = sumDownCost_;
        int number = numberTimesDown_;
        double originalValue = data.originalObjective_;
        assert (originalValue != COIN_DBL_MAX);
        double distanceToCutoff =  data.cutoff_  - originalValue;
        if (distanceToCutoff > 1.0e20)
            distanceToCutoff = 10.0 + fabs(originalValue);
        sum += INFEAS_MULTIPLIER*numberTimesDownInfeasible_ * CoinMax(distanceToCutoff, 1.0e-12 * (1.0 + fabs(originalValue)));
        setDownDynamicPseudoCost(sum / static_cast<double> (number));
#endif
    } else {
        // up
        movement = ceil(value) - value;
        if (feasible) {
#ifdef COIN_DEVELOP
            hist.status_ = 'U';
#endif
            movement = CoinMax(movement, MINIMUM_MOVEMENT);
            //printf("(up change %g value down %g ",change,movement);
            incrementNumberTimesUp();
            addToSumUpChange(1.0e-30 + movement);
            addToSumUpDecrease(data.intDecrease_);
#if TYPE2==0
            addToSumUpCost(change / (1.0e-30 + movement));
            setUpDynamicPseudoCost(sumUpCost() / static_cast<double> (numberTimesUp()));
#elif TYPE2==1
            addToSumUpCost(change);
            setUpDynamicPseudoCost(sumUpCost() / sumUpChange());
#elif TYPE2==2
            addToSumUpCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (1.0e-30 + movement));
            setUpDynamicPseudoCost(sumUpCost()*(TYPERATIO / sumUpChange() + (1.0 - TYPERATIO) / (double) numberTimesUp()));
#endif
        } else {
#ifdef COIN_DEVELOP
            hist.status_ = 'u';
#endif
            //printf("(up infeasible value down %g ",change,movement);
            incrementNumberTimesUp();
            incrementNumberTimesUpInfeasible();
#if INFEAS==2
            double distanceToCutoff = 0.0;
            double objectiveValue = model->getCurrentMinimizationObjValue();
            distanceToCutoff =  model->getCutoff()  - originalValue;
            if (distanceToCutoff < 1.0e20)
                change = distanceToCutoff * 2.0;
            else
                change = upDynamicPseudoCost() * movement * 10.0;
            change = CoinMax(1.0e-12 * (1.0 + fabs(originalValue)), change);
            addToSumUpChange(1.0e-30 + movement);
            addToSumUpDecrease(data.intDecrease_);
#if TYPE2==0
            addToSumUpCost(change / (1.0e-30 + movement));
            setUpDynamicPseudoCost(sumUpCost() / (double) numberTimesUp());
#elif TYPE2==1
            addToSumUpCost(change);
            setUpDynamicPseudoCost(sumUpCost() / sumUpChange());
#elif TYPE2==2
            addToSumUpCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (1.0e-30 + movement));
            setUpDynamicPseudoCost(sumUpCost()*(TYPERATIO / sumUpChange() + (1.0 - TYPERATIO) / (double) numberTimesUp()));
#endif
#endif
        }
#if INFEAS==1
        double sum = sumUpCost_;
        int number = numberTimesUp_;
        double originalValue = data.originalObjective_;
        assert (originalValue != COIN_DBL_MAX);
        double distanceToCutoff =  data.cutoff_  - originalValue;
        if (distanceToCutoff > 1.0e20)
            distanceToCutoff = 10.0 + fabs(originalValue);
        sum += INFEAS_MULTIPLIER*numberTimesUpInfeasible_ * CoinMax(distanceToCutoff, 1.0e-12 * (1.0 + fabs(originalValue)));
        setUpDynamicPseudoCost(sum / static_cast<double> (number));
#endif
    }
    if (data.way_ < 0)
        assert (numberTimesDown_ > 0);
    else
        assert (numberTimesUp_ > 0);
    assert (downDynamicPseudoCost_ >= 0.0 && downDynamicPseudoCost_ < 1.0e100);
    downDynamicPseudoCost_ = CoinMax(1.0e-10, downDynamicPseudoCost_);
    assert (upDynamicPseudoCost_ >= 0.0 && upDynamicPseudoCost_ < 1.0e100);
    upDynamicPseudoCost_ = CoinMax(1.0e-10, upDynamicPseudoCost_);
#ifdef COIN_DEVELOP
    hist.sequence_ = columnNumber_;
    hist.numberUp_ = numberTimesUp_;
    hist.numberUpInf_ = numberTimesUpInfeasible_;
    hist.sumUp_ = sumUpCost_;
    hist.upEst_ = change;
    hist.numberDown_ = numberTimesDown_;
    hist.numberDownInf_ = numberTimesDownInfeasible_;
    hist.sumDown_ = sumDownCost_;
    hist.downEst_ = movement;
    addRecord(hist);
#endif
    //print(1,0.5);
    assert (downDynamicPseudoCost_ > 1.0e-40 && upDynamicPseudoCost_ > 1.0e-40);
#if MOD_SHADOW>1
    if (upShadowPrice_ > 0.0 && numberTimesDown_ >= numberBeforeTrust_
            && numberTimesUp_ >= numberBeforeTrust_) {
        // Set negative
        upShadowPrice_ = -upShadowPrice_;
        assert (downShadowPrice_ > 0.0);
        downShadowPrice_ = - downShadowPrice_;
    }
#endif
}
// Updates stuff like pseudocosts after mini branch and bound
void
CbcSimpleIntegerDynamicPseudoCost::updateAfterMini(int numberDown, int numberDownInfeasible,
        double sumDown, int numberUp,
        int numberUpInfeasible, double sumUp)
{
    numberTimesDown_ = numberDown;
    numberTimesDownInfeasible_ = numberDownInfeasible;
    sumDownCost_ = sumDown;
    numberTimesUp_ = numberUp;
    numberTimesUpInfeasible_ = numberUpInfeasible;
    sumUpCost_ = sumUp;
    if (numberTimesDown_ > 0) {
        setDownDynamicPseudoCost(sumDownCost_ / static_cast<double> (numberTimesDown_));
        assert (downDynamicPseudoCost_ > 0.0 && downDynamicPseudoCost_ < 1.0e50);
    }
    if (numberTimesUp_ > 0) {
        setUpDynamicPseudoCost(sumUpCost_ / static_cast<double> (numberTimesUp_));
        assert (upDynamicPseudoCost_ > 0.0 && upDynamicPseudoCost_ < 1.0e50);
    }
    assert (downDynamicPseudoCost_ > 1.0e-40 && upDynamicPseudoCost_ > 1.0e-40);
}
// Pass in probing information
void
CbcSimpleIntegerDynamicPseudoCost::setProbingInformation(int fixedDown, int fixedUp)
{
    numberTimesProbingTotal_++;
    numberTimesDownLocalFixed_ = fixedDown;
    numberTimesDownTotalFixed_ += fixedDown;
    numberTimesUpLocalFixed_ = fixedUp;
    numberTimesUpTotalFixed_ += fixedUp;
}
// Print
void
CbcSimpleIntegerDynamicPseudoCost::print(int type, double value) const
{
    if (!type) {
        double meanDown = 0.0;
        double devDown = 0.0;
        if (numberTimesDown_) {
            meanDown = sumDownCost_ / static_cast<double> (numberTimesDown_);
            devDown = meanDown * meanDown - 2.0 * meanDown * sumDownCost_;
            if (devDown >= 0.0)
                devDown = sqrt(devDown);
        }
        double meanUp = 0.0;
        double devUp = 0.0;
        if (numberTimesUp_) {
            meanUp = sumUpCost_ / static_cast<double> (numberTimesUp_);
            devUp = meanUp * meanUp - 2.0 * meanUp * sumUpCost_;
            if (devUp >= 0.0)
                devUp = sqrt(devUp);
        }
        printf("%d down %d times (%d inf) mean %g (dev %g) up %d times (%d inf) mean %g (dev %g)\n",
               columnNumber_,
               numberTimesDown_, numberTimesDownInfeasible_, meanDown, devDown,
               numberTimesUp_, numberTimesUpInfeasible_, meanUp, devUp);
    } else {
        const double * upper = model_->getCbcColUpper();
        double integerTolerance =
            model_->getDblParam(CbcModel::CbcIntegerTolerance);
        double below = floor(value + integerTolerance);
        double above = below + 1.0;
        if (above > upper[columnNumber_]) {
            above = below;
            below = above - 1;
        }
        double objectiveValue = model_->getCurrentMinimizationObjValue();
        double distanceToCutoff =  model_->getCutoff() - objectiveValue;
        if (distanceToCutoff < 1.0e20)
            distanceToCutoff *= 10.0;
        else
            distanceToCutoff = 1.0e2 + fabs(objectiveValue);
        distanceToCutoff = CoinMax(distanceToCutoff, 1.0e-12 * (1.0 + fabs(objectiveValue)));
        double sum;
        int number;
        double downCost = CoinMax(value - below, 0.0);
        double downCost0 = downCost * downDynamicPseudoCost_;
        sum = sumDownCost();
        number = numberTimesDown();
        sum += INFEAS_MULTIPLIER*numberTimesDownInfeasible() * (distanceToCutoff / (downCost + 1.0e-12));
        if (number > 0)
            downCost *= sum / static_cast<double> (number);
        else
            downCost  *=  downDynamicPseudoCost_;
        double upCost = CoinMax((above - value), 0.0);
        double upCost0 = upCost * upDynamicPseudoCost_;
        sum = sumUpCost();
        number = numberTimesUp();
        sum += INFEAS_MULTIPLIER*numberTimesUpInfeasible() * (distanceToCutoff / (upCost + 1.0e-12));
        if (number > 0)
            upCost *= sum / static_cast<double> (number);
        else
            upCost  *=  upDynamicPseudoCost_;
        printf("%d down %d times %g (est %g)  up %d times %g (est %g)\n",
               columnNumber_,
               numberTimesDown_, downCost, downCost0,
               numberTimesUp_, upCost, upCost0);
    }
}

//##############################################################################

// Default Constructor
CbcIntegerPseudoCostBranchingObject::CbcIntegerPseudoCostBranchingObject()
        : CbcIntegerBranchingObject()
{
    changeInGuessed_ = 1.0e-5;
}

// Useful constructor
CbcIntegerPseudoCostBranchingObject::CbcIntegerPseudoCostBranchingObject (CbcModel * model,
        int variable, int way , double value)
        : CbcIntegerBranchingObject(model, variable, way, value)
{
}
// Useful constructor for fixing
CbcIntegerPseudoCostBranchingObject::CbcIntegerPseudoCostBranchingObject (CbcModel * model,
        int variable, int way,
        double lowerValue,
        double /*upperValue*/)
        : CbcIntegerBranchingObject(model, variable, way, lowerValue)
{
    changeInGuessed_ = 1.0e100;
}


// Copy constructor
CbcIntegerPseudoCostBranchingObject::CbcIntegerPseudoCostBranchingObject (
    const CbcIntegerPseudoCostBranchingObject & rhs)
        : CbcIntegerBranchingObject(rhs)
{
    changeInGuessed_ = rhs.changeInGuessed_;
}

// Assignment operator
CbcIntegerPseudoCostBranchingObject &
CbcIntegerPseudoCostBranchingObject::operator=( const CbcIntegerPseudoCostBranchingObject & rhs)
{
    if (this != &rhs) {
        CbcIntegerBranchingObject::operator=(rhs);
        changeInGuessed_ = rhs.changeInGuessed_;
    }
    return *this;
}
CbcBranchingObject *
CbcIntegerPseudoCostBranchingObject::clone() const
{
    return (new CbcIntegerPseudoCostBranchingObject(*this));
}


// Destructor
CbcIntegerPseudoCostBranchingObject::~CbcIntegerPseudoCostBranchingObject ()
{
}

/*
  Perform a branch by adjusting the bounds of the specified variable. Note
  that each arm of the branch advances the object to the next arm by
  advancing the value of way_.

  Providing new values for the variable's lower and upper bounds for each
  branching direction gives a little bit of additional flexibility and will
  be easily extensible to multi-way branching.
  Returns change in guessed objective on next branch
*/
double
CbcIntegerPseudoCostBranchingObject::branch()
{
    CbcIntegerBranchingObject::branch();
    return changeInGuessed_;
}

/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
    same type and must have the same original object, but they may have
    different feasible regions.
    Return the appropriate CbcRangeCompare value (first argument being the
    sub/superset if that's the case). In case of overlap (and if \c
    replaceIfOverlap is true) replace the current branching object with one
    whose feasible region is the overlap.
*/
CbcRangeCompare
CbcIntegerPseudoCostBranchingObject::compareBranchingObject
(const CbcBranchingObject* brObj, const bool replaceIfOverlap)
{
    const CbcIntegerPseudoCostBranchingObject* br =
        dynamic_cast<const CbcIntegerPseudoCostBranchingObject*>(brObj);
    assert(br);
    double* thisBd = way_ < 0 ? down_ : up_;
    const double* otherBd = br->way_ < 0 ? br->down_ : br->up_;
    return CbcCompareRanges(thisBd, otherBd, replaceIfOverlap);
}
#ifdef SWITCH_VARIABLES
/** Default Constructor

  Equivalent to an unspecified binary variable.
*/
CbcSwitchingBinary::CbcSwitchingBinary ()
        : CbcSimpleIntegerDynamicPseudoCost(),
	  zeroLowerBound_(NULL),
	  oneLowerBound_(NULL),
	  zeroUpperBound_(NULL),
	  oneUpperBound_(NULL),
	  otherVariable_(NULL),
	  numberOther_(0),
	  type_(0)
{
}

/** Useful constructor
*/
CbcSwitchingBinary::CbcSwitchingBinary (CbcSimpleIntegerDynamicPseudoCost * oldObject,
					int nOdd,const int * other, const int * otherRow)
  : CbcSimpleIntegerDynamicPseudoCost(*oldObject),
    zeroLowerBound_(NULL),
    oneLowerBound_(NULL),
    zeroUpperBound_(NULL),
    oneUpperBound_(NULL),
    otherVariable_(NULL),
    numberOther_(0),
    type_(0)
{
  if (nOdd)
    type_=2;
  const CoinPackedMatrix * rowCopy = model_->solver()->getMatrixByRow();
  const int * column = rowCopy->getIndices();
  //const int * rowLength = rowCopy->getVectorLengths();
  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
  //const double * rowLower = model_->solver()->getRowLower();
  const double * rowUpper = model_->solver()->getRowUpper();
  const double * columnLower = model_->solver()->getColLower();
  const double * columnUpper = model_->solver()->getColUpper();
  const double * element = rowCopy->getElements();
  int last = other[0];
  int nPair=0;
  int nInGroup=1;
  for (int i=1;i<=nOdd;i++) {
    if (other[i]==last) {
      nInGroup++;
    } else {
      if (nInGroup>2 && model_->logLevel()>2)
	printf("%d in group for column %d - some redundancy\n",
	       nInGroup,columnNumber_);
      nPair++;
      last=other[i];
      nInGroup=1;
    }
  }
  zeroLowerBound_ = new double [4*nPair];
  oneLowerBound_ = zeroLowerBound_+nPair;
  zeroUpperBound_ = oneLowerBound_+nPair;
  oneUpperBound_ = zeroUpperBound_+nPair;
  otherVariable_ = new int [nPair];
  numberOther_ = nPair;
  if (nPair>1&&model_->logLevel()>2)
    printf("%d pairs for column %d\n",
	       nPair,columnNumber_);
  // Now fill
  last = other[0];
  nPair=0;
  int rows[20];
  rows[0]= otherRow[0];
  nInGroup=1;
  for (int i=1;i<=nOdd;i++) {
    if (other[i]==last) {
      rows[nInGroup++]=otherRow[i];
    } else {
      double newLowerZero=0.0;
      double newUpperZero=COIN_DBL_MAX;
      double newLowerOne=0.0;
      double newUpperOne=COIN_DBL_MAX;
      int cColumn=-1;
      for (int j=0;j<nInGroup;j++) {
	int iRow = rows[j];
	CoinBigIndex k = rowStart[iRow];
	double bValue, cValue;
	if (column[k]==columnNumber_) {
	  bValue=element[k];
	  cValue=element[k+1];
	  cColumn=column[k+1];
	} else {
	  bValue=element[k+1];
	  cValue=element[k];
	  cColumn=column[k];
	}
	if (rowUpper[iRow]) {
	  // G row - convert to L
	  bValue=-bValue;
	  cValue=-cValue;
	}
	if (bValue>0.0) {
	  // binary*abs(bValue) <= continuous*abs(cValue);
	  newLowerOne = -bValue/cValue;
	} else {
	  // binary*abs(bValue) >= continuous*abs(cValue);
	  newUpperOne = -bValue/cValue;
	  newUpperZero = 0.0;
	}
      }
      zeroLowerBound_[nPair]=newLowerZero;
      oneLowerBound_[nPair]=newLowerOne;
      zeroUpperBound_[nPair]=newUpperZero;
      oneUpperBound_[nPair]=newUpperOne;
      // make current bounds tight
      double newLower = CoinMin(newLowerZero,newLowerOne);
      if (newLower>columnLower[cColumn])
	model_->solver()->setColLower(cColumn,newLower);
      double newUpper = CoinMax(newUpperZero,newUpperOne);
      if (newUpper<columnUpper[cColumn])
	model_->solver()->setColUpper(cColumn,newUpper);
      otherVariable_[nPair++]=cColumn;
      last=other[i];
      rows[0] = otherRow[i];
      nInGroup=1;
    }
  }
}
// Copy constructor
CbcSwitchingBinary::CbcSwitchingBinary ( const CbcSwitchingBinary & rhs)
        : CbcSimpleIntegerDynamicPseudoCost(rhs),
	  numberOther_(rhs.numberOther_),
	  type_(rhs.type_)
{
  zeroLowerBound_ = CoinCopyOfArray(rhs.zeroLowerBound_,4*numberOther_);
  oneLowerBound_ = zeroLowerBound_+numberOther_;
  zeroUpperBound_ = oneLowerBound_+numberOther_;
  oneUpperBound_ = zeroUpperBound_+numberOther_;
  otherVariable_ = CoinCopyOfArray(rhs.otherVariable_,numberOther_);
}

// Clone
CbcObject *
CbcSwitchingBinary::clone() const
{
    return new CbcSwitchingBinary(*this);
}

// Assignment operator
CbcSwitchingBinary &
CbcSwitchingBinary::operator=( const CbcSwitchingBinary & rhs)
{
    if (this != &rhs) {
        CbcSimpleIntegerDynamicPseudoCost::operator=(rhs);
	numberOther_=rhs.numberOther_;
	type_ = rhs.type_;
	delete [] zeroLowerBound_;
	delete [] otherVariable_;
	zeroLowerBound_ = CoinCopyOfArray(rhs.zeroLowerBound_,4*numberOther_);
	oneLowerBound_ = zeroLowerBound_+numberOther_;
	zeroUpperBound_ = oneLowerBound_+numberOther_;
	oneUpperBound_ = zeroUpperBound_+numberOther_;
	otherVariable_ = CoinCopyOfArray(rhs.otherVariable_,numberOther_);
    }
    return *this;
}

// Destructor
CbcSwitchingBinary::~CbcSwitchingBinary ()
{
  delete [] zeroLowerBound_;
  delete [] otherVariable_;
}
// Add in zero switches
void 
CbcSwitchingBinary::addZeroSwitches(int nAdd,const int * columns)
{
  type_ |= 1;
  int nNew = numberOther_+nAdd;
  double * bounds = new double[4*nNew];
  int * other = new int [nNew];
  memcpy(other,otherVariable_,numberOther_*sizeof(int));
  delete [] otherVariable_;
  otherVariable_=other;
  memcpy(bounds,zeroLowerBound_,numberOther_*sizeof(double));
  memcpy(bounds+nNew,oneLowerBound_,numberOther_*sizeof(double));
  memcpy(bounds+2*nNew,zeroUpperBound_,numberOther_*sizeof(double));
  memcpy(bounds+3*nNew,oneUpperBound_,numberOther_*sizeof(double));
  delete [] zeroLowerBound_;
  zeroLowerBound_ = bounds;
  oneLowerBound_ = zeroLowerBound_+nNew;
  zeroUpperBound_ = oneLowerBound_+nNew;
  oneUpperBound_ = zeroUpperBound_+nNew;
  for (int i=0;i<nAdd;i++) {
    zeroLowerBound_[numberOther_]=0.0;
    oneLowerBound_[numberOther_]=0.0;
    zeroUpperBound_[numberOther_]=0.0;
    oneUpperBound_[numberOther_]=COIN_DBL_MAX;
    otherVariable_[numberOther_++]=columns[i];
  }
}
// Same - returns true if contents match(ish)
bool
CbcSwitchingBinary::same(const CbcSwitchingBinary * otherObject) const
{
  bool okay = CbcSimpleIntegerDynamicPseudoCost::same(otherObject);
    return okay;
}
double
CbcSwitchingBinary::infeasibility(const OsiBranchingInformation * info,
        int &preferredWay) const
{
    assert (downDynamicPseudoCost_ > 1.0e-40 && upDynamicPseudoCost_ > 1.0e-40);
    double * solution = const_cast<double *>(model_->testSolution());
    const double * lower = model_->getCbcColLower();
    const double * upper = model_->getCbcColUpper();
    double saveValue = solution[columnNumber_];
    if (!lower[columnNumber_]&&upper[columnNumber_]==1.0) {
      double integerTolerance =
	model_->getDblParam(CbcModel::CbcIntegerTolerance);
      if (saveValue<integerTolerance) {
	// check others OK
	bool allGood=true;
	double tolerance;
	model_->solver()->getDblParam(OsiPrimalTolerance, tolerance) ;
	for (int i=0;i<numberOther_;i++) {
	  int otherColumn = otherVariable_[i];
	  double value = solution[otherColumn];
	  if (value<zeroLowerBound_[i]-tolerance||
	      value>zeroUpperBound_[i]+tolerance)
	    allGood=false;
	}
	if (!allGood)
	  solution[columnNumber_]=2.0*integerTolerance;
      } else if (saveValue>1.0-integerTolerance) {
	// check others OK
	bool allGood=true;
	double tolerance;
	model_->solver()->getDblParam(OsiPrimalTolerance, tolerance) ;
	for (int i=0;i<numberOther_;i++) {
	  int otherColumn = otherVariable_[i];
	  double value = solution[otherColumn];
	  if (value<oneLowerBound_[i]-tolerance||
	      value>oneUpperBound_[i]+tolerance)
	    allGood=false;
	}
	if (!allGood)
	  solution[columnNumber_]=1.0-2.0*integerTolerance;
      }
    }
    double inf = CbcSimpleIntegerDynamicPseudoCost::infeasibility(info,preferredWay);
    solution[columnNumber_]=saveValue;
    return inf;
}
// Set associated bounds
int 
CbcSwitchingBinary::setAssociatedBounds(OsiSolverInterface * solver,
					int cleanBasis) const
{
  if (!solver)
    solver = model_->solver();
#ifdef COIN_HAS_CLP
  OsiClpSolverInterface * clpSolver
    = dynamic_cast<OsiClpSolverInterface *> (solver);
  if (cleanBasis!=1)
    clpSolver=NULL;
#endif
  const double * columnLower = solver->getColLower();
  const double * columnUpper = solver->getColUpper();
  int nChanged=0;
  if (!columnUpper[columnNumber_]) {
#ifdef COIN_HAS_CLP
    if (clpSolver)
      clpSolver->setColumnStatus(columnNumber_,ClpSimplex::isFixed);
#endif
    for (int i=0;i<numberOther_;i++) {
      int otherColumn = otherVariable_[i];
      if (zeroLowerBound_[i]>columnLower[otherColumn]) {
	solver->setColLower(otherColumn,zeroLowerBound_[i]);
	nChanged++;
      }
      if (zeroUpperBound_[i]<columnUpper[otherColumn]) {
	solver->setColUpper(otherColumn,zeroUpperBound_[i]);
#ifdef COIN_DEVELOP
	const double * solution = solver->getColSolution();
	double value = solution[otherColumn];
	if (value - zeroUpperBound_[i] > 1.0e-5 && model_->logLevel()>1)
	  printf("value for continuous %d %g - above %g - switch %d is %.12g (ub 0)\n", 
		 otherColumn, value, zeroUpperBound_[i],columnNumber_,solution[columnNumber_]);
#endif
	nChanged++;
      }
    }
  } else if (columnLower[columnNumber_]==1.0) {
#ifdef COIN_HAS_CLP
    if (clpSolver)
      clpSolver->setColumnStatus(columnNumber_,ClpSimplex::isFixed);
#endif
    for (int i=0;i<numberOther_;i++) {
      int otherColumn = otherVariable_[i];
      if (oneLowerBound_[i]>columnLower[otherColumn]) {
	solver->setColLower(otherColumn,oneLowerBound_[i]);
	nChanged++;
      }
      if (oneUpperBound_[i]<columnUpper[otherColumn]) {
	solver->setColUpper(otherColumn,oneUpperBound_[i]);
	nChanged++;
      }
    }
  } else if (cleanBasis>=2) {
    // if all OK then can fix
    int state[3];
    int nBadFixed;
    const double * solution = solver->getColSolution();
    if (!checkAssociatedBounds(solver,solution,
			       0,state,nBadFixed)) {
      const double *reducedCost = solver->getReducedCost() ;
      double good=true;
      double integerTolerance =
	model_->getDblParam(CbcModel::CbcIntegerTolerance);
      if (solution[columnNumber_]<integerTolerance) {
	if (cleanBasis==2||reducedCost[columnNumber_]>1.0e-6)
	  solver->setColUpper(columnNumber_,0.0);
	else
	  good=false;
      } else if (solution[columnNumber_]>1.0-integerTolerance) {
	if (cleanBasis==2||reducedCost[columnNumber_]<-1.0e-6)
	  solver->setColLower(columnNumber_,1.0);
	else
	  good=false;
      }
      if (good)
	nChanged=setAssociatedBounds(solver,0);
    }
  } else {
    // see if any continuous bounds force binary 
    for (int i=0;i<numberOther_;i++) {
      int otherColumn = otherVariable_[i];
      if (columnLower[otherColumn]>zeroUpperBound_[i]) {
	// can't be zero
	solver->setColLower(columnNumber_,1.0);
	nChanged++;
      } else if (columnLower[otherColumn]>oneUpperBound_[i]) {
	// can't be one
	solver->setColUpper(columnNumber_,0.0);
	nChanged++;
      }
      if (columnUpper[otherColumn]<zeroLowerBound_[i]) {
	// can't be zero
	solver->setColLower(columnNumber_,1.0);
	nChanged++;
      } else if (columnUpper[otherColumn]<oneLowerBound_[i]) {
	// can't be one
	solver->setColUpper(columnNumber_,0.0);
	nChanged++;
      }
    }
  }
  return nChanged;
}
// Check associated bounds 
int 
CbcSwitchingBinary::checkAssociatedBounds(const OsiSolverInterface * solver,
					  const double * solution, int printLevel, 
					  int state[3], int & nBadFixed) const
{
  state[0] = 0;
  int nBad=0;
  if (!solver)
    solver = model_->solver();
  double tolerance;
  solver->getDblParam(OsiPrimalTolerance, tolerance) ;
  const double * columnLower = solver->getColLower();
  const double * columnUpper = solver->getColUpper();
  double integerTolerance =
    model_->getDblParam(CbcModel::CbcIntegerTolerance);
  bool printIt = printLevel>2 && model_->logLevel()>1;
  if (solution[columnNumber_]<integerTolerance) {
    state[0] = -1;
    for (int i=0;i<numberOther_;i++) {
      int otherColumn = otherVariable_[i];
      if (zeroLowerBound_[i]>solution[otherColumn]+tolerance*5.0) {
	nBad++;
	if (columnUpper[columnNumber_]==0.0) {
	  nBadFixed++;
	  //printIt=true;
	}
	if (printIt)
	  printf("switch %d at zero, other %d at %.12g below bound of %.12g\n",
		 columnNumber_,otherColumn,solution[otherColumn],zeroLowerBound_[i]);
      }
      if (zeroUpperBound_[i]<solution[otherColumn]-tolerance*5.0) {
	nBad++;
	if (columnUpper[columnNumber_]==0.0) {
	  nBadFixed++;
	  //printIt=true;
	}
	if (printIt)
	  printf("switch %d at zero, other %d at %.12g above bound of %.12g\n",
		 columnNumber_,otherColumn,solution[otherColumn],zeroUpperBound_[i]);
      }
    }
  } else if (solution[columnNumber_]>1.0-integerTolerance) {
    state[0] = 1;
    for (int i=0;i<numberOther_;i++) {
      int otherColumn = otherVariable_[i];
      if (oneLowerBound_[i]>solution[otherColumn]+tolerance*5.0) {
	nBad++;
	if (columnLower[columnNumber_]==1.0) {
	  nBadFixed++;
	  //printIt=true;
	}
	if (printIt)
	  printf("switch %d at one, other %d at %.12g below bound of %.12g\n",
		 columnNumber_,otherColumn,solution[otherColumn],oneLowerBound_[i]);
      }
      if (oneUpperBound_[i]<solution[otherColumn]-tolerance*5.0) {
	nBad++;
	if (columnLower[columnNumber_]==1.0) {
	  nBadFixed++;
	  //printIt=true;
	}
	if (printIt)
	  printf("switch %d at one, other %d at %.12g above bound of %.12g\n",
		 columnNumber_,otherColumn,solution[otherColumn],oneUpperBound_[i]);
      }
    }
  } else {
    // in between - compute tight variables
    state[1]=0;
    state[2]=0;
    // for now just compute ones away from bounds
    for (int i=0;i<numberOther_;i++) {
      int otherColumn = otherVariable_[i];
      double otherValue = solution[otherColumn];
      if (otherValue>columnLower[otherColumn]+tolerance&&
	  otherValue<columnUpper[otherColumn]-tolerance)
	state[1]++;
    }
  }
  return nBad;
}
#endif
