/* $Id: AbcDualRowSteepest.cpp 1910 2013-01-27 02:00:13Z stefan $ */
// Copyright (C) 2002, International Business Machines
// Corporation and others, Copyright (C) 2012, FasterCoin.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#include "CoinPragma.hpp"
#include "AbcSimplex.hpp"
#include "ClpMessage.hpp"
#include "AbcDualRowSteepest.hpp"
#include "CoinIndexedVector.hpp"
#include "AbcSimplexFactorization.hpp"
#include "CoinHelperFunctions.hpp"
#include "CoinAbcHelperFunctions.hpp"
#include <cstdio>
//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################
//#define CLP_DEBUG 2
//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
AbcDualRowSteepest::AbcDualRowSteepest (int mode)
  : AbcDualRowPivot(),
    norm_(0.0),
    factorizationRatio_(10.0),
    state_(-1),
    mode_(mode),
    persistence_(normal),
    weights_(NULL),
    infeasible_(NULL),
    savedWeights_(NULL)
{
  type_ = 2 + 64 * mode;
  //printf("XX %x AbcDualRowSteepest constructor\n",this);
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
AbcDualRowSteepest::AbcDualRowSteepest (const AbcDualRowSteepest & rhs)
  : AbcDualRowPivot(rhs)
{
  //printf("XX %x AbcDualRowSteepest constructor from %x\n",this,&rhs);
  norm_ = rhs.norm_;
  factorizationRatio_ = rhs.factorizationRatio_;
  state_ = rhs.state_;
  mode_ = rhs.mode_;
  persistence_ = rhs.persistence_;
  model_ = rhs.model_;
  if ((model_ && model_->whatsChanged() & 1) != 0) {
    int number = model_->numberRows();
    if (rhs.savedWeights_)
      number = CoinMin(number, rhs.savedWeights_->capacity());
    if (rhs.infeasible_) {
      infeasible_ = new CoinIndexedVector(rhs.infeasible_);
    } else {
      infeasible_ = NULL;
    }
    if (rhs.weights_) {
      weights_ = new CoinIndexedVector(rhs.weights_);
    } else {
      weights_ = NULL;
    }
    if (rhs.savedWeights_) {
      savedWeights_ = new CoinIndexedVector(rhs.savedWeights_);
    } else {
      savedWeights_ = NULL;
    }
  } else {
    infeasible_ = NULL;
    weights_ = NULL;
    savedWeights_ = NULL;
  }
}

//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
AbcDualRowSteepest::~AbcDualRowSteepest ()
{
  //printf("XX %x AbcDualRowSteepest destructor\n",this);
  delete weights_;
  delete infeasible_;
  delete savedWeights_;
}

//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
AbcDualRowSteepest &
AbcDualRowSteepest::operator=(const AbcDualRowSteepest& rhs)
{
  if (this != &rhs) {
    AbcDualRowPivot::operator=(rhs);
    norm_ = rhs.norm_;
    factorizationRatio_ = rhs.factorizationRatio_;
    state_ = rhs.state_;
    mode_ = rhs.mode_;
    persistence_ = rhs.persistence_;
    model_ = rhs.model_;
    delete weights_;
    delete infeasible_;
    delete savedWeights_;
    assert(model_);
    int number = model_->numberRows();
    if (rhs.savedWeights_)
      number = CoinMin(number, rhs.savedWeights_->capacity());
    if (rhs.infeasible_ != NULL) {
      infeasible_ = new CoinIndexedVector(rhs.infeasible_);
    } else {
      infeasible_ = NULL;
    }
    if (rhs.weights_ != NULL) {
      weights_ = new CoinIndexedVector(rhs.weights_);
    } else {
      weights_ = NULL;
    }
    if (rhs.savedWeights_ != NULL) {
      savedWeights_ = new CoinIndexedVector(rhs.savedWeights_);
    } else {
      savedWeights_ = NULL;
    }
  }
  return *this;
}
// Fill most values
void
AbcDualRowSteepest::fill(const AbcDualRowSteepest& rhs)
{
  norm_ = rhs.norm_;
  factorizationRatio_ = rhs.factorizationRatio_;
  state_ = rhs.state_;
  mode_ = rhs.mode_;
  persistence_ = rhs.persistence_;
  assert (model_->numberRows() == rhs.model_->numberRows());
  model_ = rhs.model_;
  assert(model_);
  int number = model_->numberRows();
  if (rhs.savedWeights_)
    number = CoinMin(number, rhs.savedWeights_->capacity());
  if (rhs.infeasible_ != NULL) {
    if (!infeasible_)
      infeasible_ = new CoinIndexedVector(rhs.infeasible_);
    else
      *infeasible_ = *rhs.infeasible_;
  } else {
    delete infeasible_;
    infeasible_ = NULL;
  }
  if (rhs.weights_ != NULL) {
    if (!weights_)
      weights_ = new CoinIndexedVector(rhs.weights_);
  } else {
    delete weights_;
    weights_ = NULL;
  }
  if (rhs.savedWeights_ != NULL) {
    if (!savedWeights_)
      savedWeights_ = new CoinIndexedVector(rhs.savedWeights_);
    else
      *savedWeights_ = *rhs.savedWeights_;
  } else {
    delete savedWeights_;
    savedWeights_ = NULL;
  }
}
#ifdef CHECK_NUMBER_WANTED
static int xTimes=0;
static int xWanted=0;
#endif
#if ABC_PARALLEL==2
#define DO_REDUCE 2
#ifdef DO_REDUCE
#if DO_REDUCE==1
#include <cilk/reducer_max.h>
static void choose(int & chosenRow,double & largest, int n,
		   const int * index, const double * infeas,
		   const double * weights,double tolerance)
{
  cilk::reducer_max_index<int,double> maximumIndex(chosenRow,largest);
#pragma cilk_grainsize=128
  cilk_for (int i = 0; i < n; i++) {
    int iRow = index[i];
    double value = infeas[iRow];
    if (value > tolerance) {
      double thisWeight = CoinMin(weights[iRow], 1.0e50);
      maximumIndex.calc_max(iRow,value/thisWeight);
    }
  }
  chosenRow=maximumIndex.get_index();
  largest=maximumIndex.get_value();
}
#else
static void choose(AbcDualRowSteepest * steepest,
		   int & chosenRowSave,double & largestSave, int first, int last,
		   double tolerance)
{
  if (last-first>256) {
    int mid=(last+first)>>1;
    int chosenRow2=chosenRowSave;
    double largest2=largestSave;
    cilk_spawn choose(steepest,chosenRow2,largest2, first, mid,
		      tolerance);
    choose(steepest,chosenRowSave,largestSave, mid, last,
	   tolerance);
    cilk_sync;
    if (largest2>largestSave) {
      largestSave=largest2;
      chosenRowSave=chosenRow2;
    }
  } else {
    const int * index=steepest->infeasible()->getIndices();
     const double * infeas=steepest->infeasible()->denseVector();
    const double * weights=steepest->weights()->denseVector();
    double largest=largestSave;
    int chosenRow=chosenRowSave;
    if ((steepest->model()->stateOfProblem()&VALUES_PASS2)==0) {
      for (int i = first; i < last; i++) {
	int iRow = index[i];
	double value = infeas[iRow];
	if (value > tolerance) {
	  double thisWeight = CoinMin(weights[iRow], 1.0e50);
	  if (value>largest*thisWeight) {
	    largest=value/thisWeight;
	    chosenRow=iRow;
	  }
	}
      }
    } else {
      const double * fakeDjs = steepest->model()->fakeDjs();
      const int * pivotVariable = steepest->model()->pivotVariable();
      for (int i = first; i < last; i++) {
	int iRow = index[i];
	double value = infeas[iRow];
	if (value > tolerance) {
	  int iSequence=pivotVariable[iRow];
	  value *=(fabs(fakeDjs[iSequence])+1.0e-6);
	  double thisWeight = CoinMin(weights[iRow], 1.0e50);
	  /*
	    Ideas
	    always use fake
	    use fake until chosen
	    if successful would move djs to basic region?
	    how to switch off if cilking - easiest at saveWeights
	   */
	  if (value>largest*thisWeight) {
	    largest=value/thisWeight;
	    chosenRow=iRow;
	  }
	}
      }
    }
    chosenRowSave=chosenRow;
    largestSave=largest;
  }
}
static void choose2(AbcDualRowSteepest * steepest,
		   int & chosenRowSave,double & largestSave, int first, int last,
		   double tolerance)
{
  if (last-first>256) {
    int mid=(last+first)>>1;
    int chosenRow2=chosenRowSave;
    double largest2=largestSave;
    cilk_spawn choose2(steepest,chosenRow2,largest2, first, mid,
		      tolerance);
    choose2(steepest,chosenRowSave,largestSave, mid, last,
	   tolerance);
    cilk_sync;
    if (largest2>largestSave) {
      largestSave=largest2;
      chosenRowSave=chosenRow2;
    }
  } else {
    const int * index=steepest->infeasible()->getIndices();
    const double * infeas=steepest->infeasible()->denseVector();
    double largest=largestSave;
    int chosenRow=chosenRowSave;
    for (int i = first; i < last; i++) {
      int iRow = index[i];
      double value = infeas[iRow];
      if (value > largest) {
	largest=value;
	chosenRow=iRow;
      }
    }
    chosenRowSave=chosenRow;
    largestSave=largest;
  }
}
#endif
#endif
#endif
// Returns pivot row, -1 if none
int
AbcDualRowSteepest::pivotRow()
{
  assert(model_);
  double *  COIN_RESTRICT infeas = infeasible_->denseVector();
  int *  COIN_RESTRICT index = infeasible_->getIndices();
  int number = infeasible_->getNumElements();
  int lastPivotRow = model_->lastPivotRow();
  assert (lastPivotRow < model_->numberRows());
  double tolerance = model_->currentPrimalTolerance();
  // we can't really trust infeasibilities if there is primal error
  // this coding has to mimic coding in checkPrimalSolution
  double error = CoinMin(1.0e-2, model_->largestPrimalError());
  // allow tolerance at least slightly bigger than standard
  tolerance = tolerance +  error;
  // But cap
  tolerance = CoinMin(1000.0, tolerance);
  tolerance *= tolerance; // as we are using squares
  bool toleranceChanged = false;
  const double *  COIN_RESTRICT solutionBasic = model_->solutionBasic();
  const double *  COIN_RESTRICT lowerBasic = model_->lowerBasic();
  const double *  COIN_RESTRICT upperBasic = model_->upperBasic();
  // do last pivot row one here
  if (lastPivotRow >= 0 && lastPivotRow < model_->numberRows()) {
    double value = solutionBasic[lastPivotRow];
    double lower = lowerBasic[lastPivotRow];
    double upper = upperBasic[lastPivotRow];
    if (value > upper + tolerance) {
      value -= upper;
      value *= value;
      // store square in list
      if (infeas[lastPivotRow])
	infeas[lastPivotRow] = value; // already there
      else
	infeasible_->quickAdd(lastPivotRow, value);
    } else if (value < lower - tolerance) {
      value -= lower;
      value *= value;
      // store square in list
      if (infeas[lastPivotRow])
	infeas[lastPivotRow] = value; // already there
      else
	infeasible_->add(lastPivotRow, value);
    } else {
      // feasible - was it infeasible - if so set tiny
      if (infeas[lastPivotRow])
	infeas[lastPivotRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
    }
    number = infeasible_->getNumElements();
  }
  if(model_->numberIterations() < model_->lastBadIteration() + 200) {
    // we can't really trust infeasibilities if there is dual error
    if (model_->largestDualError() > model_->largestPrimalError()) {
      tolerance *= CoinMin(model_->largestDualError() / model_->largestPrimalError(), 1000.0);
      toleranceChanged = true;
    }
  }
  int numberWanted;
  if (mode_ < 2 ) {
    numberWanted = number + 1;
  } else {
    if (model_->factorization()->pivots()==0) {
      int numberElements = model_->factorization()->numberElements();
      int numberRows = model_->numberRows();
#if 0
      int numberSlacks = model_->factorization()->numberSlacks();
      factorizationRatio_ = static_cast<double> (numberElements+1) /
	static_cast<double> (numberRows+1-numberSlacks);
#else
      factorizationRatio_ = static_cast<double> (numberElements) /
	static_cast<double> (numberRows);
#endif
      //printf("%d iterations, numberElements %d ratio %g\n",
      //     model_->numberIterations(),numberElements,factorizationRatio_);
      // Bias so less likely to go to steepest if large
      double weights[]={1.0,2.0,5.0};
      double modifier;
      if (numberRows<100000)
	modifier=weights[0];
      else if (numberRows<200000)
	modifier=weights[1];
      else
	modifier=weights[2];
      if (mode_==2&&factorizationRatio_>modifier) {
	// switch from dantzig to steepest
	mode_=3;
	saveWeights(model_,5);
      }
    }
#if 0
    // look at this and modify
    numberWanted = number+1;
    if (factorizationRatio_ < 1.0) {
      numberWanted = CoinMax(2000, numberRows / 20);
#if 0
    } else if (factorizationRatio_ > 10.0) {
      double ratio = number * (factorizationRatio_ / 80.0);
      if (ratio > number)
	numberWanted = number + 1;
      else
	numberWanted = CoinMax(2000, static_cast<int> (ratio));
#else
    } else {
      //double multiplier=CoinMin(factorizationRatio_*0.1,1.0)
#endif
    }
#else
    numberWanted = CoinMax(2000, number / 8);
    if (factorizationRatio_ < 1.5) {
      numberWanted = CoinMax(2000, number / 20);
    } else if (factorizationRatio_ > 5.0) {
      numberWanted = number + 1;
    }
#endif
    numberWanted=CoinMin(numberWanted,number+1);
  }
  if (model_->largestPrimalError() > 1.0e-3)
    numberWanted = number + 1; // be safe
#ifdef CHECK_NUMBER_WANTED
  xWanted+=numberWanted;
  xTimes++;
  if ((xTimes%1000)==0)
    printf("time %d average wanted %g\n",xTimes,static_cast<double>(xWanted)/xTimes);
#endif
  int iPass;
  // Setup two passes
  int start[4];
  start[1] = number;
  start[2] = 0;
  double dstart = static_cast<double> (number) * model_->randomNumberGenerator()->randomDouble();
  start[0] = static_cast<int> (dstart);
  start[3] = start[0];
  //double largestWeight=0.0;
  //double smallestWeight=1.0e100;
  const double * weights = weights_->denseVector();
  const int * pivotVariable = model_->pivotVariable();
  double savePivotWeight=weights_->denseVector()[lastPivotRow];
  weights_->denseVector()[lastPivotRow] *= 1.0e10;
  double largest = 0.0;
  int chosenRow = -1;
  int saveNumberWanted=numberWanted;
#ifdef DO_REDUCE
  bool doReduce=true;
  int lastChosen=-1;
  double lastLargest=0.0;
#endif
  for (iPass = 0; iPass < 2; iPass++) {
    int endThis = start[2*iPass+1];
    int startThis=start[2*iPass];
    while (startThis<endThis) {
      int end = CoinMin(endThis,startThis+numberWanted);
#ifdef DO_REDUCE 
      if (doReduce) {
#if DO_REDUCE==1
	choose(chosenRow,largest,end-startThis,
	       index+startThis,infeas,weights,tolerance);
#else
	if (mode_!=2)
	  choose(this,chosenRow,largest,startThis,end,tolerance);
	else
	  choose2(this,chosenRow,largest,startThis,end,tolerance);
#endif
	if (chosenRow!=lastChosen) {
	  assert (chosenRow>=0);
	  if (model_->flagged(pivotVariable[chosenRow])||
	      (solutionBasic[chosenRow] <= upperBasic[chosenRow] + tolerance &&
	       solutionBasic[chosenRow] >= lowerBasic[chosenRow] - tolerance)) {
	    doReduce=false;
	    chosenRow=lastChosen;
	    largest=lastLargest;
	  } else {
	    lastChosen=chosenRow;
	    lastLargest=largest;
	  }
	}
      }
      if (!doReduce) {
#endif
      for (int i = startThis; i < end; i++) {
	int iRow = index[i];
	double value = infeas[iRow];
	if (value > tolerance) {
	  //#define OUT_EQ
#ifdef OUT_EQ
	  if (upper[iRow] == lower[iRow])
	    value *= 2.0;
#endif
	  double thisWeight = CoinMin(weights[iRow], 1.0e50);
	  //largestWeight = CoinMax(largestWeight,weight);
	  //smallestWeight = CoinMin(smallestWeight,weight);
	  //double dubious = dubiousWeights_[iRow];
	  //weight *= dubious;
	  //if (value>2.0*largest*weight||(value>0.5*largest*weight&&value*largestWeight>dubious*largest*weight)) {
	  if (value > largest * thisWeight) {
	    // make last pivot row last resort choice
	    //if (iRow == lastPivotRow) {
	    //if (value * 1.0e-10 < largest * thisWeight)
	    //  continue;
	    //else
	    //  value *= 1.0e-10;
	    //}
	    if (!model_->flagged(pivotVariable[iRow])) {
	      //#define CLP_DEBUG 3
#ifdef CLP_DEBUG
	      double value2 = 0.0;
	      if (solutionBasic[iRow] > upperBasic[iRow] + tolerance)
		value2 = solutionBasic[iRow] - upperBasic[iRow];
	      else if (solutionBasic[iRow] < lowerBasic[iRow] - tolerance)
		value2 = solutionBasic[iRow] - lowerBasic[iRow];
	      assert(fabs(value2 * value2 - infeas[iRow]) < 1.0e-8 * CoinMin(value2 * value2, infeas[iRow]));
#endif
	      if (solutionBasic[iRow] > upperBasic[iRow] + tolerance ||
		  solutionBasic[iRow] < lowerBasic[iRow] - tolerance) {
		chosenRow = iRow;
		largest = value / thisWeight;
		//largestWeight = dubious;
	      }
	    }
	  }
	}
      }
#ifdef DO_REDUCE
      }
#endif
      numberWanted-=(end-startThis);
      if (!numberWanted) {
	if(chosenRow>=0)
	  break;
	else
	  numberWanted=(saveNumberWanted+1)>>1;
      }
      startThis=end;
    }
    if (!numberWanted) {
      if(chosenRow>=0)
	break;
      else
	numberWanted=(saveNumberWanted+1)>>1;
    }
  }
  weights_->denseVector()[lastPivotRow]=savePivotWeight;
  //printf("smallest %g largest %g\n",smallestWeight,largestWeight);
  if (chosenRow < 0 && toleranceChanged) {
    // won't line up with checkPrimalSolution - do again
    double saveError = model_->largestDualError();
    model_->setLargestDualError(0.0);
    // can't loop
    chosenRow = pivotRow();
    model_->setLargestDualError(saveError);
  }
  if (chosenRow < 0 && lastPivotRow < 0) {
    int nLeft = 0;
    for (int i = 0; i < number; i++) {
      int iRow = index[i];
      if (fabs(infeas[iRow]) > 1.0e-50) {
	index[nLeft++] = iRow;
      } else {
	infeas[iRow] = 0.0;
      }
    }
    infeasible_->setNumElements(nLeft);
    model_->setNumberPrimalInfeasibilities(nLeft);
  }
  if (true&&(model_->stateOfProblem()&VALUES_PASS2)!=0) {
    if (chosenRow>=0) {
      double * fakeDjs = model_->fakeDjs();
      //const int * pivotVariable = model_->pivotVariable();
      fakeDjs[pivotVariable[chosenRow]]=0.0;
    }
  }
  return chosenRow;
}
//#define PRINT_WEIGHTS_FREQUENCY
#ifdef PRINT_WEIGHTS_FREQUENCY
int xweights1=0;
int xweights2=0;
int xweights3=0;
#endif
/* Updates weights and returns pivot alpha.
   Also does FT update */
double
AbcDualRowSteepest::updateWeights(CoinIndexedVector & input,
                                  CoinIndexedVector & updateColumn)
{
   double *  COIN_RESTRICT weights = weights_->denseVector();
#if CLP_DEBUG>2
  // Very expensive debug
  {
    int numberRows = model_->numberRows();
    CoinIndexedVector temp;
    temp.reserve(numberRows);
    double * array = temp.denseVector();
    int * which = temp.getIndices();
    for (int i = 0; i < numberRows; i++) {
      double value = 0.0;
      array[i] = 1.0;
      which[0] = i;
      temp.setNumElements(1);
      model_->factorization()->updateColumnTranspose(temp);
      int number = temp.getNumElements();
      for (int j = 0; j < number; j++) {
	int iRow = which[j];
	value += array[iRow] * array[iRow];
	array[iRow] = 0.0;
      }
      temp.setNumElements(0);
      double w = CoinMax(weights[i], value) * .1;
      if (fabs(weights[i] - value) > w) {
	printf("%d old %g, true %g\n", i, weights[i], value);
	weights[i] = value; // to reduce printout
      }
    }
  }
#endif
  double alpha = 0.0;
  double norm = 0.0;
  int i;
  double *  COIN_RESTRICT work2 = input.denseVector();
  int numberNonZero = input.getNumElements();
  int *  COIN_RESTRICT which = input.getIndices();
  
  //compute norm
  for (int i = 0; i < numberNonZero; i ++ ) {
    int iRow = which[i];
    double value = work2[iRow];
    norm += value * value;
  }
  // Do FT update
  if (true) {
    model_->factorization()->updateTwoColumnsFT(updateColumn,input);
#if CLP_DEBUG>3
    printf("REGION after %d els\n", input.getNumElements());
    input.print();
#endif
  } else {
    // Leave as old way
    model_->factorization()->updateColumnFT(updateColumn);
    model_->factorization()->updateColumn(input);
  }
  //#undef CLP_DEBUG
  numberNonZero = input.getNumElements();
  int pivotRow = model_->lastPivotRow();
  assert (model_->pivotRow()==model_->lastPivotRow());
#ifdef CLP_DEBUG
  if ( model_->logLevel (  ) > 4  &&
       fabs(norm - weights[pivotRow]) > 1.0e-2 * (1.0 + norm))
    printf("on row %d, true weight %g, old %g\n",
	   pivotRow, sqrt(norm), sqrt(weights[pivotRow]));
#endif
  // could re-initialize here (could be expensive)
  norm /= model_->alpha() * model_->alpha();
  assert(model_->alpha());
  assert(norm);
  double multiplier = 2.0 / model_->alpha();
#ifdef PRINT_WEIGHTS_FREQUENCY
  xweights1++;
  if ((xweights1+xweights2+xweights3)%100==0) {
    printf("ZZ iteration %d sum weights %d - %d %d %d\n",
	   model_->numberIterations(),xweights1+xweights2+xweights3,xweights1,xweights2,xweights3);
    assert(abs(model_->numberIterations()-(xweights1+xweights2+xweights3))<=1);
  }
#endif
  // look at updated column
  double *  COIN_RESTRICT work = updateColumn.denseVector();
  numberNonZero = updateColumn.getNumElements();
  which = updateColumn.getIndices();
  
  // pivot element
  alpha=work[pivotRow];
  for (i = 0; i < numberNonZero; i++) {
    int iRow = which[i];
    double theta = work[iRow];
    double devex = weights[iRow];
    //work3[iRow] = devex; // save old
    //which3[nSave++] = iRow;
    double value = work2[iRow];
    devex +=  theta * (theta * norm + value * multiplier);
    if (devex < DEVEX_TRY_NORM)
      devex = DEVEX_TRY_NORM;
    weights[iRow] = devex;
  }
  if (norm < DEVEX_TRY_NORM)
    norm = DEVEX_TRY_NORM;
  // Try this to make less likely will happen again and stop cycling
  //norm *= 1.02;
  weights[pivotRow] = norm;
  input.clear();
#ifdef CLP_DEBUG
  input.checkClear();
#endif
#ifdef CLP_DEBUG
  input.checkClear();
#endif
  return alpha;
}
double 
AbcDualRowSteepest::updateWeights1(CoinIndexedVector & input,CoinIndexedVector & updateColumn)
{
  if (mode_==2) {
    abort();
    // no update
    // Do FT update
    model_->factorization()->updateColumnFT(updateColumn);
    // pivot element
    double alpha = 0.0;
    // look at updated column
    double * work = updateColumn.denseVector();
    int pivotRow = model_->lastPivotRow();
    assert (pivotRow == model_->pivotRow());
    
    assert (!updateColumn.packedMode());
    alpha = work[pivotRow];
    return alpha;
  }
#if CLP_DEBUG>2
  // Very expensive debug
  {
    double * weights = weights_->denseVector();
    int numberRows = model_->numberRows();
    const int * pivotVariable = model_->pivotVariable();
    CoinIndexedVector temp;
    temp.reserve(numberRows);
    double * array = temp.denseVector();
    int * which = temp.getIndices();
    for (int i = 0; i < numberRows; i++) {
      double value = 0.0;
      array[i] = 1.0;
      which[0] = i;
      temp.setNumElements(1);
      model_->factorization()->updateColumnTranspose(temp);
      int number = temp.getNumElements();
      for (int j = 0; j < number; j++) {
	int iRow = which[j];
	value += array[iRow] * array[iRow];
	array[iRow] = 0.0;
      }
      temp.setNumElements(0);
      double w = CoinMax(weights[i], value) * .1;
      if (fabs(weights[i] - value) > w) {
	printf("XX row %d (variable %d) old %g, true %g\n", i, pivotVariable[i],
	       weights[i], value);
	weights[i] = value; // to reduce printout
      }
    }
  }
#endif
  norm_ = 0.0;
  double *  COIN_RESTRICT work2 = input.denseVector();
  int numberNonZero = input.getNumElements();
  int *  COIN_RESTRICT which = input.getIndices();
  
  //compute norm
  for (int i = 0; i < numberNonZero; i ++ ) {
    int iRow = which[i];
    double value = work2[iRow];
    norm_ += value * value;
  }
  // Do FT update
  if (true) {
    model_->factorization()->updateTwoColumnsFT(updateColumn,input);
#if CLP_DEBUG>3
    printf("REGION after %d els\n", input.getNumElements());
    input.print();
#endif
  } else {
    // Leave as old way
    model_->factorization()->updateColumnFT(updateColumn);
    model_->factorization()->updateWeights(input);
  }
  // pivot element
  assert (model_->pivotRow()==model_->lastPivotRow());
  return updateColumn.denseVector()[model_->lastPivotRow()];
}
void AbcDualRowSteepest::updateWeightsOnly(CoinIndexedVector & input)
{
  if (mode_==2)
    return;
  norm_ = 0.0;
  double *  COIN_RESTRICT work2 = input.denseVector();
  int numberNonZero = input.getNumElements();
  int *  COIN_RESTRICT which = input.getIndices();
  
  //compute norm
  for (int i = 0; i < numberNonZero; i ++ ) {
    int iRow = which[i];
    double value = work2[iRow];
    norm_ += value * value;
  }
  model_->factorization()->updateWeights(input);
}
// Actually updates weights
void AbcDualRowSteepest::updateWeights2(CoinIndexedVector & input,CoinIndexedVector & updateColumn)
{
  if (mode_==2)
    return;
  double *  COIN_RESTRICT weights = weights_->denseVector();
  const double *  COIN_RESTRICT work2 = input.denseVector();
  int pivotRow = model_->lastPivotRow();
  assert (model_->pivotRow()==model_->lastPivotRow());
#ifdef CLP_DEBUG
  if ( model_->logLevel (  ) > 4  &&
       fabs(norm_ - weights[pivotRow]) > 1.0e-2 * (1.0 + norm_))
    printf("on row %d, true weight %g, old %g\n",
	   pivotRow, sqrt(norm_), sqrt(weights[pivotRow]));
#endif
  // pivot element
  double alpha=model_->alpha();
  // could re-initialize here (could be expensive)
  norm_ /= alpha * alpha;
  assert(alpha);
  assert(norm_);
  double multiplier = 2.0 / alpha;
  // look at updated column
  const double *  COIN_RESTRICT work = updateColumn.denseVector();
  int numberNonZero = updateColumn.getNumElements();
  const int * which = updateColumn.getIndices();
  double multiplier2=1.0;
#ifdef PRINT_WEIGHTS_FREQUENCY
  xweights2++;
  if ((xweights1+xweights2+xweights3)%100==0) {
    printf("ZZ iteration %d sum weights %d - %d %d %d\n",
	   model_->numberIterations(),xweights1+xweights2+xweights3,xweights1,xweights2,xweights3);
    assert(abs(model_->numberIterations()-(xweights1+xweights2+xweights3))<=1);
  }
#endif
  if (model_->directionOut()<0) {
#ifdef ABC_DEBUG
    printf("Minus out in %d %d, out %d %d\n",model_->sequenceIn(),model_->directionIn(),
	   model_->sequenceOut(),model_->directionOut());
#endif
    multiplier2=-1.0;
  }
  for (int i = 0; i < numberNonZero; i++) {
    int iRow = which[i];
    double theta = multiplier2*work[iRow];
    double devex = weights[iRow];
    double value = work2[iRow];
    devex +=  theta * (theta * norm_ + value * multiplier);
    if (devex < DEVEX_TRY_NORM)
      devex = DEVEX_TRY_NORM;
    weights[iRow] = devex;
  }
  if (norm_ < DEVEX_TRY_NORM)
    norm_ = DEVEX_TRY_NORM;
  // Try this to make less likely will happen again and stop cycling
  //norm_ *= 1.02;
  weights[pivotRow] = norm_;
  input.clear();
#ifdef CLP_DEBUG
  input.checkClear();
#endif
}

/* Updates primal solution (and maybe list of candidates)
   Uses input vector which it deletes
   Computes change in objective function
*/
void
AbcDualRowSteepest::updatePrimalSolution(
					 CoinIndexedVector & primalUpdate,
					 double primalRatio)
{
  double * COIN_RESTRICT work = primalUpdate.denseVector();
  int number = primalUpdate.getNumElements();
  int * COIN_RESTRICT which = primalUpdate.getIndices();
  double tolerance = model_->currentPrimalTolerance();
  double * COIN_RESTRICT infeas = infeasible_->denseVector();
  double * COIN_RESTRICT solutionBasic = model_->solutionBasic();
  const double * COIN_RESTRICT lowerBasic = model_->lowerBasic();
  const double * COIN_RESTRICT upperBasic = model_->upperBasic();
  assert (!primalUpdate.packedMode());
  for (int i = 0; i < number; i++) {
    int iRow = which[i];
    double value = solutionBasic[iRow];
    double change = primalRatio * work[iRow];
    // no need to keep for steepest edge
    work[iRow] = 0.0;
    value -= change;
    double lower = lowerBasic[iRow];
    double upper = upperBasic[iRow];
    solutionBasic[iRow] = value;
    if (value < lower - tolerance) {
      value -= lower;
      value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
      if (lower == upper)
	value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
      // store square in list
      if (infeas[iRow])
	infeas[iRow] = value; // already there
      else
	infeasible_->quickAdd(iRow, value);
    } else if (value > upper + tolerance) {
      value -= upper;
      value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
      if (lower == upper)
	value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
      // store square in list
      if (infeas[iRow])
	infeas[iRow] = value; // already there
      else
	infeasible_->quickAdd(iRow, value);
    } else {
      // feasible - was it infeasible - if so set tiny
      if (infeas[iRow])
	infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
    }
  }
  // Do pivot row
  int iRow = model_->lastPivotRow();
  assert (model_->pivotRow()==model_->lastPivotRow());
  // feasible - was it infeasible - if so set tiny
  //assert (infeas[iRow]);
  if (infeas[iRow])
    infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
  primalUpdate.setNumElements(0);
}
#if ABC_PARALLEL==2
static void update(int first, int last,
		   const int * COIN_RESTRICT which, double * COIN_RESTRICT work, 
		   const double * COIN_RESTRICT work2, double * COIN_RESTRICT weights,
		   const double * COIN_RESTRICT lowerBasic,double * COIN_RESTRICT solutionBasic,
		   const double * COIN_RESTRICT upperBasic,
		   double multiplier,double multiplier2,
		   double norm,double theta,double tolerance)
{
  if (last-first>256) {
    int mid=(last+first)>>1;
    cilk_spawn update(first,mid,which,work,work2,weights,lowerBasic,solutionBasic,
		      upperBasic,multiplier,multiplier2,norm,theta,tolerance);
    update(mid,last,which,work,work2,weights,lowerBasic,solutionBasic,
	   upperBasic,multiplier,multiplier2,norm,theta,tolerance);
    cilk_sync;
  } else {
    for (int i = first; i < last; i++) {
      int iRow = which[i];
      double updateValue = work[iRow];
      double thetaDevex = multiplier2*updateValue;
      double devex = weights[iRow];
      double valueDevex = work2[iRow];
      devex +=  thetaDevex * (thetaDevex * norm + valueDevex * multiplier);
      if (devex < DEVEX_TRY_NORM)
	devex = DEVEX_TRY_NORM;
      weights[iRow] = devex;
      double value = solutionBasic[iRow];
      double change = theta * updateValue;
      value -= change;
      double lower = lowerBasic[iRow];
      double upper = upperBasic[iRow];
      solutionBasic[iRow] = value;
      if (value < lower - tolerance) {
	value -= lower;
	value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
	if (lower == upper)
	  value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
      } else if (value > upper + tolerance) {
	value -= upper;
	value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
	if (lower == upper)
	  value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
      } else {
	// feasible
	value=0.0;
      }
      // store square
      work[iRow]=value;
    }
  }
}
#endif
void 
AbcDualRowSteepest::updatePrimalSolutionAndWeights(CoinIndexedVector & weightsVector,
				    CoinIndexedVector & primalUpdate,
						   double theta)
{
  //printf("updatePrimal iteration %d - weightsVector has %d, primalUpdate has %d\n",
  //	 model_->numberIterations(),weightsVector.getNumElements(),primalUpdate.getNumElements());
  double *  COIN_RESTRICT weights = weights_->denseVector();
  double *  COIN_RESTRICT work2 = weightsVector.denseVector();
  int pivotRow = model_->lastPivotRow();
  assert (model_->pivotRow()==model_->lastPivotRow());
  double * COIN_RESTRICT work = primalUpdate.denseVector();
  int numberNonZero = primalUpdate.getNumElements();
  int * COIN_RESTRICT which = primalUpdate.getIndices();
  double tolerance = model_->currentPrimalTolerance();
  double * COIN_RESTRICT infeas = infeasible_->denseVector();
  double * COIN_RESTRICT solutionBasic = model_->solutionBasic();
  const double * COIN_RESTRICT lowerBasic = model_->lowerBasic();
  const double * COIN_RESTRICT upperBasic = model_->upperBasic();
  assert (!primalUpdate.packedMode());
#ifdef CLP_DEBUG
  if ( model_->logLevel (  ) > 4  &&
       fabs(norm_ - weights[pivotRow]) > 1.0e-2 * (1.0 + norm_))
    printf("on row %d, true weight %g, old %g\n",
	   pivotRow, sqrt(norm_), sqrt(weights[pivotRow]));
#endif
  // pivot element
  double alpha=model_->alpha();
  // could re-initialize here (could be expensive)
  norm_ /= alpha * alpha;
  assert(alpha);
  assert(norm_);
  double multiplier = 2.0 / alpha;
#ifdef PRINT_WEIGHTS_FREQUENCY
  // only weights3 is used? - slightly faster to just update weights if going to invert
  xweights3++;
  if ((xweights1+xweights2+xweights3)%1000==0) {
    printf("ZZ iteration %d sum weights %d - %d %d %d\n",
	   model_->numberIterations(),xweights1+xweights2+xweights3,xweights1,xweights2,xweights3);
    assert(abs(model_->numberIterations()-(xweights1+xweights2+xweights3))<=1);
  }
#endif
  // look at updated column
  double multiplier2=1.0;
  if (model_->directionOut()<0) {
#ifdef ABC_DEBUG
    printf("Minus out in %d %d, out %d %d\n",model_->sequenceIn(),model_->directionIn(),
	   model_->sequenceOut(),model_->directionOut());
#endif
    multiplier2=-1.0;
  }
#if ABC_PARALLEL==2
  update(0,numberNonZero,which,work,work2,weights,
	 lowerBasic,solutionBasic,upperBasic,
	 multiplier,multiplier2,norm_,theta,tolerance);
  for (int i = 0; i < numberNonZero; i++) {
    int iRow = which[i];
    double infeasibility=work[iRow];
    work[iRow]=0.0;
    if (infeasibility) {
      if (infeas[iRow])
	infeas[iRow] = infeasibility; // already there
      else
	infeasible_->quickAdd(iRow, infeasibility);
    } else {
      // feasible - was it infeasible - if so set tiny
      if (infeas[iRow])
	infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
    }
  }
#else
  for (int i = 0; i < numberNonZero; i++) {
    int iRow = which[i];
    double updateValue = work[iRow];
    work[iRow]=0.0;
    double thetaDevex = multiplier2*updateValue;
    double devex = weights[iRow];
    double valueDevex = work2[iRow];
    devex +=  thetaDevex * (thetaDevex * norm_ + valueDevex * multiplier);
    if (devex < DEVEX_TRY_NORM)
      devex = DEVEX_TRY_NORM;
    weights[iRow] = devex;
    double value = solutionBasic[iRow];
    double change = theta * updateValue;
    value -= change;
    double lower = lowerBasic[iRow];
    double upper = upperBasic[iRow];
    solutionBasic[iRow] = value;
    if (value < lower - tolerance) {
      value -= lower;
      value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
      if (lower == upper)
	value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
      // store square in list
      if (infeas[iRow])
	infeas[iRow] = value; // already there
      else
	infeasible_->quickAdd(iRow, value);
    } else if (value > upper + tolerance) {
      value -= upper;
      value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
      if (lower == upper)
	value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
      // store square in list
      if (infeas[iRow])
	infeas[iRow] = value; // already there
      else
	infeasible_->quickAdd(iRow, value);
    } else {
      // feasible - was it infeasible - if so set tiny
      if (infeas[iRow])
	infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
    }
  }
#endif
  weightsVector.clear();
  primalUpdate.setNumElements(0);
#ifdef CLP_DEBUG
  weightsVector.checkClear();
#endif
  // Do pivot row
  if (norm_ < DEVEX_TRY_NORM)
    norm_ = DEVEX_TRY_NORM;
  // Try this to make less likely will happen again and stop cycling
  //norm_ *= 1.02;
  weights[pivotRow] = norm_;
  // feasible - was it infeasible - if so set tiny
  //assert (infeas[iRow]);
  if (infeas[pivotRow])
    infeas[pivotRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
  // see 1/2 above primalUpdate.setNumElements(0);
}
extern void parallelDual5(AbcSimplexFactorization * factorization,
			 CoinIndexedVector ** whichVector,
			 int numberCpu,
			 int whichCpu,
			 double * weights);
/* Saves any weights round factorization as pivot rows may change
   1) before factorization
   2) after factorization
   3) just redo infeasibilities
   4) restore weights
*/
void
AbcDualRowSteepest::saveWeights(AbcSimplex * model, int mode)
{
  model_ = model;
  int numberRows = model_->numberRows();
  // faster to save indices in array numberTotal in length
  const int * pivotVariable = model_->pivotVariable();
  double * weights = weights_ ? weights_->denseVector() : NULL;
  // see if we need to switch
  //if (mode_==2&&mode==2) {
    // switch
    //mode=5;
  //}
  if (mode == 1) {
    if(weights_) {
      // Check if size has changed
      if (infeasible_->capacity() == numberRows) {
	// change from row numbers to sequence numbers
	CoinAbcMemcpy(weights_->getIndices(),pivotVariable,numberRows);
	state_ = 1;
      } else {
	// size has changed - clear everything
	delete weights_;
	weights_ = NULL;
	delete infeasible_;
	infeasible_ = NULL;
	delete savedWeights_;
	savedWeights_ = NULL;
	state_ = -1;
      }
    }
  } else if (mode !=3) {
    // restore
    if (!weights_ || state_ == -1 || mode == 5) {
      // see if crash basis???
      int numberBasicSlacks=0;
      bool initializeNorms=false;
      for (int i=0;i<numberRows;i++) {
	if (model_->getInternalStatus(i)==AbcSimplex::basic)
	  numberBasicSlacks++;
      }
      if (numberBasicSlacks<numberRows&&!model_->numberIterations()) {
	char line[100];
	if (numberBasicSlacks>numberRows-(numberRows>>1)&&mode_==3&&
	    (model_->moreSpecialOptions()&256)==0) {
	  sprintf(line,"Steep initial basis has %d structurals out of %d - initializing norms\n",numberRows-numberBasicSlacks,numberRows);
	  initializeNorms=true;
	} else {
	  sprintf(line,"Steep initial basis has %d structurals out of %d - too many\n",numberRows-numberBasicSlacks,numberRows);
	}
	model_->messageHandler()->message(CLP_GENERAL2,*model_->messagesPointer())
	  << line << CoinMessageEol;
      }
      // initialize weights
      delete weights_;
      delete savedWeights_;
      delete infeasible_;
      weights_ = new CoinIndexedVector();
      weights_->reserve(numberRows);
      savedWeights_ = new CoinIndexedVector();
      // allow for dense multiple of 8!
      savedWeights_->reserve(numberRows+((initializeNorms) ? 8 : 0));
      infeasible_ = new CoinIndexedVector();
      infeasible_->reserve(numberRows);
      weights = weights_->denseVector();
      if (mode == 5||(mode_!=1&&!initializeNorms)) {
	// initialize to 1.0 (can we do better?)
	for (int i = 0; i < numberRows; i++) {
	  weights[i] = 1.0;
	}
      } else {
	double *  COIN_RESTRICT array = savedWeights_->denseVector();
	int *  COIN_RESTRICT which = savedWeights_->getIndices();
	// Later look at factorization to see which can be skipped
	// also use threads to parallelize
#if 0
	// use infeasible to collect row counts
	int * COIN_RESTRICT counts = infeasible_->getIndices();
	CoinAbcMemset0(counts,numberRows);
	// get matrix data pointers
	int maximumRows = model_->maximumAbcNumberRows();
	const CoinBigIndex * columnStart = model_->abcMatrix()->getPackedMatrix()->getVectorStarts()-maximumRows;
	//const int * columnLength = model_->abcMatrix()->getPackedMatrix()->getVectorLengths()-maximumRows;
	const int * row = model_->abcMatrix()->getPackedMatrix()->getIndices();
	const int * pivotVariable = model_->pivotVariable();
	for (int i = 0; i < numberRows; i++) {
	  int iSequence = pivotVariable[i];
	  if (iSequence>=numberRows) {
	    for (CoinBigIndex j=columnStart[iSequence];j<columnStart[iSequence+1];j++) {
	      int iRow=row[j];
	      counts[iRow]++;
	    }
	  }
	}
	int nSlack=0;
#endif
	//#undef ABC_PARALLEL
	// for now just with cilk
#if ABC_PARALLEL==2
	if (model_->parallelMode()==0) {
#endif	
	for (int i = 0; i < numberRows; i++) {
	  double value = 0.0;
	  array[i] = 1.0;
	  which[0] = i;
	  savedWeights_->setNumElements(1);
	  model_->factorization()->updateColumnTranspose(*savedWeights_);
	  int number = savedWeights_->getNumElements();
	  for (int j = 0; j < number; j++) {
	    int k= which[j];
	    value += array[k] * array[k];
	    array[k] = 0.0;
	  }
#if 0
	  if (!counts[i]) {
	    assert (value==1.0);
	    nSlack++;
	  }
#endif
	  savedWeights_->setNumElements(0);
	  weights[i] = value;
	}
#if ABC_PARALLEL==2
	} else {
	  // parallel
	  // get arrays
	  int numberCpuMinusOne=CoinMin(model_->parallelMode(),3);
	  int which[3];
	  CoinIndexedVector * whichVector[4];
	  for (int i=0;i<numberCpuMinusOne;i++) {
	    which[i]=model_->getAvailableArray();
	    whichVector[i]=model_->usefulArray(which[i]);
	    assert(!whichVector[i]->packedMode());
	  }
	  whichVector[numberCpuMinusOne]=savedWeights_;
	  parallelDual5(model_->factorization(),whichVector,numberCpuMinusOne+1,numberCpuMinusOne,weights);
	  for (int i=0;i<numberCpuMinusOne;i++) 
	    model_->clearArrays(which[i]);
	}
#endif	
#if 0
	printf("Steep %d can be skipped\n",nSlack);
#endif
      }
    } else {
      int useArray=model_->getAvailableArrayPublic();
      CoinIndexedVector * usefulArray = model_->usefulArray(useArray);
      int *  COIN_RESTRICT which = usefulArray->getIndices();
      double *  COIN_RESTRICT element = usefulArray->denseVector();
      if (mode!=4) {
	CoinAbcMemcpy(which,weights_->getIndices(),numberRows);
	CoinAbcScatterTo(weights_->denseVector(),element,which,numberRows);
      } else {
	// restore weights
	CoinAbcMemcpy(which,savedWeights_->getIndices(),numberRows);
	CoinAbcScatterTo(savedWeights_->denseVector(),element,which,numberRows);
      }
      for (int i = 0; i < numberRows; i++) {
	int iPivot = pivotVariable[i];
	double thisWeight=element[iPivot];
	if (thisWeight) {
	  if (thisWeight < DEVEX_TRY_NORM)
	    thisWeight = DEVEX_TRY_NORM; // may need to check more
	  weights[i] = thisWeight;
	} else {
	  // odd
	  weights[i] = 1.0;
	}
      }
      if (0) {
	double w[1000];
	int s[1000];
	assert (numberRows<=1000);
	memcpy(w,weights,numberRows*sizeof(double));
	memcpy(s,pivotVariable,numberRows*sizeof(int));
	CoinSort_2(s,s+numberRows,w);
	printf("Weights===========\n");
	for (int i=0;i<numberRows;i++) {
	  printf("%d seq %d weight %g\n",i,s[i],w[i]);
	}
	printf("End weights===========\n");
      }
      usefulArray->setNumElements(numberRows);
      usefulArray->clear();
      // won't be done in parallel
      model_->clearArraysPublic(useArray);
    }
    state_ = 0;
    CoinAbcMemcpy(savedWeights_->denseVector(),weights_->denseVector(),numberRows);
    CoinAbcMemcpy(savedWeights_->getIndices(),pivotVariable,numberRows);
  }
  if (mode >= 2) {
    infeasible_->clear();
    double tolerance = model_->currentPrimalTolerance();
    const double *  COIN_RESTRICT solutionBasic = model_->solutionBasic();
    const double *  COIN_RESTRICT lowerBasic = model_->lowerBasic();
    const double *  COIN_RESTRICT upperBasic = model_->upperBasic();
    if ((model_->stateOfProblem()&VALUES_PASS2)==0) {
      for (int iRow = 0; iRow < numberRows; iRow++) {
	double value = solutionBasic[iRow];
	double lower = lowerBasic[iRow];
	double upper = upperBasic[iRow];
	if (value < lower - tolerance) {
	  value -= lower;
	  value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
	  if (lower == upper)
	    value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
	  // store square in list
	  infeasible_->quickAdd(iRow, value);
	} else if (value > upper + tolerance) {
	  value -= upper;
	  value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
	  if (lower == upper)
	    value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
	  // store square in list
	infeasible_->quickAdd(iRow, value);
	}
      }
    } else {
      // check values pass
      const double * fakeDjs = model_->fakeDjs();
      int numberFake=0;
      for (int iRow = 0; iRow < numberRows; iRow++) {
	double value = solutionBasic[iRow];
	double lower = lowerBasic[iRow];
	double upper = upperBasic[iRow];
	if (value < lower - tolerance) {
	  value -= lower;
	} else if (value > upper + tolerance) {
	  value -= upper;
	} else {
	  value=0.0;
	}
	if (value) {
	  value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
	  if (lower == upper)
	    value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
	  // store square in list
	  infeasible_->quickAdd(iRow, value);
	  int iSequence=pivotVariable[iRow];
	  double fakeDj=fakeDjs[iSequence];
	  if (fabs(fakeDj)>10.0*tolerance) 
	    numberFake++;
	}
      }
      if (numberFake)
	printf("%d fake basic djs\n",numberFake);
      else
	model_->setStateOfProblem(model_->stateOfProblem()&~VALUES_PASS2);
    }
  }
}
// Recompute infeasibilities
void 
AbcDualRowSteepest::recomputeInfeasibilities()
{
  int numberRows = model_->numberRows();
  infeasible_->clear();
  double tolerance = model_->currentPrimalTolerance();
  const double *  COIN_RESTRICT solutionBasic = model_->solutionBasic();
  const double *  COIN_RESTRICT lowerBasic = model_->lowerBasic();
  const double *  COIN_RESTRICT upperBasic = model_->upperBasic();
  for (int iRow = 0; iRow < numberRows; iRow++) {
    double value = solutionBasic[iRow];
    double lower = lowerBasic[iRow];
    double upper = upperBasic[iRow];
    if (value < lower - tolerance) {
      value -= lower;
      value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
      if (lower == upper)
	value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
      // store square in list
      infeasible_->quickAdd(iRow, value);
    } else if (value > upper + tolerance) {
      value -= upper;
      value *= value;
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
      if (lower == upper)
	value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
      // store square in list
      infeasible_->quickAdd(iRow, value);
    }
  }
}
//-------------------------------------------------------------------
// Clone
//-------------------------------------------------------------------
AbcDualRowPivot * AbcDualRowSteepest::clone(bool CopyData) const
{
  if (CopyData) {
    return new AbcDualRowSteepest(*this);
  } else {
    return new AbcDualRowSteepest();
  }
}
// Gets rid of all arrays
void
AbcDualRowSteepest::clearArrays()
{
  if (persistence_ == normal) {
    delete weights_;
    weights_ = NULL;
    delete infeasible_;
    infeasible_ = NULL;
    delete savedWeights_;
    savedWeights_ = NULL;
  }
  state_ = -1;
}
// Returns true if would not find any row
bool
AbcDualRowSteepest::looksOptimal() const
{
  int iRow;
  double tolerance = model_->currentPrimalTolerance();
  // we can't really trust infeasibilities if there is primal error
  // this coding has to mimic coding in checkPrimalSolution
  double error = CoinMin(1.0e-2, model_->largestPrimalError());
  // allow tolerance at least slightly bigger than standard
  tolerance = tolerance +  error;
  // But cap
  tolerance = CoinMin(1000.0, tolerance);
  int numberRows = model_->numberRows();
  int numberInfeasible = 0;
  const double *  COIN_RESTRICT solutionBasic = model_->solutionBasic();
  const double *  COIN_RESTRICT lowerBasic = model_->lowerBasic();
  const double *  COIN_RESTRICT upperBasic = model_->upperBasic();
  for (iRow = 0; iRow < numberRows; iRow++) {
    double value = solutionBasic[iRow];
    double lower = lowerBasic[iRow];
    double upper = upperBasic[iRow];
    if (value < lower - tolerance) {
      numberInfeasible++;
    } else if (value > upper + tolerance) {
      numberInfeasible++;
    }
  }
  return (numberInfeasible == 0);
}
