/* $Id$ */
// Copyright (C) 2008, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#include "CoinPragma.hpp"
#include "ClpSimplex.hpp"
#include "ClpNode.hpp"
#include "ClpFactorization.hpp"
#include "ClpDualRowSteepest.hpp"

//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################

//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
ClpNode::ClpNode()
  : branchingValue_(0.5)
  , objectiveValue_(0.0)
  , sumInfeasibilities_(0.0)
  , estimatedSolution_(0.0)
  , factorization_(NULL)
  , weights_(NULL)
  , status_(NULL)
  , primalSolution_(NULL)
  , dualSolution_(NULL)
  , lower_(NULL)
  , upper_(NULL)
  , pivotVariables_(NULL)
  , fixed_(NULL)
  , sequence_(1)
  , numberInfeasibilities_(0)
  , depth_(0)
  , numberFixed_(0)
  , flags_(0)
  , maximumFixed_(0)
  , maximumRows_(0)
  , maximumColumns_(0)
  , maximumIntegers_(0)
{
  branchState_.firstBranch = 0;
  branchState_.branch = 0;
}
//-------------------------------------------------------------------
// Useful Constructor from model
//-------------------------------------------------------------------
ClpNode::ClpNode(ClpSimplex *model, const ClpNodeStuff *stuff, int depth)
  : branchingValue_(0.5)
  , objectiveValue_(0.0)
  , sumInfeasibilities_(0.0)
  , estimatedSolution_(0.0)
  , factorization_(NULL)
  , weights_(NULL)
  , status_(NULL)
  , primalSolution_(NULL)
  , dualSolution_(NULL)
  , lower_(NULL)
  , upper_(NULL)
  , pivotVariables_(NULL)
  , fixed_(NULL)
  , sequence_(1)
  , numberInfeasibilities_(0)
  , depth_(0)
  , numberFixed_(0)
  , flags_(0)
  , maximumFixed_(0)
  , maximumRows_(0)
  , maximumColumns_(0)
  , maximumIntegers_(0)
{
  branchState_.firstBranch = 0;
  branchState_.branch = 0;
  gutsOfConstructor(model, stuff, 0, depth);
}

//-------------------------------------------------------------------
// Most of work of constructor from model
//-------------------------------------------------------------------
void ClpNode::gutsOfConstructor(ClpSimplex *model, const ClpNodeStuff *stuff,
  int arraysExist, int depth)
{
  int numberRows = model->numberRows();
  int numberColumns = model->numberColumns();
  int numberTotal = numberRows + numberColumns;
  int maximumTotal = maximumRows_ + maximumColumns_;
  depth_ = depth;
  // save stuff
  objectiveValue_ = model->objectiveValue() * model->optimizationDirection();
  estimatedSolution_ = objectiveValue_;
  flags_ = 1; //say scaled
  if (!arraysExist) {
    maximumRows_ = CoinMax(maximumRows_, numberRows);
    maximumColumns_ = CoinMax(maximumColumns_, numberColumns);
    maximumTotal = maximumRows_ + maximumColumns_;
    assert(!factorization_);
    factorization_ = new ClpFactorization(*model->factorization(), numberRows);
    status_ = CoinCopyOfArrayPartial(model->statusArray(), maximumTotal, numberTotal);
    primalSolution_ = CoinCopyOfArrayPartial(model->solutionRegion(), maximumTotal, numberTotal);
    dualSolution_ = CoinCopyOfArrayPartial(model->djRegion(), maximumTotal, numberTotal); //? has duals as well?
    pivotVariables_ = CoinCopyOfArrayPartial(model->pivotVariable(), maximumRows_, numberRows);
    ClpDualRowSteepest *pivot = dynamic_cast< ClpDualRowSteepest * >(model->dualRowPivot());
    if (pivot) {
      assert(!weights_);
      weights_ = new ClpDualRowSteepest(*pivot);
    }
  } else {
    if (arraysExist == 2)
      assert(lower_);
    if (numberRows <= maximumRows_ && numberColumns <= maximumColumns_) {
      CoinMemcpyN(model->statusArray(), numberTotal, status_);
      if (arraysExist == 1) {
        *factorization_ = *model->factorization();
        CoinMemcpyN(model->solutionRegion(), numberTotal, primalSolution_);
        CoinMemcpyN(model->djRegion(), numberTotal, dualSolution_); //? has duals as well?
        ClpDualRowSteepest *pivot = dynamic_cast< ClpDualRowSteepest * >(model->dualRowPivot());
        if (pivot) {
          if (weights_) {
            //if (weights_->numberRows()==pivot->numberRows()) {
            weights_->fill(*pivot);
            //} else {
            //delete weights_;
            //weights_ = new ClpDualRowSteepest(*pivot);
            //}
          } else {
            weights_ = new ClpDualRowSteepest(*pivot);
          }
        }
        CoinMemcpyN(model->pivotVariable(), numberRows, pivotVariables_);
      } else {
        CoinMemcpyN(model->primalColumnSolution(), numberColumns, primalSolution_);
        CoinMemcpyN(model->dualColumnSolution(), numberColumns, dualSolution_);
        flags_ = 0;
        CoinMemcpyN(model->dualRowSolution(), numberRows, dualSolution_ + numberColumns);
      }
    } else {
      // size has changed
      maximumRows_ = CoinMax(maximumRows_, numberRows);
      maximumColumns_ = CoinMax(maximumColumns_, numberColumns);
      maximumTotal = maximumRows_ + maximumColumns_;
      delete weights_;
      weights_ = NULL;
      delete[] status_;
      delete[] primalSolution_;
      delete[] dualSolution_;
      delete[] pivotVariables_;
      status_ = CoinCopyOfArrayPartial(model->statusArray(), maximumTotal, numberTotal);
      primalSolution_ = new double[maximumTotal * sizeof(double)];
      dualSolution_ = new double[maximumTotal * sizeof(double)];
      if (arraysExist == 1) {
        *factorization_ = *model->factorization(); // I think this is OK
        CoinMemcpyN(model->solutionRegion(), numberTotal, primalSolution_);
        CoinMemcpyN(model->djRegion(), numberTotal, dualSolution_); //? has duals as well?
        ClpDualRowSteepest *pivot = dynamic_cast< ClpDualRowSteepest * >(model->dualRowPivot());
        if (pivot) {
          assert(!weights_);
          weights_ = new ClpDualRowSteepest(*pivot);
        }
      } else {
        CoinMemcpyN(model->primalColumnSolution(), numberColumns, primalSolution_);
        CoinMemcpyN(model->dualColumnSolution(), numberColumns, dualSolution_);
        flags_ = 0;
        CoinMemcpyN(model->dualRowSolution(), numberRows, dualSolution_ + numberColumns);
      }
      pivotVariables_ = new int[maximumRows_];
      if (model->pivotVariable() && model->numberRows() == numberRows)
        CoinMemcpyN(model->pivotVariable(), numberRows, pivotVariables_);
      else
        CoinFillN(pivotVariables_, numberRows, -1);
    }
  }
  numberFixed_ = 0;
  const double *lower = model->columnLower();
  const double *upper = model->columnUpper();
  const double *solution = model->primalColumnSolution();
  const char *integerType = model->integerInformation();
  const double *columnScale = model->columnScale();
  if (!flags_)
    columnScale = NULL; // as duals correct
  int iColumn;
  sequence_ = -1;
  double integerTolerance = stuff->integerTolerance_;
  double mostAway = 0.0;
  int bestPriority = COIN_INT_MAX;
  sumInfeasibilities_ = 0.0;
  numberInfeasibilities_ = 0;
  int nFix = 0;
  double gap = CoinMax(model->dualObjectiveLimit() - objectiveValue_, 1.0e-4);
#define PSEUDO 3
#if PSEUDO == 1 || PSEUDO == 2
  // Column copy of matrix
  ClpPackedMatrix *matrix = model->clpScaledMatrix();
  const double *objective = model->costRegion();
  if (!objective) {
    objective = model->objective();
    //if (!matrix)
    matrix = dynamic_cast< ClpPackedMatrix * >(model->clpMatrix());
  } else if (!matrix) {
    matrix = dynamic_cast< ClpPackedMatrix * >(model->clpMatrix());
  }
  const double *element = matrix->getElements();
  const int *row = matrix->getIndices();
  const CoinBigIndex *columnStart = matrix->getVectorStarts();
  const int *columnLength = matrix->getVectorLengths();
  double direction = model->optimizationDirection();
  const double *dual = dualSolution_ + numberColumns;
#if PSEUDO == 2
  double *activeWeight = new double[numberRows];
  const double *rowLower = model->rowLower();
  const double *rowUpper = model->rowUpper();
  const double *rowActivity = model->primalRowSolution();
  double tolerance = 1.0e-6;
  for (int iRow = 0; iRow < numberRows; iRow++) {
    // could use pi to see if active or activity
    if (rowActivity[iRow] > rowUpper[iRow] - tolerance
      || rowActivity[iRow] < rowLower[iRow] + tolerance) {
      activeWeight[iRow] = 0.0;
    } else {
      activeWeight[iRow] = -1.0;
    }
  }
  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
    if (integerType[iColumn]) {
      double value = solution[iColumn];
      if (fabs(value - floor(value + 0.5)) > 1.0e-6) {
        CoinBigIndex start = columnStart[iColumn];
        CoinBigIndex end = start + columnLength[iColumn];
        for (CoinBigIndex j = start; j < end; j++) {
          int iRow = row[j];
          if (activeWeight[iRow] >= 0.0)
            activeWeight[iRow] += 1.0;
        }
      }
    }
  }
  for (int iRow = 0; iRow < numberRows; iRow++) {
    if (activeWeight[iRow] > 0.0) {
      // could use pi
      activeWeight[iRow] = 1.0 / activeWeight[iRow];
    } else {
      activeWeight[iRow] = 0.0;
    }
  }
#endif
#endif
  const double *downPseudo = stuff->downPseudo_;
  const int *numberDown = stuff->numberDown_;
  const int *numberDownInfeasible = stuff->numberDownInfeasible_;
  const double *upPseudo = stuff->upPseudo_;
  const int *priority = stuff->priority_;
  const int *numberUp = stuff->numberUp_;
  const int *numberUpInfeasible = stuff->numberUpInfeasible_;
  int numberBeforeTrust = stuff->numberBeforeTrust_;
  int stateOfSearch = stuff->stateOfSearch_;
  int iInteger = 0;
  // weight at 1.0 is max min (CbcBranch was 0.8,0.1) (ClpNode was 0.9,0.9)
#define WEIGHT_AFTER 0.9
#define WEIGHT_BEFORE 0.2
  //Stolen from Constraint Integer Programming book (with epsilon change)
#define WEIGHT_PRODUCT
#ifdef WEIGHT_PRODUCT
  double smallChange = stuff->smallChange_;
#endif
#ifndef INFEAS_MULTIPLIER
#define INFEAS_MULTIPLIER 1.0
#endif
  for (iColumn = 0; iColumn < numberColumns; iColumn++) {
    if (integerType[iColumn]) {
      double value = solution[iColumn];
      value = CoinMax(value, static_cast< double >(lower[iColumn]));
      value = CoinMin(value, static_cast< double >(upper[iColumn]));
      double nearest = floor(value + 0.5);
      if (fabs(value - nearest) > integerTolerance) {
        numberInfeasibilities_++;
        sumInfeasibilities_ += fabs(value - nearest);
#if PSEUDO == 1 || PSEUDO == 2
        double upValue = 0.0;
        double downValue = 0.0;
        double value2 = direction * objective[iColumn];
        //double dj2=value2;
        if (value2) {
          if (value2 > 0.0)
            upValue += 1.5 * value2;
          else
            downValue -= 1.5 * value2;
        }
        CoinBigIndex start = columnStart[iColumn];
        CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
        for (CoinBigIndex j = start; j < end; j++) {
          int iRow = row[j];
          value2 = -dual[iRow];
          if (value2) {
            value2 *= element[j];
            //dj2 += value2;
#if PSEUDO == 2
            assert(activeWeight[iRow] > 0.0 || fabs(dual[iRow]) < 1.0e-6);
            value2 *= activeWeight[iRow];
#endif
            if (value2 > 0.0)
              upValue += value2;
            else
              downValue -= value2;
          }
        }
        //assert (fabs(dj2)<1.0e-4);
        int nUp = numberUp[iInteger];
        double upValue2 = (upPseudo[iInteger] / (1.0 + nUp));
        // Extra for infeasible branches
        if (nUp) {
          double ratio = 1.0 + INFEAS_MULTIPLIER * static_cast< double >(numberUpInfeasible[iInteger]) / static_cast< double >(nUp);
          upValue2 *= ratio;
        }
        int nDown = numberDown[iInteger];
        double downValue2 = (downPseudo[iInteger] / (1.0 + nDown));
        if (nDown) {
          double ratio = 1.0 + INFEAS_MULTIPLIER * static_cast< double >(numberDownInfeasible[iInteger]) / static_cast< double >(nDown);
          downValue2 *= ratio;
        }
        //printf("col %d - downPi %g up %g, downPs %g up %g\n",
        //     iColumn,upValue,downValue,upValue2,downValue2);
        upValue = CoinMax(0.1 * upValue, upValue2);
        downValue = CoinMax(0.1 * downValue, downValue2);
        //upValue = CoinMax(upValue,1.0e-8);
        //downValue = CoinMax(downValue,1.0e-8);
        upValue *= ceil(value) - value;
        downValue *= value - floor(value);
        double infeasibility;
        //if (depth>1000)
        //infeasibility = CoinMax(upValue,downValue)+integerTolerance;
        //else
        if (stateOfSearch <= 2) {
          // no solution
          infeasibility = (1.0 - WEIGHT_BEFORE) * CoinMax(upValue, downValue) + WEIGHT_BEFORE * CoinMin(upValue, downValue) + integerTolerance;
        } else {
#ifndef WEIGHT_PRODUCT
          infeasibility = (1.0 - WEIGHT_AFTER) * CoinMax(upValue, downValue) + WEIGHT_AFTER * CoinMin(upValue, downValue) + integerTolerance;
#else
          infeasibility = CoinMax(CoinMax(upValue, downValue), smallChange) * CoinMax(CoinMin(upValue, downValue), smallChange);
#endif
        }
        estimatedSolution_ += CoinMin(upValue2, downValue2);
#elif PSEUDO == 3
        int nUp = numberUp[iInteger];
        int nDown = numberDown[iInteger];
        // Extra 100% for infeasible branches
        double upValue = (ceil(value) - value) * (upPseudo[iInteger] / (1.0 + nUp));
        if (nUp) {
          double ratio = 1.0 + INFEAS_MULTIPLIER * static_cast< double >(numberUpInfeasible[iInteger]) / static_cast< double >(nUp);
          upValue *= ratio;
        }
        double downValue = (value - floor(value)) * (downPseudo[iInteger] / (1.0 + nDown));
        if (nDown) {
          double ratio = 1.0 + INFEAS_MULTIPLIER * static_cast< double >(numberDownInfeasible[iInteger]) / static_cast< double >(nDown);
          downValue *= ratio;
        }
        if (nUp < numberBeforeTrust || nDown < numberBeforeTrust) {
          upValue *= 10.0;
          downValue *= 10.0;
        }

        double infeasibility;
        //if (depth>1000)
        //infeasibility = CoinMax(upValue,downValue)+integerTolerance;
        //else
        if (stateOfSearch <= 2) {
          // no solution
          infeasibility = (1.0 - WEIGHT_BEFORE) * CoinMax(upValue, downValue) + WEIGHT_BEFORE * CoinMin(upValue, downValue) + integerTolerance;
        } else {
#ifndef WEIGHT_PRODUCT
          infeasibility = (1.0 - WEIGHT_AFTER) * CoinMax(upValue, downValue) + WEIGHT_AFTER * CoinMin(upValue, downValue) + integerTolerance;
#else
          infeasibility = CoinMax(CoinMax(upValue, downValue), smallChange) * CoinMax(CoinMin(upValue, downValue), smallChange);
          //infeasibility += CoinMin(upValue,downValue)*smallChange;
#endif
        }
        //infeasibility = 0.1*CoinMax(upValue,downValue)+
        //0.9*CoinMin(upValue,downValue) + integerTolerance;
        estimatedSolution_ += CoinMin(upValue, downValue);
#else
        double infeasibility = fabs(value - nearest);
#endif
        assert(infeasibility > 0.0);
        if (priority[iInteger] < bestPriority) {
          mostAway = 0.0;
          bestPriority = priority[iInteger];
        } else if (priority[iInteger] > bestPriority) {
          infeasibility = 0.0;
        }
        if (infeasibility > mostAway) {
          mostAway = infeasibility;
          sequence_ = iColumn;
          branchingValue_ = value;
          branchState_.branch = 0;
#if PSEUDO > 0
          if (upValue <= downValue)
            branchState_.firstBranch = 1; // up
          else
            branchState_.firstBranch = 0; // down
#else
          if (value <= nearest)
            branchState_.firstBranch = 1; // up
          else
            branchState_.firstBranch = 0; // down
#endif
        }
      } else if (model->getColumnStatus(iColumn) == ClpSimplex::atLowerBound) {
        bool fix = false;
        if (columnScale) {
          if (dualSolution_[iColumn] > gap * columnScale[iColumn])
            fix = true;
        } else {
          if (dualSolution_[iColumn] > gap)
            fix = true;
        }
        if (fix) {
          nFix++;
          //printf("fixed %d to zero gap %g dj %g %g\n",iColumn,
          // gap,dualSolution_[iColumn], columnScale ? columnScale[iColumn]:1.0);
          model->setColumnStatus(iColumn, ClpSimplex::isFixed);
        }
      } else if (model->getColumnStatus(iColumn) == ClpSimplex::atUpperBound) {
        bool fix = false;
        if (columnScale) {
          if (-dualSolution_[iColumn] > gap * columnScale[iColumn])
            fix = true;
        } else {
          if (-dualSolution_[iColumn] > gap)
            fix = true;
        }
        if (fix) {
          nFix++;
          //printf("fixed %d to one gap %g dj %g %g\n",iColumn,
          // gap,dualSolution_[iColumn], columnScale ? columnScale[iColumn]:1.0);
          model->setColumnStatus(iColumn, ClpSimplex::isFixed);
        }
      }
      iInteger++;
    }
  }
  //printf("Choosing %d inf %g pri %d\n",
  // sequence_,mostAway,bestPriority);
#if PSEUDO == 2
  delete[] activeWeight;
#endif
  if (lower_) {
    // save bounds
    if (iInteger > maximumIntegers_) {
      delete[] lower_;
      delete[] upper_;
      maximumIntegers_ = iInteger;
      lower_ = new int[maximumIntegers_];
      upper_ = new int[maximumIntegers_];
    }
    iInteger = 0;
    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
      if (integerType[iColumn]) {
        lower_[iInteger] = static_cast< int >(lower[iColumn]);
        upper_[iInteger] = static_cast< int >(upper[iColumn]);
        iInteger++;
      }
    }
  }
  // Could omit save of fixed if doing full save of bounds
  if (sequence_ >= 0 && nFix) {
    if (nFix > maximumFixed_) {
      delete[] fixed_;
      fixed_ = new int[nFix];
      maximumFixed_ = nFix;
    }
    numberFixed_ = 0;
    unsigned char *status = model->statusArray();
    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
      if (status[iColumn] != status_[iColumn]) {
        if (solution[iColumn] <= lower[iColumn] + 2.0 * integerTolerance) {
          model->setColumnUpper(iColumn, lower[iColumn]);
          fixed_[numberFixed_++] = iColumn;
        } else {
          assert(solution[iColumn] >= upper[iColumn] - 2.0 * integerTolerance);
          model->setColumnLower(iColumn, upper[iColumn]);
          fixed_[numberFixed_++] = iColumn | 0x10000000;
        }
      }
    }
    //printf("%d fixed\n",numberFixed_);
  }
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpNode::ClpNode(const ClpNode &)
{
  printf("ClpNode copy not implemented\n");
  abort();
}

//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
ClpNode::~ClpNode()
{
  delete factorization_;
  delete weights_;
  delete[] status_;
  delete[] primalSolution_;
  delete[] dualSolution_;
  delete[] lower_;
  delete[] upper_;
  delete[] pivotVariables_;
  delete[] fixed_;
}

//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpNode &
ClpNode::operator=(const ClpNode &rhs)
{
  if (this != &rhs) {
    printf("ClpNode = not implemented\n");
    abort();
  }
  return *this;
}
// Create odd arrays
void ClpNode::createArrays(ClpSimplex *model)
{
  int numberColumns = model->numberColumns();
  const char *integerType = model->integerInformation();
  int iColumn;
  int numberIntegers = 0;
  for (iColumn = 0; iColumn < numberColumns; iColumn++) {
    if (integerType[iColumn])
      numberIntegers++;
  }
  if (numberIntegers > maximumIntegers_ || !lower_) {
    delete[] lower_;
    delete[] upper_;
    maximumIntegers_ = numberIntegers;
    lower_ = new int[numberIntegers];
    upper_ = new int[numberIntegers];
  }
}
// Clean up as crunch is different model
void ClpNode::cleanUpForCrunch()
{
  delete weights_;
  weights_ = NULL;
}
/* Applies node to model
   0 - just tree bounds
   1 - tree bounds and basis etc
   2 - saved bounds and basis etc
*/
void ClpNode::applyNode(ClpSimplex *model, int doBoundsEtc)
{
  int numberColumns = model->numberColumns();
  const double *lower = model->columnLower();
  const double *upper = model->columnUpper();
  if (doBoundsEtc < 2) {
    // current bound
    int way = branchState_.firstBranch;
    if (branchState_.branch > 0)
      way = 1 - way;
    if (!way) {
      // This should also do underlying internal bound
      model->setColumnUpper(sequence_, floor(branchingValue_));
    } else {
      // This should also do underlying internal bound
      model->setColumnLower(sequence_, ceil(branchingValue_));
    }
    // apply dj fixings
    for (int i = 0; i < numberFixed_; i++) {
      int iColumn = fixed_[i];
      if ((iColumn & 0x10000000) != 0) {
        iColumn &= 0xfffffff;
        model->setColumnLower(iColumn, upper[iColumn]);
      } else {
        model->setColumnUpper(iColumn, lower[iColumn]);
      }
    }
  } else {
    // restore bounds
    assert(lower_);
    int iInteger = -1;
    const char *integerType = model->integerInformation();
    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
      if (integerType[iColumn]) {
        iInteger++;
        if (lower_[iInteger] != static_cast< int >(lower[iColumn]))
          model->setColumnLower(iColumn, lower_[iInteger]);
        if (upper_[iInteger] != static_cast< int >(upper[iColumn]))
          model->setColumnUpper(iColumn, upper_[iInteger]);
      }
    }
  }
  if (doBoundsEtc && doBoundsEtc < 3) {
    //model->copyFactorization(*factorization_);
    model->copyFactorization(*factorization_);
    ClpDualRowSteepest *pivot = dynamic_cast< ClpDualRowSteepest * >(model->dualRowPivot());
    if (pivot && weights_) {
      pivot->fill(*weights_);
    }
    int numberRows = model->numberRows();
    int numberTotal = numberRows + numberColumns;
    CoinMemcpyN(status_, numberTotal, model->statusArray());
    if (doBoundsEtc < 2) {
      CoinMemcpyN(primalSolution_, numberTotal, model->solutionRegion());
      CoinMemcpyN(dualSolution_, numberTotal, model->djRegion());
      CoinMemcpyN(pivotVariables_, numberRows, model->pivotVariable());
      CoinMemcpyN(dualSolution_ + numberColumns, numberRows, model->dualRowSolution());
    } else {
      CoinMemcpyN(primalSolution_, numberColumns, model->primalColumnSolution());
      CoinMemcpyN(dualSolution_, numberColumns, model->dualColumnSolution());
      CoinMemcpyN(dualSolution_ + numberColumns, numberRows, model->dualRowSolution());
      if (model->columnScale()) {
        // See if just primal will work
        double *solution = model->primalColumnSolution();
        const double *columnScale = model->columnScale();
        int i;
        for (i = 0; i < numberColumns; i++) {
          solution[i] *= columnScale[i];
        }
      }
    }
    model->setObjectiveValue(objectiveValue_);
  }
}
// Choose a new variable
void ClpNode::chooseVariable(ClpSimplex *, ClpNodeStuff * /*info*/)
{
#if 0
     int way = branchState_.firstBranch;
     if (branchState_.branch > 0)
          way = 1 - way;
     assert (!branchState_.branch);
     // We need to use pseudo costs to choose a variable
     int numberColumns = model->numberColumns();
#endif
}
// Fix on reduced costs
int ClpNode::fixOnReducedCosts(ClpSimplex *)
{

  return 0;
}
/* Way for integer variable -1 down , +1 up */
int ClpNode::way() const
{
  int way = branchState_.firstBranch;
  if (branchState_.branch > 0)
    way = 1 - way;
  return way == 0 ? -1 : +1;
}
// Return true if branch exhausted
bool ClpNode::fathomed() const
{
  return branchState_.branch >= 1;
}
// Change state of variable i.e. go other way
void ClpNode::changeState()
{
  branchState_.branch++;
  assert(branchState_.branch <= 2);
}
//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################

//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
ClpNodeStuff::ClpNodeStuff()
  : integerTolerance_(1.0e-7)
  , integerIncrement_(1.0e-8)
  , smallChange_(1.0e-8)
  , downPseudo_(NULL)
  , upPseudo_(NULL)
  , priority_(NULL)
  , numberDown_(NULL)
  , numberUp_(NULL)
  , numberDownInfeasible_(NULL)
  , numberUpInfeasible_(NULL)
  , saveCosts_(NULL)
  , nodeInfo_(NULL)
  , large_(NULL)
  , whichRow_(NULL)
  , whichColumn_(NULL)
  ,
#ifndef NO_FATHOM_PRINT
  handler_(NULL)
  ,
#endif
  nBound_(0)
  , saveOptions_(0)
  , solverOptions_(0)
  , maximumNodes_(0)
  , numberBeforeTrust_(0)
  , stateOfSearch_(0)
  , nDepth_(-1)
  , nNodes_(0)
  , numberNodesExplored_(0)
  , numberIterations_(0)
  , presolveType_(0)
#ifndef NO_FATHOM_PRINT
  , startingDepth_(-1)
  , nodeCalled_(-1)
#endif
{
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpNodeStuff::ClpNodeStuff(const ClpNodeStuff &rhs)
  : integerTolerance_(rhs.integerTolerance_)
  , integerIncrement_(rhs.integerIncrement_)
  , smallChange_(rhs.smallChange_)
  , downPseudo_(NULL)
  , upPseudo_(NULL)
  , priority_(NULL)
  , numberDown_(NULL)
  , numberUp_(NULL)
  , numberDownInfeasible_(NULL)
  , numberUpInfeasible_(NULL)
  , saveCosts_(NULL)
  , nodeInfo_(NULL)
  , large_(NULL)
  , whichRow_(NULL)
  , whichColumn_(NULL)
  ,
#ifndef NO_FATHOM_PRINT
  handler_(rhs.handler_)
  ,
#endif
  nBound_(0)
  , saveOptions_(rhs.saveOptions_)
  , solverOptions_(rhs.solverOptions_)
  , maximumNodes_(rhs.maximumNodes_)
  , numberBeforeTrust_(rhs.numberBeforeTrust_)
  , stateOfSearch_(rhs.stateOfSearch_)
  , nDepth_(rhs.nDepth_)
  , nNodes_(rhs.nNodes_)
  , numberNodesExplored_(rhs.numberNodesExplored_)
  , numberIterations_(rhs.numberIterations_)
  , presolveType_(rhs.presolveType_)
#ifndef NO_FATHOM_PRINT
  , startingDepth_(rhs.startingDepth_)
  , nodeCalled_(rhs.nodeCalled_)
#endif
{
}
//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpNodeStuff &
ClpNodeStuff::operator=(const ClpNodeStuff &rhs)
{
  if (this != &rhs) {
    integerTolerance_ = rhs.integerTolerance_;
    integerIncrement_ = rhs.integerIncrement_;
    smallChange_ = rhs.smallChange_;
    downPseudo_ = NULL;
    upPseudo_ = NULL;
    priority_ = NULL;
    numberDown_ = NULL;
    numberUp_ = NULL;
    numberDownInfeasible_ = NULL;
    numberUpInfeasible_ = NULL;
    saveCosts_ = NULL;
    nodeInfo_ = NULL;
    large_ = NULL;
    whichRow_ = NULL;
    whichColumn_ = NULL;
    nBound_ = 0;
    saveOptions_ = rhs.saveOptions_;
    solverOptions_ = rhs.solverOptions_;
    maximumNodes_ = rhs.maximumNodes_;
    numberBeforeTrust_ = rhs.numberBeforeTrust_;
    stateOfSearch_ = rhs.stateOfSearch_;
    int n = maximumNodes();
    if (n) {
      for (int i = 0; i < n; i++)
        delete nodeInfo_[i];
    }
    delete[] nodeInfo_;
    nodeInfo_ = NULL;
    nDepth_ = rhs.nDepth_;
    nNodes_ = rhs.nNodes_;
    numberNodesExplored_ = rhs.numberNodesExplored_;
    numberIterations_ = rhs.numberIterations_;
    presolveType_ = rhs.presolveType_;
#ifndef NO_FATHOM_PRINT
    handler_ = rhs.handler_;
    startingDepth_ = rhs.startingDepth_;
    nodeCalled_ = rhs.nodeCalled_;
#endif
  }
  return *this;
}
// Zaps stuff 1 - arrays, 2 ints, 3 both
void ClpNodeStuff::zap(int type)
{
  if ((type & 1) != 0) {
    downPseudo_ = NULL;
    upPseudo_ = NULL;
    priority_ = NULL;
    numberDown_ = NULL;
    numberUp_ = NULL;
    numberDownInfeasible_ = NULL;
    numberUpInfeasible_ = NULL;
    saveCosts_ = NULL;
    nodeInfo_ = NULL;
    large_ = NULL;
    whichRow_ = NULL;
    whichColumn_ = NULL;
  }
  if ((type & 2) != 0) {
    nBound_ = 0;
    saveOptions_ = 0;
    solverOptions_ = 0;
    maximumNodes_ = 0;
    numberBeforeTrust_ = 0;
    stateOfSearch_ = 0;
    nDepth_ = -1;
    nNodes_ = 0;
    presolveType_ = 0;
    numberNodesExplored_ = 0;
    numberIterations_ = 0;
  }
}

//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
ClpNodeStuff::~ClpNodeStuff()
{
  delete[] downPseudo_;
  delete[] upPseudo_;
  delete[] priority_;
  delete[] numberDown_;
  delete[] numberUp_;
  delete[] numberDownInfeasible_;
  delete[] numberUpInfeasible_;
  int n = maximumNodes();
  if (n) {
    for (int i = 0; i < n; i++)
      delete nodeInfo_[i];
  }
  delete[] nodeInfo_;
#ifdef CLP_INVESTIGATE
  // Should be NULL - find out why not?
  assert(!saveCosts_);
#endif
  delete[] saveCosts_;
}
// Return maximum number of nodes
int ClpNodeStuff::maximumNodes() const
{
  int n = 0;
#if 0
     if (nDepth_ != -1) {
          if ((solverOptions_ & 32) == 0)
               n = (1 << nDepth_);
          else if (nDepth_)
               n = 1;
     }
     assert (n == maximumNodes_ - (1 + nDepth_) || n == 0);
#else
  if (nDepth_ != -1) {
    n = maximumNodes_ - (1 + nDepth_);
    assert(n > 0);
  }
#endif
  return n;
}
// Return maximum space for nodes
int ClpNodeStuff::maximumSpace() const
{
  return maximumNodes_;
}
/* Fill with pseudocosts */
void ClpNodeStuff::fillPseudoCosts(const double *down, const double *up,
  const int *priority,
  const int *numberDown, const int *numberUp,
  const int *numberDownInfeasible,
  const int *numberUpInfeasible,
  int number)
{
  delete[] downPseudo_;
  delete[] upPseudo_;
  delete[] priority_;
  delete[] numberDown_;
  delete[] numberUp_;
  delete[] numberDownInfeasible_;
  delete[] numberUpInfeasible_;
  downPseudo_ = CoinCopyOfArray(down, number);
  upPseudo_ = CoinCopyOfArray(up, number);
  priority_ = CoinCopyOfArray(priority, number);
  numberDown_ = CoinCopyOfArray(numberDown, number);
  numberUp_ = CoinCopyOfArray(numberUp, number);
  numberDownInfeasible_ = CoinCopyOfArray(numberDownInfeasible, number);
  numberUpInfeasible_ = CoinCopyOfArray(numberUpInfeasible, number);
  // scale
  for (int i = 0; i < number; i++) {
    int n;
    n = numberDown_[i];
    if (n)
      downPseudo_[i] *= n;
    n = numberUp_[i];
    if (n)
      upPseudo_[i] *= n;
  }
}
// Update pseudo costs
void ClpNodeStuff::update(int way, int sequence, double change, bool feasible)
{
  assert(numberDown_[sequence] >= numberDownInfeasible_[sequence]);
  assert(numberUp_[sequence] >= numberUpInfeasible_[sequence]);
  if (way < 0) {
    numberDown_[sequence]++;
    if (!feasible)
      numberDownInfeasible_[sequence]++;
    downPseudo_[sequence] += CoinMax(change, 1.0e-12);
  } else {
    numberUp_[sequence]++;
    if (!feasible)
      numberUpInfeasible_[sequence]++;
    upPseudo_[sequence] += CoinMax(change, 1.0e-12);
  }
}
//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################

//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
ClpHashValue::ClpHashValue()
  : hash_(NULL)
  , numberHash_(0)
  , maxHash_(0)
  , lastUsed_(-1)
{
}
//-------------------------------------------------------------------
// Useful Constructor from model
//-------------------------------------------------------------------
ClpHashValue::ClpHashValue(ClpSimplex *model)
  : hash_(NULL)
  , numberHash_(0)
  , maxHash_(0)
  , lastUsed_(-1)
{
  maxHash_ = 1000;
  int numberColumns = model->numberColumns();
  const double *columnLower = model->columnLower();
  const double *columnUpper = model->columnUpper();
  int numberRows = model->numberRows();
  const double *rowLower = model->rowLower();
  const double *rowUpper = model->rowUpper();
  const double *objective = model->objective();
  CoinPackedMatrix *matrix = model->matrix();
  const int *columnLength = matrix->getVectorLengths();
  const CoinBigIndex *columnStart = matrix->getVectorStarts();
  const double *elementByColumn = matrix->getElements();
  int i;
  int ipos;

  hash_ = new CoinHashLink[maxHash_];

  for (i = 0; i < maxHash_; i++) {
    hash_[i].value = -1.0e-100;
    hash_[i].index = -1;
    hash_[i].next = -1;
  }
  // Put in +0
  hash_[0].value = 0.0;
  hash_[0].index = 0;
  numberHash_ = 1;
  /*
      * Initialize the hash table.  Only the index of the first value that
      * hashes to a value is entered in the table; subsequent values that
      * collide with it are not entered.
      */
  for (i = 0; i < numberColumns; i++) {
    int length = columnLength[i];
    CoinBigIndex start = columnStart[i];
    for (CoinBigIndex i = start; i < start + length; i++) {
      double value = elementByColumn[i];
      ipos = hash(value);
      if (hash_[ipos].index == -1) {
        hash_[ipos].index = numberHash_;
        numberHash_++;
        hash_[ipos].value = elementByColumn[i];
      }
    }
  }

  /*
      * Now take care of the values that collided in the preceding loop,
      * Also do other stuff
      */
  for (i = 0; i < numberRows; i++) {
    if (numberHash_ * 2 > maxHash_)
      resize(true);
    double value;
    value = rowLower[i];
    ipos = index(value);
    if (ipos < 0)
      addValue(value);
    value = rowUpper[i];
    ipos = index(value);
    if (ipos < 0)
      addValue(value);
  }
  for (i = 0; i < numberColumns; i++) {
    int length = columnLength[i];
    CoinBigIndex start = columnStart[i];
    if (numberHash_ * 2 > maxHash_)
      resize(true);
    double value;
    value = objective[i];
    ipos = index(value);
    if (ipos < 0)
      addValue(value);
    value = columnLower[i];
    ipos = index(value);
    if (ipos < 0)
      addValue(value);
    value = columnUpper[i];
    ipos = index(value);
    if (ipos < 0)
      addValue(value);
    for (CoinBigIndex j = start; j < start + length; j++) {
      if (numberHash_ * 2 > maxHash_)
        resize(true);
      value = elementByColumn[j];
      ipos = index(value);
      if (ipos < 0)
        addValue(value);
    }
  }
  resize(false);
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpHashValue::ClpHashValue(const ClpHashValue &rhs)
  : hash_(NULL)
  , numberHash_(rhs.numberHash_)
  , maxHash_(rhs.maxHash_)
  , lastUsed_(rhs.lastUsed_)
{
  if (maxHash_) {
    CoinHashLink *newHash = new CoinHashLink[maxHash_];
    int i;
    for (i = 0; i < maxHash_; i++) {
      newHash[i].value = rhs.hash_[i].value;
      newHash[i].index = rhs.hash_[i].index;
      newHash[i].next = rhs.hash_[i].next;
    }
  }
}

//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
ClpHashValue::~ClpHashValue()
{
  delete[] hash_;
}

//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpHashValue &
ClpHashValue::operator=(const ClpHashValue &rhs)
{
  if (this != &rhs) {
    numberHash_ = rhs.numberHash_;
    maxHash_ = rhs.maxHash_;
    lastUsed_ = rhs.lastUsed_;
    delete[] hash_;
    if (maxHash_) {
      CoinHashLink *newHash = new CoinHashLink[maxHash_];
      int i;
      for (i = 0; i < maxHash_; i++) {
        newHash[i].value = rhs.hash_[i].value;
        newHash[i].index = rhs.hash_[i].index;
        newHash[i].next = rhs.hash_[i].next;
      }
    } else {
      hash_ = NULL;
    }
  }
  return *this;
}
// Return index or -1 if not found
int ClpHashValue::index(double value) const
{
  if (!value)
    return 0;
  int ipos = hash(value);
  int returnCode = -1;
  while (hash_[ipos].index >= 0) {
    if (value == hash_[ipos].value) {
      returnCode = hash_[ipos].index;
      break;
    } else {
      int k = hash_[ipos].next;
      if (k == -1) {
        break;
      } else {
        ipos = k;
      }
    }
  }
  return returnCode;
}
// Add value to list and return index
int ClpHashValue::addValue(double value)
{
  int ipos = hash(value);

  assert(value != hash_[ipos].value);
  if (hash_[ipos].index == -1) {
    // can put in here
    hash_[ipos].index = numberHash_;
    numberHash_++;
    hash_[ipos].value = value;
    return numberHash_ - 1;
  }
  int k = hash_[ipos].next;
  while (k != -1) {
    ipos = k;
    k = hash_[ipos].next;
  }
  while (true) {
    ++lastUsed_;
    assert(lastUsed_ <= maxHash_);
    if (hash_[lastUsed_].index == -1) {
      break;
    }
  }
  hash_[ipos].next = lastUsed_;
  hash_[lastUsed_].index = numberHash_;
  numberHash_++;
  hash_[lastUsed_].value = value;
  return numberHash_ - 1;
}

namespace {
/*
    Originally a local static variable in ClpHashValue::hash.
	Local static variables are a problem when building DLLs on Windows, but
	file-local constants seem to be ok.  -- lh, 101016 --
  */
const int mmult_for_hash[] = {
  262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247,
  241667, 239179, 236609, 233983, 231289, 228859, 226357, 223829,
  221281, 218849, 216319, 213721, 211093, 208673, 206263, 203773,
  201233, 198637, 196159, 193603, 191161, 188701, 186149, 183761,
  181303, 178873, 176389, 173897, 171469, 169049, 166471, 163871,
  161387, 158941, 156437, 153949, 151531, 149159, 146749, 144299,
  141709, 139369, 136889, 134591, 132169, 129641, 127343, 124853,
  122477, 120163, 117757, 115361, 112979, 110567, 108179, 105727,
  103387, 101021, 98639, 96179, 93911, 91583, 89317, 86939, 84521,
  82183, 79939, 77587, 75307, 72959, 70793, 68447, 66103
};
}
int ClpHashValue::hash(double value) const
{

  union {
    double d;
    char c[8];
  } v1;
  assert(sizeof(double) == 8);
  v1.d = value;
  int n = 0;
  int j;

  for (j = 0; j < 8; ++j) {
    int ichar = v1.c[j];
    n += mmult_for_hash[j] * ichar;
  }
  return (abs(n) % maxHash_); /* integer abs */
}
void ClpHashValue::resize(bool increaseMax)
{
  int newSize = increaseMax ? ((3 * maxHash_) >> 1) + 1000 : maxHash_;
  CoinHashLink *newHash = new CoinHashLink[newSize];
  int i;
  for (i = 0; i < newSize; i++) {
    newHash[i].value = -1.0e-100;
    newHash[i].index = -1;
    newHash[i].next = -1;
  }
  // swap
  CoinHashLink *oldHash = hash_;
  hash_ = newHash;
  int oldSize = maxHash_;
  maxHash_ = newSize;
  /*
      * Initialize the hash table.  Only the index of the first value that
      * hashes to a value is entered in the table; subsequent values that
      * collide with it are not entered.
      */
  int ipos;
  int n = 0;
  for (i = 0; i < oldSize; i++) {
    if (oldHash[i].index >= 0) {
      ipos = hash(oldHash[i].value);
      if (hash_[ipos].index == -1) {
        hash_[ipos].index = n;
        n++;
        hash_[ipos].value = oldHash[i].value;
        // unmark
        oldHash[i].index = -1;
      }
    }
  }
  /*
      * Now take care of the values that collided in the preceding loop,
      * by finding some other entry in the table for them.
      * Since there are as many entries in the table as there are values,
      * there must be room for them.
      */
  lastUsed_ = -1;
  for (i = 0; i < oldSize; ++i) {
    if (oldHash[i].index >= 0) {
      double value = oldHash[i].value;
      ipos = hash(value);
      int k;
      while (true) {
        assert(value != hash_[ipos].value);
        k = hash_[ipos].next;
        if (k == -1) {
          while (true) {
            ++lastUsed_;
            assert(lastUsed_ <= maxHash_);
            if (hash_[lastUsed_].index == -1) {
              break;
            }
          }
          hash_[ipos].next = lastUsed_;
          hash_[lastUsed_].index = n;
          n++;
          hash_[lastUsed_].value = value;
          break;
        } else {
          ipos = k;
        }
      }
    }
  }
  assert(n == numberHash_);
  delete[] oldHash;
}

/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
*/
