/* $Id$ */
// 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 <cstdio>
#include "CoinPragma.hpp"
#include "CoinIndexedVector.hpp"
#include "CoinHelperFunctions.hpp"
#include "CoinAbcHelperFunctions.hpp"
#include "AbcSimplexFactorization.hpp"
#include "AbcPrimalColumnDantzig.hpp"
#include "AbcPrimalColumnSteepest.hpp"
#include "CoinTime.hpp"

#include "AbcSimplex.hpp"
#include "AbcSimplexDual.hpp"
// at end to get min/max!
#include "AbcMatrix.hpp"
#include "ClpMessage.hpp"
#ifdef INTEL_MKL
#include "mkl_spblas.h"
#endif
#if ABC_INSTRUMENT > 1
extern int abcPricing[20];
extern int abcPricingDense[20];
#endif
//=============================================================================

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

//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
AbcMatrix::AbcMatrix()
  : matrix_(NULL)
  , model_(NULL)
  , rowStart_(NULL)
  , element_(NULL)
  , column_(NULL)
  , numberColumnBlocks_(0)
  , numberRowBlocks_(0)
  ,
#ifdef COUNT_COPY
  countRealColumn_(NULL)
  , countStartLarge_(NULL)
  , countRow_(NULL)
  , countElement_(NULL)
  , smallestCount_(0)
  , largestCount_(0)
  ,
#endif
  startFraction_(0.0)
  , endFraction_(1.0)
  , savedBestDj_(0.0)
  , originalWanted_(0)
  , currentWanted_(0)
  , savedBestSequence_(-1)
  , minimumObjectsScan_(-1)
  , minimumGoodReducedCosts_(-1)
{
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
AbcMatrix::AbcMatrix(const AbcMatrix &rhs)
{
#ifndef COIN_SPARSE_MATRIX
  matrix_ = new CoinPackedMatrix(*(rhs.matrix_), -1, -1);
#else
  matrix_ = new CoinPackedMatrix(*(rhs.matrix_), -0, -0);
#endif
  model_ = rhs.model_;
  rowStart_ = NULL;
  element_ = NULL;
  column_ = NULL;
#ifdef COUNT_COPY
  countRealColumn_ = NULL;
  countStartLarge_ = NULL;
  countRow_ = NULL;
  countElement_ = NULL;
#endif
  numberColumnBlocks_ = rhs.numberColumnBlocks_;
  CoinAbcMemcpy(startColumnBlock_, rhs.startColumnBlock_, numberColumnBlocks_ + 1);
  numberRowBlocks_ = rhs.numberRowBlocks_;
  if (numberRowBlocks_) {
    assert(model_);
    int numberRows = model_->numberRows();
    int numberElements = matrix_->getNumElements();
    memcpy(blockStart_, rhs.blockStart_, sizeof(blockStart_));
    rowStart_ = CoinCopyOfArray(rhs.rowStart_, numberRows * (numberRowBlocks_ + 2));
    element_ = CoinCopyOfArray(rhs.element_, numberElements);
    column_ = CoinCopyOfArray(rhs.column_, numberElements);
#ifdef COUNT_COPY
    smallestCount_ = rhs.smallestCount_;
    largestCount_ = rhs.largestCount_;
    int numberColumns = model_->numberColumns();
    countRealColumn_ = CoinCopyOfArray(rhs.countRealColumn_, numberColumns);
    memcpy(countStart_, rhs.countStart_, reinterpret_cast< char * >(&countRealColumn_) - reinterpret_cast< char * >(countStart_));
    int numberLarge = numberColumns - countStart_[MAX_COUNT];
    countStartLarge_ = CoinCopyOfArray(rhs.countStartLarge_, numberLarge + 1);
    numberElements = countStartLarge_[numberLarge];
    countElement_ = CoinCopyOfArray(rhs.countElement_, numberElements);
    countRow_ = CoinCopyOfArray(rhs.countRow_, numberElements);
#endif
  }
}

AbcMatrix::AbcMatrix(const CoinPackedMatrix &rhs)
{
#ifndef COIN_SPARSE_MATRIX
  matrix_ = new CoinPackedMatrix(rhs, -1, -1);
#else
  matrix_ = new CoinPackedMatrix(rhs, -0, -0);
#endif
  matrix_->cleanMatrix();
  model_ = NULL;
  rowStart_ = NULL;
  element_ = NULL;
  column_ = NULL;
#ifdef COUNT_COPY
  countRealColumn_ = NULL;
  countStartLarge_ = NULL;
  countRow_ = NULL;
  countElement_ = NULL;
  smallestCount_ = 0;
  largestCount_ = 0;
#endif
  numberColumnBlocks_ = 1;
  startColumnBlock_[0] = 0;
  startColumnBlock_[1] = 0;
  numberRowBlocks_ = 0;
  startFraction_ = 0;
  endFraction_ = 1.0;
  savedBestDj_ = 0;
  originalWanted_ = 0;
  currentWanted_ = 0;
  savedBestSequence_ = -1;
  minimumObjectsScan_ = -1;
  minimumGoodReducedCosts_ = -1;
}
#ifdef ABC_SPRINT
/* Subset constructor (without gaps). */
AbcMatrix::AbcMatrix(const AbcMatrix &wholeMatrix,
  int numberRows, const int *whichRows,
  int numberColumns, const int *whichColumns)
{
#ifndef COIN_SPARSE_MATRIX
  matrix_ = new CoinPackedMatrix(*wholeMatrix.matrix_, numberRows, whichRows,
    numberColumns, whichColumns);
#else
  matrix_ = new CoinPackedMatrix(rhs, -0, -0);
  abort();
#endif
  matrix_->cleanMatrix();
  model_ = NULL;
  rowStart_ = NULL;
  element_ = NULL;
  column_ = NULL;
#ifdef COUNT_COPY
  countRealColumn_ = NULL;
  countStartLarge_ = NULL;
  countRow_ = NULL;
  countElement_ = NULL;
  smallestCount_ = 0;
  largestCount_ = 0;
#endif
  numberColumnBlocks_ = 1;
  startColumnBlock_[0] = 0;
  startColumnBlock_[1] = 0;
  numberRowBlocks_ = 0;
  startFraction_ = 0;
  endFraction_ = 1.0;
  savedBestDj_ = 0;
  originalWanted_ = 0;
  currentWanted_ = 0;
  savedBestSequence_ = -1;
  minimumObjectsScan_ = -1;
  minimumGoodReducedCosts_ = -1;
}
#endif
//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
AbcMatrix::~AbcMatrix()
{
  delete matrix_;
  delete[] rowStart_;
  delete[] element_;
  delete[] column_;
#ifdef COUNT_COPY
  delete[] countRealColumn_;
  delete[] countStartLarge_;
  delete[] countRow_;
  delete[] countElement_;
#endif
}

//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
AbcMatrix &
AbcMatrix::operator=(const AbcMatrix &rhs)
{
  if (this != &rhs) {
    delete matrix_;
#ifndef COIN_SPARSE_MATRIX
    matrix_ = new CoinPackedMatrix(*(rhs.matrix_));
#else
    matrix_ = new CoinPackedMatrix(*(rhs.matrix_), -0, -0);
#endif
    model_ = rhs.model_;
    delete[] rowStart_;
    delete[] element_;
    delete[] column_;
#ifdef COUNT_COPY
    delete[] countRealColumn_;
    delete[] countStartLarge_;
    delete[] countRow_;
    delete[] countElement_;
#endif
    rowStart_ = NULL;
    element_ = NULL;
    column_ = NULL;
#ifdef COUNT_COPY
    countRealColumn_ = NULL;
    countStartLarge_ = NULL;
    countRow_ = NULL;
    countElement_ = NULL;
#endif
    numberColumnBlocks_ = rhs.numberColumnBlocks_;
    CoinAbcMemcpy(startColumnBlock_, rhs.startColumnBlock_, numberColumnBlocks_ + 1);
    numberRowBlocks_ = rhs.numberRowBlocks_;
    if (numberRowBlocks_) {
      assert(model_);
      int numberRows = model_->numberRows();
      int numberElements = matrix_->getNumElements();
      memcpy(blockStart_, rhs.blockStart_, sizeof(blockStart_));
      rowStart_ = CoinCopyOfArray(rhs.rowStart_, numberRows * (numberRowBlocks_ + 2));
      element_ = CoinCopyOfArray(rhs.element_, numberElements);
      column_ = CoinCopyOfArray(rhs.column_, numberElements);
#ifdef COUNT_COPY
      smallestCount_ = rhs.smallestCount_;
      largestCount_ = rhs.largestCount_;
      int numberColumns = model_->numberColumns();
      countRealColumn_ = CoinCopyOfArray(rhs.countRealColumn_, numberColumns);
      memcpy(countStart_, rhs.countStart_, reinterpret_cast< char * >(&countRealColumn_) - reinterpret_cast< char * >(countStart_));
      int numberLarge = numberColumns - countStart_[MAX_COUNT];
      countStartLarge_ = CoinCopyOfArray(rhs.countStartLarge_, numberLarge + 1);
      numberElements = countStartLarge_[numberLarge];
      countElement_ = CoinCopyOfArray(rhs.countElement_, numberElements);
      countRow_ = CoinCopyOfArray(rhs.countRow_, numberElements);
#endif
    }
    startFraction_ = rhs.startFraction_;
    endFraction_ = rhs.endFraction_;
    savedBestDj_ = rhs.savedBestDj_;
    originalWanted_ = rhs.originalWanted_;
    currentWanted_ = rhs.currentWanted_;
    savedBestSequence_ = rhs.savedBestSequence_;
    minimumObjectsScan_ = rhs.minimumObjectsScan_;
    minimumGoodReducedCosts_ = rhs.minimumGoodReducedCosts_;
  }
  return *this;
}
// Sets model
void AbcMatrix::setModel(AbcSimplex *model)
{
  model_ = model;
  int numberColumns = model_->numberColumns();
  bool needExtension = numberColumns > matrix_->getNumCols();
  if (needExtension) {
    CoinBigIndex lastElement = matrix_->getNumElements();
    matrix_->reserve(numberColumns, lastElement, true);
    CoinBigIndex *columnStart = matrix_->getMutableVectorStarts();
    for (int i = numberColumns; i >= 0; i--) {
      if (columnStart[i] == 0)
        columnStart[i] = lastElement;
      else
        break;
    }
    assert(lastElement == columnStart[numberColumns]);
  }
}
/* Returns a new matrix in reverse order without gaps */
CoinPackedMatrix *
AbcMatrix::reverseOrderedCopy() const
{
  CoinPackedMatrix *matrix = new CoinPackedMatrix();
  matrix->setExtraGap(0.0);
  matrix->setExtraMajor(0.0);
  matrix->reverseOrderedCopyOf(*matrix_);
  return matrix;
}
/// returns number of elements in column part of basis,
CoinBigIndex
AbcMatrix::countBasis(const int *whichColumn,
  int &numberColumnBasic)
{
  const int *COIN_RESTRICT columnLength = matrix_->getVectorLengths();
  CoinBigIndex numberElements = 0;
  int numberRows = model_->numberRows();
  // just count - can be over so ignore zero problem
  for (int i = 0; i < numberColumnBasic; i++) {
    int iColumn = whichColumn[i] - numberRows;
    numberElements += columnLength[iColumn];
  }
  return numberElements;
}
void AbcMatrix::fillBasis(const int *COIN_RESTRICT whichColumn,
  int &numberColumnBasic,
  int *COIN_RESTRICT indexRowU,
  int *COIN_RESTRICT start,
  int *COIN_RESTRICT rowCount,
  int *COIN_RESTRICT columnCount,
  CoinFactorizationDouble *COIN_RESTRICT elementU)
{
  const int *COIN_RESTRICT columnLength = matrix_->getVectorLengths();
  CoinBigIndex numberElements = start[0];
  // fill
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts();
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  int numberRows = model_->numberRows();
  for (int i = 0; i < numberColumnBasic; i++) {
    int iColumn = whichColumn[i] - numberRows;
    int length = columnLength[iColumn];
    CoinBigIndex startThis = columnStart[iColumn];
    columnCount[i] = length;
    CoinBigIndex endThis = startThis + length;
    for (CoinBigIndex j = startThis; j < endThis; j++) {
      int iRow = row[j];
      indexRowU[numberElements] = iRow;
      rowCount[iRow]++;
      assert(elementByColumn[j]);
      elementU[numberElements++] = elementByColumn[j];
    }
    start[i + 1] = numberElements;
  }
}
#ifdef ABC_LONG_FACTORIZATION
void AbcMatrix::fillBasis(const int *COIN_RESTRICT whichColumn,
  int &numberColumnBasic,
  int *COIN_RESTRICT indexRowU,
  int *COIN_RESTRICT start,
  int *COIN_RESTRICT rowCount,
  int *COIN_RESTRICT columnCount,
  long double *COIN_RESTRICT elementU)
{
  const int *COIN_RESTRICT columnLength = matrix_->getVectorLengths();
  CoinBigIndex numberElements = start[0];
  // fill
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts();
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  int numberRows = model_->numberRows();
  for (int i = 0; i < numberColumnBasic; i++) {
    int iColumn = whichColumn[i] - numberRows;
    int length = columnLength[iColumn];
    CoinBigIndex startThis = columnStart[iColumn];
    columnCount[i] = length;
    CoinBigIndex endThis = startThis + length;
    for (CoinBigIndex j = startThis; j < endThis; j++) {
      int iRow = row[j];
      indexRowU[numberElements] = iRow;
      rowCount[iRow]++;
      assert(elementByColumn[j]);
      elementU[numberElements++] = elementByColumn[j];
    }
    start[i + 1] = numberElements;
  }
}
#endif
#if 0 
/// Move largest in column to beginning
void 
AbcMatrix::moveLargestToStart()
{
  // get matrix data pointers
  int *  COIN_RESTRICT row = matrix_->getMutableIndices();
  const CoinBigIndex *  COIN_RESTRICT columnStart = matrix_->getVectorStarts();
  double *  COIN_RESTRICT elementByColumn = matrix_->getMutableElements();
  int numberColumns=model_->numberColumns();
  CoinBigIndex start = 0;
  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
    CoinBigIndex end = columnStart[iColumn+1];
    double largest=0.0;
    int position=-1;
    for (CoinBigIndex j = start; j < end; j++) {
      double value = fabs(elementByColumn[j]);
      if (value>largest) {
	largest=value;
	position=j;
      }
    }
    assert (position>=0); // ? empty column
    if (position>start) {
      double value=elementByColumn[start];
      elementByColumn[start]=elementByColumn[position];
      elementByColumn[position]=value;
      int iRow=row[start];
      row[start]=row[position];
      row[position]=iRow;
    }
    start=end;
  }
}
#endif
// Creates row copy
void AbcMatrix::createRowCopy()
{
#if ABC_PARALLEL
  if (model_->parallelMode() == 0)
#endif
    numberRowBlocks_ = 1;
#if ABC_PARALLEL
  else
    numberRowBlocks_ = CoinMin(NUMBER_ROW_BLOCKS, model_->numberCpus());
#endif
  int maximumRows = model_->maximumAbcNumberRows();
  int numberRows = model_->numberRows();
  int numberColumns = model_->numberColumns();
  int numberElements = matrix_->getNumElements();
  assert(!rowStart_);
  char *whichBlock_ = new char[numberColumns];
  rowStart_ = new CoinBigIndex[numberRows * (numberRowBlocks_ + 2)];
  element_ = new double[numberElements];
  column_ = new int[numberElements];
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts();
  memset(blockStart_, 0, sizeof(blockStart_));
  int ecount[10];
  assert(numberRowBlocks_ < 16);
  CoinAbcMemset0(ecount, 10);
  // allocate to blocks (put a bit less in first as will be dealing with slacks) LATER
  CoinBigIndex start = 0;
  int block = 0;
  CoinBigIndex work = (2 * numberColumns + matrix_->getNumElements() + numberRowBlocks_ - 1) / numberRowBlocks_;
  CoinBigIndex thisWork = work;
  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
    CoinBigIndex end = columnStart[iColumn + 1];
    assert(block >= 0 && block < numberRowBlocks_);
    whichBlock_[iColumn] = static_cast< char >(block);
    thisWork -= 2 + end - start;
    ecount[block] += end - start;
    start = end;
    blockStart_[block]++;
    if (thisWork <= 0) {
      block++;
      thisWork = work;
    }
  }
#if 0
  printf("Blocks ");
  for (int i=0;i<numberRowBlocks_;i++)
    printf("(%d %d) ",blockStart_[i],ecount[i]);
  printf("\n");
#endif
  start = 0;
  for (int i = 0; i < numberRowBlocks_; i++) {
    int next = start + blockStart_[i];
    blockStart_[i] = start;
    start = next;
  }
  blockStart_[numberRowBlocks_] = start;
  assert(start == numberColumns);
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  // counts
  CoinAbcMemset0(rowStart_, numberRows * (numberRowBlocks_ + 2));
  int *COIN_RESTRICT last = rowStart_ + numberRows * (numberRowBlocks_ + 1);
  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
    int block = whichBlock_[iColumn];
    blockStart_[block]++;
    int base = (block + 1) * numberRows;
    for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn + 1]; j++) {
      int iRow = row[j];
      rowStart_[base + iRow]++;
      last[iRow]++;
    }
  }
  // back to real starts
  for (int iBlock = numberRowBlocks_ - 1; iBlock >= 0; iBlock--)
    blockStart_[iBlock + 1] = blockStart_[iBlock];
  blockStart_[0] = 0;
  CoinBigIndex put = 0;
  for (int iRow = 1; iRow < numberRows; iRow++) {
    int n = last[iRow - 1];
    last[iRow - 1] = put;
    put += n;
    rowStart_[iRow] = put;
  }
  int n = last[numberRows - 1];
  last[numberRows - 1] = put;
  put += n;
  assert(put == numberElements);
  //last[numberRows-1]=put;
  // starts
  int base = 0;
  for (int iBlock = 0; iBlock < numberRowBlocks_; iBlock++) {
    for (int iRow = 0; iRow < numberRows; iRow++) {
      rowStart_[base + numberRows + iRow] += rowStart_[base + iRow];
    }
    base += numberRows;
  }
  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
    int block = whichBlock_[iColumn];
    int where = blockStart_[block];
    blockStart_[block]++;
    int base = block * numberRows;
    for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn + 1]; j++) {
      int iRow = row[j];
      CoinBigIndex put = rowStart_[base + iRow];
      rowStart_[base + iRow]++;
      column_[put] = where + maximumRows;
      element_[put] = elementByColumn[j];
    }
  }
  // back to real starts etc
  base = numberRows * numberRowBlocks_;
  for (int iBlock = numberRowBlocks_ - 1; iBlock >= 0; iBlock--) {
    blockStart_[iBlock + 1] = blockStart_[iBlock] + maximumRows;
    CoinAbcMemcpy(rowStart_ + base, rowStart_ + base - numberRows, numberRows);
    base -= numberRows;
  }
  blockStart_[0] = 0; //maximumRows;
  delete[] whichBlock_;
  // and move
  CoinAbcMemcpy(rowStart_, last, numberRows);
  // All in useful
  CoinAbcMemcpy(rowStart_ + (numberRowBlocks_ + 1) * numberRows,
    rowStart_ + (numberRowBlocks_)*numberRows, numberRows);
#ifdef COUNT_COPY
  // now blocked by element count
  countRealColumn_ = new int[numberColumns];
  int counts[2 * MAX_COUNT];
  memset(counts, 0, sizeof(counts));
  //memset(countFirst_,0,sizeof(countFirst_));
  int numberLarge = 0;
  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
    int n = columnStart[iColumn + 1] - columnStart[iColumn];
    if (n < MAX_COUNT)
      counts[n]++;
    else
      numberLarge++;
  }
  CoinBigIndex numberExtra = 3; // for alignment
#define SMALL_COUNT 1
  for (int i = 0; i < MAX_COUNT; i++) {
    int n = counts[i];
    if (n >= SMALL_COUNT) {
      n &= 3;
      int extra = (4 - n) & 3;
      numberExtra += i * extra;
    } else {
      // treat as large
      numberLarge += n;
    }
  }
  countElement_ = new double[numberElements + numberExtra];
  countRow_ = new int[numberElements + numberExtra];
  countStartLarge_ = new CoinBigIndex[numberLarge + 1];
  countStartLarge_[numberLarge] = numberElements + numberExtra;
  //return;
  CoinInt64 xx = reinterpret_cast< CoinInt64 >(countElement_);
  int iBottom = static_cast< int >(xx & 31);
  int offset = iBottom >> 3;
  CoinBigIndex firstElementLarge = 0;
  if (offset)
    firstElementLarge = 4 - offset;
  //countStart_[0]=firstElementLarge;
  int positionLarge = 0;
  smallestCount_ = 0;
  largestCount_ = 0;
  for (int i = 0; i < MAX_COUNT; i++) {
    int n = counts[i];
    countFirst_[i] = positionLarge;
    countStart_[i] = firstElementLarge;
    if (n >= SMALL_COUNT) {
      counts[i + MAX_COUNT] = 1;
      if (smallestCount_ == 0)
        smallestCount_ = i;
      largestCount_ = i;
      positionLarge += n;
      firstElementLarge += n * i;
      n &= 3;
      int extra = (4 - n) & 3;
      firstElementLarge += i * extra;
    }
    counts[i] = 0;
  }
  largestCount_++;
  countFirst_[MAX_COUNT] = positionLarge;
  countStart_[MAX_COUNT] = firstElementLarge;
  numberLarge = 0;
  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
    CoinBigIndex start = columnStart[iColumn];
    int n = columnStart[iColumn + 1] - start;
    CoinBigIndex put;
    int position;
    if (n < MAX_COUNT && counts[MAX_COUNT + n] != 0) {
      int iWhich = counts[n];
      position = countFirst_[n] + iWhich;
      int iBlock4 = iWhich & (~3);
      iWhich &= 3;
      put = countStart_[n] + iBlock4 * n;
      put += iWhich;
      counts[n]++;
      for (int i = 0; i < n; i++) {
        countRow_[put] = row[start + i];
        countElement_[put] = elementByColumn[start + i];
        put += 4;
      }
    } else {
      position = positionLarge + numberLarge;
      put = firstElementLarge;
      countStartLarge_[numberLarge] = put;
      firstElementLarge += n;
      numberLarge++;
      CoinAbcMemcpy(countRow_ + put, row + start, n);
      CoinAbcMemcpy(countElement_ + put, elementByColumn + start, n);
    }
    countRealColumn_[position] = iColumn + maximumRows;
  }
  countStartLarge_[numberLarge] = firstElementLarge;
  assert(firstElementLarge <= numberElements + numberExtra);
#endif
}
// Make all useful
void AbcMatrix::makeAllUseful(CoinIndexedVector & /*spare*/)
{
  int numberRows = model_->numberRows();
  CoinBigIndex *COIN_RESTRICT rowEnd = rowStart_ + numberRows;
  const CoinBigIndex *COIN_RESTRICT rowReallyEnd = rowStart_ + 2 * numberRows;
  for (int iRow = 0; iRow < numberRows; iRow++) {
    rowEnd[iRow] = rowReallyEnd[iRow];
  }
}
#define SQRT_ARRAY
// Creates scales for column copy (rowCopy in model may be modified)
void AbcMatrix::scale(int numberAlreadyScaled)
{
  int numberRows = model_->numberRows();
  bool inBranchAndBound = (model_->specialOptions(), 0x1000000) != 0;
  bool doScaling = numberAlreadyScaled >= 0;
  if (!doScaling)
    numberAlreadyScaled = 0;
  if (numberAlreadyScaled == numberRows)
    return; // no need to do anything
  int numberColumns = model_->numberColumns();
  double *COIN_RESTRICT rowScale = model_->rowScale2();
  double *COIN_RESTRICT inverseRowScale = model_->inverseRowScale2();
  double *COIN_RESTRICT columnScale = model_->columnScale2();
  double *COIN_RESTRICT inverseColumnScale = model_->inverseColumnScale2();
  // we are going to mark bits we are interested in
  int whichArray = model_->getAvailableArrayPublic();
  char *COIN_RESTRICT usefulColumn = reinterpret_cast< char * >(model_->usefulArray(whichArray)->getIndices());
  memset(usefulColumn, 1, numberColumns);
  const double *COIN_RESTRICT rowLower = model_->rowLower();
  const double *COIN_RESTRICT rowUpper = model_->rowUpper();
  const double *COIN_RESTRICT columnLower = model_->columnLower();
  const double *COIN_RESTRICT columnUpper = model_->columnUpper();
  //#define LEAVE_FIXED
  // mark empty and fixed columns
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts();
  double *COIN_RESTRICT elementByColumn = matrix_->getMutableElements();
  CoinPackedMatrix *COIN_RESTRICT rowCopy = reverseOrderedCopy();
  const int *column = rowCopy->getIndices();
  const CoinBigIndex *COIN_RESTRICT rowStart = rowCopy->getVectorStarts();
  const double *COIN_RESTRICT element = rowCopy->getElements();
  assert(numberAlreadyScaled >= 0 && numberAlreadyScaled < numberRows);
#ifndef LEAVE_FIXED
  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
    if (columnUpper[iColumn] == columnLower[iColumn])
      usefulColumn[iColumn] = 0;
  }
#endif
  double overallLargest = -1.0e-20;
  double overallSmallest = 1.0e20;
  if (!numberAlreadyScaled) {
    // may be redundant
    CoinFillN(rowScale, numberRows, 1.0);
    CoinFillN(columnScale, numberColumns, 1.0);
    CoinBigIndex start = 0;
    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
      CoinBigIndex end = columnStart[iColumn + 1];
      if (usefulColumn[iColumn]) {
        if (end > start) {
          for (CoinBigIndex j = start; j < end; j++) {
            double value = fabs(elementByColumn[j]);
            overallLargest = CoinMax(overallLargest, value);
            overallSmallest = CoinMin(overallSmallest, value);
          }
        } else {
          usefulColumn[iColumn] = 0;
        }
      }
      start = end;
    }
  } else {
    CoinBigIndex start = rowStart[numberAlreadyScaled];
    for (int iRow = numberAlreadyScaled; iRow < numberRows; iRow++) {
      rowScale[iRow] = 1.0;
      CoinBigIndex end = rowStart[iRow + 1];
      for (CoinBigIndex j = start; j < end; j++) {
        int iColumn = column[j];
        if (usefulColumn[iColumn]) {
          double value = fabs(elementByColumn[j]) * columnScale[iColumn];
          overallLargest = CoinMax(overallLargest, value);
          overallSmallest = CoinMin(overallSmallest, value);
        }
      }
    }
  }
  if ((overallSmallest >= 0.5 && overallLargest <= 2.0) || !doScaling) {
    //printf("no scaling\n");
    delete rowCopy;
    model_->clearArraysPublic(whichArray);
    CoinFillN(inverseRowScale + numberAlreadyScaled, numberRows - numberAlreadyScaled, 1.0);
    if (!numberAlreadyScaled)
      CoinFillN(inverseColumnScale, numberColumns, 1.0);
    //moveLargestToStart();
    return;
  }
  // need to scale
  double largest;
  double smallest;
  int scalingMethod = model_->scalingFlag();
  if (scalingMethod == 4) {
    // As auto
    scalingMethod = 3;
  } else if (scalingMethod == 5) {
    // As geometric
    scalingMethod = 2;
  }
  double savedOverallRatio = 0.0;
  double tolerance = 5.0 * model_->primalTolerance();
  bool finished = false;
  // if scalingMethod 3 then may change
  bool extraDetails = (model_->logLevel() > 2);
  bool secondTime = false;
  while (!finished) {
    int numberPass = !numberAlreadyScaled ? 3 : 1;
    overallLargest = -1.0e-20;
    overallSmallest = 1.0e20;
    if (!secondTime) {
      secondTime = true;
    } else {
      CoinFillN(rowScale, numberRows, 1.0);
      CoinFillN(columnScale, numberColumns, 1.0);
    }
    if (scalingMethod == 1 || scalingMethod == 3) {
      // Maximum in each row
      for (int iRow = numberAlreadyScaled; iRow < numberRows; iRow++) {
        largest = 1.0e-10;
        for (CoinBigIndex j = rowStart[iRow]; j < rowStart[iRow + 1]; j++) {
          int iColumn = column[j];
          if (usefulColumn[iColumn]) {
            double value = fabs(element[j]);
            largest = CoinMax(largest, value);
            assert(largest < 1.0e40);
          }
        }
        rowScale[iRow] = 1.0 / largest;
#ifdef COIN_DEVELOP
        if (extraDetails) {
          overallLargest = CoinMax(overallLargest, largest);
          overallSmallest = CoinMin(overallSmallest, largest);
        }
#endif
      }
    } else {
      while (numberPass) {
        overallLargest = 0.0;
        overallSmallest = 1.0e50;
        numberPass--;
        // Geometric mean on row scales
        for (int iRow = numberAlreadyScaled; iRow < numberRows; iRow++) {
          largest = 1.0e-50;
          smallest = 1.0e50;
          for (CoinBigIndex j = rowStart[iRow]; j < rowStart[iRow + 1]; j++) {
            int iColumn = column[j];
            if (usefulColumn[iColumn]) {
              double value = fabs(element[j]);
              value *= columnScale[iColumn];
              largest = CoinMax(largest, value);
              smallest = CoinMin(smallest, value);
            }
          }
#ifdef SQRT_ARRAY
          rowScale[iRow] = smallest * largest;
#else
          rowScale[iRow] = 1.0 / sqrt(smallest * largest);
#endif
          if (extraDetails) {
            overallLargest = CoinMax(largest * rowScale[iRow], overallLargest);
            overallSmallest = CoinMin(smallest * rowScale[iRow], overallSmallest);
          }
        }
        if (model_->scalingFlag() == 5)
          break; // just scale rows
#ifdef SQRT_ARRAY
        CoinAbcInverseSqrts(rowScale, numberRows);
#endif
        if (!inBranchAndBound)
          model_->messageHandler()->message(CLP_PACKEDSCALE_WHILE, *model_->messagesPointer())
            << overallSmallest
            << overallLargest
            << CoinMessageEol;
        // skip last column round
        if (numberPass == 1)
          break;
        // Geometric mean on column scales
        for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
          if (usefulColumn[iColumn]) {
            largest = 1.0e-50;
            smallest = 1.0e50;
            for (CoinBigIndex j = columnStart[iColumn];
                 j < columnStart[iColumn + 1]; j++) {
              int iRow = row[j];
              double value = fabs(elementByColumn[j]);
              value *= rowScale[iRow];
              largest = CoinMax(largest, value);
              smallest = CoinMin(smallest, value);
            }
#ifdef SQRT_ARRAY
            columnScale[iColumn] = smallest * largest;
#else
            columnScale[iColumn] = 1.0 / sqrt(smallest * largest);
#endif
          }
        }
#ifdef SQRT_ARRAY
        CoinAbcInverseSqrts(columnScale, numberColumns);
#endif
      }
    }
    // If ranges will make horrid then scale
    for (int iRow = numberAlreadyScaled; iRow < numberRows; iRow++) {
      double difference = rowUpper[iRow] - rowLower[iRow];
      double scaledDifference = difference * rowScale[iRow];
      if (scaledDifference > tolerance && scaledDifference < 1.0e-4) {
        // make gap larger
        rowScale[iRow] *= 1.0e-4 / scaledDifference;
        rowScale[iRow] = CoinMax(1.0e-10, CoinMin(1.0e10, rowScale[iRow]));
        //printf("Row %d difference %g scaled diff %g => %g\n",iRow,difference,
        // scaledDifference,difference*rowScale[iRow]);
      }
    }
    // final pass to scale columns so largest is reasonable
    // See what smallest will be if largest is 1.0
    if (model_->scalingFlag() != 5) {
      overallSmallest = 1.0e50;
      for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
        if (usefulColumn[iColumn]) {
          largest = 1.0e-20;
          smallest = 1.0e50;
          for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn + 1]; j++) {
            int iRow = row[j];
            double value = fabs(elementByColumn[j] * rowScale[iRow]);
            largest = CoinMax(largest, value);
            smallest = CoinMin(smallest, value);
          }
          if (overallSmallest * largest > smallest)
            overallSmallest = smallest / largest;
        }
      }
    }
    if (scalingMethod == 1 || scalingMethod == 2) {
      finished = true;
    } else if (savedOverallRatio == 0.0 && scalingMethod != 4) {
      savedOverallRatio = overallSmallest;
      scalingMethod = 4;
    } else {
      assert(scalingMethod == 4);
      if (overallSmallest > 2.0 * savedOverallRatio) {
        finished = true; // geometric was better
        if (model_->scalingFlag() == 4) {
          // If in Branch and bound change
          if ((model_->specialOptions() & 1024) != 0) {
            model_->scaling(2);
          }
        }
      } else {
        scalingMethod = 1; // redo equilibrium
        if (model_->scalingFlag() == 4) {
          // If in Branch and bound change
          if ((model_->specialOptions() & 1024) != 0) {
            model_->scaling(1);
          }
        }
      }
#if 0
      if (extraDetails) {
	if (finished)
	  printf("equilibrium ratio %g, geometric ratio %g , geo chosen\n",
		 savedOverallRatio, overallSmallest);
	else
	  printf("equilibrium ratio %g, geometric ratio %g , equi chosen\n",
		 savedOverallRatio, overallSmallest);
      }
#endif
    }
  }
  //#define RANDOMIZE
#ifdef RANDOMIZE
  // randomize by up to 10%
  for (int iRow = numberAlreadyScaled; iRow < numberRows; iRow++) {
    double value = 0.5 - randomNumberGenerator_.randomDouble(); //between -0.5 to + 0.5
    rowScale[iRow] *= (1.0 + 0.1 * value);
  }
#endif
  overallLargest = 1.0;
  if (overallSmallest < 1.0e-1)
    overallLargest = 1.0 / sqrt(overallSmallest);
  overallLargest = CoinMin(100.0, overallLargest);
  overallSmallest = 1.0e50;
  char *COIN_RESTRICT usedRow = reinterpret_cast< char * >(inverseRowScale);
  memset(usedRow, 0, numberRows);
  //printf("scaling %d\n",model_->scalingFlag());
  if (model_->scalingFlag() != 5) {
    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
      if (usefulColumn[iColumn]) {
        largest = 1.0e-20;
        smallest = 1.0e50;
        for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn + 1]; j++) {
          int iRow = row[j];
          usedRow[iRow] = 1;
          double value = fabs(elementByColumn[j] * rowScale[iRow]);
          largest = CoinMax(largest, value);
          smallest = CoinMin(smallest, value);
        }
        columnScale[iColumn] = overallLargest / largest;
        //columnScale[iColumn]=CoinMax(1.0e-10,CoinMin(1.0e10,columnScale[iColumn]));
#ifdef RANDOMIZE
        if (!numberAlreadyScaled) {
          double value = 0.5 - randomNumberGenerator_.randomDouble(); //between -0.5 to + 0.5
          columnScale[iColumn] *= (1.0 + 0.1 * value);
        }
#endif
        double difference = columnUpper[iColumn] - columnLower[iColumn];
        if (difference < 1.0e-5 * columnScale[iColumn]) {
          // make gap larger
          columnScale[iColumn] = difference / 1.0e-5;
          //printf("Column %d difference %g scaled diff %g => %g\n",iColumn,difference,
          // scaledDifference,difference*columnScale[iColumn]);
        }
        double value = smallest * columnScale[iColumn];
        if (overallSmallest > value)
          overallSmallest = value;
        //overallSmallest = CoinMin(overallSmallest,smallest*columnScale[iColumn]);
      } else {
        assert(columnScale[iColumn] == 1.0);
        //columnScale[iColumn]=1.0;
      }
    }
    for (int iRow = numberAlreadyScaled; iRow < numberRows; iRow++) {
      if (!usedRow[iRow]) {
        rowScale[iRow] = 1.0;
      }
    }
  }
  if (!inBranchAndBound)
    model_->messageHandler()->message(CLP_PACKEDSCALE_FINAL, *model_->messagesPointer())
      << overallSmallest
      << overallLargest
      << CoinMessageEol;
  if (overallSmallest < 1.0e-13) {
    // Change factorization zero tolerance
    double newTolerance = CoinMax(1.0e-15 * (overallSmallest / 1.0e-13),
      1.0e-18);
    if (model_->factorization()->zeroTolerance() > newTolerance)
      model_->factorization()->zeroTolerance(newTolerance);
    newTolerance = CoinMax(overallSmallest * 0.5, 1.0e-18);
    model_->setZeroTolerance(newTolerance);
#ifndef NDEBUG
    assert(newTolerance < 0.0); // just so we can fix
#endif
  }
  // make copy (could do faster by using previous values)
  // could just do partial
  CoinAbcReciprocal(inverseRowScale + numberAlreadyScaled, numberRows - numberAlreadyScaled,
    rowScale + numberAlreadyScaled);
  if (!numberAlreadyScaled)
    CoinAbcReciprocal(inverseColumnScale, numberColumns, columnScale);
  // Do scaled copy //NO and move largest to start
  CoinBigIndex start = 0;
  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
    double scale = columnScale[iColumn];
    CoinBigIndex end = columnStart[iColumn + 1];
    for (CoinBigIndex j = start; j < end; j++) {
      double value = elementByColumn[j];
      int iRow = row[j];
      if (iRow >= numberAlreadyScaled) {
        value *= scale * rowScale[iRow];
        elementByColumn[j] = value;
      }
    }
    start = end;
  }
  delete rowCopy;
#if 0
  if (model_->rowCopy()) {
    // need to replace row by row
    CoinPackedMatrix * rowCopy = NULL;
    //static_cast< AbcMatrix*>(model_->rowCopy());
    double * element = rowCopy->getMutableElements();
    const int * column = rowCopy->getIndices();
    const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
    // scale row copy
    for (iRow = 0; iRow < numberRows; iRow++) {
      CoinBigIndex j;
      double scale = rowScale[iRow];
      double * elementsInThisRow = element + rowStart[iRow];
      const int * columnsInThisRow = column + rowStart[iRow];
      int number = rowStart[iRow+1] - rowStart[iRow];
      assert (number <= numberColumns);
      for (j = 0; j < number; j++) {
	int iColumn = columnsInThisRow[j];
	elementsInThisRow[j] *= scale * columnScale[iColumn];
      }
    }
  }
#endif
  model_->clearArraysPublic(whichArray);
}
/* Return <code>y + A * scalar *x</code> in <code>y</code>.
   @pre <code>x</code> must be of size <code>numColumns()</code>
   @pre <code>y</code> must be of size <code>numRows()</code> */
//scaled versions
void AbcMatrix::timesModifyExcludingSlacks(double scalar,
  const double *x, double *y) const
{
  int numberTotal = model_->numberTotal();
  int maximumRows = model_->maximumAbcNumberRows();
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  for (int iColumn = maximumRows; iColumn < numberTotal; iColumn++) {
    double value = x[iColumn];
    if (value) {
      CoinBigIndex start = columnStart[iColumn];
      CoinBigIndex end = columnStart[iColumn + 1];
      value *= scalar;
      for (CoinBigIndex j = start; j < end; j++) {
        int iRow = row[j];
        y[iRow] += value * elementByColumn[j];
      }
    }
  }
}
/* Return <code>y + A * scalar(+-1) *x</code> in <code>y</code>.
   @pre <code>x</code> must be of size <code>numColumns()+numRows()</code>
   @pre <code>y</code> must be of size <code>numRows()</code> */
void AbcMatrix::timesModifyIncludingSlacks(double scalar,
  const double *x, double *y) const
{
  int numberRows = model_->numberRows();
  int numberTotal = model_->numberTotal();
  int maximumRows = model_->maximumAbcNumberRows();
  // makes no sense for x==y??
  assert(x != y);
  // For now just by column and assumes already scaled (use reallyScale)
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  if (scalar == 1.0) {
    // add
    if (x != y) {
      for (int i = 0; i < numberRows; i++)
        y[i] += x[i];
    } else {
      for (int i = 0; i < numberRows; i++)
        y[i] += y[i];
    }
    for (int iColumn = maximumRows; iColumn < numberTotal; iColumn++) {
      double value = x[iColumn];
      if (value) {
        CoinBigIndex start = columnStart[iColumn];
        CoinBigIndex next = columnStart[iColumn + 1];
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          y[jRow] += value * elementByColumn[j];
        }
      }
    }
  } else {
    // subtract
    if (x != y) {
      for (int i = 0; i < numberRows; i++)
        y[i] -= x[i];
    } else {
      for (int i = 0; i < numberRows; i++)
        y[i] = 0.0;
    }
    for (int iColumn = maximumRows; iColumn < numberTotal; iColumn++) {
      double value = x[iColumn];
      if (value) {
        CoinBigIndex start = columnStart[iColumn];
        CoinBigIndex next = columnStart[iColumn + 1];
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          y[jRow] -= value * elementByColumn[j];
        }
      }
    }
  }
}
/* Return A * scalar(+-1) *x</code> in <code>y</code>.
   @pre <code>x</code> must be of size <code>numColumns()+numRows()</code>
   @pre <code>y</code> must be of size <code>numRows()</code> */
void AbcMatrix::timesIncludingSlacks(double scalar,
  const double *x, double *y) const
{
  int numberRows = model_->numberRows();
  int numberTotal = model_->numberTotal();
  int maximumRows = model_->maximumAbcNumberRows();
  // For now just by column and assumes already scaled (use reallyScale)
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  if (scalar == 1.0) {
    // add
    if (x != y) {
      for (int i = 0; i < numberRows; i++)
        y[i] = x[i];
    }
    for (int iColumn = maximumRows; iColumn < numberTotal; iColumn++) {
      double value = x[iColumn];
      if (value) {
        CoinBigIndex start = columnStart[iColumn];
        CoinBigIndex next = columnStart[iColumn + 1];
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          y[jRow] += value * elementByColumn[j];
        }
      }
    }
  } else {
    // subtract
    if (x != y) {
      for (int i = 0; i < numberRows; i++)
        y[i] = -x[i];
    } else {
      for (int i = 0; i < numberRows; i++)
        y[i] = -y[i];
    }
    for (int iColumn = maximumRows; iColumn < numberTotal; iColumn++) {
      double value = x[iColumn];
      if (value) {
        CoinBigIndex start = columnStart[iColumn];
        CoinBigIndex next = columnStart[iColumn + 1];
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          y[jRow] -= value * elementByColumn[j];
        }
      }
    }
  }
}
extern double parallelDual4(AbcSimplexDual *);
static double firstPass(AbcSimplex *model, int iBlock,
  double upperTheta, int &freeSequence,
  CoinPartitionedVector &tableauRow,
  CoinPartitionedVector &candidateList)
{
  int *COIN_RESTRICT index = tableauRow.getIndices();
  double *COIN_RESTRICT array = tableauRow.denseVector();
  double *COIN_RESTRICT arrayCandidate = candidateList.denseVector();
  int *COIN_RESTRICT indexCandidate = candidateList.getIndices();
  const double *COIN_RESTRICT abcDj = model->djRegion();
  const unsigned char *COIN_RESTRICT internalStatus = model->internalStatus();
  // do first pass to get possibles
  double bestPossible = 0.0;
  // We can also see if infeasible or pivoting on free
  double tentativeTheta = 1.0e25; // try with this much smaller as guess
  double acceptablePivot = model->currentAcceptablePivot();
  double dualT = -model->currentDualTolerance();
  // fixed will have been taken out by now
  const double multiplier[] = { 1.0, -1.0 };
  freeSequence = -1;
  int firstIn = model->abcMatrix()->blockStart(iBlock);
  int numberNonZero = tableauRow.getNumElements(iBlock) + firstIn;
  int numberRemaining = firstIn;
  //first=tableauRow.getNumElements();
  // could pass in last and if numberNonZero==last-firstIn scan as well
  if (model->ordinaryVariables()) {
    for (int i = firstIn; i < numberNonZero; i++) {
      int iSequence = index[i];
      double tableauValue = array[i];
      unsigned char iStatus = internalStatus[iSequence] & 7;
      double mult = multiplier[iStatus];
      double alpha = tableauValue * mult;
      double oldValue = abcDj[iSequence] * mult;
      double value = oldValue - tentativeTheta * alpha;
      if (value < dualT) {
        bestPossible = CoinMax(bestPossible, alpha);
        value = oldValue - upperTheta * alpha;
        if (value < dualT && alpha >= acceptablePivot) {
          upperTheta = (oldValue - dualT) / alpha;
        }
        // add to list
        arrayCandidate[numberRemaining] = alpha;
        indexCandidate[numberRemaining++] = iSequence;
      }
    }
  } else {
    double badFree = 0.0;
    double freeAlpha = model->currentAcceptablePivot();
    int freeSequenceIn = model->freeSequenceIn();
    double currentDualTolerance = model->currentDualTolerance();
    for (int i = firstIn; i < numberNonZero; i++) {
      int iSequence = index[i];
      double tableauValue = array[i];
      unsigned char iStatus = internalStatus[iSequence] & 7;
      if ((iStatus & 4) == 0) {
        double mult = multiplier[iStatus];
        double alpha = tableauValue * mult;
        double oldValue = abcDj[iSequence] * mult;
        double value = oldValue - tentativeTheta * alpha;
        if (value < dualT) {
          bestPossible = CoinMax(bestPossible, alpha);
          value = oldValue - upperTheta * alpha;
          if (value < dualT && alpha >= acceptablePivot) {
            upperTheta = (oldValue - dualT) / alpha;
          }
          // add to list
          arrayCandidate[numberRemaining] = alpha;
          indexCandidate[numberRemaining++] = iSequence;
        }
      } else {
        bool keep;
        bestPossible = CoinMax(bestPossible, fabs(tableauValue));
        double oldValue = abcDj[iSequence];
        // If free has to be very large - should come in via dualRow
        //if (getInternalStatus(iSequence+addSequence)==isFree&&fabs(tableauValue)<1.0e-3)
        //break;
        if (oldValue > currentDualTolerance) {
          keep = true;
        } else if (oldValue < -currentDualTolerance) {
          keep = true;
        } else {
          if (fabs(tableauValue) > CoinMax(10.0 * acceptablePivot, 1.0e-5)) {
            keep = true;
          } else {
            keep = false;
            badFree = CoinMax(badFree, fabs(tableauValue));
          }
        }
        if (keep) {
#ifdef PAN
          if (model->fakeSuperBasic(iSequence) >= 0) {
#endif
            if (iSequence == freeSequenceIn)
              tableauValue = COIN_DBL_MAX;
            // free - choose largest
            if (fabs(tableauValue) > fabs(freeAlpha)) {
              freeAlpha = tableauValue;
              freeSequence = iSequence;
            }
#ifdef PAN
          }
#endif
        }
      }
    }
  }
  //firstInX=numberNonZero-firstIn;
  //lastInX=-1;//numberRemaining-lastInX;
  tableauRow.setNumElementsPartition(iBlock, numberNonZero - firstIn);
  candidateList.setNumElementsPartition(iBlock, numberRemaining - firstIn);
  return upperTheta;
}
// gets sorted tableau row and a possible value of theta
double
AbcMatrix::dualColumn1Row(int iBlock, double upperTheta, int &freeSequence,
  const CoinIndexedVector &update,
  CoinPartitionedVector &tableauRow,
  CoinPartitionedVector &candidateList) const
{
  int maximumRows = model_->maximumAbcNumberRows();
  int number = update.getNumElements();
  const double *COIN_RESTRICT pi = update.denseVector();
  const int *COIN_RESTRICT piIndex = update.getIndices();
  const CoinBigIndex *COIN_RESTRICT rowStart = rowStart_;
  int numberRows = model_->numberRows();
  const CoinBigIndex *COIN_RESTRICT rowEnd = rowStart + numberRows * numberRowBlocks_;
  // count down
  int nColumns;
  int firstIn = blockStart_[iBlock];
  int first = firstIn;
  if (!first)
    first = maximumRows;
  int last = blockStart_[iBlock + 1];
  nColumns = last - first;
  int target = nColumns;
  rowStart += iBlock * numberRows;
  rowEnd = rowStart + numberRows;
  for (int i = 0; i < number; i++) {
    int iRow = piIndex[i];
    CoinBigIndex end = rowEnd[iRow];
    target -= end - rowStart[iRow];
    if (target < 0)
      break;
  }
  if (target > 0) {
    //printf("going to few %d ops %d\n",number,nColumns-target);
    return dualColumn1RowFew(iBlock, upperTheta, freeSequence,
      update, tableauRow, candidateList);
  }
  const unsigned char *COIN_RESTRICT internalStatus = model_->internalStatus();
  int *COIN_RESTRICT index = tableauRow.getIndices();
  double *COIN_RESTRICT array = tableauRow.denseVector();
  const double *COIN_RESTRICT element = element_;
  const int *COIN_RESTRICT column = column_;
  for (int i = 0; i < number; i++) {
    int iRow = piIndex[i];
    double piValue = pi[iRow];
    CoinBigIndex end = rowEnd[iRow];
    for (CoinBigIndex j = rowStart[iRow]; j < end; j++) {
      int iColumn = column[j];
      assert(iColumn >= first && iColumn < last);
      double value = element[j];
      array[iColumn] += piValue * value;
    }
  }
  int numberNonZero;
  int numberRemaining;
  if (iBlock == 0) {
#if 1
    upperTheta = static_cast< AbcSimplexDual * >(model_)->dualColumn1A();
    numberNonZero = tableauRow.getNumElements(0);
    numberRemaining = candidateList.getNumElements(0);
#else
    numberNonZero = 0;
    for (int i = 0; i < number; i++) {
      int iRow = piIndex[i];
      unsigned char type = internalStatus[iRow];
      if ((type & 7) < 6) {
        index[numberNonZero] = iRow;
        double piValue = pi[iRow];
        array[numberNonZero++] = piValue;
      }
    }
    numberRemaining = 0;
#endif
  } else {
    numberNonZero = firstIn;
    numberRemaining = firstIn;
  }
  double *COIN_RESTRICT arrayCandidate = candidateList.denseVector();
  int *COIN_RESTRICT indexCandidate = candidateList.getIndices();
  //printf("first %d last %d firstIn %d lastIn %d\n",
  //	 first,last,firstIn,lastIn);
  const double *COIN_RESTRICT abcDj = model_->djRegion();
  // do first pass to get possibles
  double bestPossible = 0.0;
  // We can also see if infeasible or pivoting on free
  double tentativeTheta = 1.0e25; // try with this much smaller as guess
  double acceptablePivot = model_->currentAcceptablePivot();
  double dualT = -model_->currentDualTolerance();
  const double multiplier[] = { 1.0, -1.0 };
  double zeroTolerance = model_->zeroTolerance();
  freeSequence = -1;
  if (model_->ordinaryVariables()) {
    for (int iSequence = first; iSequence < last; iSequence++) {
      double tableauValue = array[iSequence];
      if (tableauValue) {
        array[iSequence] = 0.0;
        if (fabs(tableauValue) > zeroTolerance) {
          unsigned char iStatus = internalStatus[iSequence] & 7;
          if (iStatus < 4) {
            index[numberNonZero] = iSequence;
            array[numberNonZero++] = tableauValue;
            double mult = multiplier[iStatus];
            double alpha = tableauValue * mult;
            double oldValue = abcDj[iSequence] * mult;
            double value = oldValue - tentativeTheta * alpha;
            if (value < dualT) {
              bestPossible = CoinMax(bestPossible, alpha);
              value = oldValue - upperTheta * alpha;
              if (value < dualT && alpha >= acceptablePivot) {
                upperTheta = (oldValue - dualT) / alpha;
              }
              // add to list
              arrayCandidate[numberRemaining] = alpha;
              indexCandidate[numberRemaining++] = iSequence;
            }
          }
        }
      }
    }
  } else {
    double badFree = 0.0;
    double freeAlpha = model_->currentAcceptablePivot();
    int freeSequenceIn = model_->freeSequenceIn();
    //printf("block %d freeSequence %d acceptable %g\n",iBlock,freeSequenceIn,freeAlpha);
    double currentDualTolerance = model_->currentDualTolerance();
    for (int iSequence = first; iSequence < last; iSequence++) {
      double tableauValue = array[iSequence];
      if (tableauValue) {
        array[iSequence] = 0.0;
        if (fabs(tableauValue) > zeroTolerance) {
          unsigned char iStatus = internalStatus[iSequence] & 7;
          if (iStatus < 6) {
            if ((iStatus & 4) == 0) {
              index[numberNonZero] = iSequence;
              array[numberNonZero++] = tableauValue;
              double mult = multiplier[iStatus];
              double alpha = tableauValue * mult;
              double oldValue = abcDj[iSequence] * mult;
              double value = oldValue - tentativeTheta * alpha;
              if (value < dualT) {
                bestPossible = CoinMax(bestPossible, alpha);
                value = oldValue - upperTheta * alpha;
                if (value < dualT && alpha >= acceptablePivot) {
                  upperTheta = (oldValue - dualT) / alpha;
                }
                // add to list
                arrayCandidate[numberRemaining] = alpha;
                indexCandidate[numberRemaining++] = iSequence;
              }
            } else {
              bool keep;
              index[numberNonZero] = iSequence;
              array[numberNonZero++] = tableauValue;
              bestPossible = CoinMax(bestPossible, fabs(tableauValue));
              double oldValue = abcDj[iSequence];
              // If free has to be very large - should come in via dualRow
              //if (getInternalStatus(iSequence+addSequence)==isFree&&fabs(tableauValue)<1.0e-3)
              //break;
              // may be fake super basic
              if (oldValue > currentDualTolerance) {
                keep = true;
              } else if (oldValue < -currentDualTolerance) {
                keep = true;
              } else {
                if (fabs(tableauValue) > CoinMax(10.0 * acceptablePivot, 1.0e-5)) {
                  keep = true;
                } else {
                  keep = false;
                  badFree = CoinMax(badFree, fabs(tableauValue));
                }
              }
#if 0
	      if (iSequence==freeSequenceIn)
		assert (keep);
#endif
              if (keep) {
#ifdef PAN
                if (model_->fakeSuperBasic(iSequence) >= 0) {
#endif
                  if (iSequence == freeSequenceIn)
                    tableauValue = COIN_DBL_MAX;
                  // free - choose largest
                  if (fabs(tableauValue) > fabs(freeAlpha)) {
                    freeAlpha = tableauValue;
                    freeSequence = iSequence;
                  }
#ifdef PAN
                }
#endif
              }
            }
          }
        }
      }
    }
  }
#if 0
  if (model_->freeSequenceIn()>=first&&model_->freeSequenceIn()<last)
    assert (freeSequence==model_->freeSequenceIn());
  extern int xxInfo[6][8];
  xxInfo[0][iBlock]=first;
  xxInfo[1][iBlock]=last;
  xxInfo[2][iBlock]=firstIn;
  xxInfo[3][iBlock]=numberNonZero-firstIn;
  xxInfo[4][iBlock]=numberRemaining-firstIn;
#endif
  tableauRow.setNumElementsPartition(iBlock, numberNonZero - firstIn);
  candidateList.setNumElementsPartition(iBlock, numberRemaining - firstIn);
  return upperTheta;
}
// gets sorted tableau row and a possible value of theta
double
AbcMatrix::dualColumn1Row2(double upperTheta, int &freeSequence,
  const CoinIndexedVector &update,
  CoinPartitionedVector &tableauRow,
  CoinPartitionedVector &candidateList) const
{
  //int first=model_->maximumAbcNumberRows();
  assert(update.getNumElements() == 2);
  const double *COIN_RESTRICT pi = update.denseVector();
  const int *COIN_RESTRICT piIndex = update.getIndices();
  int *COIN_RESTRICT index = tableauRow.getIndices();
  double *COIN_RESTRICT array = tableauRow.denseVector();
  const CoinBigIndex *COIN_RESTRICT rowStart = rowStart_;
  int numberRows = model_->numberRows();
  const CoinBigIndex *COIN_RESTRICT rowEnd = rowStart + numberRows * numberRowBlocks_;
  const double *COIN_RESTRICT element = element_;
  const int *COIN_RESTRICT column = column_;
  int iRow0 = piIndex[0];
  int iRow1 = piIndex[1];
  CoinBigIndex end0 = rowEnd[iRow0];
  CoinBigIndex end1 = rowEnd[iRow1];
  if (end0 - rowStart[iRow0] > end1 - rowStart[iRow1]) {
    int temp = iRow0;
    iRow0 = iRow1;
    iRow1 = temp;
  }
  CoinBigIndex start = rowStart[iRow0];
  CoinBigIndex end = rowEnd[iRow0];
  double piValue = pi[iRow0];
  double *COIN_RESTRICT arrayCandidate = candidateList.denseVector();
  int numberNonZero;
  numberNonZero = tableauRow.getNumElements(0);
  int n = numberNonZero;
  for (CoinBigIndex j = start; j < end; j++) {
    int iSequence = column[j];
    double value = element[j];
    arrayCandidate[iSequence] = piValue * value;
    index[n++] = iSequence;
  }
  start = rowStart[iRow1];
  end = rowEnd[iRow1];
  piValue = pi[iRow1];
  for (CoinBigIndex j = start; j < end; j++) {
    int iSequence = column[j];
    double value = element[j];
    value *= piValue;
    if (!arrayCandidate[iSequence]) {
      arrayCandidate[iSequence] = value;
      index[n++] = iSequence;
    } else {
      arrayCandidate[iSequence] += value;
    }
  }
  // pack down
  const unsigned char *COIN_RESTRICT internalStatus = model_->internalStatus();
  double zeroTolerance = model_->zeroTolerance();
  while (numberNonZero < n) {
    int iSequence = index[numberNonZero];
    double value = arrayCandidate[iSequence];
    arrayCandidate[iSequence] = 0.0;
    unsigned char iStatus = internalStatus[iSequence] & 7;
    if (fabs(value) > zeroTolerance && iStatus < 6) {
      index[numberNonZero] = iSequence;
      array[numberNonZero++] = value;
    } else {
      // kill
      n--;
      index[numberNonZero] = index[n];
    }
  }
  tableauRow.setNumElementsPartition(0, numberNonZero);
  return firstPass(model_, 0, upperTheta, freeSequence,
    tableauRow,
    candidateList);
}
//static int ixxxxxx=1;
// gets sorted tableau row and a possible value of theta
double
AbcMatrix::dualColumn1RowFew(int iBlock, double upperTheta, int &freeSequence,
  const CoinIndexedVector &update,
  CoinPartitionedVector &tableauRow,
  CoinPartitionedVector &candidateList) const
{
  //int first=model_->maximumAbcNumberRows();
  int number = update.getNumElements();
  const double *COIN_RESTRICT pi = update.denseVector();
  const int *COIN_RESTRICT piIndex = update.getIndices();
  int *COIN_RESTRICT index = tableauRow.getIndices();
  double *COIN_RESTRICT array = tableauRow.denseVector();
  const CoinBigIndex *COIN_RESTRICT rowStart = rowStart_;
  int numberRows = model_->numberRows();
  const CoinBigIndex *COIN_RESTRICT rowEnd = rowStart + numberRows * numberRowBlocks_;
  const double *COIN_RESTRICT element = element_;
  const int *COIN_RESTRICT column = column_;
  double *COIN_RESTRICT arrayCandidate = candidateList.denseVector();
  int numberNonZero;
  assert(iBlock >= 0);
  const unsigned char *COIN_RESTRICT internalStatus = model_->internalStatus();
  int firstIn = blockStart_[iBlock];
  if (iBlock == 0) {
    numberNonZero = 0;
    for (int i = 0; i < number; i++) {
      int iRow = piIndex[i];
      unsigned char type = internalStatus[iRow];
      if ((type & 7) < 6) {
        index[numberNonZero] = iRow;
        double piValue = pi[iRow];
        array[numberNonZero++] = piValue;
      }
    }
  } else {
    numberNonZero = firstIn;
  }
  int n = numberNonZero;
  rowStart += iBlock * numberRows;
  rowEnd = rowStart + numberRows;
  for (int i = 0; i < number; i++) {
    int iRow = piIndex[i];
    double piValue = pi[iRow];
    CoinBigIndex end = rowEnd[iRow];
    for (CoinBigIndex j = rowStart[iRow]; j < end; j++) {
      int iColumn = column[j];
      double value = element[j] * piValue;
      double oldValue = arrayCandidate[iColumn];
      value += oldValue;
      if (!oldValue) {
        arrayCandidate[iColumn] = value;
        index[n++] = iColumn;
      } else if (value) {
        arrayCandidate[iColumn] = value;
      } else {
        arrayCandidate[iColumn] = COIN_INDEXED_REALLY_TINY_ELEMENT;
      }
    }
  }
  // pack down
  double zeroTolerance = model_->zeroTolerance();
  while (numberNonZero < n) {
    int iSequence = index[numberNonZero];
    double value = arrayCandidate[iSequence];
    arrayCandidate[iSequence] = 0.0;
    unsigned char iStatus = internalStatus[iSequence] & 7;
    if (fabs(value) > zeroTolerance && iStatus < 6) {
      index[numberNonZero] = iSequence;
      array[numberNonZero++] = value;
    } else {
      // kill
      n--;
      index[numberNonZero] = index[n];
    }
  }
  tableauRow.setNumElementsPartition(iBlock, numberNonZero - firstIn);
  upperTheta = firstPass(model_, iBlock, upperTheta, freeSequence,
    tableauRow,
    candidateList);
  return upperTheta;
}
// gets sorted tableau row and a possible value of theta
double
AbcMatrix::dualColumn1Row1(double upperTheta, int &freeSequence,
  const CoinIndexedVector &update,
  CoinPartitionedVector &tableauRow,
  CoinPartitionedVector &candidateList) const
{
  assert(update.getNumElements() == 1);
  int iRow = update.getIndices()[0];
  double piValue = update.denseVector()[iRow];
  int *COIN_RESTRICT index = tableauRow.getIndices();
  double *COIN_RESTRICT array = tableauRow.denseVector();
  const CoinBigIndex *COIN_RESTRICT rowStart = rowStart_;
  int numberRows = model_->numberRows();
  const CoinBigIndex *COIN_RESTRICT rowEnd = rowStart + numberRows * numberRowBlocks_;
  CoinBigIndex start = rowStart[iRow];
  CoinBigIndex end = rowEnd[iRow];
  const double *COIN_RESTRICT element = element_;
  const int *COIN_RESTRICT column = column_;
  int numberNonZero;
  int numberRemaining;
  numberNonZero = tableauRow.getNumElements(0);
  numberRemaining = candidateList.getNumElements(0);
  double *COIN_RESTRICT arrayCandidate = candidateList.denseVector();
  int *COIN_RESTRICT indexCandidate = candidateList.getIndices();
  const double *COIN_RESTRICT abcDj = model_->djRegion();
  const unsigned char *COIN_RESTRICT internalStatus = model_->internalStatus();
  // do first pass to get possibles
  double bestPossible = 0.0;
  // We can also see if infeasible or pivoting on free
  double tentativeTheta = 1.0e25; // try with this much smaller as guess
  double acceptablePivot = model_->currentAcceptablePivot();
  double dualT = -model_->currentDualTolerance();
  const double multiplier[] = { 1.0, -1.0 };
  double zeroTolerance = model_->zeroTolerance();
  freeSequence = -1;
  if (model_->ordinaryVariables()) {
    for (CoinBigIndex j = start; j < end; j++) {
      int iSequence = column[j];
      double value = element[j];
      double tableauValue = piValue * value;
      if (fabs(tableauValue) > zeroTolerance) {
        unsigned char iStatus = internalStatus[iSequence] & 7;
        if (iStatus < 4) {
          index[numberNonZero] = iSequence;
          array[numberNonZero++] = tableauValue;
          double mult = multiplier[iStatus];
          double alpha = tableauValue * mult;
          double oldValue = abcDj[iSequence] * mult;
          double value = oldValue - tentativeTheta * alpha;
          if (value < dualT) {
            bestPossible = CoinMax(bestPossible, alpha);
            value = oldValue - upperTheta * alpha;
            if (value < dualT && alpha >= acceptablePivot) {
              upperTheta = (oldValue - dualT) / alpha;
            }
            // add to list
            arrayCandidate[numberRemaining] = alpha;
            indexCandidate[numberRemaining++] = iSequence;
          }
        }
      }
    }
  } else {
    double badFree = 0.0;
    double freeAlpha = model_->currentAcceptablePivot();
    int freeSequenceIn = model_->freeSequenceIn();
    double currentDualTolerance = model_->currentDualTolerance();
    for (CoinBigIndex j = start; j < end; j++) {
      int iSequence = column[j];
      double value = element[j];
      double tableauValue = piValue * value;
      if (fabs(tableauValue) > zeroTolerance) {
        unsigned char iStatus = internalStatus[iSequence] & 7;
        if (iStatus < 6) {
          if ((iStatus & 4) == 0) {
            index[numberNonZero] = iSequence;
            array[numberNonZero++] = tableauValue;
            double mult = multiplier[iStatus];
            double alpha = tableauValue * mult;
            double oldValue = abcDj[iSequence] * mult;
            double value = oldValue - tentativeTheta * alpha;
            if (value < dualT) {
              bestPossible = CoinMax(bestPossible, alpha);
              value = oldValue - upperTheta * alpha;
              if (value < dualT && alpha >= acceptablePivot) {
                upperTheta = (oldValue - dualT) / alpha;
              }
              // add to list
              arrayCandidate[numberRemaining] = alpha;
              indexCandidate[numberRemaining++] = iSequence;
            }
          } else {
            bool keep;
            index[numberNonZero] = iSequence;
            array[numberNonZero++] = tableauValue;
            bestPossible = CoinMax(bestPossible, fabs(tableauValue));
            double oldValue = abcDj[iSequence];
            // If free has to be very large - should come in via dualRow
            //if (getInternalStatus(iSequence+addSequence)==isFree&&fabs(tableauValue)<1.0e-3)
            //break;
            if (oldValue > currentDualTolerance) {
              keep = true;
            } else if (oldValue < -currentDualTolerance) {
              keep = true;
            } else {
              if (fabs(tableauValue) > CoinMax(10.0 * acceptablePivot, 1.0e-5)) {
                keep = true;
              } else {
                keep = false;
                badFree = CoinMax(badFree, fabs(tableauValue));
              }
            }
            if (keep) {
#ifdef PAN
              if (model_->fakeSuperBasic(iSequence) >= 0) {
#endif
                if (iSequence == freeSequenceIn)
                  tableauValue = COIN_DBL_MAX;
                // free - choose largest
                if (fabs(tableauValue) > fabs(freeAlpha)) {
                  freeAlpha = tableauValue;
                  freeSequence = iSequence;
                }
#ifdef PAN
              }
#endif
            }
          }
        }
      }
    }
  }
  tableauRow.setNumElementsPartition(0, numberNonZero);
  candidateList.setNumElementsPartition(0, numberRemaining);
  return upperTheta;
}
//#define PARALLEL2
#ifdef PARALLEL2
#undef cilk_for
#undef cilk_spawn
#undef cilk_sync
#include <cilk/cilk.h>
#include <cilk/cilk_api.h>
#endif
#if 0
static void compact(int numberBlocks,CoinIndexedVector * vector,const int * starts,const int * lengths)
{
  int numberNonZeroIn=vector->getNumElements();
  int * index = vector->getIndices();
  double * array = vector->denseVector();
  CoinAbcCompact(numberBlocks,numberNonZeroIn,
		 array,starts,lengths); 
  int numberNonZero = CoinAbcCompact(numberBlocks,numberNonZeroIn,
				     index,starts,lengths); 
  vector->setNumElements(numberNonZero);
}
static void compactBoth(int numberBlocks,CoinIndexedVector * vector1,CoinIndexedVector * vector2,
			const int * starts,const int * lengths1, const int * lengths2)
{
  cilk_spawn compact(numberBlocks,vector1,starts,lengths1);
  compact(numberBlocks,vector2,starts,lengths2);
  cilk_sync;
}
#endif
void AbcMatrix::rebalance() const
{
  int maximumRows = model_->maximumAbcNumberRows();
  int numberTotal = model_->numberTotal();
  /* rebalance
     For non-vector version
     each basic etc column is 1
     each real column is 5+2*nel
     each basic slack is 0
     each real slack is 3
   */
#if ABC_PARALLEL
  int howOften = CoinMax(model_->factorization()->maximumPivots(), 200);
  if ((model_->numberIterations() % howOften) == 0 || !startColumnBlock_[1]) {
    int numberCpus = model_->numberCpus();
    if (numberCpus > 1) {
      const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
      const unsigned char *COIN_RESTRICT internalStatus = model_->internalStatus();
      int numberRows = model_->numberRows();
      int total = 0;
      for (int iSequence = 0; iSequence < numberRows; iSequence++) {
        unsigned char iStatus = internalStatus[iSequence] & 7;
        if (iStatus < 4)
          total += 3;
      }
      int totalSlacks = total;
      CoinBigIndex end = columnStart[maximumRows];
      for (int iSequence = maximumRows; iSequence < numberTotal; iSequence++) {
        CoinBigIndex start = end;
        end = columnStart[iSequence + 1];
        unsigned char iStatus = internalStatus[iSequence] & 7;
        if (iStatus < 4)
          total += 5 + 2 * (end - start);
        else
          total += 1;
      }
      int chunk = (total + numberCpus - 1) / numberCpus;
      total = totalSlacks;
      int iCpu = 0;
      startColumnBlock_[0] = 0;
      end = columnStart[maximumRows];
      for (int iSequence = maximumRows; iSequence < numberTotal; iSequence++) {
        CoinBigIndex start = end;
        end = columnStart[iSequence + 1];
        unsigned char iStatus = internalStatus[iSequence] & 7;
        if (iStatus < 4)
          total += 5 + 2 * (end - start);
        else
          total += 1;
        if (total > chunk) {
          iCpu++;
          total = 0;
          startColumnBlock_[iCpu] = iSequence;
        }
      }
      assert(iCpu < numberCpus);
      iCpu++;
      for (; iCpu <= numberCpus; iCpu++)
        startColumnBlock_[iCpu] = numberTotal;
      numberColumnBlocks_ = numberCpus;
    } else {
      numberColumnBlocks_ = 1;
      startColumnBlock_[0] = 0;
      startColumnBlock_[1] = numberTotal;
    }
  }
#else
  startColumnBlock_[0] = 0;
  startColumnBlock_[1] = numberTotal;
#endif
}
double
AbcMatrix::dualColumn1(const CoinIndexedVector &update,
  CoinPartitionedVector &tableauRow, CoinPartitionedVector &candidateList) const
{
  int numberTotal = model_->numberTotal();
  // rebalance
  rebalance();
  tableauRow.setPackedMode(true);
  candidateList.setPackedMode(true);
  int number = update.getNumElements();
  double upperTheta;
  if (rowStart_ && number < 3) {
#if ABC_INSTRUMENT > 1
    {
      int n = update.getNumElements();
      abcPricing[n < 19 ? n : 19]++;
    }
#endif
    // always do serially
    // do slacks first
    int starts[2];
    starts[0] = 0;
    starts[1] = numberTotal;
    tableauRow.setPartitions(1, starts);
    candidateList.setPartitions(1, starts);
    upperTheta = static_cast< AbcSimplexDual * >(model_)->dualColumn1A();
    //assert (upperTheta>-100*model_->dualTolerance()||model_->sequenceIn()>=0||model_->lastFirstFree()>=0);
    int freeSequence = -1;
    // worth using row copy
    assert(number);
    if (number == 2) {
      upperTheta = dualColumn1Row2(upperTheta, freeSequence, update, tableauRow, candidateList);
    } else {
      upperTheta = dualColumn1Row1(upperTheta, freeSequence, update, tableauRow, candidateList);
    }
    if (freeSequence >= 0) {
      int numberNonZero = tableauRow.getNumElements(0);
      const int *COIN_RESTRICT index = tableauRow.getIndices();
      const double *COIN_RESTRICT array = tableauRow.denseVector();
      // search for free coming in
      double freeAlpha = 0.0;
      int bestSequence = model_->sequenceIn();
      if (bestSequence >= 0)
        freeAlpha = model_->alpha();
      index = tableauRow.getIndices();
      array = tableauRow.denseVector();
      // free variable - search
      for (int k = 0; k < numberNonZero; k++) {
        if (freeSequence == index[k]) {
          if (fabs(freeAlpha) < fabs(array[k])) {
            freeAlpha = array[k];
          }
          break;
        }
      }
      if (model_->sequenceIn() < 0 || fabs(freeAlpha) > fabs(model_->alpha())) {
        double oldValue = model_->djRegion()[freeSequence];
        model_->setSequenceIn(freeSequence);
        model_->setAlpha(freeAlpha);
        model_->setTheta(oldValue / freeAlpha);
      }
    }
  } else {
    // three or more
    // need to do better job on dividing up (but wait until vector or by row)
    upperTheta = parallelDual4(static_cast< AbcSimplexDual * >(model_));
  }
  //tableauRow.compact();
  //candidateList.compact();
#if 0 //ndef NDEBUG
  model_->checkArrays();
#endif
  candidateList.computeNumberElements();
  int numberRemaining = candidateList.getNumElements();
  if (!numberRemaining && model_->sequenceIn() < 0) {
    return COIN_DBL_MAX; // Looks infeasible
  } else {
    return upperTheta;
  }
}
#define _mm256_broadcast_sd(x) static_cast< __m256d >(__builtin_ia32_vbroadcastsd256(x))
#define _mm256_load_pd(x) *(__m256d *)(x)
#define _mm256_store_pd (s, x) * ((__m256d *)s) = x
void AbcMatrix::dualColumn1Part(int iBlock, int &sequenceIn, double &upperThetaResult,
  const CoinIndexedVector &update,
  CoinPartitionedVector &tableauRow, CoinPartitionedVector &candidateList) const
{
  double upperTheta = upperThetaResult;
#if 0
  double time0=CoinCpuTime();
#endif
  int maximumRows = model_->maximumAbcNumberRows();
  int firstIn = startColumnBlock_[iBlock];
  int last = startColumnBlock_[iBlock + 1];
  int numberNonZero;
  int numberRemaining;
  int first;
  if (firstIn == 0) {
    upperTheta = static_cast< AbcSimplexDual * >(model_)->dualColumn1A();
    numberNonZero = tableauRow.getNumElements(0);
    numberRemaining = candidateList.getNumElements(0);
    first = maximumRows;
  } else {
    first = firstIn;
    numberNonZero = first;
    numberRemaining = first;
  }
  sequenceIn = -1;
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  const double *COIN_RESTRICT pi = update.denseVector();
  //const int *  COIN_RESTRICT piIndex = update.getIndices();
  int *COIN_RESTRICT index = tableauRow.getIndices();
  double *COIN_RESTRICT array = tableauRow.denseVector();
  // pivot elements
  double *COIN_RESTRICT arrayCandidate = candidateList.denseVector();
  // indices
  int *COIN_RESTRICT indexCandidate = candidateList.getIndices();
  const double *COIN_RESTRICT abcDj = model_->djRegion();
  const unsigned char *COIN_RESTRICT internalStatus = model_->internalStatus();
  // do first pass to get possibles
  double bestPossible = 0.0;
  // We can also see if infeasible or pivoting on free
  double tentativeTheta = 1.0e25; // try with this much smaller as guess
  double acceptablePivot = model_->currentAcceptablePivot();
  double dualT = -model_->currentDualTolerance();
  const double multiplier[] = { 1.0, -1.0 };
  double zeroTolerance = model_->zeroTolerance();
  if (model_->ordinaryVariables()) {
#ifdef COUNT_COPY
    if (first > maximumRows || last < model_->numberTotal() || false) {
#endif
#if 1
      for (int iSequence = first; iSequence < last; iSequence++) {
        unsigned char iStatus = internalStatus[iSequence] & 7;
        if (iStatus < 4) {
          CoinBigIndex start = columnStart[iSequence];
          CoinBigIndex next = columnStart[iSequence + 1];
          double tableauValue = 0.0;
          for (CoinBigIndex j = start; j < next; j++) {
            int jRow = row[j];
            tableauValue += pi[jRow] * elementByColumn[j];
          }
          if (fabs(tableauValue) > zeroTolerance) {
#else
    cilk_for(int iSequence = first; iSequence < last; iSequence++)
    {
      unsigned char iStatus = internalStatus[iSequence] & 7;
      if (iStatus < 4) {
        CoinBigIndex start = columnStart[iSequence];
        CoinBigIndex next = columnStart[iSequence + 1];
        double tableauValue = 0.0;
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          tableauValue += pi[jRow] * elementByColumn[j];
        }
        array[iSequence] = tableauValue;
      }
    }
    //printf("time %.6g\n",CoinCpuTime()-time0);
    for (int iSequence = first; iSequence < last; iSequence++) {
      double tableauValue = array[iSequence];
      if (tableauValue) {
        array[iSequence] = 0.0;
        if (fabs(tableauValue) > zeroTolerance) {
          unsigned char iStatus = internalStatus[iSequence] & 7;
#endif
            index[numberNonZero] = iSequence;
            array[numberNonZero++] = tableauValue;
            double mult = multiplier[iStatus];
            double alpha = tableauValue * mult;
            double oldValue = abcDj[iSequence] * mult;
            double value = oldValue - tentativeTheta * alpha;
            if (value < dualT) {
              bestPossible = CoinMax(bestPossible, alpha);
              value = oldValue - upperTheta * alpha;
              if (value < dualT && alpha >= acceptablePivot) {
                upperTheta = (oldValue - dualT) / alpha;
              }
              // add to list
              arrayCandidate[numberRemaining] = alpha;
              indexCandidate[numberRemaining++] = iSequence;
            }
          }
        }
      }
#ifdef COUNT_COPY
    } else {
      const double *COIN_RESTRICT element = countElement_;
      const int *COIN_RESTRICT row = countRow_;
      double temp[4] __attribute__((aligned(32)));
      memset(temp, 0, sizeof(temp));
      for (int iCount = smallestCount_; iCount < largestCount_; iCount++) {
        int iStart = countFirst_[iCount];
        int number = countFirst_[iCount + 1] - iStart;
        if (!number)
          continue;
        const int *COIN_RESTRICT blockRow = row + countStart_[iCount];
        const double *COIN_RESTRICT blockElement = element + countStart_[iCount];
        const int *COIN_RESTRICT sequence = countRealColumn_ + iStart;
        // really need to sort and swap to avoid tests
        int numberBlocks = number >> 2;
        number &= 3;
        for (int iBlock = 0; iBlock < numberBlocks; iBlock++) {
          double tableauValue0 = 0.0;
          double tableauValue1 = 0.0;
          double tableauValue2 = 0.0;
          double tableauValue3 = 0.0;
          for (int j = 0; j < iCount; j++) {
            tableauValue0 += pi[blockRow[0]] * blockElement[0];
            tableauValue1 += pi[blockRow[1]] * blockElement[1];
            tableauValue2 += pi[blockRow[2]] * blockElement[2];
            tableauValue3 += pi[blockRow[3]] * blockElement[3];
            blockRow += 4;
            blockElement += 4;
          }
          if (fabs(tableauValue0) > zeroTolerance) {
            int iSequence = sequence[0];
            unsigned char iStatus = internalStatus[iSequence] & 7;
            if (iStatus < 4) {
              index[numberNonZero] = iSequence;
              array[numberNonZero++] = tableauValue0;
              double mult = multiplier[iStatus];
              double alpha = tableauValue0 * mult;
              double oldValue = abcDj[iSequence] * mult;
              double value = oldValue - tentativeTheta * alpha;
              if (value < dualT) {
                bestPossible = CoinMax(bestPossible, alpha);
                value = oldValue - upperTheta * alpha;
                if (value < dualT && alpha >= acceptablePivot) {
                  upperTheta = (oldValue - dualT) / alpha;
                }
                // add to list
                arrayCandidate[numberRemaining] = alpha;
                indexCandidate[numberRemaining++] = iSequence;
              }
            }
          }
          if (fabs(tableauValue1) > zeroTolerance) {
            int iSequence = sequence[1];
            unsigned char iStatus = internalStatus[iSequence] & 7;
            if (iStatus < 4) {
              index[numberNonZero] = iSequence;
              array[numberNonZero++] = tableauValue1;
              double mult = multiplier[iStatus];
              double alpha = tableauValue1 * mult;
              double oldValue = abcDj[iSequence] * mult;
              double value = oldValue - tentativeTheta * alpha;
              if (value < dualT) {
                bestPossible = CoinMax(bestPossible, alpha);
                value = oldValue - upperTheta * alpha;
                if (value < dualT && alpha >= acceptablePivot) {
                  upperTheta = (oldValue - dualT) / alpha;
                }
                // add to list
                arrayCandidate[numberRemaining] = alpha;
                indexCandidate[numberRemaining++] = iSequence;
              }
            }
          }
          if (fabs(tableauValue2) > zeroTolerance) {
            int iSequence = sequence[2];
            unsigned char iStatus = internalStatus[iSequence] & 7;
            if (iStatus < 4) {
              index[numberNonZero] = iSequence;
              array[numberNonZero++] = tableauValue2;
              double mult = multiplier[iStatus];
              double alpha = tableauValue2 * mult;
              double oldValue = abcDj[iSequence] * mult;
              double value = oldValue - tentativeTheta * alpha;
              if (value < dualT) {
                bestPossible = CoinMax(bestPossible, alpha);
                value = oldValue - upperTheta * alpha;
                if (value < dualT && alpha >= acceptablePivot) {
                  upperTheta = (oldValue - dualT) / alpha;
                }
                // add to list
                arrayCandidate[numberRemaining] = alpha;
                indexCandidate[numberRemaining++] = iSequence;
              }
            }
          }
          if (fabs(tableauValue3) > zeroTolerance) {
            int iSequence = sequence[3];
            unsigned char iStatus = internalStatus[iSequence] & 7;
            if (iStatus < 4) {
              index[numberNonZero] = iSequence;
              array[numberNonZero++] = tableauValue3;
              double mult = multiplier[iStatus];
              double alpha = tableauValue3 * mult;
              double oldValue = abcDj[iSequence] * mult;
              double value = oldValue - tentativeTheta * alpha;
              if (value < dualT) {
                bestPossible = CoinMax(bestPossible, alpha);
                value = oldValue - upperTheta * alpha;
                if (value < dualT && alpha >= acceptablePivot) {
                  upperTheta = (oldValue - dualT) / alpha;
                }
                // add to list
                arrayCandidate[numberRemaining] = alpha;
                indexCandidate[numberRemaining++] = iSequence;
              }
            }
          }
          sequence += 4;
        }
        for (int i = 0; i < number; i++) {
          int iSequence = sequence[i];
          unsigned char iStatus = internalStatus[iSequence] & 7;
          if (iStatus < 4) {
            double tableauValue = 0.0;
            for (int j = 0; j < iCount; j++) {
              int iRow = blockRow[4 * j];
              tableauValue += pi[iRow] * blockElement[4 * j];
            }
            if (fabs(tableauValue) > zeroTolerance) {
              index[numberNonZero] = iSequence;
              array[numberNonZero++] = tableauValue;
              double mult = multiplier[iStatus];
              double alpha = tableauValue * mult;
              double oldValue = abcDj[iSequence] * mult;
              double value = oldValue - tentativeTheta * alpha;
              if (value < dualT) {
                bestPossible = CoinMax(bestPossible, alpha);
                value = oldValue - upperTheta * alpha;
                if (value < dualT && alpha >= acceptablePivot) {
                  upperTheta = (oldValue - dualT) / alpha;
                }
                // add to list
                arrayCandidate[numberRemaining] = alpha;
                indexCandidate[numberRemaining++] = iSequence;
              }
            }
          }
          blockRow++;
          blockElement++;
        }
      }
      int numberColumns = model_->numberColumns();
      // large ones
      const CoinBigIndex *COIN_RESTRICT largeStart = countStartLarge_ - countFirst_[MAX_COUNT];
      for (int i = countFirst_[MAX_COUNT]; i < numberColumns; i++) {
        int iSequence = countRealColumn_[i];
        unsigned char iStatus = internalStatus[iSequence] & 7;
        if (iStatus < 4) {
          CoinBigIndex start = largeStart[i];
          CoinBigIndex next = largeStart[i + 1];
          double tableauValue = 0.0;
          for (CoinBigIndex j = start; j < next; j++) {
            int jRow = row[j];
            tableauValue += pi[jRow] * element[j];
          }
          if (fabs(tableauValue) > zeroTolerance) {
            index[numberNonZero] = iSequence;
            array[numberNonZero++] = tableauValue;
            double mult = multiplier[iStatus];
            double alpha = tableauValue * mult;
            double oldValue = abcDj[iSequence] * mult;
            double value = oldValue - tentativeTheta * alpha;
            if (value < dualT) {
              bestPossible = CoinMax(bestPossible, alpha);
              value = oldValue - upperTheta * alpha;
              if (value < dualT && alpha >= acceptablePivot) {
                upperTheta = (oldValue - dualT) / alpha;
              }
              // add to list
              arrayCandidate[numberRemaining] = alpha;
              indexCandidate[numberRemaining++] = iSequence;
            }
          }
        }
      }
    }
#endif
  } else {
    double badFree = 0.0;
    double freePivot = model_->currentAcceptablePivot();
    int freeSequenceIn = model_->freeSequenceIn();
    double currentDualTolerance = model_->currentDualTolerance();
    for (int iSequence = first; iSequence < last; iSequence++) {
      unsigned char iStatus = internalStatus[iSequence] & 7;
      if (iStatus < 6) {
        CoinBigIndex start = columnStart[iSequence];
        CoinBigIndex next = columnStart[iSequence + 1];
        double tableauValue = 0.0;
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          tableauValue += pi[jRow] * elementByColumn[j];
        }
        if (fabs(tableauValue) > zeroTolerance) {
          if ((iStatus & 4) == 0) {
            index[numberNonZero] = iSequence;
            array[numberNonZero++] = tableauValue;
            double mult = multiplier[iStatus];
            double alpha = tableauValue * mult;
            double oldValue = abcDj[iSequence] * mult;
            double value = oldValue - tentativeTheta * alpha;
            if (value < dualT) {
              bestPossible = CoinMax(bestPossible, alpha);
              value = oldValue - upperTheta * alpha;
              if (value < dualT && alpha >= acceptablePivot) {
                upperTheta = (oldValue - dualT) / alpha;
              }
              // add to list
              arrayCandidate[numberRemaining] = alpha;
              indexCandidate[numberRemaining++] = iSequence;
            }
          } else {
            bool keep;
            index[numberNonZero] = iSequence;
            array[numberNonZero++] = tableauValue;
            bestPossible = CoinMax(bestPossible, fabs(tableauValue));
            double oldValue = abcDj[iSequence];
            // If free has to be very large - should come in via dualRow
            //if (getInternalStatus(iSequence+addSequence)==isFree&&fabs(tableauValue)<1.0e-3)
            //break;
            if (oldValue > currentDualTolerance) {
              keep = true;
            } else if (oldValue < -currentDualTolerance) {
              keep = true;
            } else {
              if (fabs(tableauValue) > CoinMax(10.0 * acceptablePivot, 1.0e-5)) {
                keep = true;
              } else {
                keep = false;
                badFree = CoinMax(badFree, fabs(tableauValue));
              }
            }
            if (keep) {
#ifdef PAN
              if (model_->fakeSuperBasic(iSequence) >= 0) {
#endif
                if (iSequence == freeSequenceIn)
                  tableauValue = COIN_DBL_MAX;
                // free - choose largest
                if (fabs(tableauValue) > fabs(freePivot)) {
                  freePivot = tableauValue;
                  sequenceIn = iSequence;
                }
#ifdef PAN
              }
#endif
            }
          }
        }
      }
    }
  }
  // adjust
  numberNonZero -= firstIn;
  numberRemaining -= firstIn;
  tableauRow.setNumElementsPartition(iBlock, numberNonZero);
  candidateList.setNumElementsPartition(iBlock, numberRemaining);
  if (!numberRemaining && model_->sequenceIn() < 0) {

    upperThetaResult = COIN_DBL_MAX; // Looks infeasible
  } else {
    upperThetaResult = upperTheta;
  }
}
// gets tableau row - returns number of slacks in block
int AbcMatrix::primalColumnRow(int iBlock, bool doByRow, const CoinIndexedVector &updates,
  CoinPartitionedVector &tableauRow) const
{
  int maximumRows = model_->maximumAbcNumberRows();
  int first = tableauRow.startPartition(iBlock);
  int last = tableauRow.startPartition(iBlock + 1);
  if (doByRow) {
    assert(first == blockStart_[iBlock]);
    assert(last == blockStart_[iBlock + 1]);
  } else {
    assert(first == startColumnBlock_[iBlock]);
    assert(last == startColumnBlock_[iBlock + 1]);
  }
  int numberSlacks = updates.getNumElements();
  int numberNonZero = 0;
  const double *COIN_RESTRICT pi = updates.denseVector();
  const int *COIN_RESTRICT piIndex = updates.getIndices();
  int *COIN_RESTRICT index = tableauRow.getIndices() + first;
  double *COIN_RESTRICT array = tableauRow.denseVector() + first;
  const unsigned char *COIN_RESTRICT internalStatus = model_->internalStatus();
  if (!iBlock) {
    numberNonZero = numberSlacks;
    for (int i = 0; i < numberSlacks; i++) {
      int iRow = piIndex[i];
      index[i] = iRow;
      array[i] = pi[iRow]; // ? what if small or basic
    }
    first = maximumRows;
  }
  double zeroTolerance = model_->zeroTolerance();
  if (doByRow) {
    int numberRows = model_->numberRows();
    const CoinBigIndex *COIN_RESTRICT rowStart = rowStart_ + iBlock * numberRows;
    const CoinBigIndex *COIN_RESTRICT rowEnd = rowStart + numberRows;
    const double *COIN_RESTRICT element = element_;
    const int *COIN_RESTRICT column = column_;
    if (numberSlacks > 1) {
      double *COIN_RESTRICT arrayTemp = tableauRow.denseVector();
      for (int i = 0; i < numberSlacks; i++) {
        int iRow = piIndex[i];
        double piValue = pi[iRow];
        CoinBigIndex end = rowEnd[iRow];
        for (CoinBigIndex j = rowStart[iRow]; j < end; j++) {
          int iColumn = column[j];
          arrayTemp[iColumn] += element[j] * piValue;
        }
      }
      for (int iSequence = first; iSequence < last; iSequence++) {
        double tableauValue = arrayTemp[iSequence];
        if (tableauValue) {
          arrayTemp[iSequence] = 0.0;
          if (fabs(tableauValue) > zeroTolerance) {
            unsigned char iStatus = internalStatus[iSequence] & 7;
            if (iStatus < 6) {
              index[numberNonZero] = iSequence;
              array[numberNonZero++] = tableauValue;
            }
          }
        }
      }
    } else {
      int iRow = piIndex[0];
      double piValue = pi[iRow];
      CoinBigIndex end = rowEnd[iRow];
      for (CoinBigIndex j = rowStart[iRow]; j < end; j++) {
        int iSequence = column[j];
        double tableauValue = element[j] * piValue;
        if (fabs(tableauValue) > zeroTolerance) {
          unsigned char iStatus = internalStatus[iSequence] & 7;
          if (iStatus < 6) {
            index[numberNonZero] = iSequence;
            array[numberNonZero++] = tableauValue;
          }
        }
      }
    }
  } else {
    // get matrix data pointers
    const int *COIN_RESTRICT row = matrix_->getIndices();
    const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
    const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
    const double *COIN_RESTRICT pi = updates.denseVector();
    for (int iSequence = first; iSequence < last; iSequence++) {
      unsigned char iStatus = internalStatus[iSequence] & 7;
      if (iStatus < 6) {
        CoinBigIndex start = columnStart[iSequence];
        CoinBigIndex next = columnStart[iSequence + 1];
        double tableauValue = 0.0;
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          tableauValue += pi[jRow] * elementByColumn[j];
        }
        if (fabs(tableauValue) > zeroTolerance) {
          index[numberNonZero] = iSequence;
          array[numberNonZero++] = tableauValue;
        }
      }
    }
  }
  tableauRow.setNumElementsPartition(iBlock, numberNonZero);
  return numberSlacks;
}
// Get sequenceIn when Dantzig
int AbcMatrix::pivotColumnDantzig(const CoinIndexedVector &updates,
  CoinPartitionedVector &spare) const
{
  int maximumRows = model_->maximumAbcNumberRows();
  // rebalance
  rebalance();
  spare.setPackedMode(true);
  bool useRowCopy = false;
  if (rowStart_) {
    // see if worth using row copy
    int number = updates.getNumElements();
    assert(number);
    useRowCopy = (number << 2) < maximumRows;
  }
  const int *starts;
  if (useRowCopy)
    starts = blockStart();
  else
    starts = startColumnBlock();
#if ABC_PARALLEL
#define NUMBER_BLOCKS NUMBER_ROW_BLOCKS
  int numberBlocks = CoinMin(NUMBER_BLOCKS, model_->numberCpus());
#else
#define NUMBER_BLOCKS 1
  int numberBlocks = NUMBER_BLOCKS;
#endif
#if ABC_PARALLEL
  if (model_->parallelMode() == 0)
    numberBlocks = 1;
#endif
  spare.setPartitions(numberBlocks, starts);
  int which[NUMBER_BLOCKS];
  double best[NUMBER_BLOCKS];
  for (int i = 0; i < numberBlocks - 1; i++)
    which[i] = cilk_spawn pivotColumnDantzig(i, useRowCopy, updates, spare, best[i]);
  which[numberBlocks - 1] = pivotColumnDantzig(numberBlocks - 1, useRowCopy, updates,
    spare, best[numberBlocks - 1]);
  cilk_sync;
  int bestSequence = -1;
  double bestValue = model_->dualTolerance();
  for (int i = 0; i < numberBlocks; i++) {
    if (best[i] > bestValue) {
      bestValue = best[i];
      bestSequence = which[i];
    }
  }
  return bestSequence;
}
// Get sequenceIn when Dantzig (One block)
int AbcMatrix::pivotColumnDantzig(int iBlock, bool doByRow, const CoinIndexedVector &updates,
  CoinPartitionedVector &spare,
  double &bestValue) const
{
  // could rewrite to do more directly
  int numberSlacks = primalColumnRow(iBlock, doByRow, updates, spare);
  double *COIN_RESTRICT reducedCost = model_->djRegion();
  int first = spare.startPartition(iBlock);
  int last = spare.startPartition(iBlock + 1);
  int *COIN_RESTRICT index = spare.getIndices() + first;
  double *COIN_RESTRICT array = spare.denseVector() + first;
  int numberNonZero = spare.getNumElements(iBlock);
  int bestSequence = -1;
  double bestDj = model_->dualTolerance();
  double bestFreeDj = model_->dualTolerance();
  int bestFreeSequence = -1;
  // redo LOTS so signs for slacks and columns same
  if (!first) {
    first = model_->maximumAbcNumberRows();
    for (int i = 0; i < numberSlacks; i++) {
      int iSequence = index[i];
      double value = reducedCost[iSequence];
      value += array[i];
      array[i] = 0.0;
      reducedCost[iSequence] = value;
    }
#ifndef CLP_PRIMAL_SLACK_MULTIPLIER
#define CLP_PRIMAL_SLACK_MULTIPLIER 1.0
#endif
    int numberRows = model_->numberRows();
    for (int iSequence = 0; iSequence < numberRows; iSequence++) {
      // check flagged variable
      if (!model_->flagged(iSequence)) {
        double value = reducedCost[iSequence] * CLP_PRIMAL_SLACK_MULTIPLIER;
        AbcSimplex::Status status = model_->getInternalStatus(iSequence);

        switch (status) {

        case AbcSimplex::basic:
        case AbcSimplex::isFixed:
          break;
        case AbcSimplex::isFree:
        case AbcSimplex::superBasic:
          if (fabs(value) > bestFreeDj) {
            bestFreeDj = fabs(value);
            bestFreeSequence = iSequence;
          }
          break;
        case AbcSimplex::atUpperBound:
          if (value > bestDj) {
            bestDj = value;
            bestSequence = iSequence;
          }
          break;
        case AbcSimplex::atLowerBound:
          if (value < -bestDj) {
            bestDj = -value;
            bestSequence = iSequence;
          }
        }
      }
    }
  }
  for (int i = numberSlacks; i < numberNonZero; i++) {
    int iSequence = index[i];
    double value = reducedCost[iSequence];
    value += array[i];
    array[i] = 0.0;
    reducedCost[iSequence] = value;
  }
  for (int iSequence = first; iSequence < last; iSequence++) {
    // check flagged variable
    if (!model_->flagged(iSequence)) {
      double value = reducedCost[iSequence];
      AbcSimplex::Status status = model_->getInternalStatus(iSequence);

      switch (status) {

      case AbcSimplex::basic:
      case AbcSimplex::isFixed:
        break;
      case AbcSimplex::isFree:
      case AbcSimplex::superBasic:
        if (fabs(value) > bestFreeDj) {
          bestFreeDj = fabs(value);
          bestFreeSequence = iSequence;
        }
        break;
      case AbcSimplex::atUpperBound:
        if (value > bestDj) {
          bestDj = value;
          bestSequence = iSequence;
        }
        break;
      case AbcSimplex::atLowerBound:
        if (value < -bestDj) {
          bestDj = -value;
          bestSequence = iSequence;
        }
      }
    }
  }
  spare.setNumElementsPartition(iBlock, 0);
  // bias towards free
  if (bestFreeSequence >= 0 && bestFreeDj > 0.1 * bestDj) {
    bestSequence = bestFreeSequence;
    bestDj = 10.0 * bestFreeDj;
  }
  bestValue = bestDj;
  return bestSequence;
}
// gets tableau row and dj row - returns number of slacks in block
int AbcMatrix::primalColumnRowAndDjs(int iBlock, const CoinIndexedVector &updateTableau,
  const CoinIndexedVector &updateDjs,
  CoinPartitionedVector &tableauRow) const
{
  int maximumRows = model_->maximumAbcNumberRows();
  int first = tableauRow.startPartition(iBlock);
  int last = tableauRow.startPartition(iBlock + 1);
  assert(first == startColumnBlock_[iBlock]);
  assert(last == startColumnBlock_[iBlock + 1]);
  int numberSlacks = updateTableau.getNumElements();
  int numberNonZero = 0;
  const double *COIN_RESTRICT piTableau = updateTableau.denseVector();
  const double *COIN_RESTRICT pi = updateDjs.denseVector();
  int *COIN_RESTRICT index = tableauRow.getIndices() + first;
  double *COIN_RESTRICT array = tableauRow.denseVector() + first;
  const unsigned char *COIN_RESTRICT internalStatus = model_->internalStatus();
  double *COIN_RESTRICT reducedCost = model_->djRegion();
  if (!iBlock) {
    const int *COIN_RESTRICT piIndexTableau = updateTableau.getIndices();
    numberNonZero = numberSlacks;
    for (int i = 0; i < numberSlacks; i++) {
      int iRow = piIndexTableau[i];
      index[i] = iRow;
      array[i] = piTableau[iRow]; // ? what if small or basic
    }
    const int *COIN_RESTRICT piIndex = updateDjs.getIndices();
    int number = updateDjs.getNumElements();
    for (int i = 0; i < number; i++) {
      int iRow = piIndex[i];
      reducedCost[iRow] -= pi[iRow]; // sign?
    }
    first = maximumRows;
  }
  double zeroTolerance = model_->zeroTolerance();
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  for (int iSequence = first; iSequence < last; iSequence++) {
    unsigned char iStatus = internalStatus[iSequence] & 7;
    if (iStatus < 6) {
      CoinBigIndex start = columnStart[iSequence];
      CoinBigIndex next = columnStart[iSequence + 1];
      double tableauValue = 0.0;
      double djValue = reducedCost[iSequence];
      for (CoinBigIndex j = start; j < next; j++) {
        int jRow = row[j];
        tableauValue += piTableau[jRow] * elementByColumn[j];
        djValue -= pi[jRow] * elementByColumn[j]; // sign?
      }
      reducedCost[iSequence] = djValue;
      if (fabs(tableauValue) > zeroTolerance) {
        index[numberNonZero] = iSequence;
        array[numberNonZero++] = tableauValue;
      }
    }
  }
  tableauRow.setNumElementsPartition(iBlock, numberNonZero);
  return numberSlacks;
}
/* does steepest edge double or triple update
   If scaleFactor!=0 then use with tableau row to update djs
   otherwise use updateForDjs
*/
int AbcMatrix::primalColumnDouble(int iBlock, CoinPartitionedVector &updateForTableauRow,
  CoinPartitionedVector &updateForDjs,
  const CoinIndexedVector &updateForWeights,
  CoinPartitionedVector &spareColumn1,
  double *infeasibilities,
  double referenceIn, double devex,
  // Array for exact devex to say what is in reference framework
  unsigned int *reference,
  double *weights, double scaleFactor) const
{
  int maximumRows = model_->maximumAbcNumberRows();
  int first = startColumnBlock_[iBlock];
  int last = startColumnBlock_[iBlock + 1];
  const double *COIN_RESTRICT piTableau = updateForTableauRow.denseVector();
  const double *COIN_RESTRICT pi = updateForDjs.denseVector();
  const double *COIN_RESTRICT piWeights = updateForWeights.denseVector();
  const unsigned char *COIN_RESTRICT internalStatus = model_->internalStatus();
  double *COIN_RESTRICT reducedCost = model_->djRegion();
  double tolerance = model_->currentDualTolerance();
  // use spareColumn to track new infeasibilities
  int *COIN_RESTRICT newInfeas = spareColumn1.getIndices() + first;
  int numberNewInfeas = 0;
  // we can't really trust infeasibilities if there is dual error
  // this coding has to mimic coding in checkDualSolution
  double error = CoinMin(1.0e-2, model_->largestDualError());
  // allow tolerance at least slightly bigger than standard
  tolerance = tolerance + error;
  double mult[2] = { 1.0, -1.0 };
  bool updateWeights = devex != 0.0;
#define isReference(i) (((reference[i >> 5] >> (i & 31)) & 1) != 0)
  // Scale factor is other way round so tableau row is 1.0* while dj update is scaleFactor*
  if (!iBlock) {
    int numberSlacks = updateForTableauRow.getNumElements();
    const int *COIN_RESTRICT piIndexTableau = updateForTableauRow.getIndices();
    if (!scaleFactor) {
      const int *COIN_RESTRICT piIndex = updateForDjs.getIndices();
      int number = updateForDjs.getNumElements();
      for (int i = 0; i < number; i++) {
        int iRow = piIndex[i];
        int iStatus = internalStatus[iRow] & 7;
        double value = reducedCost[iRow];
        value += pi[iRow];
        if (iStatus < 4) {
          reducedCost[iRow] = value;
          value *= mult[iStatus];
          if (value < 0.0) {
            if (!infeasibilities[iRow])
              newInfeas[numberNewInfeas++] = iRow;
#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
            infeasibilities[iRow] = value * value * CLP_PRIMAL_SLACK_MULTIPLIER;
#else
            infeasibilities[iRow] = value * value;
#endif
          } else {
            if (infeasibilities[iRow])
              infeasibilities[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
          }
        }
      }
    } else if (scaleFactor != COIN_DBL_MAX) {
      for (int i = 0; i < numberSlacks; i++) {
        int iRow = piIndexTableau[i];
        int iStatus = internalStatus[iRow] & 7;
        if (iStatus < 4) {
          double value = reducedCost[iRow];
          value += scaleFactor * piTableau[iRow]; // sign?
          reducedCost[iRow] = value;
          value *= mult[iStatus];
          if (value < 0.0) {
            if (!infeasibilities[iRow])
              newInfeas[numberNewInfeas++] = iRow;
#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
            infeasibilities[iRow] = value * value * CLP_PRIMAL_SLACK_MULTIPLIER;
#else
            infeasibilities[iRow] = value * value;
#endif
          } else {
            if (infeasibilities[iRow])
              infeasibilities[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
          }
        }
      }
    }
    if (updateWeights) {
      for (int i = 0; i < numberSlacks; i++) {
        int iRow = piIndexTableau[i];
        double modification = piWeights[iRow];
        double thisWeight = weights[iRow];
        double pivot = piTableau[iRow];
        double pivotSquared = pivot * pivot;
        thisWeight += pivotSquared * devex - pivot * modification;
        if (thisWeight < DEVEX_TRY_NORM) {
          if (referenceIn < 0.0) {
            // steepest
            thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
          } else {
            // exact
            thisWeight = referenceIn * pivotSquared;
            if (isReference(iRow))
              thisWeight += 1.0;
            thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
          }
        }
        weights[iRow] = thisWeight;
      }
    }
    first = maximumRows;
  }
  double zeroTolerance = model_->zeroTolerance();
  double freeTolerance = FREE_ACCEPT * tolerance;
  ;
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  bool updateDjs = scaleFactor != COIN_DBL_MAX;
  for (int iSequence = first; iSequence < last; iSequence++) {
    unsigned char iStatus = internalStatus[iSequence] & 7;
    if (iStatus < 6) {
      CoinBigIndex start = columnStart[iSequence];
      CoinBigIndex next = columnStart[iSequence + 1];
      double tableauValue = 0.0;
      double djValue = reducedCost[iSequence];
      if (!scaleFactor) {
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          tableauValue += piTableau[jRow] * elementByColumn[j];
          djValue += pi[jRow] * elementByColumn[j];
        }
      } else {
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          tableauValue += piTableau[jRow] * elementByColumn[j];
        }
        djValue += tableauValue * scaleFactor; // sign?
      }
      if (updateDjs) {
        reducedCost[iSequence] = djValue;
        if (iStatus < 4) {
          djValue *= mult[iStatus];
          if (djValue < 0.0) {
            if (!infeasibilities[iSequence])
              newInfeas[numberNewInfeas++] = iSequence;
            infeasibilities[iSequence] = djValue * djValue;
          } else {
            if (infeasibilities[iSequence])
              infeasibilities[iSequence] = COIN_INDEXED_REALLY_TINY_ELEMENT;
          }
        } else {
          if (fabs(djValue) > freeTolerance) {
            // we are going to bias towards free (but only if reasonable)
            djValue *= FREE_BIAS;
            if (!infeasibilities[iSequence])
              newInfeas[numberNewInfeas++] = iSequence;
            // store square in list
            infeasibilities[iSequence] = djValue * djValue;
          } else {
            if (infeasibilities[iSequence])
              infeasibilities[iSequence] = COIN_INDEXED_REALLY_TINY_ELEMENT;
          }
        }
      }
      if (fabs(tableauValue) > zeroTolerance && updateWeights) {
        double modification = 0.0;
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          modification += piWeights[jRow] * elementByColumn[j];
        }
        double thisWeight = weights[iSequence];
        double pivot = tableauValue;
        double pivotSquared = pivot * pivot;
        thisWeight += pivotSquared * devex - pivot * modification;
        if (thisWeight < DEVEX_TRY_NORM) {
          if (referenceIn < 0.0) {
            // steepest
            thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
          } else {
            // exact
            thisWeight = referenceIn * pivotSquared;
            if (isReference(iSequence))
              thisWeight += 1.0;
            thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
          }
        }
        weights[iSequence] = thisWeight;
      }
    }
  }
  spareColumn1.setTempNumElementsPartition(iBlock, numberNewInfeas);
  int bestSequence = -1;
#if 0
  if (!iBlock)
    first=0;
  // not at present - maybe later
  double bestDj=tolerance*tolerance;
  for (int iSequence=first;iSequence<last;iSequence++) {
    if (infeasibilities[iSequence]>bestDj*weights[iSequence]) {
      int iStatus=internalStatus[iSequence]&7;
      assert (iStatus<6);
      bestSequence=iSequence;
      bestDj=infeasibilities[iSequence]/weights[iSequence];
    }
  }
#endif
  return bestSequence;
}
/* does steepest edge double or triple update
   If scaleFactor!=0 then use with tableau row to update djs
   otherwise use updateForDjs
*/
int AbcMatrix::primalColumnSparseDouble(int iBlock, CoinPartitionedVector &updateForTableauRow,
  CoinPartitionedVector &updateForDjs,
  const CoinIndexedVector &updateForWeights,
  CoinPartitionedVector &spareColumn1,
  double *infeasibilities,
  double referenceIn, double devex,
  // Array for exact devex to say what is in reference framework
  unsigned int *reference,
  double *weights, double scaleFactor) const
{
  int maximumRows = model_->maximumAbcNumberRows();
  int first = blockStart_[iBlock];
  //int last=blockStart_[iBlock+1];
  const double *COIN_RESTRICT piTableau = updateForTableauRow.denseVector();
  //const double *  COIN_RESTRICT pi=updateForDjs.denseVector();
  const double *COIN_RESTRICT piWeights = updateForWeights.denseVector();
  const unsigned char *COIN_RESTRICT internalStatus = model_->internalStatus();
  double *COIN_RESTRICT reducedCost = model_->djRegion();
  double tolerance = model_->currentDualTolerance();
  // use spareColumn to track new infeasibilities
  int *COIN_RESTRICT newInfeas = spareColumn1.getIndices() + first;
  int numberNewInfeas = 0;
  // we can't really trust infeasibilities if there is dual error
  // this coding has to mimic coding in checkDualSolution
  double error = CoinMin(1.0e-2, model_->largestDualError());
  // allow tolerance at least slightly bigger than standard
  tolerance = tolerance + error;
  double mult[2] = { 1.0, -1.0 };
  bool updateWeights = devex != 0.0;
  int numberSlacks = updateForTableauRow.getNumElements();
  const int *COIN_RESTRICT piIndexTableau = updateForTableauRow.getIndices();
#define isReference(i) (((reference[i >> 5] >> (i & 31)) & 1) != 0)
  // Scale factor is other way round so tableau row is 1.0* while dj update is scaleFactor*
  assert(scaleFactor);
  if (!iBlock) {
    if (scaleFactor != COIN_DBL_MAX) {
      for (int i = 0; i < numberSlacks; i++) {
        int iRow = piIndexTableau[i];
        int iStatus = internalStatus[iRow] & 7;
        if (iStatus < 4) {
          double value = reducedCost[iRow];
          value += scaleFactor * piTableau[iRow]; // sign?
          reducedCost[iRow] = value;
          value *= mult[iStatus];
          if (value < 0.0) {
            if (!infeasibilities[iRow])
              newInfeas[numberNewInfeas++] = iRow;
#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
            infeasibilities[iRow] = value * value * CLP_PRIMAL_SLACK_MULTIPLIER;
#else
            infeasibilities[iRow] = value * value;
#endif
          } else {
            if (infeasibilities[iRow])
              infeasibilities[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
          }
        }
      }
    }
    if (updateWeights) {
      for (int i = 0; i < numberSlacks; i++) {
        int iRow = piIndexTableau[i];
        double modification = piWeights[iRow];
        double thisWeight = weights[iRow];
        double pivot = piTableau[iRow];
        double pivotSquared = pivot * pivot;
        thisWeight += pivotSquared * devex - pivot * modification;
        if (thisWeight < DEVEX_TRY_NORM) {
          if (referenceIn < 0.0) {
            // steepest
            thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
          } else {
            // exact
            thisWeight = referenceIn * pivotSquared;
            if (isReference(iRow))
              thisWeight += 1.0;
            thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
          }
        }
        weights[iRow] = thisWeight;
      }
    }
    first = maximumRows;
  }
  double zeroTolerance = model_->zeroTolerance();
  double freeTolerance = FREE_ACCEPT * tolerance;
  ;
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  // get tableau row
  int *COIN_RESTRICT index = updateForTableauRow.getIndices() + first;
  double *COIN_RESTRICT array = updateForTableauRow.denseVector();
  int numberRows = model_->numberRows();
  const CoinBigIndex *COIN_RESTRICT rowStart = rowStart_ + iBlock * numberRows;
  const CoinBigIndex *COIN_RESTRICT rowEnd = rowStart + numberRows;
  const double *COIN_RESTRICT element = element_;
  const int *COIN_RESTRICT column = column_;
  int numberInRow = 0;
  if (numberSlacks > 2) {
    for (int i = 0; i < numberSlacks; i++) {
      int iRow = piIndexTableau[i];
      double piValue = piTableau[iRow];
      CoinBigIndex end = rowEnd[iRow];
      for (CoinBigIndex j = rowStart[iRow]; j < end; j++) {
        int iSequence = column[j];
        double value = element[j] * piValue;
        double oldValue = array[iSequence];
        value += oldValue;
        if (!oldValue) {
          array[iSequence] = value;
          index[numberInRow++] = iSequence;
        } else if (value) {
          array[iSequence] = value;
        } else {
          array[iSequence] = COIN_INDEXED_REALLY_TINY_ELEMENT;
        }
      }
    }
  } else if (numberSlacks == 2) {
    int iRow0 = piIndexTableau[0];
    int iRow1 = piIndexTableau[1];
    CoinBigIndex end0 = rowEnd[iRow0];
    CoinBigIndex end1 = rowEnd[iRow1];
    if (end0 - rowStart[iRow0] > end1 - rowStart[iRow1]) {
      int temp = iRow0;
      iRow0 = iRow1;
      iRow1 = temp;
    }
    CoinBigIndex start = rowStart[iRow0];
    CoinBigIndex end = rowEnd[iRow0];
    double piValue = piTableau[iRow0];
    for (CoinBigIndex j = start; j < end; j++) {
      int iSequence = column[j];
      double value = element[j];
      array[iSequence] = piValue * value;
      index[numberInRow++] = iSequence;
    }
    start = rowStart[iRow1];
    end = rowEnd[iRow1];
    piValue = piTableau[iRow1];
    for (CoinBigIndex j = start; j < end; j++) {
      int iSequence = column[j];
      double value = element[j];
      value *= piValue;
      if (!array[iSequence]) {
        array[iSequence] = value;
        index[numberInRow++] = iSequence;
      } else {
        value += array[iSequence];
        if (value)
          array[iSequence] = value;
        else
          array[iSequence] = COIN_INDEXED_REALLY_TINY_ELEMENT;
      }
    }
  } else {
    int iRow0 = piIndexTableau[0];
    CoinBigIndex start = rowStart[iRow0];
    CoinBigIndex end = rowEnd[iRow0];
    double piValue = piTableau[iRow0];
    for (CoinBigIndex j = start; j < end; j++) {
      int iSequence = column[j];
      double value = element[j];
      array[iSequence] = piValue * value;
      index[numberInRow++] = iSequence;
    }
  }
  bool updateDjs = scaleFactor != COIN_DBL_MAX;
  for (int iLook = 0; iLook < numberInRow; iLook++) {
    int iSequence = index[iLook];
    unsigned char iStatus = internalStatus[iSequence] & 7;
    if (iStatus < 6) {
      double tableauValue = array[iSequence];
      array[iSequence] = 0.0;
      double djValue = reducedCost[iSequence];
      djValue += tableauValue * scaleFactor; // sign?
      if (updateDjs) {
        reducedCost[iSequence] = djValue;
        if (iStatus < 4) {
          djValue *= mult[iStatus];
          if (djValue < 0.0) {
            if (!infeasibilities[iSequence])
              newInfeas[numberNewInfeas++] = iSequence;
            infeasibilities[iSequence] = djValue * djValue;
          } else {
            if (infeasibilities[iSequence])
              infeasibilities[iSequence] = COIN_INDEXED_REALLY_TINY_ELEMENT;
          }
        } else {
          if (fabs(djValue) > freeTolerance) {
            // we are going to bias towards free (but only if reasonable)
            djValue *= FREE_BIAS;
            if (!infeasibilities[iSequence])
              newInfeas[numberNewInfeas++] = iSequence;
            // store square in list
            infeasibilities[iSequence] = djValue * djValue;
          } else {
            if (infeasibilities[iSequence])
              infeasibilities[iSequence] = COIN_INDEXED_REALLY_TINY_ELEMENT;
          }
        }
      }
      if (fabs(tableauValue) > zeroTolerance && updateWeights) {
        CoinBigIndex start = columnStart[iSequence];
        CoinBigIndex next = columnStart[iSequence + 1];
        double modification = 0.0;
        for (CoinBigIndex j = start; j < next; j++) {
          int jRow = row[j];
          modification += piWeights[jRow] * elementByColumn[j];
        }
        double thisWeight = weights[iSequence];
        double pivot = tableauValue;
        double pivotSquared = pivot * pivot;
        thisWeight += pivotSquared * devex - pivot * modification;
        if (thisWeight < DEVEX_TRY_NORM) {
          if (referenceIn < 0.0) {
            // steepest
            thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
          } else {
            // exact
            thisWeight = referenceIn * pivotSquared;
            if (isReference(iSequence))
              thisWeight += 1.0;
            thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
          }
        }
        weights[iSequence] = thisWeight;
      }
    } else {
      array[iSequence] = 0.0;
    }
  }
  spareColumn1.setTempNumElementsPartition(iBlock, numberNewInfeas);
  int bestSequence = -1;
#if 0
  if (!iBlock)
    first=0;
  // not at present - maybe later
  double bestDj=tolerance*tolerance;
  for (int iSequence=first;iSequence<last;iSequence++) {
    if (infeasibilities[iSequence]>bestDj*weights[iSequence]) {
      int iStatus=internalStatus[iSequence]&7;
      assert (iStatus<6);
      bestSequence=iSequence;
      bestDj=infeasibilities[iSequence]/weights[iSequence];
    }
  }
#endif
  return bestSequence;
}
#if 0
/* Chooses best weighted dj
 */
int 
AbcMatrix::chooseBestDj(int iBlock,const CoinIndexedVector & infeasibilities, 
			const double * weights) const
{
  return 0;
}
#endif
/* does steepest edge double or triple update
   If scaleFactor!=0 then use with tableau row to update djs
   otherwise use updateForDjs
   Returns best
*/
int AbcMatrix::primalColumnDouble(CoinPartitionedVector &updateForTableauRow,
  CoinPartitionedVector &updateForDjs,
  const CoinIndexedVector &updateForWeights,
  CoinPartitionedVector &spareColumn1,
  CoinIndexedVector &infeasible,
  double referenceIn, double devex,
  // Array for exact devex to say what is in reference framework
  unsigned int *reference,
  double *weights, double scaleFactor) const
{
  //int maximumRows = model_->maximumAbcNumberRows();
  // rebalance
  rebalance();
#ifdef PRICE_IN_ABC_MATRIX
  int which[NUMBER_BLOCKS];
#endif
  double *infeasibilities = infeasible.denseVector();
  int bestSequence = -1;
  // see if worth using row copy
  int maximumRows = model_->maximumAbcNumberRows();
  int number = updateForTableauRow.getNumElements();
#ifdef GCC_4_9
  assert(number);
#else
  if (!number) {
    printf("Null tableau row!\n");
  }
#endif
  bool useRowCopy = (gotRowCopy() && (number << 2) < maximumRows);
  //useRowCopy=false;
  if (!scaleFactor)
    useRowCopy = false; // look again later
  const int *starts;
  int numberBlocks;
  if (useRowCopy) {
    starts = blockStart_;
    numberBlocks = numberRowBlocks_;
  } else {
    starts = startColumnBlock_;
    numberBlocks = numberColumnBlocks_;
  }
  if (useRowCopy) {
    for (int i = 0; i < numberBlocks; i++)
#ifdef PRICE_IN_ABC_MATRIX
      which[i] =
#endif
        cilk_spawn primalColumnSparseDouble(i, updateForTableauRow, updateForDjs, updateForWeights,
          spareColumn1,
          infeasibilities, referenceIn, devex, reference, weights, scaleFactor);
    cilk_sync;
  } else {
    for (int i = 0; i < numberBlocks; i++)
#ifdef PRICE_IN_ABC_MATRIX
      which[i] =
#endif
        cilk_spawn primalColumnDouble(i, updateForTableauRow, updateForDjs, updateForWeights,
          spareColumn1,
          infeasibilities, referenceIn, devex, reference, weights, scaleFactor);
    cilk_sync;
  }
#ifdef PRICE_IN_ABC_MATRIX
  double bestValue = model_->dualTolerance();
  int sequenceIn[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
#endif
  assert(numberColumnBlocks_ <= 8);
#ifdef PRICE_IN_ABC_MATRIX
  double weightedDj[8];
  int nPossible = 0;
#endif
  //const double * reducedCost = model_->djRegion();
  // use spareColumn to track new infeasibilities
  int numberInfeas = infeasible.getNumElements();
  int *COIN_RESTRICT infeas = infeasible.getIndices();
  const int *COIN_RESTRICT newInfeasAll = spareColumn1.getIndices();
  for (int i = 0; i < numberColumnBlocks_; i++) {
    const int *COIN_RESTRICT newInfeas = newInfeasAll + starts[i];
    int numberNewInfeas = spareColumn1.getNumElements(i);
    spareColumn1.setTempNumElementsPartition(i, 0);
    for (int j = 0; j < numberNewInfeas; j++)
      infeas[numberInfeas++] = newInfeas[j];
#ifdef PRICE_IN_ABC_MATRIX
    if (which[i] >= 0) {
      int iSequence = which[i];
      double value = fabs(infeasibilities[iSequence] / weights[iSequence]);
      if (value > bestValue) {
        bestValue = value;
        bestSequence = which[i];
      }
      weightedDj[nPossible] = -value;
      sequenceIn[nPossible++] = iSequence;
    }
#endif
  }
  infeasible.setNumElements(numberInfeas);
#ifdef PRICE_IN_ABC_MATRIX
  CoinSort_2(weightedDj, weightedDj + nPossible, sequenceIn);
  //model_->setMultipleSequenceIn(sequenceIn);
#endif
  return bestSequence;
}
// Partial pricing
void AbcMatrix::partialPricing(double startFraction, double endFraction,
  int &bestSequence, int &numberWanted)
{
  numberWanted = currentWanted_;
  int maximumRows = model_->maximumAbcNumberRows();
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  int numberColumns = model_->numberColumns();
  int start = static_cast< int >(startFraction * numberColumns);
  int end = CoinMin(static_cast< int >(endFraction * numberColumns + 1), numberColumns);
  // adjust
  start += maximumRows;
  end += maximumRows;
  double tolerance = model_->currentDualTolerance();
  double *reducedCost = model_->djRegion();
  const double *duals = model_->dualRowSolution();
  const double *cost = model_->costRegion();
  double bestDj;
  if (bestSequence >= 0)
    bestDj = fabs(reducedCost[bestSequence]);
  else
    bestDj = tolerance;
  int sequenceOut = model_->sequenceOut();
  int saveSequence = bestSequence;
  int lastScan = minimumObjectsScan_ < 0 ? end : start + minimumObjectsScan_;
  int minNeg = minimumGoodReducedCosts_ == -1 ? numberWanted : minimumGoodReducedCosts_;
  for (int iSequence = start; iSequence < end; iSequence++) {
    if (iSequence != sequenceOut) {
      double value;
      AbcSimplex::Status status = model_->getInternalStatus(iSequence);
      switch (status) {
      case AbcSimplex::basic:
      case AbcSimplex::isFixed:
        break;
      case AbcSimplex::isFree:
      case AbcSimplex::superBasic:
        value = cost[iSequence];
        for (CoinBigIndex j = columnStart[iSequence];
             j < columnStart[iSequence + 1]; j++) {
          int jRow = row[j];
          value -= duals[jRow] * elementByColumn[j];
        }
        value = fabs(value);
        if (value > FREE_ACCEPT * tolerance) {
          numberWanted--;
          // we are going to bias towards free (but only if reasonable)
          value *= FREE_BIAS;
          if (value > bestDj) {
            // check flagged variable and correct dj
            if (!model_->flagged(iSequence)) {
              bestDj = value;
              bestSequence = iSequence;
            } else {
              // just to make sure we don't exit before got something
              numberWanted++;
            }
          }
        }
        break;
      case AbcSimplex::atUpperBound:
        value = cost[iSequence];
        // scaled
        for (CoinBigIndex j = columnStart[iSequence];
             j < columnStart[iSequence + 1]; j++) {
          int jRow = row[j];
          value -= duals[jRow] * elementByColumn[j];
        }
        if (value > tolerance) {
          numberWanted--;
          if (value > bestDj) {
            // check flagged variable and correct dj
            if (!model_->flagged(iSequence)) {
              bestDj = value;
              bestSequence = iSequence;
            } else {
              // just to make sure we don't exit before got something
              numberWanted++;
            }
          }
        }
        break;
      case AbcSimplex::atLowerBound:
        value = cost[iSequence];
        for (CoinBigIndex j = columnStart[iSequence];
             j < columnStart[iSequence + 1]; j++) {
          int jRow = row[j];
          value -= duals[jRow] * elementByColumn[j];
        }
        value = -value;
        if (value > tolerance) {
          numberWanted--;
          if (value > bestDj) {
            // check flagged variable and correct dj
            if (!model_->flagged(iSequence)) {
              bestDj = value;
              bestSequence = iSequence;
            } else {
              // just to make sure we don't exit before got something
              numberWanted++;
            }
          }
        }
        break;
      }
    }
    if (numberWanted + minNeg < originalWanted_ && iSequence > lastScan) {
      // give up
      break;
    }
    if (!numberWanted)
      break;
  }
  if (bestSequence != saveSequence) {
    // recompute dj
    double value = cost[bestSequence];
    for (CoinBigIndex j = columnStart[bestSequence];
         j < columnStart[bestSequence + 1]; j++) {
      int jRow = row[j];
      value -= duals[jRow] * elementByColumn[j];
    }
    reducedCost[bestSequence] = value;
    savedBestSequence_ = bestSequence;
    savedBestDj_ = reducedCost[savedBestSequence_];
  }
  currentWanted_ = numberWanted;
}
/* Return <code>x *A</code> in <code>z</code> but
   just for indices Already in z.
   Note - z always packed mode */
void AbcMatrix::subsetTransposeTimes(const CoinIndexedVector &x,
  CoinIndexedVector &z) const
{
  int maximumRows = model_->maximumAbcNumberRows();
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  const double *COIN_RESTRICT other = x.denseVector();
  int numberNonZero = z.getNumElements();
  int *COIN_RESTRICT index = z.getIndices();
  double *COIN_RESTRICT array = z.denseVector();
  int numberRows = model_->numberRows();
  for (int i = 0; i < numberNonZero; i++) {
    int iSequence = index[i];
    if (iSequence >= numberRows) {
      CoinBigIndex start = columnStart[iSequence];
      CoinBigIndex next = columnStart[iSequence + 1];
      double value = 0.0;
      for (CoinBigIndex j = start; j < next; j++) {
        int jRow = row[j];
        value -= other[jRow] * elementByColumn[j];
      }
      array[i] = value;
    } else {
      array[i] = -other[iSequence];
    }
  }
}
// Return <code>-x *A</code> in <code>z</code>
void AbcMatrix::transposeTimes(const CoinIndexedVector &x,
  CoinIndexedVector &z) const
{
  int maximumRows = model_->maximumAbcNumberRows();
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  const double *COIN_RESTRICT other = x.denseVector();
  int numberNonZero = 0;
  int *COIN_RESTRICT index = z.getIndices();
  double *COIN_RESTRICT array = z.denseVector();
  int numberColumns = model_->numberColumns();
  double zeroTolerance = model_->zeroTolerance();
  for (int iSequence = maximumRows; iSequence < maximumRows + numberColumns; iSequence++) {
    CoinBigIndex start = columnStart[iSequence];
    CoinBigIndex next = columnStart[iSequence + 1];
    double value = 0.0;
    for (CoinBigIndex j = start; j < next; j++) {
      int jRow = row[j];
      value -= other[jRow] * elementByColumn[j];
    }
    if (fabs(value) > zeroTolerance) {
      // TEMP
      array[iSequence - maximumRows] = value;
      index[numberNonZero++] = iSequence - maximumRows;
    }
  }
  z.setNumElements(numberNonZero);
}
/* Return A * scalar(+-1) *x + y</code> in <code>y</code>.
   @pre <code>x</code> must be of size <code>numRows()</code>
   @pre <code>y</code> must be of size <code>numRows()+numColumns()</code> */
void AbcMatrix::transposeTimesNonBasic(double scalar,
  const double *pi, double *y) const
{
  int numberTotal = model_->numberTotal();
  int maximumRows = model_->maximumAbcNumberRows();
  assert(scalar == -1.0);
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  int numberRows = model_->numberRows();
  const unsigned char *COIN_RESTRICT status = model_->internalStatus();
  for (int i = 0; i < numberRows; i++) {
    y[i] += scalar * pi[i];
  }
  for (int iColumn = maximumRows; iColumn < numberTotal; iColumn++) {
    unsigned char type = status[iColumn] & 7;
    if (type < 6) {
      CoinBigIndex start = columnStart[iColumn];
      CoinBigIndex next = columnStart[iColumn + 1];
      double value = 0.0;
      for (CoinBigIndex j = start; j < next; j++) {
        int jRow = row[j];
        value += scalar * pi[jRow] * elementByColumn[j];
      }
      y[iColumn] += value;
    } else {
      y[iColumn] = 0.0; // may not be but .....
    }
  }
}
/* Return y - A * x</code> in <code>y</code>.
   @pre <code>x</code> must be of size <code>numRows()</code>
   @pre <code>y</code> must be of size <code>numRows()+numColumns()</code> */
void AbcMatrix::transposeTimesAll(const double *pi, double *y) const
{
  int numberTotal = model_->numberTotal();
  int maximumRows = model_->maximumAbcNumberRows();
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - maximumRows;
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  int numberRows = model_->numberRows();
  for (int i = 0; i < numberRows; i++) {
    y[i] -= pi[i];
  }
  for (int iColumn = maximumRows; iColumn < numberTotal; iColumn++) {
    CoinBigIndex start = columnStart[iColumn];
    CoinBigIndex next = columnStart[iColumn + 1];
    double value = 0.0;
    for (CoinBigIndex j = start; j < next; j++) {
      int jRow = row[j];
      value += pi[jRow] * elementByColumn[j];
    }
    y[iColumn] -= value;
  }
}
/* Return y  + A * scalar(+-1) *x</code> in <code>y</code>.
   @pre <code>x</code> must be of size <code>numRows()</code>
   @pre <code>y</code> must be of size <code>numRows()</code> */
void AbcMatrix::transposeTimesBasic(double scalar,
  const double *pi, double *y) const
{
  assert(scalar == -1.0);
  int numberRows = model_->numberRows();
  //AbcMemset0(y,numberRows);
  // get matrix data pointers
  const int *COIN_RESTRICT row = matrix_->getIndices();
  const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts() - model_->maximumAbcNumberRows();
  const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
  const int *COIN_RESTRICT pivotVariable = model_->pivotVariable();
  for (int i = 0; i < numberRows; i++) {
    int iSequence = pivotVariable[i];
    double value;
    if (iSequence >= numberRows) {
      CoinBigIndex start = columnStart[iSequence];
      CoinBigIndex next = columnStart[iSequence + 1];
      value = 0.0;
      for (CoinBigIndex j = start; j < next; j++) {
        int jRow = row[j];
        value += pi[jRow] * elementByColumn[j];
      }
    } else {
      value = pi[iSequence];
    }
    y[i] += scalar * value;
  }
}
// Adds multiple of a column (or slack) into an CoinIndexedvector
void AbcMatrix::add(CoinIndexedVector &rowArray, int iSequence, double multiplier) const
{
  int maximumRows = model_->maximumAbcNumberRows();
  if (iSequence >= maximumRows) {
    const int *COIN_RESTRICT row = matrix_->getIndices();
    iSequence -= maximumRows;
    const CoinBigIndex *COIN_RESTRICT columnStart = matrix_->getVectorStarts();
    const double *COIN_RESTRICT elementByColumn = matrix_->getElements();
    CoinBigIndex start = columnStart[iSequence];
    CoinBigIndex next = columnStart[iSequence + 1];
    for (CoinBigIndex j = start; j < next; j++) {
      int jRow = row[j];
      rowArray.quickAdd(jRow, elementByColumn[j] * multiplier);
    }
  } else {
    rowArray.quickAdd(iSequence, multiplier);
  }
}
/* Unpacks a column into an CoinIndexedVector
 */
void AbcMatrix::unpack(CoinIndexedVector &usefulArray,
  int sequence) const
{
  usefulArray.clear();
  int maximumRows = model_->maximumAbcNumberRows();
  if (sequence < maximumRows) {
    //slack
    usefulArray.insert(sequence, 1.0);
  } else {
    // column
    const CoinBigIndex *COIN_RESTRICT columnStart = matrix()->getVectorStarts() - maximumRows;
    CoinBigIndex start = columnStart[sequence];
    CoinBigIndex end = columnStart[sequence + 1];
    const int *COIN_RESTRICT row = matrix()->getIndices() + start;
    const double *COIN_RESTRICT elementByColumn = matrix()->getElements() + start;
    int *COIN_RESTRICT index = usefulArray.getIndices();
    double *COIN_RESTRICT array = usefulArray.denseVector();
    int numberNonZero = end - start;
    for (int j = 0; j < numberNonZero; j++) {
      int iRow = row[j];
      index[j] = iRow;
      array[iRow] = elementByColumn[j];
    }
    usefulArray.setNumElements(numberNonZero);
  }
}
// Row starts
CoinBigIndex *
AbcMatrix::rowStart() const
{
  return rowStart_;
}
// Row ends
CoinBigIndex *
AbcMatrix::rowEnd() const
{
  //if (numberRowBlocks_<2) {
  //return rowStart_+1;
  //} else {
  return rowStart_ + model_->numberRows() * (numberRowBlocks_ + 1);
  //}
}
// Row elements
double *
AbcMatrix::rowElements() const
{
  return element_;
}
// Row columnss
CoinSimplexInt *
AbcMatrix::rowColumns() const
{
  return column_;
}

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