/* $Id: ClpNode.cpp 1430 2009-09-15 15:51:17Z forrest $ */
// Copyright (C) 2008, International Business Machines
// Corporation and others.  All Rights Reserved.

#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
  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+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+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+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+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),
  nBound_(0),
  saveOptions_(0),
  solverOptions_(0),
  maximumNodes_(0),
  numberBeforeTrust_(0),
  stateOfSearch_(0),
  nDepth_(-1),
  nNodes_(0),
  numberNodesExplored_(0),
  numberIterations_(0),
  presolveType_(0)
{

}

//-------------------------------------------------------------------
// 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),
    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_)
{  
}
//----------------------------------------------------------------
// 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_;
  }
  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;
}

int
ClpHashValue::hash ( double value) const
{
  static int mmult[] = {
    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
  };
  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[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;
}
