/* $Id: AbcSimplexFactorization.cpp 2165 2015-09-06 09:00:21Z forrest $ */
// 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).
#define USE_DENSE_FAC -1
#define USE_SMALL_FAC 200
#define USE_LONG_FAC 10000
#include "CoinPragma.hpp"
#include "AbcSimplexFactorization.hpp"
#include "ClpFactorization.hpp"
#include "ClpMessage.hpp"
#include "CoinAbcCommon.hpp"
#include "CoinHelperFunctions.hpp"
#include "CoinIndexedVector.hpp"
#include "AbcSimplex.hpp"
#include "AbcSimplexDual.hpp"
#include "AbcMatrix.hpp"
#include "CoinAbcFactorization.hpp"
#include "CoinFactorization.hpp"
#ifdef ABC_JUST_ONE_FACTORIZATION
#define CoinAbcFactorization CoinAbcBaseFactorization
#define CoinAbcSmallFactorization CoinAbcBaseFactorization
#define CoinAbcLongFactorization CoinAbcBaseFactorization
#define CoinAbcOrderedFactorization CoinAbcBaseFactorization
#endif
#ifndef ABC_LONG_FACTORIZATION
#undef CoinAbcLongFactorization
#define CoinAbcLongFactorization CoinAbcOrderedFactorization
#endif
#ifdef ABC_TEMPORARY_FACTORIZATION
#undef CoinAbcSmallFactorization
#define CoinAbcSmallFactorization CoinAbcOrderedFactorization
#endif
#ifdef ABC_USE_COIN_FACTORIZATION
#undef CoinAbcFactorization
#undef CoinAbcSmallFactorization
#undef CoinAbcLongFactorization
#undef CoinAbcOrderedFactorization
#define CoinAbcFactorization CoinFactorization
#define CoinAbcSmallFactorization CoinFactorization
#define CoinAbcLongFactorization CoinFactorization
#define CoinAbcOrderedFactorization CoinFactorization
#endif
#ifndef ABC_USE_COIN_FACTORIZATION
#undef CLP_FACTORIZATION_NEW_TIMING
#else
#ifndef CLP_FACTORIZATION_NEW_TIMING
#define CLP_FACTORIZATION_NEW_TIMING 1
#endif
#endif
//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
AbcSimplexFactorization::AbcSimplexFactorization (int /*numberRows*/)
{
  model_=NULL;
  coinAbcFactorization_ = new CoinAbcFactorization();
  forceB_ = 0;
  goDenseThreshold_ = USE_DENSE_FAC;
  goSmallThreshold_ = USE_SMALL_FAC;
  goLongThreshold_ = USE_LONG_FAC;
  numberSlacks_=0;
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
AbcSimplexFactorization::AbcSimplexFactorization (const AbcSimplexFactorization & rhs,
						  int denseIfSmaller)
{
  forceB_ = rhs.forceB_;
  goDenseThreshold_ = rhs.goDenseThreshold_;
  goSmallThreshold_ = rhs.goSmallThreshold_;
  goLongThreshold_ = rhs.goLongThreshold_;
  numberSlacks_=rhs.numberSlacks_;
  model_=rhs.model_;
#ifndef ABC_USE_COIN_FACTORIZATION
  int goDense = 0;
  if (denseIfSmaller > 0 && denseIfSmaller <= goDenseThreshold_) {
    CoinAbcDenseFactorization * denseR =
      dynamic_cast<CoinAbcDenseFactorization *>(rhs.coinAbcFactorization_);
    if (!denseR)
      goDense = 1;
  }
  if (denseIfSmaller > 0 && !rhs.coinAbcFactorization_) {
    if (denseIfSmaller <= goDenseThreshold_)
      goDense = 1;
    else if (denseIfSmaller <= goSmallThreshold_)
      goDense = 2;
    else if (denseIfSmaller >= goLongThreshold_)
      goDense = 3;
  } else if (denseIfSmaller < 0) {
    if (-denseIfSmaller <= goDenseThreshold_)
      goDense = 1;
    else if (-denseIfSmaller <= goSmallThreshold_)
      goDense = 2;
    else if (-denseIfSmaller >= goLongThreshold_)
      goDense = 3;
  }
  if (rhs.coinAbcFactorization_ && (denseIfSmaller >= 0 || !goDense))
    coinAbcFactorization_ = rhs.coinAbcFactorization_->clone();
  else
    coinAbcFactorization_ = NULL;
  if (goDense) {
    delete coinAbcFactorization_;
    if (goDense == 1)
      coinAbcFactorization_ = new CoinAbcDenseFactorization();
    else if (goDense == 2)
      coinAbcFactorization_ = new CoinAbcSmallFactorization();
    else if (goDense == 3)
      coinAbcFactorization_ = new CoinAbcLongFactorization();
    else
      coinAbcFactorization_ = new CoinAbcFactorization();
    assert (coinAbcFactorization_);
    coinAbcFactorization_->maximumPivots(rhs.coinAbcFactorization_->maximumPivots());
    coinAbcFactorization_->pivotTolerance(rhs.coinAbcFactorization_->pivotTolerance());
    coinAbcFactorization_->zeroTolerance(rhs.coinAbcFactorization_->zeroTolerance());
  }
#else
  coinAbcFactorization_ = new CoinFactorization(*rhs.coinAbcFactorization_);
#endif
}
//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
AbcSimplexFactorization::~AbcSimplexFactorization ()
{
  delete coinAbcFactorization_;
}

//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
AbcSimplexFactorization &
AbcSimplexFactorization::operator=(const AbcSimplexFactorization& rhs)
{
  if (this != &rhs) {
    forceB_ = rhs.forceB_;
    model_=rhs.model_;
    goDenseThreshold_ = rhs.goDenseThreshold_;
    goSmallThreshold_ = rhs.goSmallThreshold_;
    goLongThreshold_ = rhs.goLongThreshold_;
    numberSlacks_=rhs.numberSlacks_;
    
    if (rhs.coinAbcFactorization_) {
      delete coinAbcFactorization_;
#ifndef ABC_USE_COIN_FACTORIZATION
      coinAbcFactorization_ = rhs.coinAbcFactorization_->clone();
#else
      coinAbcFactorization_ = new CoinFactorization(*rhs.coinAbcFactorization_);
#endif
    }
  }
  return *this;
}
// Go over to dense code
void
AbcSimplexFactorization::goDenseOrSmall(int numberRows)
{
#ifndef ABC_USE_COIN_FACTORIZATION
  if (!forceB_) {
    delete coinAbcFactorization_;
    if (numberRows <= goDenseThreshold_) {
      coinAbcFactorization_ = new CoinAbcDenseFactorization();
    } else if (numberRows <= goSmallThreshold_) {
      coinAbcFactorization_ = new CoinAbcSmallFactorization();
    } else if (numberRows >= goLongThreshold_) {
      coinAbcFactorization_ = new CoinAbcLongFactorization();
    } else {
      coinAbcFactorization_ = new CoinAbcFactorization();
    }
  }
#endif
}
// If nonzero force use of 1,dense 2,small 3,long
void
AbcSimplexFactorization::forceOtherFactorization(int which)
{
#ifndef ABC_USE_COIN_FACTORIZATION
  delete coinAbcFactorization_;
  forceB_ = 0;
  coinAbcFactorization_ = NULL;
  if (which > 0 && which < 6) {
    forceB_ = which;
    switch (which) {
    case 1:
      coinAbcFactorization_ = new CoinAbcDenseFactorization();
      goDenseThreshold_ = COIN_INT_MAX;
      break;
    case 2:
    case 4:
      coinAbcFactorization_ = new CoinAbcSmallFactorization();
      goSmallThreshold_ = COIN_INT_MAX;
      break;
    case 3:
    case 5:
      coinAbcFactorization_ = new CoinAbcLongFactorization();
      goLongThreshold_ = 0;
      break;
    }
  } else {
    coinAbcFactorization_ = new CoinAbcFactorization();
  }
#endif
}
#ifdef CLP_FACTORIZATION_NEW_TIMING
static bool readTwiddle=false;
static double weightIncU=1.0;
static double weightR=2.0;
static double weightRest=1.0;
static double weightFactL=30.0;
static double weightFactDense=0.1; 
static double weightNrows=10.0;
static double increaseNeeded=1.1;
static double constWeightIterate = 1.0;
static double weightNrowsIterate = 3.0;
bool 
AbcSimplexFactorization::timeToRefactorize() const 
{
  bool reFactor = (coinAbcFactorization_->pivots() * 3 > coinAbcFactorization_->maximumPivots() * 2 &&
		   coinAbcFactorization_->numberElementsR() * 3 > (coinAbcFactorization_->numberElementsL() +
								   coinAbcFactorization_->numberElementsU()) * 2 + 1000 &&
		   !coinAbcFactorization_->numberDense());
  bool reFactor3=false;
  int numberPivots=coinAbcFactorization_->pivots();
  //if (coinAbcFactorization_->pivots()<2)
  if (numberPivots>lastNumberPivots_) {
    if (!lastNumberPivots_) {
      //lastR=0;
      //lastU=endLengthU;
      totalInR_=0.0;
      totalInIncreasingU_=0.0;
      shortestAverage_=COIN_DBL_MAX;
      if (!readTwiddle) {
	readTwiddle=true;
	char * environ = getenv("CLP_TWIDDLE");
	if (environ) {
	  sscanf(environ,"%lg %lg %lg %lg %lg %lg %lg %lg %lg",
		 &weightIncU,&weightR,&weightRest,&weightFactL,
		 &weightFactDense,&weightNrows,&increaseNeeded,
		 &constWeightIterate,&weightNrowsIterate);
	}
	printf("weightIncU %g, weightR %g, weightRest %g, weightFactL %g, weightFactDense %g, weightNrows %g increaseNeeded %g constWeightIterate %g weightNrowsIterate %g\n",
	       weightIncU,weightR,weightRest,weightFactL,
	       weightFactDense,weightNrows,increaseNeeded,
	       constWeightIterate,weightNrowsIterate);
      }
    }
    lastNumberPivots_=numberPivots;
    int numberDense=coinAbcFactorization_->numberDense();
    double nnd=numberDense*numberDense;
    int lengthL=coinAbcFactorization_->numberElementsL();
    int lengthR=coinAbcFactorization_->numberElementsR();
    int numberRows = coinAbcFactorization_->numberRows();
    int lengthU=coinAbcFactorization_->numberElementsU()-
      (numberRows-numberDense);
    totalInR_ += lengthR;
    int effectiveU=lengthU-effectiveStartNumberU_;
    totalInIncreasingU_ += effectiveU;
    //lastR=lengthR;
    //lastU=lengthU;
    double rest=lengthL+0.05*nnd;
    double constWeightFactor = weightFactL*lengthL+weightFactDense*nnd
      + weightNrows*numberRows;
    double constWeightIterateX = constWeightIterate*(lengthL+endLengthU_)
      + weightNrowsIterate*numberRows;
    double variableWeight = weightIncU*totalInIncreasingU_+
      weightR*totalInR_+weightRest*rest;
    double average=constWeightIterateX+
      (constWeightFactor+variableWeight)/static_cast<double>(numberPivots);
#if 0
    if ((numberPivots%20)==0&&!ifPrint3)
      printf("PIV %d nrow %d startU %d now %d L %d R %d dense %g average %g\n",
	     numberPivots,numberRows,effectiveStartNumberU_,
	     lengthU,lengthL,lengthR,nnd,average);
#endif
    shortestAverage_=CoinMin(shortestAverage_,average);
    if (average>increaseNeeded*shortestAverage_&&
	coinAbcFactorization_->pivots()>30) {
      //printf("PIVX %d nrow %d startU %d now %d L %d R %d dense %g average %g\n",
      //     numberPivots,numberRows,effectiveStartNumberU_,
      //     lengthU,lengthL,lengthR,nnd,average);
      reFactor3=true;
    }
  }
  if (reFactor|| reFactor3) {
    reFactor=true;
  }
  return reFactor;
}
#if CLP_FACTORIZATION_NEW_TIMING>1
void 
AbcSimplexFactorization::statsRefactor(char when) const
{
  int numberPivots=coinAbcFactorization_->pivots();
  int numberDense=coinAbcFactorization_->numberDense();
  double nnd=numberDense*numberDense;
  int lengthL=coinAbcFactorization_->numberElementsL();
  int lengthR=coinAbcFactorization_->numberElementsR();
  int numberRows = coinAbcFactorization_->numberRows();
  int lengthU=coinAbcFactorization_->numberElementsU()-
    (numberRows-numberDense);
  double rest=lengthL+0.05*nnd;
  double constWeightFactor = weightFactL*lengthL+weightFactDense*nnd
    + weightNrows*numberRows;
  double constWeightIterateX = constWeightIterate*(lengthL+endLengthU_)
    + weightNrowsIterate*numberRows;
  double variableWeight = weightIncU*totalInIncreasingU_+
    weightR*totalInR_+weightRest*rest;
  double average=constWeightIterateX+
    (constWeightFactor+variableWeight)/static_cast<double>(numberPivots);
  printf("APIV%c %d nrow %d startU %d now %d L %d R %d dense %g average %g - shortest %g\n",
	 when,numberPivots,numberRows,effectiveStartNumberU_,
	 lengthU,lengthL,lengthR,nnd,average,shortestAverage_);
}
#endif
#else
bool 
AbcSimplexFactorization::timeToRefactorize() const 
{
  return coinAbcFactorization_->pivots() > coinAbcFactorization_->numberRows() / 2.45 + 20;
}
#endif
/* returns empty fake vector carved out of existing
   later - maybe use associated arrays */
static CoinIndexedVector * fakeVector(CoinIndexedVector * vector,
				      int fakeCapacity)
{
  int oldCapacity=vector->capacity();
  CoinIndexedVector * newVector = new CoinIndexedVector();
  newVector->setCapacity(fakeCapacity);
  newVector->setDenseVector(vector->denseVector()+oldCapacity);
  newVector->setIndexVector(vector->getIndices()+
			    oldCapacity+((oldCapacity+3)>>2));
  vector->checkClean();
  newVector->checkClear();
  return newVector;
}
static void deleteFakeVector(CoinIndexedVector * vector,
			     CoinIndexedVector * fakeVector)
{
  int * index = vector->getIndices();
  fakeVector->checkClear();
  fakeVector->setCapacity(0);
  fakeVector->setDenseVector(NULL);
  fakeVector->setIndexVector(NULL);
  delete fakeVector;
  vector->checkClean();
}
// Synchronize stuff
void 
AbcSimplexFactorization::synchronize(const ClpFactorization * otherFactorization,const AbcSimplex * model)
{
  goDenseThreshold_=otherFactorization->goDenseThreshold();
  goSmallThreshold_=otherFactorization->goSmallThreshold();
  goLongThreshold_=otherFactorization->goOslThreshold();
  //forceOtherFactorization(otherFactorization->typeOfFactorization());
  goDenseOrSmall(model->numberRows());
  maximumPivots(static_cast<int>(otherFactorization->maximumPivots()*1.2));
#ifdef ABC_USE_COIN_FACTORIZATION
  // redo region sizes
  int maximumRows=model->numberRows()+maximumPivots()+1;
  int currentCapacity = model->usefulArray(0)->capacity();
  int newCapacity = currentCapacity+maximumRows+3;
  for (int i=0;i<ABC_NUMBER_USEFUL;i++) {
    CoinPartitionedVector * vector = model->usefulArray(i);
    vector->reserve(newCapacity);
    // zero 
    CoinZeroN(vector->getIndices(),newCapacity);
    // but pretend old
    //vector->setCapacity(currentCapacity);
#if 0 //ndef NDEBUG
    vector->checkClear();
    CoinIndexedVector * newVector = fakeVector(vector,maximumRows);
    deleteFakeVector(vector,newVector);
#endif
  }
#endif
}
#ifdef CLP_FACTORIZATION_INSTRUMENT
extern double externalTimeStart;
extern double timeInFactorize;
extern double timeInUpdate;
extern double timeInUpdateTranspose;
extern double timeInUpdateFT;
extern double timeInUpdateTwoFT;
extern double timeInReplace;
extern int numberUpdate;
extern int numberUpdateTranspose;
extern int numberUpdateFT;
extern int numberUpdateTwoFT;
extern int numberReplace;
extern int currentLengthR;
extern int currentLengthU;
extern int currentTakeoutU;
#endif
int
AbcSimplexFactorization::factorize ( AbcSimplex * model,
				     int solveType, bool valuesPass)
{
#ifdef CLP_FACTORIZATION_INSTRUMENT
  externalTimeStart=CoinCpuTime();
#endif
  model_= model;
  AbcMatrix * matrix = model->abcMatrix();
  int numberRows = model->numberRows();
  if (!numberRows)
    return 0;
  bool anyChanged = false;
  coinAbcFactorization_->setStatus(-99);
#ifndef ABC_USE_COIN_FACTORIZATION
  const
#endif 
    int *  COIN_RESTRICT pivotVariable = model->pivotVariable();
  //returns 0 -okay, -1 singular, -2 too many in basis */
  // allow dense
  int solveMode = coinAbcFactorization_->solveMode()&1;
  if (model->numberIterations()>model->baseIteration())
    solveMode |= 9;  // was +8 - this allows dense
  else
    solveMode = 1; // try dense
  if (valuesPass)
    solveMode += 4;
  coinAbcFactorization_->setSolveMode(solveMode);
  while (status() < -98) {
    
    int i;
    int numberBasic = 0;
    // Move pivot variables across if they look good
    int *  COIN_RESTRICT pivotTemp = model->usefulArray(0)->getIndices();
#ifndef NDEBUG
    model_->checkArrays();
#endif
    assert (!model->usefulArray(0)->getNumElements());
    // Seems to prefer things in order so quickest
    // way is to go though like this
    for (i = 0; i < numberRows; i++) {
      if (pivotVariable[i]<numberRows)
	pivotTemp[numberBasic++] = pivotVariable[i];
    }
    numberSlacks_ = numberBasic;
    /* Put column basic variables into pivotVariable
    */
    for (i = 0; i < numberRows; i++) {
      if (pivotVariable[i]>=numberRows)
	pivotTemp[numberBasic++] = pivotVariable[i];
    }
    CoinBigIndex numberElements = numberSlacks_;
    
    // compute how much in basis
    int numberColumnBasic = numberBasic - numberSlacks_;
    
    numberElements += matrix->countBasis(pivotTemp + numberSlacks_,
					 numberColumnBasic);
    //printf("Basis has %d slacks - size %d\n",numberSlacks_,numberElements);
    // Not needed for dense
    numberElements = 3 * numberBasic + 3 * numberElements + 20000;
#ifndef ABC_USE_COIN_FACTORIZATION
    int numberIterations = model->numberIterations();
    coinAbcFactorization_->setUsefulInformation(&numberIterations, 0);
#else
    coinAbcFactorization_->gutsOfDestructor();
    coinAbcFactorization_->gutsOfInitialize(2);
#endif
    coinAbcFactorization_->getAreas ( numberRows,
				    numberSlacks_ + numberColumnBasic, numberElements,
				    2 * numberElements );
#if 0
    if (!model->numberIterations())
      printf("do I need destructor etc in getAreas?\n");
#endif
    // Fill in counts so we can skip part of preProcess
    // This is NOT needed for dense but would be needed for later versions
    CoinFactorizationDouble *  COIN_RESTRICT elementU;
    int *  COIN_RESTRICT indexRowU;
    CoinBigIndex *  COIN_RESTRICT startColumnU;
    int *  COIN_RESTRICT numberInRow;
    int *  COIN_RESTRICT numberInColumn;
#define slackValue 1.0
#ifndef ABC_USE_COIN_FACTORIZATION
    elementU = coinAbcFactorization_->elements();
    indexRowU = coinAbcFactorization_->indices();
    startColumnU = coinAbcFactorization_->starts();
    numberInRow = coinAbcFactorization_->numberInRow();
    numberInColumn = coinAbcFactorization_->numberInColumn();
    coinAbcFactorization_->setNumberSlacks(numberSlacks_);
    CoinZeroN ( numberInRow, numberRows  );
    CoinZeroN ( numberInColumn, numberRows );
#else
    elementU = coinAbcFactorization_->elementU();
    indexRowU = coinAbcFactorization_->indexRowU();
    startColumnU = coinAbcFactorization_->startColumnU();
    numberInRow = coinAbcFactorization_->numberInRow();
    numberInColumn = coinAbcFactorization_->numberInColumn();
    CoinZeroN ( numberInRow, coinAbcFactorization_->numberRows() + 1 );
    CoinZeroN ( numberInColumn, coinAbcFactorization_->maximumColumnsExtra() + 1 );
#endif
    for (i = 0; i < numberSlacks_; i++) {
      int iRow = pivotTemp[i];
      indexRowU[i] = iRow;
      startColumnU[i] = i;
      elementU[i] = slackValue;
      numberInRow[iRow] = 1;
      numberInColumn[i] = 1;
    }
    startColumnU[numberSlacks_] = numberSlacks_;
    // can change for gub so redo
    numberColumnBasic = numberRows - numberSlacks_;
    matrix->fillBasis(pivotTemp + numberSlacks_,
		      numberColumnBasic,
		      indexRowU,
		      startColumnU + numberSlacks_,
		      numberInRow,
		      numberInColumn + numberSlacks_,
		      elementU);
    numberElements = startColumnU[numberRows-1]
      + numberInColumn[numberRows-1];
#ifndef ABC_USE_COIN_FACTORIZATION
    coinAbcFactorization_->preProcess ( );
    coinAbcFactorization_->factor (model);
#else
    // recompute number basic
    numberBasic = numberSlacks_ + numberColumnBasic;
    if (numberBasic)
      numberElements = startColumnU[numberBasic-1]
	+ numberInColumn[numberBasic-1];
    else
      numberElements = 0;
    coinAbcFactorization_->setNumberElementsU(numberElements);
#ifdef CLP_FACTORIZATION_NEW_TIMING
    lastNumberPivots_=0;
    effectiveStartNumberU_=numberElements-numberRows;
    //printf("%d slacks,%d in U at beginning\n",
    //numberRowBasic,numberElements);
#endif
    //saveFactorization("dump.d");
    if (coinAbcFactorization_->biasLU() >= 3 || coinAbcFactorization_->numberRows() != coinAbcFactorization_->numberColumns())
      coinAbcFactorization_->preProcess ( 2 );
    else
      coinAbcFactorization_->preProcess ( 3 ); // no row copy
    coinAbcFactorization_->factor (  );
#endif
#if 0
    if (model_->numberIterations()==23) {
      CoinAbcFactorization * factor = dynamic_cast<CoinAbcFactorization *>(coinAbcFactorization_);
      if (factor)
	factor->show_self();
    }
#endif
    if (coinAbcFactorization_->status() == -1 &&
	(coinAbcFactorization_->solveMode() & 1) != 0) {
      int solveMode = coinAbcFactorization_->solveMode();
      solveMode --; // so bottom will be 0
      coinAbcFactorization_->setSolveMode(solveMode);
      coinAbcFactorization_->setStatus(-99);
    } else if (coinAbcFactorization_->status() == -99) {
      // get more memory
      coinAbcFactorization_->areaFactor( coinAbcFactorization_->areaFactor() * 2.0);
    }
    if (coinAbcFactorization_->status() == -99) 
      continue;
    // If we get here status is 0 or -1
    if (coinAbcFactorization_->status() == 0 && numberBasic == numberRows) {
#ifndef ABC_USE_COIN_FACTORIZATION
      coinAbcFactorization_->postProcess(pivotTemp, model->pivotVariable());
#else
      const int * permuteBack = coinAbcFactorization_->permuteBack();
      const int * back = coinAbcFactorization_->pivotColumnBack();
      // Redo pivot order
      for (i = 0; i < numberRows; i++) {
	int k = pivotTemp[i];
	// so rowIsBasic[k] would be permuteBack[back[i]]
	int j = permuteBack[back[i]];
	//assert (pivotVariable[j] == -1);
	pivotVariable[j] = k;
      }
      // Set up permutation vector
      // these arrays start off as copies of permute
      // (and we could use permute_ instead of pivotColumn (not back though))
      ClpDisjointCopyN ( coinAbcFactorization_->permute(), numberRows , coinAbcFactorization_->pivotColumn()  );
      ClpDisjointCopyN ( coinAbcFactorization_->permuteBack(), numberRows , coinAbcFactorization_->pivotColumnBack()  );
      // See if worth going sparse and when
      coinAbcFactorization_->checkSparse();
#ifdef CLP_FACTORIZATION_NEW_TIMING
      endLengthU_ = coinAbcFactorization_->numberElements() - 
	coinAbcFactorization_->numberDense()*coinAbcFactorization_->numberDense()
	-coinAbcFactorization_->numberElementsL();
#endif
#endif
      model_->moveToBasic();
    } else if (solveType == 0 || solveType == 2/*||solveType==1*/) {
      // Change pivotTemp to be correct list
      anyChanged = true;
      coinAbcFactorization_->makeNonSingular(pivotTemp);
      const double *  COIN_RESTRICT lowerArray = model->lowerRegion();
      const double *  COIN_RESTRICT upperArray = model->upperRegion();
      double *  COIN_RESTRICT solution = model->solutionRegion();
      //int * pivotVariable=model_->pivotVariable();
      //int * fromExternal=model_->fromExternal();
      int numberTotal=model_->numberTotal();
      //can use external status_
      unsigned char *  COIN_RESTRICT statusArray = model_->statusArray();
      CoinAbcMemset0(statusArray,numberTotal);
      for (int iRow=0;iRow<numberRows;iRow++) {
	int iPivot=pivotVariable[iRow];
	//if (iPivot!=pivotTemp[iRow])
	//printf("row %d bad pivot %d good %d\n",iRow,iPivot,pivotTemp[iRow]);
	statusArray[iPivot]=1;
      }
      for (int iRow=0;iRow<numberRows;iRow++) {
	int iPivot=pivotTemp[iRow];
	statusArray[iPivot]|=2;
      }
      int jPivot=0;
      double largeValue = model->largeValue();
      for (int iRow=0;iRow<numberRows;iRow++) {
	int iPivot=pivotVariable[iRow];
	if (statusArray[iPivot]==1) {
	  // clean
	  while (statusArray[jPivot]!=2) {
	    jPivot++;
	  }
	  statusArray[iPivot]=0;
	  statusArray[jPivot]=0;
#ifndef NDEBUG
	  printf("On Row %d replacing %d by %d\n",iRow,iPivot,jPivot);
#endif
	  AbcSimplex::Status thisStatus;
	  if (!valuesPass) {
	    double lower = lowerArray[iPivot];
	    double upper = upperArray[iPivot];
	    double value = solution[iPivot];
	    if (lower > -largeValue || upper < largeValue) {
	      if (lower!=upper) {
		if (fabs(value - lower) < fabs(value - upper)) {
		  thisStatus=AbcSimplex::atLowerBound;
		  solution[iPivot] = lower;
		} else {
		  thisStatus= AbcSimplex::atUpperBound;
		  solution[iPivot] = upper;
		}
	      } else {
		thisStatus= AbcSimplex::isFixed;
	      }
	    } else {
	      thisStatus=AbcSimplex::isFree;
	    }
	  } else {
	    thisStatus=AbcSimplex::superBasic;
	  }
	  model_->setInternalStatus(iPivot,thisStatus);
	  model_->setInternalStatus(jPivot,AbcSimplex::basic);
	  // swap (solution will be wrong - but that doesn't matter as basic)
	  model_->swap(iRow,jPivot);
	}
      }
      CoinAbcMemcpy(model_->pivotVariable(),pivotTemp,numberRows);
#ifndef NDEBUG
      model_->checkConsistentPivots();
#endif
      // signal repeat
      coinAbcFactorization_->pivotTolerance(0.999);
      coinAbcFactorization_->setStatus(-99);
    }
  }
  //coinAbcFactorization_->setSolveMode(solveMode|1);
  if ( anyChanged && model->algorithm() < 0 && solveType > 0) {
    double dummyCost;
    static_cast<AbcSimplexDual *> (model)->changeBounds(3,dummyCost);
  }
  return coinAbcFactorization_->status();
}
#if 0
/* Checks if can replace one Column to basis,
   returns 0=OK, 1=Probably OK, 2=singular, 3=no room, 5 max pivots
   Fills in region for use later
   partial update already in U */
int 
AbcSimplexFactorization::checkReplace ( const AbcSimplex * model,
					CoinIndexedVector * regionSparse,
					int pivotRow,
					double &pivotCheck,
					double acceptablePivot)
{
  if (pivots()==maximumPivots())
    return 5;
  else 
    return coinAbcFactorization_->checkReplace(model,regionSparse,pivotRow,pivotCheck,acceptablePivot);
}
/* Replaces one Column in basis,
   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
   If skipBtranU is false will do btran part
   partial update already in U */
int
AbcSimplexFactorization::replaceColumn ( const AbcSimplex * model,
					 CoinIndexedVector * regionSparse,
					 CoinIndexedVector * tableauColumn,
					 int pivotRow,
					 double pivotCheck ,
					 bool skipBtranU,
					 double acceptablePivot)
{
  bool tab = coinAbcFactorization_->wantsTableauColumn();
  int tempInfo[1];
  tempInfo[0] = model->numberIterations();
  coinAbcFactorization_->setUsefulInformation(tempInfo, 1);
#ifdef CLP_FACTORIZATION_NEW_TIMING
  int nOld=0;
  int nNew=0;
  int seq;
  const CoinPackedMatrix * matrix=model->matrix();
  const int * columnLength = matrix->getVectorLengths();
  seq=model->sequenceIn();
  if (seq>=0&&seq<model->numberColumns()+model->numberRows()) {
    if (seq<model->numberRows())
      nNew=1;
    else
      nNew=columnLength[seq-model->numberRows()];
  }
  seq=model->sequenceOut();
  if (seq>=0&&seq<model->numberColumns()+model->numberRows()) {
    if (seq<model->numberRows())
      nOld=1;
    else
      nOld=columnLength[seq-model->numberRows()];
  }
  effectiveStartNumberU_ += nNew-nOld;
#endif
  int returnCode =
    coinAbcFactorization_->replaceColumn(tab ? tableauColumn : regionSparse,
				       pivotRow,
				       pivotCheck,
				       skipBtranU,
				       acceptablePivot);
  return returnCode;
}
#endif
/* Replaces one Column to basis,
   partial update already in U */
void 
AbcSimplexFactorization::replaceColumnPart3 ( const AbcSimplex * model,
					      CoinIndexedVector * regionSparse,
					      CoinIndexedVector * tableauColumn,
					      int pivotRow,
#ifdef ABC_LONG_FACTORIZATION 
					      long
#endif
					      double alpha )
{
#ifndef ABC_USE_COIN_FACTORIZATION
  bool tab = coinAbcFactorization_->wantsTableauColumn();
  int tempInfo[1];
  tempInfo[0] = model->numberIterations();
  coinAbcFactorization_->setUsefulInformation(tempInfo, 1);
  if (tab)
    coinAbcFactorization_->replaceColumnPart3(model,NULL,tableauColumn,
				       pivotRow,
					      tableauColumn->denseVector()[pivotRow]);
  else
    coinAbcFactorization_->replaceColumnPart3(model,regionSparse,NULL,
					      pivotRow,
					      alpha);
#else
#ifdef CLP_FACTORIZATION_NEW_TIMING
  int nOld=0;
  int nNew=0;
  int seq;
  const CoinPackedMatrix * matrix=model->matrix();
  const int * columnLength = matrix->getVectorLengths();
  seq=model->sequenceIn();
  if (seq>=0&&seq<model->numberColumns()+model->numberRows()) {
    if (seq<model->numberRows())
      nNew=1;
    else
      nNew=columnLength[seq-model->numberRows()];
  }
  seq=model->sequenceOut();
  if (seq>=0&&seq<model->numberColumns()+model->numberRows()) {
    if (seq<model->numberRows())
      nOld=1;
    else
      nOld=columnLength[seq-model->numberRows()];
  }
  effectiveStartNumberU_ += nNew-nOld;
#endif
  coinAbcFactorization_->replaceColumnPart3(regionSparse,
					      pivotRow,
					      alpha);
#endif
}
/* Replaces one Column to basis,
   partial update in vector */
void 
AbcSimplexFactorization::replaceColumnPart3 ( const AbcSimplex * model,
					      CoinIndexedVector * regionSparse,
					      CoinIndexedVector * tableauColumn,
					      CoinIndexedVector * partialUpdate,
					      int pivotRow,
#ifdef ABC_LONG_FACTORIZATION 
					      long
#endif
					      double alpha )
{
#ifndef ABC_USE_COIN_FACTORIZATION
  bool tab = coinAbcFactorization_->wantsTableauColumn();
  int tempInfo[1];
  tempInfo[0] = model->numberIterations();
  coinAbcFactorization_->setUsefulInformation(tempInfo, 1);
  if (tab)
    coinAbcFactorization_->replaceColumnPart3(model,NULL,tableauColumn,
					      pivotRow,
					      tableauColumn->denseVector()[pivotRow]);
  else
    coinAbcFactorization_->replaceColumnPart3(model,regionSparse,NULL,partialUpdate,
					      pivotRow,
					      alpha);
#else
    coinAbcFactorization_->replaceColumnPart3(regionSparse,partialUpdate,
					      pivotRow,
					      alpha);
#endif
}
#if 0
/* Updates one column (FTRAN) from region2
   number returned is negative if no room
   region1 starts as zero and is zero at end */
int
AbcSimplexFactorization::updateColumnFT ( CoinIndexedVector * regionSparse,
					  CoinIndexedVector * regionSparse2)
{
  if (!numberRows())
    return 0;
  int returnCode;
  returnCode = coinAbcFactorization_->updateColumnFT(regionSparse,
						   regionSparse2);
  return returnCode;
}
/* Updates one column (FTRAN) from region2
   number returned is negative if no room
   region1 starts as zero and is zero at end */
int
AbcSimplexFactorization::updateColumn ( CoinIndexedVector * regionSparse,
					CoinIndexedVector * regionSparse2) const
{
  if (!numberRows())
    return 0;
  int returnCode;
  returnCode = coinAbcFactorization_->updateColumn(regionSparse,
						 regionSparse2,true);
  return returnCode;
}
/* Updates one column (FTRAN) from region2
   Tries to do FT update
   number returned is negative if no room.
   Also updates region3
   region1 starts as zero and is zero at end */
int
AbcSimplexFactorization::updateTwoColumnsFT ( CoinIndexedVector * regionSparse1,
					      CoinIndexedVector * regionSparse2,
					      CoinIndexedVector * regionSparse3)
{
  if (!numberRows())
    return 0;
  int returnCode = 0;
  returnCode = 
    coinAbcFactorization_->updateTwoColumnsFT(
					    regionSparse1,
					    regionSparse2,
					    regionSparse3,
					    true);
  return returnCode;
}
/* Updates one column (BTRAN) from region2
   region1 starts as zero and is zero at end */
int
AbcSimplexFactorization::updateColumnTranspose ( CoinIndexedVector * regionSparse,
						 CoinIndexedVector * regionSparse2) const
{
  if (!numberRows())
    return 0;
  int returnCode;
  returnCode = coinAbcFactorization_->updateColumnTranspose(regionSparse,
							  regionSparse2);
  return returnCode;
}
/* Updates one column for dual steepest edge weights (FTRAN) */
void 
AbcSimplexFactorization::updateWeights ( CoinIndexedVector & regionSparse) const
{
  // NOTE either switch off sparse or pass in a sparseArray_ so can go parallel
  // may be best to use inner product approach
  static double fraction[2]={0.0,0.0};
  static int times=0;
  times++;
  fraction[0] += static_cast<double>(regionSparse.getNumElements())/
    (static_cast<double>(model_->numberRows())+1.0);
  updateColumn(regionSparse);
  fraction[1] += static_cast<double>(regionSparse.getNumElements())/
    (static_cast<double>(model_->numberRows())+1.0);
  if ((times%1000)==0)
    printf("Average density %g before then %g\n",
	   (100.0*fraction[0])/static_cast<double>(times),
	   (100.0*fraction[1])/static_cast<double>(times));
}
#endif
/* makes a row copy of L for speed and to allow very sparse problems */
void
AbcSimplexFactorization::goSparse()
{
#ifdef ABC_USE_COIN_FACTORIZATION
  // sparse methods
  coinAbcFactorization_->sparseThreshold(0);
  coinAbcFactorization_->goSparse();
#else
  abort();
  coinAbcFactorization_->goSparse();
#endif
}
// Set tolerances to safer of existing and given
void
AbcSimplexFactorization::saferTolerances (  double zeroValue,
					    double pivotValue)
{
  double newValue1;
  // better to have small tolerance even if slower
  if (zeroValue > 0.0)
    newValue1 = zeroValue;
  else
    newValue1 = -zeroTolerance() * zeroValue; 
  newValue1 = CoinMin(zeroTolerance(),newValue1);
  if (newValue1>1.0e-15)
    zeroTolerance(newValue1);
  double  newValue2;
  // better to have large tolerance even if slower
  if (pivotValue > 0.0)
    newValue2 = pivotValue;
  else
    newValue2 = -pivotTolerance() * pivotValue;
  newValue2 =CoinMin(CoinMax(pivotTolerance(), newValue2), 0.999);
  if (newValue2>pivotTolerance()) {
    pivotTolerance(newValue2);
    char line[100];
    sprintf(line,"new zero tolerance %g new pivot tolerance %g",
	    zeroTolerance(),pivotTolerance());
    model_->messageHandler()->message(CLP_GENERAL2,*model_->messagesPointer())
      << line << CoinMessageEol;
  }
}
// Sets factorization
void
AbcSimplexFactorization::setFactorization(AbcSimplexFactorization & rhs)
{
  AbcSimplexFactorization::operator=(rhs);
}
