/* $Id: ClpDynamicMatrix.cpp 2385 2019-01-06 19:43:06Z unxusr $ */
// Copyright (C) 2004, International Business Machines
// Corporation and others.  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 "ClpSimplex.hpp"
#include "ClpFactorization.hpp"
#include "ClpQuadraticObjective.hpp"
#include "ClpNonLinearCost.hpp"
// at end to get min/max!
#include "ClpDynamicMatrix.hpp"
#include "ClpMessage.hpp"
//#define CLP_DEBUG
//#define CLP_DEBUG_PRINT
//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################

//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
ClpDynamicMatrix::ClpDynamicMatrix()
  : ClpPackedMatrix()
  , sumDualInfeasibilities_(0.0)
  , sumPrimalInfeasibilities_(0.0)
  , sumOfRelaxedDualInfeasibilities_(0.0)
  , sumOfRelaxedPrimalInfeasibilities_(0.0)
  , savedBestGubDual_(0.0)
  , savedBestSet_(0)
  , backToPivotRow_(NULL)
  , keyVariable_(NULL)
  , toIndex_(NULL)
  , fromIndex_(NULL)
  , numberSets_(0)
  , numberActiveSets_(0)
  , objectiveOffset_(0.0)
  , lowerSet_(NULL)
  , upperSet_(NULL)
  , status_(NULL)
  , model_(NULL)
  , firstAvailable_(0)
  , firstAvailableBefore_(0)
  , firstDynamic_(0)
  , lastDynamic_(0)
  , numberStaticRows_(0)
  , numberElements_(0)
  , numberDualInfeasibilities_(0)
  , numberPrimalInfeasibilities_(0)
  , noCheck_(-1)
  , infeasibilityWeight_(0.0)
  , numberGubColumns_(0)
  , maximumGubColumns_(0)
  , maximumElements_(0)
  , startSet_(NULL)
  , next_(NULL)
  , startColumn_(NULL)
  , row_(NULL)
  , element_(NULL)
  , cost_(NULL)
  , id_(NULL)
  , dynamicStatus_(NULL)
  , columnLower_(NULL)
  , columnUpper_(NULL)
{
  setType(15);
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpDynamicMatrix::ClpDynamicMatrix(const ClpDynamicMatrix &rhs)
  : ClpPackedMatrix(rhs)
{
  objectiveOffset_ = rhs.objectiveOffset_;
  numberSets_ = rhs.numberSets_;
  numberActiveSets_ = rhs.numberActiveSets_;
  firstAvailable_ = rhs.firstAvailable_;
  firstAvailableBefore_ = rhs.firstAvailableBefore_;
  firstDynamic_ = rhs.firstDynamic_;
  lastDynamic_ = rhs.lastDynamic_;
  numberStaticRows_ = rhs.numberStaticRows_;
  numberElements_ = rhs.numberElements_;
  backToPivotRow_ = ClpCopyOfArray(rhs.backToPivotRow_, lastDynamic_);
  keyVariable_ = ClpCopyOfArray(rhs.keyVariable_, numberSets_);
  toIndex_ = ClpCopyOfArray(rhs.toIndex_, numberSets_);
  fromIndex_ = ClpCopyOfArray(rhs.fromIndex_, getNumRows() + 1 - numberStaticRows_);
  lowerSet_ = ClpCopyOfArray(rhs.lowerSet_, numberSets_);
  upperSet_ = ClpCopyOfArray(rhs.upperSet_, numberSets_);
  status_ = ClpCopyOfArray(rhs.status_, static_cast< int >(2 * numberSets_ + 4 * sizeof(int)));
  model_ = rhs.model_;
  sumDualInfeasibilities_ = rhs.sumDualInfeasibilities_;
  sumPrimalInfeasibilities_ = rhs.sumPrimalInfeasibilities_;
  sumOfRelaxedDualInfeasibilities_ = rhs.sumOfRelaxedDualInfeasibilities_;
  sumOfRelaxedPrimalInfeasibilities_ = rhs.sumOfRelaxedPrimalInfeasibilities_;
  numberDualInfeasibilities_ = rhs.numberDualInfeasibilities_;
  numberPrimalInfeasibilities_ = rhs.numberPrimalInfeasibilities_;
  savedBestGubDual_ = rhs.savedBestGubDual_;
  savedBestSet_ = rhs.savedBestSet_;
  noCheck_ = rhs.noCheck_;
  infeasibilityWeight_ = rhs.infeasibilityWeight_;
  // Now secondary data
  numberGubColumns_ = rhs.numberGubColumns_;
  maximumGubColumns_ = rhs.maximumGubColumns_;
  maximumElements_ = rhs.maximumElements_;
  startSet_ = ClpCopyOfArray(rhs.startSet_, numberSets_ + 1);
  next_ = ClpCopyOfArray(rhs.next_, maximumGubColumns_);
  startColumn_ = ClpCopyOfArray(rhs.startColumn_, maximumGubColumns_ + 1);
  row_ = ClpCopyOfArray(rhs.row_, maximumElements_);
  element_ = ClpCopyOfArray(rhs.element_, maximumElements_);
  cost_ = ClpCopyOfArray(rhs.cost_, maximumGubColumns_);
  id_ = ClpCopyOfArray(rhs.id_, lastDynamic_ - firstDynamic_);
  columnLower_ = ClpCopyOfArray(rhs.columnLower_, maximumGubColumns_);
  columnUpper_ = ClpCopyOfArray(rhs.columnUpper_, maximumGubColumns_);
  dynamicStatus_ = ClpCopyOfArray(rhs.dynamicStatus_, 2 * maximumGubColumns_);
}

/* This is the real constructor*/
ClpDynamicMatrix::ClpDynamicMatrix(ClpSimplex *model, int numberSets,
  int numberGubColumns, const int *starts,
  const double *lower, const double *upper,
  const CoinBigIndex *startColumn, const int *row,
  const double *element, const double *cost,
  const double *columnLower, const double *columnUpper,
  const unsigned char *status,
  const unsigned char *dynamicStatus)
  : ClpPackedMatrix()
{
  setType(15);
  objectiveOffset_ = model->objectiveOffset();
  model_ = model;
  numberSets_ = numberSets;
  numberGubColumns_ = numberGubColumns;
  maximumGubColumns_ = numberGubColumns_;
  if (numberGubColumns_)
    maximumElements_ = startColumn[numberGubColumns_];
  else
    maximumElements_ = 0;
  startSet_ = new int[numberSets_ + 1];
  next_ = new int[maximumGubColumns_];
  // fill in startSet and next
  int iSet;
  if (numberGubColumns_) {
    for (iSet = 0; iSet < numberSets_; iSet++) {
      int first = starts[iSet];
      int last = starts[iSet + 1] - 1;
      startSet_[iSet] = first;
      for (int i = first; i < last; i++)
        next_[i] = i + 1;
      next_[last] = -iSet - 1;
    }
    startSet_[numberSets_] = starts[numberSets_];
  }
  int numberColumns = model->numberColumns();
  int numberRows = model->numberRows();
  numberStaticRows_ = numberRows;
  savedBestGubDual_ = 0.0;
  savedBestSet_ = 0;
  // Number of columns needed
  int frequency = model->factorizationFrequency();
  int numberGubInSmall = numberRows + frequency + CoinMin(frequency, numberSets_) + 4;
  // But we may have two per row + one for incoming (make it two)
  numberGubInSmall = CoinMax(2 * numberRows + 2, numberGubInSmall);
  // for small problems this could be too big
  //numberGubInSmall = CoinMin(numberGubInSmall,numberGubColumns_);
  int numberNeeded = numberGubInSmall + numberColumns;
  firstAvailable_ = numberColumns;
  firstAvailableBefore_ = firstAvailable_;
  firstDynamic_ = numberColumns;
  lastDynamic_ = numberNeeded;
  startColumn_ = ClpCopyOfArray(startColumn, numberGubColumns_ + 1);
  if (!numberGubColumns_) {
    if (!startColumn_)
      startColumn_ = new CoinBigIndex[1];
    startColumn_[0] = 0;
  }
  CoinBigIndex numberElements = startColumn_[numberGubColumns_];
  row_ = ClpCopyOfArray(row, numberElements);
  element_ = new double[numberElements];
  CoinBigIndex i;
  for (i = 0; i < numberElements; i++)
    element_[i] = element[i];
  cost_ = new double[numberGubColumns_];
  for (i = 0; i < numberGubColumns_; i++) {
    cost_[i] = cost[i];
    // I don't think I need sorted but ...
    CoinSort_2(row_ + startColumn_[i], row_ + startColumn_[i + 1], element_ + startColumn_[i]);
  }
  if (columnLower) {
    columnLower_ = new double[numberGubColumns_];
    for (i = 0; i < numberGubColumns_; i++)
      columnLower_[i] = columnLower[i];
  } else {
    columnLower_ = NULL;
  }
  if (columnUpper) {
    columnUpper_ = new double[numberGubColumns_];
    for (i = 0; i < numberGubColumns_; i++)
      columnUpper_[i] = columnUpper[i];
  } else {
    columnUpper_ = NULL;
  }
  lowerSet_ = new double[numberSets_];
  for (i = 0; i < numberSets_; i++) {
    if (lower[i] > -1.0e20)
      lowerSet_[i] = lower[i];
    else
      lowerSet_[i] = -1.0e30;
  }
  upperSet_ = new double[numberSets_];
  for (i = 0; i < numberSets_; i++) {
    if (upper[i] < 1.0e20)
      upperSet_[i] = upper[i];
    else
      upperSet_[i] = 1.0e30;
  }
  id_ = new int[numberGubInSmall];
  for (i = 0; i < numberGubInSmall; i++)
    id_[i] = -1;
  ClpPackedMatrix *originalMatrixA = dynamic_cast< ClpPackedMatrix * >(model->clpMatrix());
  assert(originalMatrixA);
  CoinPackedMatrix *originalMatrix = originalMatrixA->getPackedMatrix();
  originalMatrixA->setMatrixNull(); // so can be deleted safely
  // guess how much space needed
  double guess = numberElements;
  guess /= static_cast< double >(numberColumns);
  guess *= 2 * numberGubInSmall;
  numberElements_ = static_cast< int >(guess);
  numberElements_ = CoinMin(numberElements_, numberElements) + originalMatrix->getNumElements();
  matrix_ = originalMatrix;
  //delete originalMatrixA;
  flags_ &= ~1;
  // resize model (matrix stays same)
  // modify frequency
  if (frequency >= 50)
    frequency = 50 + (frequency - 50) / 2;
  int newRowSize = numberRows + CoinMin(numberSets_, frequency + numberRows) + 1;
  model->resize(newRowSize, numberNeeded);
  for (i = numberRows; i < newRowSize; i++)
    model->setRowStatus(i, ClpSimplex::basic);
  if (columnUpper_) {
    // set all upper bounds so we have enough space
    double *columnUpper = model->columnUpper();
    for (i = firstDynamic_; i < lastDynamic_; i++)
      columnUpper[i] = 1.0e10;
  }
  // resize matrix
  // extra 1 is so can keep number of elements handy
  originalMatrix->reserve(numberNeeded, numberElements_, true);
  originalMatrix->reserve(numberNeeded + 1, numberElements_, false);
  originalMatrix->getMutableVectorStarts()[numberColumns] = originalMatrix->getNumElements();
  originalMatrix->setDimensions(newRowSize, -1);
  numberActiveColumns_ = firstDynamic_;
  // redo number of columns
  numberColumns = matrix_->getNumCols();
  backToPivotRow_ = new int[numberNeeded];
  keyVariable_ = new int[numberSets_];
  if (status) {
    status_ = ClpCopyOfArray(status, static_cast< int >(2 * numberSets_ + 4 * sizeof(int)));
    assert(dynamicStatus);
    dynamicStatus_ = ClpCopyOfArray(dynamicStatus, 2 * numberGubColumns_);
  } else {
    status_ = new unsigned char[2 * numberSets_ + 4 * sizeof(int)];
    memset(status_, 0, numberSets_);
    int i;
    for (i = 0; i < numberSets_; i++) {
      // make slack key
      setStatus(i, ClpSimplex::basic);
    }
    dynamicStatus_ = new unsigned char[2 * numberGubColumns_];
    memset(dynamicStatus_, 0, numberGubColumns_); // for clarity
    for (i = 0; i < numberGubColumns_; i++)
      setDynamicStatus(i, atLowerBound);
  }
  toIndex_ = new int[numberSets_];
  for (iSet = 0; iSet < numberSets_; iSet++)
    toIndex_[iSet] = -1;
  fromIndex_ = new int[newRowSize - numberStaticRows_ + 1];
  numberActiveSets_ = 0;
  rhsOffset_ = NULL;
  if (numberGubColumns_) {
    if (!status) {
      gubCrash();
    } else {
      initialProblem();
    }
  }
  noCheck_ = -1;
  infeasibilityWeight_ = 0.0;
}

//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
ClpDynamicMatrix::~ClpDynamicMatrix()
{
  delete[] backToPivotRow_;
  delete[] keyVariable_;
  delete[] toIndex_;
  delete[] fromIndex_;
  delete[] lowerSet_;
  delete[] upperSet_;
  delete[] status_;
  delete[] startSet_;
  delete[] next_;
  delete[] startColumn_;
  delete[] row_;
  delete[] element_;
  delete[] cost_;
  delete[] id_;
  delete[] dynamicStatus_;
  delete[] columnLower_;
  delete[] columnUpper_;
}

//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpDynamicMatrix &
ClpDynamicMatrix::operator=(const ClpDynamicMatrix &rhs)
{
  if (this != &rhs) {
    ClpPackedMatrix::operator=(rhs);
    delete[] backToPivotRow_;
    delete[] keyVariable_;
    delete[] toIndex_;
    delete[] fromIndex_;
    delete[] lowerSet_;
    delete[] upperSet_;
    delete[] status_;
    delete[] startSet_;
    delete[] next_;
    delete[] startColumn_;
    delete[] row_;
    delete[] element_;
    delete[] cost_;
    delete[] id_;
    delete[] dynamicStatus_;
    delete[] columnLower_;
    delete[] columnUpper_;
    objectiveOffset_ = rhs.objectiveOffset_;
    numberSets_ = rhs.numberSets_;
    numberActiveSets_ = rhs.numberActiveSets_;
    firstAvailable_ = rhs.firstAvailable_;
    firstAvailableBefore_ = rhs.firstAvailableBefore_;
    firstDynamic_ = rhs.firstDynamic_;
    lastDynamic_ = rhs.lastDynamic_;
    numberStaticRows_ = rhs.numberStaticRows_;
    numberElements_ = rhs.numberElements_;
    backToPivotRow_ = ClpCopyOfArray(rhs.backToPivotRow_, lastDynamic_);
    keyVariable_ = ClpCopyOfArray(rhs.keyVariable_, numberSets_);
    toIndex_ = ClpCopyOfArray(rhs.toIndex_, numberSets_);
    fromIndex_ = ClpCopyOfArray(rhs.fromIndex_, getNumRows() + 1 - numberStaticRows_);
    lowerSet_ = ClpCopyOfArray(rhs.lowerSet_, numberSets_);
    upperSet_ = ClpCopyOfArray(rhs.upperSet_, numberSets_);
    status_ = ClpCopyOfArray(rhs.status_, static_cast< int >(2 * numberSets_ + 4 * sizeof(int)));
    model_ = rhs.model_;
    sumDualInfeasibilities_ = rhs.sumDualInfeasibilities_;
    sumPrimalInfeasibilities_ = rhs.sumPrimalInfeasibilities_;
    sumOfRelaxedDualInfeasibilities_ = rhs.sumOfRelaxedDualInfeasibilities_;
    sumOfRelaxedPrimalInfeasibilities_ = rhs.sumOfRelaxedPrimalInfeasibilities_;
    numberDualInfeasibilities_ = rhs.numberDualInfeasibilities_;
    numberPrimalInfeasibilities_ = rhs.numberPrimalInfeasibilities_;
    savedBestGubDual_ = rhs.savedBestGubDual_;
    savedBestSet_ = rhs.savedBestSet_;
    noCheck_ = rhs.noCheck_;
    infeasibilityWeight_ = rhs.infeasibilityWeight_;
    // Now secondary data
    numberGubColumns_ = rhs.numberGubColumns_;
    maximumGubColumns_ = rhs.maximumGubColumns_;
    maximumElements_ = rhs.maximumElements_;
    startSet_ = ClpCopyOfArray(rhs.startSet_, numberSets_ + 1);
    next_ = ClpCopyOfArray(rhs.next_, maximumGubColumns_);
    startColumn_ = ClpCopyOfArray(rhs.startColumn_, maximumGubColumns_ + 1);
    row_ = ClpCopyOfArray(rhs.row_, maximumElements_);
    element_ = ClpCopyOfArray(rhs.element_, maximumElements_);
    cost_ = ClpCopyOfArray(rhs.cost_, maximumGubColumns_);
    id_ = ClpCopyOfArray(rhs.id_, lastDynamic_ - firstDynamic_);
    columnLower_ = ClpCopyOfArray(rhs.columnLower_, maximumGubColumns_);
    columnUpper_ = ClpCopyOfArray(rhs.columnUpper_, maximumGubColumns_);
    dynamicStatus_ = ClpCopyOfArray(rhs.dynamicStatus_, 2 * maximumGubColumns_);
  }
  return *this;
}
//-------------------------------------------------------------------
// Clone
//-------------------------------------------------------------------
ClpMatrixBase *ClpDynamicMatrix::clone() const
{
  return new ClpDynamicMatrix(*this);
}
// Partial pricing
void ClpDynamicMatrix::partialPricing(ClpSimplex *model, double startFraction, double endFraction,
  int &bestSequence, int &numberWanted)
{
  numberWanted = currentWanted_;
  assert(!model->rowScale());
  if (numberSets_) {
    // Do packed part before gub
    // always???
    //printf("normal packed price - start %d end %d (passed end %d, first %d)\n",
    ClpPackedMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted);
  } else {
    // no gub
    ClpPackedMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted);
    return;
  }
  if (numberWanted > 0) {
    // and do some proportion of full set
    int startG2 = static_cast< int >(startFraction * numberSets_);
    int endG2 = static_cast< int >(endFraction * numberSets_ + 0.1);
    endG2 = CoinMin(endG2, numberSets_);
    //printf("gub price - set start %d end %d\n",
    //   startG2,endG2);
    double tolerance = model->currentDualTolerance();
    double *reducedCost = model->djRegion();
    const double *duals = model->dualRowSolution();
    double bestDj;
    int numberRows = model->numberRows();
    int slackOffset = lastDynamic_ + numberRows;
    int structuralOffset = slackOffset + numberSets_;
    // If nothing found yet can go all the way to end
    int endAll = endG2;
    if (bestSequence < 0 && !startG2)
      endAll = numberSets_;
    if (bestSequence >= 0) {
      if (bestSequence != savedBestSequence_)
        bestDj = fabs(reducedCost[bestSequence]); // dj from slacks or permanent
      else
        bestDj = savedBestDj_;
    } else {
      bestDj = tolerance;
    }
    int saveSequence = bestSequence;
    double djMod = 0.0;
    double bestDjMod = 0.0;
    //printf("iteration %d start %d end %d - wanted %d\n",model->numberIterations(),
    //     startG2,endG2,numberWanted);
    int bestSet = -1;
#if 0
          // make sure first available is clean (in case last iteration rejected)
          cost[firstAvailable_] = 0.0;
          length[firstAvailable_] = 0;
          model->nonLinearCost()->setOne(firstAvailable_, 0.0, 0.0, COIN_DBL_MAX, 0.0);
          model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
          {
               for (int i = firstAvailable_; i < lastDynamic_; i++)
                    assert(!cost[i]);
          }
#endif
    int minSet = minimumObjectsScan_ < 0 ? 5 : minimumObjectsScan_;
    int minNeg = minimumGoodReducedCosts_ < 0 ? 5 : minimumGoodReducedCosts_;
    for (int iSet = startG2; iSet < endAll; iSet++) {
      if (numberWanted + minNeg < originalWanted_ && iSet > startG2 + minSet) {
        // give up
        numberWanted = 0;
        break;
      } else if (iSet == endG2 && bestSequence >= 0) {
        break;
      }
      int gubRow = toIndex_[iSet];
      if (gubRow >= 0) {
        djMod = duals[gubRow + numberStaticRows_]; // have I got sign right?
      } else {
        int iBasic = keyVariable_[iSet];
        if (iBasic >= maximumGubColumns_) {
          djMod = 0.0; // set not in
        } else {
          // get dj without
          djMod = 0.0;
          for (CoinBigIndex j = startColumn_[iBasic];
               j < startColumn_[iBasic + 1]; j++) {
            int jRow = row_[j];
            djMod -= duals[jRow] * element_[j];
          }
          djMod += cost_[iBasic];
          // See if gub slack possible - dj is djMod
          if (getStatus(iSet) == ClpSimplex::atLowerBound) {
            double value = -djMod;
            if (value > tolerance) {
              numberWanted--;
              if (value > bestDj) {
                // check flagged variable and correct dj
                if (!flagged(iSet)) {
                  bestDj = value;
                  bestSequence = slackOffset + iSet;
                  bestDjMod = djMod;
                  bestSet = iSet;
                } else {
                  // just to make sure we don't exit before got something
                  numberWanted++;
                  abort();
                }
              }
            }
          } else if (getStatus(iSet) == ClpSimplex::atUpperBound) {
            double value = djMod;
            if (value > tolerance) {
              numberWanted--;
              if (value > bestDj) {
                // check flagged variable and correct dj
                if (!flagged(iSet)) {
                  bestDj = value;
                  bestSequence = slackOffset + iSet;
                  bestDjMod = djMod;
                  bestSet = iSet;
                } else {
                  // just to make sure we don't exit before got something
                  numberWanted++;
                  abort();
                }
              }
            }
          }
        }
      }
      int iSequence = startSet_[iSet];
      while (iSequence >= 0) {
        DynamicStatus status = getDynamicStatus(iSequence);
        if (status == atLowerBound || status == atUpperBound) {
          double value = cost_[iSequence] - djMod;
          for (CoinBigIndex j = startColumn_[iSequence];
               j < startColumn_[iSequence + 1]; j++) {
            int jRow = row_[j];
            value -= duals[jRow] * element_[j];
          }
          // change sign if at lower bound
          if (status == atLowerBound)
            value = -value;
          if (value > tolerance) {
            numberWanted--;
            if (value > bestDj) {
              // check flagged variable and correct dj
              if (!flagged(iSequence)) {
                if (false /*status == atLowerBound
						&&keyValue(iSet)<1.0e-7*/
                ) {
                  // can't come in because
                  // of ones at ub
                  numberWanted++;
                } else {

                  bestDj = value;
                  bestSequence = structuralOffset + iSequence;
                  bestDjMod = djMod;
                  bestSet = iSet;
                }
              } else {
                // just to make sure we don't exit before got something
                numberWanted++;
              }
            }
          }
        }
        iSequence = next_[iSequence]; //onto next in set
      }
      if (numberWanted <= 0) {
        numberWanted = 0;
        break;
      }
    }
    if (bestSequence != saveSequence) {
      savedBestGubDual_ = bestDjMod;
      savedBestDj_ = bestDj;
      savedBestSequence_ = bestSequence;
      savedBestSet_ = bestSet;
    }
    // See if may be finished
    if (!startG2 && bestSequence < 0)
      infeasibilityWeight_ = model_->infeasibilityCost();
    else if (bestSequence >= 0)
      infeasibilityWeight_ = -1.0;
  }
  currentWanted_ = numberWanted;
}
/* Returns effective RHS if it is being used.  This is used for long problems
   or big gub or anywhere where going through full columns is
   expensive.  This may re-compute */
double *
ClpDynamicMatrix::rhsOffset(ClpSimplex *model, bool forceRefresh,
  bool
#ifdef CLP_DEBUG
    check
#endif
)
{
  // forceRefresh=true;printf("take out forceRefresh\n");
  if (!model_->numberIterations())
    forceRefresh = true;
    //check=false;
#ifdef CLP_DEBUG
  double *saveE = NULL;
  if (rhsOffset_ && check) {
    int numberRows = model->numberRows();
    saveE = new double[numberRows];
  }
#endif
  if (rhsOffset_) {
#ifdef CLP_DEBUG
    if (check) {
      // no need - but check anyway
      int numberRows = model->numberRows();
      double *rhs = new double[numberRows];
      int iRow;
      int iSet;
      CoinZeroN(rhs, numberRows);
      // do ones at bounds before gub
      const double *smallSolution = model->solutionRegion();
      const double *element = matrix_->getElements();
      const int *row = matrix_->getIndices();
      const CoinBigIndex *startColumn = matrix_->getVectorStarts();
      const int *length = matrix_->getVectorLengths();
      int iColumn;
      double objectiveOffset = 0.0;
      for (iColumn = 0; iColumn < firstDynamic_; iColumn++) {
        if (model->getStatus(iColumn) != ClpSimplex::basic) {
          double value = smallSolution[iColumn];
          for (CoinBigIndex j = startColumn[iColumn];
               j < startColumn[iColumn] + length[iColumn]; j++) {
            int jRow = row[j];
            rhs[jRow] -= value * element[j];
          }
        }
      }
      if (columnLower_ || columnUpper_) {
        double *solution = new double[numberGubColumns_];
        for (iSet = 0; iSet < numberSets_; iSet++) {
          int j = startSet_[iSet];
          while (j >= 0) {
            double value = 0.0;
            if (getDynamicStatus(j) != inSmall) {
              if (getDynamicStatus(j) == atLowerBound) {
                if (columnLower_)
                  value = columnLower_[j];
              } else if (getDynamicStatus(j) == atUpperBound) {
                value = columnUpper_[j];
              } else if (getDynamicStatus(j) == soloKey) {
                value = keyValue(iSet);
              }
              objectiveOffset += value * cost_[j];
            }
            solution[j] = value;
            j = next_[j]; //onto next in set
          }
        }
        // ones in gub and in small problem
        for (iColumn = firstDynamic_; iColumn < firstAvailable_; iColumn++) {
          if (model_->getStatus(iColumn) != ClpSimplex::basic) {
            int jFull = id_[iColumn - firstDynamic_];
            solution[jFull] = smallSolution[iColumn];
          }
        }
        for (iSet = 0; iSet < numberSets_; iSet++) {
          int kRow = toIndex_[iSet];
          if (kRow >= 0)
            kRow += numberStaticRows_;
          int j = startSet_[iSet];
          while (j >= 0) {
            double value = solution[j];
            if (value) {
              for (CoinBigIndex k = startColumn_[j]; k < startColumn_[j + 1]; k++) {
                int iRow = row_[k];
                rhs[iRow] -= element_[k] * value;
              }
              if (kRow >= 0)
                rhs[kRow] -= value;
            }
            j = next_[j]; //onto next in set
          }
        }
        delete[] solution;
      } else {
        // bounds
        ClpSimplex::Status iStatus;
        for (int iSet = 0; iSet < numberSets_; iSet++) {
          int kRow = toIndex_[iSet];
          if (kRow < 0) {
            int iColumn = keyVariable_[iSet];
            if (iColumn < maximumGubColumns_) {
              // key is not treated as basic
              double b = 0.0;
              // key is structural - where is slack
              iStatus = getStatus(iSet);
              assert(iStatus != ClpSimplex::basic);
              if (iStatus == ClpSimplex::atLowerBound)
                b = lowerSet_[iSet];
              else
                b = upperSet_[iSet];
              if (b) {
                objectiveOffset += b * cost_[iColumn];
                for (CoinBigIndex j = startColumn_[iColumn]; j < startColumn_[iColumn + 1]; j++) {
                  int iRow = row_[j];
                  rhs[iRow] -= element_[j] * b;
                }
              }
            }
          }
        }
      }
      if (fabs(model->objectiveOffset() - objectiveOffset_ - objectiveOffset) > 1.0e-1)
        printf("old offset %g, true %g\n", model->objectiveOffset(),
          objectiveOffset_ - objectiveOffset);
      for (iRow = 0; iRow < numberRows; iRow++) {
        if (fabs(rhs[iRow] - rhsOffset_[iRow]) > 1.0e-3)
          printf("** bad effective %d - true %g old %g\n", iRow, rhs[iRow], rhsOffset_[iRow]);
      }
      CoinMemcpyN(rhs, numberRows, saveE);
      delete[] rhs;
    }
#endif
    if (forceRefresh || (refreshFrequency_ && model->numberIterations() >= lastRefresh_ + refreshFrequency_)) {
      int numberRows = model->numberRows();
      int iSet;
      CoinZeroN(rhsOffset_, numberRows);
      // do ones at bounds before gub
      const double *smallSolution = model->solutionRegion();
      const double *element = matrix_->getElements();
      const int *row = matrix_->getIndices();
      const CoinBigIndex *startColumn = matrix_->getVectorStarts();
      const int *length = matrix_->getVectorLengths();
      int iColumn;
      double objectiveOffset = 0.0;
      for (iColumn = 0; iColumn < firstDynamic_; iColumn++) {
        if (model->getStatus(iColumn) != ClpSimplex::basic) {
          double value = smallSolution[iColumn];
          for (CoinBigIndex j = startColumn[iColumn];
               j < startColumn[iColumn] + length[iColumn]; j++) {
            int jRow = row[j];
            rhsOffset_[jRow] -= value * element[j];
          }
        }
      }
      if (columnLower_ || columnUpper_) {
        double *solution = new double[numberGubColumns_];
        for (iSet = 0; iSet < numberSets_; iSet++) {
          int j = startSet_[iSet];
          while (j >= 0) {
            double value = 0.0;
            if (getDynamicStatus(j) != inSmall) {
              if (getDynamicStatus(j) == atLowerBound) {
                if (columnLower_)
                  value = columnLower_[j];
              } else if (getDynamicStatus(j) == atUpperBound) {
                value = columnUpper_[j];
                assert(value < 1.0e30);
              } else if (getDynamicStatus(j) == soloKey) {
                value = keyValue(iSet);
              }
              objectiveOffset += value * cost_[j];
            }
            solution[j] = value;
            j = next_[j]; //onto next in set
          }
        }
        // ones in gub and in small problem
        for (iColumn = firstDynamic_; iColumn < firstAvailable_; iColumn++) {
          if (model_->getStatus(iColumn) != ClpSimplex::basic) {
            int jFull = id_[iColumn - firstDynamic_];
            solution[jFull] = smallSolution[iColumn];
          }
        }
        for (iSet = 0; iSet < numberSets_; iSet++) {
          int kRow = toIndex_[iSet];
          if (kRow >= 0)
            kRow += numberStaticRows_;
          int j = startSet_[iSet];
          while (j >= 0) {
            //? use DynamicStatus status = getDynamicStatus(j);
            double value = solution[j];
            if (value) {
              for (CoinBigIndex k = startColumn_[j]; k < startColumn_[j + 1]; k++) {
                int iRow = row_[k];
                rhsOffset_[iRow] -= element_[k] * value;
              }
              if (kRow >= 0)
                rhsOffset_[kRow] -= value;
            }
            j = next_[j]; //onto next in set
          }
        }
        delete[] solution;
      } else {
        // bounds
        ClpSimplex::Status iStatus;
        for (int iSet = 0; iSet < numberSets_; iSet++) {
          int kRow = toIndex_[iSet];
          if (kRow < 0) {
            int iColumn = keyVariable_[iSet];
            if (iColumn < maximumGubColumns_) {
              // key is not treated as basic
              double b = 0.0;
              // key is structural - where is slack
              iStatus = getStatus(iSet);
              assert(iStatus != ClpSimplex::basic);
              if (iStatus == ClpSimplex::atLowerBound)
                b = lowerSet_[iSet];
              else
                b = upperSet_[iSet];
              if (b) {
                objectiveOffset += b * cost_[iColumn];
                for (CoinBigIndex j = startColumn_[iColumn]; j < startColumn_[iColumn + 1]; j++) {
                  int iRow = row_[j];
                  rhsOffset_[iRow] -= element_[j] * b;
                }
              }
            }
          }
        }
      }
      model->setObjectiveOffset(objectiveOffset_ - objectiveOffset);
#ifdef CLP_DEBUG
      if (saveE) {
        int iRow;
        for (iRow = 0; iRow < numberRows; iRow++) {
          if (fabs(saveE[iRow] - rhsOffset_[iRow]) > 1.0e-3)
            printf("** %d - old eff %g new %g\n", iRow, saveE[iRow], rhsOffset_[iRow]);
        }
        delete[] saveE;
      }
#endif
      lastRefresh_ = model->numberIterations();
    }
  }
  return rhsOffset_;
}
/*
  update information for a pivot (and effective rhs)
*/
int ClpDynamicMatrix::updatePivot(ClpSimplex *model, double oldInValue, double oldOutValue)
{

  // now update working model
  int sequenceIn = model->sequenceIn();
  int sequenceOut = model->sequenceOut();
  int numberColumns = model->numberColumns();
  if (sequenceIn != sequenceOut && sequenceIn < numberColumns)
    backToPivotRow_[sequenceIn] = model->pivotRow();
  if (sequenceIn >= firstDynamic_ && sequenceIn < numberColumns) {
    int bigSequence = id_[sequenceIn - firstDynamic_];
    if (getDynamicStatus(bigSequence) != inSmall) {
      firstAvailable_++;
      setDynamicStatus(bigSequence, inSmall);
    }
  }
  // make sure slack is synchronized
  if (sequenceIn >= numberColumns + numberStaticRows_) {
    int iDynamic = sequenceIn - numberColumns - numberStaticRows_;
    int iSet = fromIndex_[iDynamic];
    setStatus(iSet, model->getStatus(sequenceIn));
  }
  if (sequenceOut >= numberColumns + numberStaticRows_) {
    int iDynamic = sequenceOut - numberColumns - numberStaticRows_;
    int iSet = fromIndex_[iDynamic];
    // out may have gone through barrier - so check
    double valueOut = model->lowerRegion()[sequenceOut];
    if (fabs(valueOut - static_cast< double >(lowerSet_[iSet])) < fabs(valueOut - static_cast< double >(upperSet_[iSet])))
      setStatus(iSet, ClpSimplex::atLowerBound);
    else
      setStatus(iSet, ClpSimplex::atUpperBound);
    if (lowerSet_[iSet] == upperSet_[iSet])
      setStatus(iSet, ClpSimplex::isFixed);
#if 0
          if (getStatus(iSet) != model->getStatus(sequenceOut))
               printf("** set %d status %d, var status %d\n", iSet,
                      getStatus(iSet), model->getStatus(sequenceOut));
#endif
  }
  ClpMatrixBase::updatePivot(model, oldInValue, oldOutValue);
#ifdef CLP_DEBUG
  char *inSmall = new char[numberGubColumns_];
  memset(inSmall, 0, numberGubColumns_);
  const double *solution = model->solutionRegion();
  for (int i = 0; i < numberGubColumns_; i++)
    if (getDynamicStatus(i) == ClpDynamicMatrix::inSmall)
      inSmall[i] = 1;
  for (int i = firstDynamic_; i < firstAvailable_; i++) {
    int k = id_[i - firstDynamic_];
    inSmall[k] = 0;
    //if (k>=23289&&k<23357&&solution[i])
    //printf("var %d (in small %d) has value %g\n",k,i,solution[i]);
  }
  for (int i = 0; i < numberGubColumns_; i++)
    assert(!inSmall[i]);
  delete[] inSmall;
#ifndef NDEBUG
  for (int i = 0; i < numberActiveSets_; i++) {
    int iSet = fromIndex_[i];
    assert(toIndex_[iSet] == i);
    //if (getStatus(iSet)!=model->getRowStatus(i+numberStaticRows_))
    //printf("*** set %d status %d, var status %d\n",iSet,
    //     getStatus(iSet),model->getRowStatus(i+numberStaticRows_));
    //assert (model->getRowStatus(i+numberStaticRows_)==getStatus(iSet));
    //if (iSet==1035) {
    //printf("rhs for set %d (%d) is %g %g - cost %g\n",iSet,i,model->lowerRegion(0)[i+numberStaticRows_],
    //     model->upperRegion(0)[i+numberStaticRows_],model->costRegion(0)[i+numberStaticRows_]);
    //}
  }
#endif
#endif
  if (numberStaticRows_ + numberActiveSets_ < model->numberRows())
    return 0;
  else
    return 1;
}
/*
     utility dual function for dealing with dynamic constraints
     mode=n see ClpGubMatrix.hpp for definition
     Remember to update here when settled down
*/
void ClpDynamicMatrix::dualExpanded(ClpSimplex *model,
  CoinIndexedVector * /*array*/,
  double * /*other*/, int mode)
{
  switch (mode) {
    // modify costs before transposeUpdate
  case 0:
    break;
    // create duals for key variables (without check on dual infeasible)
  case 1:
    break;
    // as 1 but check slacks and compute djs
  case 2: {
    // do pivots
    int *pivotVariable = model->pivotVariable();
    int numberRows = numberStaticRows_ + numberActiveSets_;
    int numberColumns = model->numberColumns();
    for (int iRow = 0; iRow < numberRows; iRow++) {
      int iPivot = pivotVariable[iRow];
      if (iPivot < numberColumns)
        backToPivotRow_[iPivot] = iRow;
    }
    if (noCheck_ >= 0) {
      if (infeasibilityWeight_ != model_->infeasibilityCost()) {
        // don't bother checking
        sumDualInfeasibilities_ = 100.0;
        numberDualInfeasibilities_ = 1;
        sumOfRelaxedDualInfeasibilities_ = 100.0;
        return;
      }
    }
    // In theory we should subtract out ones we have done but ....
    // If key slack then dual 0.0
    // If not then slack could be dual infeasible
    // dj for key is zero so that defines dual on set
    int i;
    double *dual = model->dualRowSolution();
    double dualTolerance = model->dualTolerance();
    double relaxedTolerance = dualTolerance;
    // we can't really trust infeasibilities if there is dual error
    double error = CoinMin(1.0e-2, model->largestDualError());
    // allow tolerance at least slightly bigger than standard
    relaxedTolerance = relaxedTolerance + error;
    // but we will be using difference
    relaxedTolerance -= dualTolerance;
    sumDualInfeasibilities_ = 0.0;
    numberDualInfeasibilities_ = 0;
    sumOfRelaxedDualInfeasibilities_ = 0.0;
    for (i = 0; i < numberSets_; i++) {
      double value = 0.0;
      int gubRow = toIndex_[i];
      if (gubRow < 0) {
        int kColumn = keyVariable_[i];
        if (kColumn < maximumGubColumns_) {
          // dj without set
          value = cost_[kColumn];
          for (CoinBigIndex j = startColumn_[kColumn];
               j < startColumn_[kColumn + 1]; j++) {
            int iRow = row_[j];
            value -= dual[iRow] * element_[j];
          }
          double infeasibility = 0.0;
          if (getStatus(i) == ClpSimplex::atLowerBound) {
            if (-value > dualTolerance)
              infeasibility = -value - dualTolerance;
          } else if (getStatus(i) == ClpSimplex::atUpperBound) {
            if (value > dualTolerance)
              infeasibility = value - dualTolerance;
          }
          if (infeasibility > 0.0) {
            sumDualInfeasibilities_ += infeasibility;
            if (infeasibility > relaxedTolerance)
              sumOfRelaxedDualInfeasibilities_ += infeasibility;
            numberDualInfeasibilities_++;
          }
        }
      } else {
        value = dual[gubRow + numberStaticRows_];
      }
      // Now subtract out from all
      int k = startSet_[i];
      while (k >= 0) {
        if (getDynamicStatus(k) != inSmall) {
          double djValue = cost_[k] - value;
          for (CoinBigIndex j = startColumn_[k];
               j < startColumn_[k + 1]; j++) {
            int iRow = row_[j];
            djValue -= dual[iRow] * element_[j];
          }
          double infeasibility = 0.0;
          if (getDynamicStatus(k) == atLowerBound) {
            if (djValue < -dualTolerance)
              infeasibility = -djValue - dualTolerance;
          } else if (getDynamicStatus(k) == atUpperBound) {
            // at upper bound
            if (djValue > dualTolerance)
              infeasibility = djValue - dualTolerance;
          }
          if (infeasibility > 0.0) {
            sumDualInfeasibilities_ += infeasibility;
            if (infeasibility > relaxedTolerance)
              sumOfRelaxedDualInfeasibilities_ += infeasibility;
            numberDualInfeasibilities_++;
          }
        }
        k = next_[k]; //onto next in set
      }
    }
  }
    infeasibilityWeight_ = -1.0;
    break;
  // Report on infeasibilities of key variables
  case 3: {
    model->setSumDualInfeasibilities(model->sumDualInfeasibilities() + sumDualInfeasibilities_);
    model->setNumberDualInfeasibilities(model->numberDualInfeasibilities() + numberDualInfeasibilities_);
    model->setSumOfRelaxedDualInfeasibilities(model->sumOfRelaxedDualInfeasibilities() + sumOfRelaxedDualInfeasibilities_);
  } break;
  // modify costs before transposeUpdate for partial pricing
  case 4:
    break;
  }
}
/*
     general utility function for dealing with dynamic constraints
     mode=n see ClpGubMatrix.hpp for definition
     Remember to update here when settled down
*/
int ClpDynamicMatrix::generalExpanded(ClpSimplex *model, int mode, int &number)
{
  int returnCode = 0;
#if 0 //ndef NDEBUG
     {
       int numberColumns = model->numberColumns();
       int numberRows = model->numberRows();
       int * pivotVariable = model->pivotVariable();
       if (pivotVariable&&model->numberIterations()) {
	 for (int i=numberStaticRows_+numberActiveSets_;i<numberRows;i++) {
	   assert (pivotVariable[i]==i+numberColumns);
	 }
       }
     }
#endif
  switch (mode) {
    // Fill in pivotVariable
  case 0: {
    // If no effective rhs - form it
    if (!rhsOffset_) {
      rhsOffset_ = new double[model->numberRows()];
      rhsOffset(model, true);
    }
    int i;
    int numberBasic = number;
    int numberColumns = model->numberColumns();
    // Use different array so can build from true pivotVariable_
    //int * pivotVariable = model->pivotVariable();
    int *pivotVariable = model->rowArray(0)->getIndices();
    for (i = 0; i < numberColumns; i++) {
      if (model->getColumnStatus(i) == ClpSimplex::basic)
        pivotVariable[numberBasic++] = i;
    }
    number = numberBasic;
  } break;
  // Do initial extra rows + maximum basic
  case 2: {
    number = model->numberRows();
  } break;
  // Before normal replaceColumn
  case 3: {
    if (numberActiveSets_ + numberStaticRows_ == model_->numberRows()) {
      // no space - re-factorize
      returnCode = 4;
      number = -1; // say no need for normal replaceColumn
    }
  } break;
  // To see if can dual or primal
  case 4: {
    returnCode = 1;
  } break;
  // save status
  case 5: {
    memcpy(status_ + numberSets_, status_, numberSets_);
    memcpy(status_ + 2 * numberSets_, &numberActiveSets_, sizeof(int));
    memcpy(dynamicStatus_ + maximumGubColumns_,
      dynamicStatus_, maximumGubColumns_);
  } break;
  // restore status
  case 6: {
    memcpy(status_, status_ + numberSets_, numberSets_);
    memcpy(&numberActiveSets_, status_ + 2 * numberSets_, sizeof(int));
    memcpy(dynamicStatus_, dynamicStatus_ + maximumGubColumns_,
      maximumGubColumns_);
    initialProblem();
  } break;
  // unflag all variables
  case 8: {
    for (int i = 0; i < numberGubColumns_; i++) {
      if (flagged(i)) {
        unsetFlagged(i);
        returnCode++;
      }
    }
  } break;
  // redo costs in primal
  case 9: {
    double *cost = model->costRegion();
    double *solution = model->solutionRegion();
    double *columnLower = model->lowerRegion();
    double *columnUpper = model->upperRegion();
    int i;
    bool doCosts = (number & 4) != 0;
    bool doBounds = (number & 1) != 0;
    for (i = firstDynamic_; i < firstAvailable_; i++) {
      int jColumn = id_[i - firstDynamic_];
      if (doBounds) {
        if (!columnLower_ && !columnUpper_) {
          columnLower[i] = 0.0;
          columnUpper[i] = COIN_DBL_MAX;
        } else {
          if (columnLower_)
            columnLower[i] = columnLower_[jColumn];
          else
            columnLower[i] = 0.0;
          if (columnUpper_)
            columnUpper[i] = columnUpper_[jColumn];
          else
            columnUpper[i] = COIN_DBL_MAX;
        }
      }
      if (doCosts) {
        cost[i] = cost_[jColumn];
        // Original bounds
        if (model->nonLinearCost())
          model->nonLinearCost()->setOne(i, solution[i],
            this->columnLower(jColumn),
            this->columnUpper(jColumn), cost_[jColumn]);
      }
    }
    // and active sets
    for (i = 0; i < numberActiveSets_; i++) {
      int iSet = fromIndex_[i];
      int iSequence = lastDynamic_ + numberStaticRows_ + i;
      if (doBounds) {
        if (lowerSet_[iSet] > -1.0e20)
          columnLower[iSequence] = lowerSet_[iSet];
        else
          columnLower[iSequence] = -COIN_DBL_MAX;
        if (upperSet_[iSet] < 1.0e20)
          columnUpper[iSequence] = upperSet_[iSet];
        else
          columnUpper[iSequence] = COIN_DBL_MAX;
      }
      if (doCosts) {
        if (model->nonLinearCost()) {
          double trueLower;
          if (lowerSet_[iSet] > -1.0e20)
            trueLower = lowerSet_[iSet];
          else
            trueLower = -COIN_DBL_MAX;
          double trueUpper;
          if (upperSet_[iSet] < 1.0e20)
            trueUpper = upperSet_[iSet];
          else
            trueUpper = COIN_DBL_MAX;
          model->nonLinearCost()->setOne(iSequence, solution[iSequence],
            trueLower, trueUpper, 0.0);
        }
      }
    }
  } break;
  // return 1 if there may be changing bounds on variable (column generation)
  case 10: {
    // return 1 as bounds on rhs will change
    returnCode = 1;
  } break;
  // make sure set is clean
  case 7: {
    // first flag
    if (number >= firstDynamic_ && number < lastDynamic_) {
      int sequence = id_[number - firstDynamic_];
      setFlagged(sequence);
      //model->clearFlagged(number);
    } else if (number >= model_->numberColumns() + numberStaticRows_) {
      // slack
      int iSet = fromIndex_[number - model_->numberColumns() - numberStaticRows_];
      setFlaggedSlack(iSet);
      //model->clearFlagged(number);
    }
  }
  case 11: {
    //int sequenceIn = model->sequenceIn();
    if (number >= firstDynamic_ && number < lastDynamic_) {
      //assert (number == model->sequenceIn());
      // take out variable (but leave key)
      double *cost = model->costRegion();
      double *columnLower = model->lowerRegion();
      double *columnUpper = model->upperRegion();
      double *solution = model->solutionRegion();
      int *length = matrix_->getMutableVectorLengths();
#ifndef NDEBUG
      if (length[number]) {
        int *row = matrix_->getMutableIndices();
        CoinBigIndex *startColumn = matrix_->getMutableVectorStarts();
        int iRow = row[startColumn[number] + length[number] - 1];
        int which = iRow - numberStaticRows_;
        assert(which >= 0);
        int iSet = fromIndex_[which];
        assert(toIndex_[iSet] == which);
      }
#endif
      // no need firstAvailable_--;
      solution[firstAvailable_] = 0.0;
      cost[firstAvailable_] = 0.0;
      length[firstAvailable_] = 0;
      model->nonLinearCost()->setOne(firstAvailable_, 0.0, 0.0, COIN_DBL_MAX, 0.0);
      model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
      columnLower[firstAvailable_] = 0.0;
      columnUpper[firstAvailable_] = COIN_DBL_MAX;

      // not really in small problem
      int iBig = id_[number - firstDynamic_];
      if (model->getStatus(number) == ClpSimplex::atLowerBound) {
        setDynamicStatus(iBig, atLowerBound);
        if (columnLower_)
          modifyOffset(number, columnLower_[iBig]);
      } else {
        setDynamicStatus(iBig, atUpperBound);
        modifyOffset(number, columnUpper_[iBig]);
      }
    } else if (number >= model_->numberColumns() + numberStaticRows_) {
      // slack
      int iSet = fromIndex_[number - model_->numberColumns() - numberStaticRows_];
      printf("what now - set %d\n", iSet);
    }
  } break;
  default:
    break;
  }
  return returnCode;
}
/* Purely for column generation and similar ideas.  Allows
   matrix and any bounds or costs to be updated (sensibly).
   Returns non-zero if any changes.
*/
int ClpDynamicMatrix::refresh(ClpSimplex *model)
{
  // If at beginning then create initial problem
  if (firstDynamic_ == firstAvailable_) {
    initialProblem();
    return 1;
  } else if (!model->nonLinearCost()) {
    // will be same as last time
    return 1;
  }
#ifndef NDEBUG
  {
    int numberColumns = model->numberColumns();
    int numberRows = model->numberRows();
    int *pivotVariable = model->pivotVariable();
    for (int i = numberStaticRows_ + numberActiveSets_; i < numberRows; i++) {
      assert(pivotVariable[i] == i + numberColumns);
    }
  }
#endif
  // lookup array
  int *active = new int[numberActiveSets_];
  CoinZeroN(active, numberActiveSets_);
  int iColumn;
  int numberColumns = model->numberColumns();
  double *element = matrix_->getMutableElements();
  int *row = matrix_->getMutableIndices();
  CoinBigIndex *startColumn = matrix_->getMutableVectorStarts();
  int *length = matrix_->getMutableVectorLengths();
  double *cost = model->costRegion();
  double *columnLower = model->lowerRegion();
  double *columnUpper = model->upperRegion();
  CoinBigIndex numberElements = startColumn[firstDynamic_];
  // first just do lookup and basic stuff
  int currentNumber = firstAvailable_;
  firstAvailable_ = firstDynamic_;
  double objectiveChange = 0.0;
  double *solution = model->solutionRegion();
  int currentNumberActiveSets = numberActiveSets_;
  for (iColumn = firstDynamic_; iColumn < currentNumber; iColumn++) {
    int iRow = row[startColumn[iColumn] + length[iColumn] - 1];
    int which = iRow - numberStaticRows_;
    assert(which >= 0);
    int iSet = fromIndex_[which];
    assert(toIndex_[iSet] == which);
    if (model->getStatus(iColumn) == ClpSimplex::basic) {
      active[which]++;
      // may as well make key
      keyVariable_[iSet] = id_[iColumn - firstDynamic_];
    }
  }
  int i;
  numberActiveSets_ = 0;
  int numberDeleted = 0;
  for (i = 0; i < currentNumberActiveSets; i++) {
    int iRow = i + numberStaticRows_;
    int numberActive = active[i];
    int iSet = fromIndex_[i];
    if (model->getRowStatus(iRow) == ClpSimplex::basic) {
      numberActive++;
      // may as well make key
      keyVariable_[iSet] = maximumGubColumns_ + iSet;
    }
    if (numberActive > 1) {
      // keep
      active[i] = numberActiveSets_;
      numberActiveSets_++;
    } else {
      active[i] = -1;
    }
  }

  for (iColumn = firstDynamic_; iColumn < currentNumber; iColumn++) {
    int iRow = row[startColumn[iColumn] + length[iColumn] - 1];
    int which = iRow - numberStaticRows_;
    int jColumn = id_[iColumn - firstDynamic_];
    if (model->getStatus(iColumn) == ClpSimplex::atLowerBound || model->getStatus(iColumn) == ClpSimplex::atUpperBound) {
      double value = solution[iColumn];
      bool toLowerBound = true;
      assert(jColumn >= 0);
      assert(iColumn >= 0);
      if (columnUpper_) {
        if (!columnLower_) {
          if (fabs(value - columnUpper_[jColumn]) < fabs(value))
            toLowerBound = false;
        } else if (fabs(value - columnUpper_[jColumn]) < fabs(value - columnLower_[jColumn])) {
          toLowerBound = false;
        }
      }
      if (toLowerBound) {
        // throw out to lower bound
        if (columnLower_) {
          setDynamicStatus(jColumn, atLowerBound);
          // treat solution as if exactly at a bound
          double value = columnLower[iColumn];
          objectiveChange += cost[iColumn] * value;
        } else {
          setDynamicStatus(jColumn, atLowerBound);
        }
      } else {
        // throw out to upper bound
        setDynamicStatus(jColumn, atUpperBound);
        double value = columnUpper[iColumn];
        objectiveChange += cost[iColumn] * value;
      }
      numberDeleted++;
    } else {
      assert(model->getStatus(iColumn) != ClpSimplex::superBasic); // deal with later
      int iPut = active[which];
      if (iPut >= 0) {
        // move
        id_[firstAvailable_ - firstDynamic_] = jColumn;
        int numberThis = startColumn_[jColumn + 1] - startColumn_[jColumn] + 1;
        length[firstAvailable_] = numberThis;
        cost[firstAvailable_] = cost[iColumn];
        columnLower[firstAvailable_] = columnLower[iColumn];
        columnUpper[firstAvailable_] = columnUpper[iColumn];
        model->nonLinearCost()->setOne(firstAvailable_, solution[iColumn], 0.0, COIN_DBL_MAX,
          cost_[jColumn]);
        CoinBigIndex base = startColumn_[jColumn];
        for (int j = 0; j < numberThis - 1; j++) {
          row[numberElements] = row_[base + j];
          element[numberElements++] = element_[base + j];
        }
        row[numberElements] = iPut + numberStaticRows_;
        element[numberElements++] = 1.0;
        model->setStatus(firstAvailable_, model->getStatus(iColumn));
        solution[firstAvailable_] = solution[iColumn];
        firstAvailable_++;
        startColumn[firstAvailable_] = numberElements;
      }
    }
  }
  // zero solution
  CoinZeroN(solution + firstAvailable_, currentNumber - firstAvailable_);
  // zero cost
  CoinZeroN(cost + firstAvailable_, currentNumber - firstAvailable_);
  // zero lengths
  CoinZeroN(length + firstAvailable_, currentNumber - firstAvailable_);
  for (iColumn = firstAvailable_; iColumn < currentNumber; iColumn++) {
    model->nonLinearCost()->setOne(iColumn, 0.0, 0.0, COIN_DBL_MAX, 0.0);
    model->setStatus(iColumn, ClpSimplex::atLowerBound);
    columnLower[iColumn] = 0.0;
    columnUpper[iColumn] = COIN_DBL_MAX;
  }
  // move rhs and set rest to infinite
  numberActiveSets_ = 0;
  for (i = 0; i < currentNumberActiveSets; i++) {
    int iSet = fromIndex_[i];
    assert(toIndex_[iSet] == i);
    int iRow = i + numberStaticRows_;
    int iPut = active[i];
    if (iPut >= 0) {
      int in = iRow + numberColumns;
      int out = iPut + numberColumns + numberStaticRows_;
      solution[out] = solution[in];
      columnLower[out] = columnLower[in];
      columnUpper[out] = columnUpper[in];
      cost[out] = cost[in];
      double trueLower;
      if (lowerSet_[iSet] > -1.0e20)
        trueLower = lowerSet_[iSet];
      else
        trueLower = -COIN_DBL_MAX;
      double trueUpper;
      if (upperSet_[iSet] < 1.0e20)
        trueUpper = upperSet_[iSet];
      else
        trueUpper = COIN_DBL_MAX;
      model->nonLinearCost()->setOne(out, solution[out],
        trueLower, trueUpper, 0.0);
      model->setStatus(out, model->getStatus(in));
      toIndex_[iSet] = numberActiveSets_;
      rhsOffset_[numberActiveSets_ + numberStaticRows_] = rhsOffset_[i + numberStaticRows_];
      fromIndex_[numberActiveSets_++] = fromIndex_[i];
    } else {
      // adjust offset
      // put out as key
      int jColumn = keyVariable_[iSet];
      toIndex_[iSet] = -1;
      if (jColumn < maximumGubColumns_) {
        setDynamicStatus(jColumn, soloKey);
        double value = keyValue(iSet);
        objectiveChange += cost_[jColumn] * value;
        modifyOffset(jColumn, -value);
      }
    }
  }
  model->setObjectiveOffset(model->objectiveOffset() - objectiveChange);
  delete[] active;
  for (i = numberActiveSets_; i < currentNumberActiveSets; i++) {
    int iSequence = i + numberStaticRows_ + numberColumns;
    solution[iSequence] = 0.0;
    columnLower[iSequence] = -COIN_DBL_MAX;
    columnUpper[iSequence] = COIN_DBL_MAX;
    cost[iSequence] = 0.0;
    model->nonLinearCost()->setOne(iSequence, solution[iSequence],
      columnLower[iSequence],
      columnUpper[iSequence], 0.0);
    model->setStatus(iSequence, ClpSimplex::basic);
    rhsOffset_[i + numberStaticRows_] = 0.0;
  }
  if (currentNumberActiveSets != numberActiveSets_ || numberDeleted) {
    // deal with pivotVariable
    int *pivotVariable = model->pivotVariable();
    int sequence = firstDynamic_;
    int iRow = 0;
    int base1 = firstDynamic_;
    int base2 = lastDynamic_;
    int base3 = numberColumns + numberStaticRows_;
    int numberRows = numberStaticRows_ + currentNumberActiveSets;
    while (sequence < firstAvailable_) {
      int iPivot = pivotVariable[iRow];
      while (iPivot < base1 || (iPivot >= base2 && iPivot < base3)) {
        iPivot = pivotVariable[++iRow];
      }
      pivotVariable[iRow++] = sequence;
      sequence++;
    }
    // move normal basic ones down
    int iPut = iRow;
    for (; iRow < numberRows; iRow++) {
      int iPivot = pivotVariable[iRow];
      if (iPivot < base1 || (iPivot >= base2 && iPivot < base3)) {
        pivotVariable[iPut++] = iPivot;
      }
    }
    // and basic others
    for (i = 0; i < numberActiveSets_; i++) {
      if (model->getRowStatus(i + numberStaticRows_) == ClpSimplex::basic) {
        pivotVariable[iPut++] = i + base3;
      }
    }
    if (iPut < numberStaticRows_ + numberActiveSets_) {
      printf("lost %d sets\n",
        numberStaticRows_ + numberActiveSets_ - iPut);
      iPut = numberStaticRows_ + numberActiveSets_;
    }
    for (i = numberActiveSets_; i < currentNumberActiveSets; i++) {
      pivotVariable[iPut++] = i + base3;
    }
    //assert (iPut == numberRows);
  }
#ifdef CLP_DEBUG
#if 0
     printf("row for set 244 is %d, row status %d value %g ", toIndex_[244], status_[244],
            keyValue(244));
     int jj = startSet_[244];
     while (jj >= 0) {
          printf("var %d status %d ", jj, dynamicStatus_[jj]);
          jj = next_[jj];
     }
     printf("\n");
#endif
#ifdef CLP_DEBUG
  {
    // debug coding to analyze set
    int i;
    int kSet = -6;
    if (kSet >= 0) {
      int *back = new int[numberGubColumns_];
      for (i = 0; i < numberGubColumns_; i++)
        back[i] = -1;
      for (i = firstDynamic_; i < firstAvailable_; i++)
        back[id_[i - firstDynamic_]] = i;
      int sequence = startSet_[kSet];
      if (toIndex_[kSet] < 0) {
        printf("Not in - Set %d - slack status %d, key %d\n", kSet, status_[kSet], keyVariable_[kSet]);
        while (sequence >= 0) {
          printf("( %d status %d ) ", sequence, getDynamicStatus(sequence));
          sequence = next_[sequence];
        }
      } else {
        int iRow = numberStaticRows_ + toIndex_[kSet];
        printf("In - Set %d - slack status %d, key %d offset %g slack %g\n", kSet, status_[kSet], keyVariable_[kSet],
          rhsOffset_[iRow], model->solutionRegion(0)[iRow]);
        while (sequence >= 0) {
          int iBack = back[sequence];
          printf("( %d status %d value %g) ", sequence, getDynamicStatus(sequence), model->solutionRegion()[iBack]);
          sequence = next_[sequence];
        }
      }
      printf("\n");
      delete[] back;
    }
  }
#endif
  int n = numberActiveSets_;
  for (i = 0; i < numberSets_; i++) {
    if (toIndex_[i] < 0) {
      //assert(keyValue(i)>=lowerSet_[i]&&keyValue(i)<=upperSet_[i]);
      n++;
    }
    int k = 0;
    for (int j = startSet_[i]; j < startSet_[i + 1]; j++) {
      if (getDynamicStatus(j) == soloKey)
        k++;
    }
    assert(k < 2);
  }
  assert(n == numberSets_);
#endif
  return 1;
}
void ClpDynamicMatrix::times(double scalar,
  const double *x, double *y) const
{
  if (model_->specialOptions() != 16) {
    ClpPackedMatrix::times(scalar, x, y);
  } else {
    int iRow;
    const double *element = matrix_->getElements();
    const int *row = matrix_->getIndices();
    const CoinBigIndex *startColumn = matrix_->getVectorStarts();
    const int *length = matrix_->getVectorLengths();
    int *pivotVariable = model_->pivotVariable();
    for (iRow = 0; iRow < numberStaticRows_ + numberActiveSets_; iRow++) {
      y[iRow] -= scalar * rhsOffset_[iRow];
      int iColumn = pivotVariable[iRow];
      if (iColumn < lastDynamic_) {
        CoinBigIndex j;
        double value = scalar * x[iColumn];
        if (value) {
          for (j = startColumn[iColumn];
               j < startColumn[iColumn] + length[iColumn]; j++) {
            int jRow = row[j];
            y[jRow] += value * element[j];
          }
        }
      }
    }
  }
}
// Modifies rhs offset
void ClpDynamicMatrix::modifyOffset(int sequence, double amount)
{
  if (amount) {
    assert(rhsOffset_);
    CoinBigIndex j;
    for (j = startColumn_[sequence]; j < startColumn_[sequence + 1]; j++) {
      int iRow = row_[j];
      rhsOffset_[iRow] += amount * element_[j];
    }
  }
}
// Gets key value when none in small
double
ClpDynamicMatrix::keyValue(int iSet) const
{
  double value = 0.0;
  if (toIndex_[iSet] < 0) {
    int key = keyVariable_[iSet];
    if (key < maximumGubColumns_) {
      if (getStatus(iSet) == ClpSimplex::atLowerBound)
        value = lowerSet_[iSet];
      else
        value = upperSet_[iSet];
      int numberKey = 0;
      int j = startSet_[iSet];
      while (j >= 0) {
        DynamicStatus status = getDynamicStatus(j);
        assert(status != inSmall);
        if (status == soloKey) {
          numberKey++;
        } else if (status == atUpperBound) {
          value -= columnUpper_[j];
        } else if (columnLower_) {
          value -= columnLower_[j];
        }
        j = next_[j]; //onto next in set
      }
      assert(numberKey == 1);
    } else {
      int j = startSet_[iSet];
      while (j >= 0) {
        DynamicStatus status = getDynamicStatus(j);
        assert(status != inSmall);
        assert(status != soloKey);
        if (status == atUpperBound) {
          value += columnUpper_[j];
        } else if (columnLower_) {
          value += columnLower_[j];
        }
        j = next_[j]; //onto next in set
      }
#if 0
	       // slack must be feasible
	       double oldValue=value;
	       value = CoinMax(value,lowerSet_[iSet]);
               value = CoinMin(value,upperSet_[iSet]);
	       if (value!=oldValue)
		 printf("using %g (not %g) for slack on set %d (%g,%g)\n",
			value,oldValue,iSet,lowerSet_[iSet],upperSet_[iSet]);
#endif
    }
  }
  return value;
}
// Switches off dj checking each factorization (for BIG models)
void ClpDynamicMatrix::switchOffCheck()
{
  noCheck_ = 0;
  infeasibilityWeight_ = 0.0;
}
/* Creates a variable.  This is called after partial pricing and may modify matrix.
   May update bestSequence.
*/
void ClpDynamicMatrix::createVariable(ClpSimplex *model, int &bestSequence)
{
  int numberRows = model->numberRows();
  int slackOffset = lastDynamic_ + numberRows;
  int structuralOffset = slackOffset + numberSets_;
  int bestSequence2 = savedBestSequence_ - structuralOffset;
  if (bestSequence >= slackOffset) {
    double *columnLower = model->lowerRegion();
    double *columnUpper = model->upperRegion();
    double *solution = model->solutionRegion();
    double *reducedCost = model->djRegion();
    const double *duals = model->dualRowSolution();
    if (toIndex_[savedBestSet_] < 0) {
      // need to put key into basis
      int newRow = numberActiveSets_ + numberStaticRows_;
      model->dualRowSolution()[newRow] = savedBestGubDual_;
      double valueOfKey = keyValue(savedBestSet_); // done before toIndex_ set
      toIndex_[savedBestSet_] = numberActiveSets_;
      fromIndex_[numberActiveSets_++] = savedBestSet_;
      int iSequence = lastDynamic_ + newRow;
      // we need to get lower and upper correct
      double shift = 0.0;
      int j = startSet_[savedBestSet_];
      while (j >= 0) {
        if (getDynamicStatus(j) == atUpperBound)
          shift += columnUpper_[j];
        else if (getDynamicStatus(j) == atLowerBound && columnLower_)
          shift += columnLower_[j];
        j = next_[j]; //onto next in set
      }
      if (lowerSet_[savedBestSet_] > -1.0e20)
        columnLower[iSequence] = lowerSet_[savedBestSet_];
      else
        columnLower[iSequence] = -COIN_DBL_MAX;
      if (upperSet_[savedBestSet_] < 1.0e20)
        columnUpper[iSequence] = upperSet_[savedBestSet_];
      else
        columnUpper[iSequence] = COIN_DBL_MAX;
#ifdef CLP_DEBUG
      if (model_->logLevel() == 63) {
        printf("%d in in set %d, key is %d rhs %g %g - keyvalue %g\n",
          bestSequence2, savedBestSet_, keyVariable_[savedBestSet_],
          columnLower[iSequence], columnUpper[iSequence], valueOfKey);
        int j = startSet_[savedBestSet_];
        while (j >= 0) {
          if (getDynamicStatus(j) == atUpperBound)
            printf("%d atup ", j);
          else if (getDynamicStatus(j) == atLowerBound)
            printf("%d atlo ", j);
          else if (getDynamicStatus(j) == soloKey)
            printf("%d solo ", j);
          else
            abort();
          j = next_[j]; //onto next in set
        }
        printf("\n");
      }
#endif
      if (keyVariable_[savedBestSet_] < maximumGubColumns_) {
        // slack not key
        model_->pivotVariable()[newRow] = firstAvailable_;
        backToPivotRow_[firstAvailable_] = newRow;
        model->setStatus(iSequence, getStatus(savedBestSet_));
        model->djRegion()[iSequence] = savedBestGubDual_;
        solution[iSequence] = valueOfKey;
        // create variable and pivot in
        int key = keyVariable_[savedBestSet_];
        setDynamicStatus(key, inSmall);
        double *element = matrix_->getMutableElements();
        int *row = matrix_->getMutableIndices();
        CoinBigIndex *startColumn = matrix_->getMutableVectorStarts();
        int *length = matrix_->getMutableVectorLengths();
        CoinBigIndex numberElements = startColumn[firstAvailable_];
        int numberThis = startColumn_[key + 1] - startColumn_[key] + 1;
        if (numberElements + numberThis > numberElements_) {
          // need to redo
          numberElements_ = CoinMax(3 * numberElements_ / 2, numberElements + numberThis);
          matrix_->reserve(lastDynamic_, numberElements_);
          element = matrix_->getMutableElements();
          row = matrix_->getMutableIndices();
          // these probably okay but be safe
          startColumn = matrix_->getMutableVectorStarts();
          length = matrix_->getMutableVectorLengths();
        }
        // already set startColumn[firstAvailable_]=numberElements;
        length[firstAvailable_] = numberThis;
        model->costRegion()[firstAvailable_] = cost_[key];
        CoinBigIndex base = startColumn_[key];
        for (int j = 0; j < numberThis - 1; j++) {
          row[numberElements] = row_[base + j];
          element[numberElements++] = element_[base + j];
        }
        row[numberElements] = newRow;
        element[numberElements++] = 1.0;
        id_[firstAvailable_ - firstDynamic_] = key;
        model->setObjectiveOffset(model->objectiveOffset() + cost_[key] * valueOfKey);
        model->solutionRegion()[firstAvailable_] = valueOfKey;
        model->setStatus(firstAvailable_, ClpSimplex::basic);
        // ***** need to adjust effective rhs
        if (!columnLower_ && !columnUpper_) {
          columnLower[firstAvailable_] = 0.0;
          columnUpper[firstAvailable_] = COIN_DBL_MAX;
        } else {
          if (columnLower_)
            columnLower[firstAvailable_] = columnLower_[key];
          else
            columnLower[firstAvailable_] = 0.0;
          if (columnUpper_)
            columnUpper[firstAvailable_] = columnUpper_[key];
          else
            columnUpper[firstAvailable_] = COIN_DBL_MAX;
        }
        model->nonLinearCost()->setOne(firstAvailable_, solution[firstAvailable_],
          columnLower[firstAvailable_],
          columnUpper[firstAvailable_], cost_[key]);
        startColumn[firstAvailable_ + 1] = numberElements;
        reducedCost[firstAvailable_] = 0.0;
        modifyOffset(key, valueOfKey);
        rhsOffset_[newRow] = -shift; // sign?
#ifdef CLP_DEBUG
        model->rowArray(1)->checkClear();
#endif
        // now pivot in
        unpack(model, model->rowArray(1), firstAvailable_);
        model->factorization()->updateColumnFT(model->rowArray(2), model->rowArray(1));
        double alpha = model->rowArray(1)->denseVector()[newRow];
        int updateStatus = model->factorization()->replaceColumn(model,
          model->rowArray(2),
          model->rowArray(1),
          newRow, alpha);
        model->rowArray(1)->clear();
        if (updateStatus) {
          if (updateStatus == 3) {
            // out of memory
            // increase space if not many iterations
            if (model->factorization()->pivots() < 0.5 * model->factorization()->maximumPivots() && model->factorization()->pivots() < 400)
              model->factorization()->areaFactor(
                model->factorization()->areaFactor() * 1.1);
          } else {
            printf("Bad returncode %d from replaceColumn\n", updateStatus);
          }
          bestSequence = -1;
          return;
        }
        // firstAvailable_ only finally updated if good pivot (in updatePivot)
        // otherwise it reverts to firstAvailableBefore_
        firstAvailable_++;
      } else {
        // slack key
        model->setStatus(iSequence, ClpSimplex::basic);
        model->djRegion()[iSequence] = 0.0;
        solution[iSequence] = valueOfKey + shift;
        rhsOffset_[newRow] = -shift; // sign?
      }
      // correct slack
      model->costRegion()[iSequence] = 0.0;
      model->nonLinearCost()->setOne(iSequence, solution[iSequence], columnLower[iSequence],
        columnUpper[iSequence], 0.0);
    }
    if (savedBestSequence_ >= structuralOffset) {
      // recompute dj and create
      double value = cost_[bestSequence2] - savedBestGubDual_;
      for (CoinBigIndex jBigIndex = startColumn_[bestSequence2];
           jBigIndex < startColumn_[bestSequence2 + 1]; jBigIndex++) {
        int jRow = row_[jBigIndex];
        value -= duals[jRow] * element_[jBigIndex];
      }
      int gubRow = toIndex_[savedBestSet_] + numberStaticRows_;
      double *element = matrix_->getMutableElements();
      int *row = matrix_->getMutableIndices();
      CoinBigIndex *startColumn = matrix_->getMutableVectorStarts();
      int *length = matrix_->getMutableVectorLengths();
      CoinBigIndex numberElements = startColumn[firstAvailable_];
      int numberThis = startColumn_[bestSequence2 + 1] - startColumn_[bestSequence2] + 1;
      if (numberElements + numberThis > numberElements_) {
        // need to redo
        numberElements_ = CoinMax(3 * numberElements_ / 2, numberElements + numberThis);
        matrix_->reserve(lastDynamic_, numberElements_);
        element = matrix_->getMutableElements();
        row = matrix_->getMutableIndices();
        // these probably okay but be safe
        startColumn = matrix_->getMutableVectorStarts();
        length = matrix_->getMutableVectorLengths();
      }
      // already set startColumn[firstAvailable_]=numberElements;
      length[firstAvailable_] = numberThis;
      model->costRegion()[firstAvailable_] = cost_[bestSequence2];
      CoinBigIndex base = startColumn_[bestSequence2];
      for (int j = 0; j < numberThis - 1; j++) {
        row[numberElements] = row_[base + j];
        element[numberElements++] = element_[base + j];
      }
      row[numberElements] = gubRow;
      element[numberElements++] = 1.0;
      id_[firstAvailable_ - firstDynamic_] = bestSequence2;
      //printf("best %d\n",bestSequence2);
      model->solutionRegion()[firstAvailable_] = 0.0;
      model->clearFlagged(firstAvailable_);
      if (!columnLower_ && !columnUpper_) {
        model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
        columnLower[firstAvailable_] = 0.0;
        columnUpper[firstAvailable_] = COIN_DBL_MAX;
      } else {
        DynamicStatus status = getDynamicStatus(bestSequence2);
        if (columnLower_)
          columnLower[firstAvailable_] = columnLower_[bestSequence2];
        else
          columnLower[firstAvailable_] = 0.0;
        if (columnUpper_)
          columnUpper[firstAvailable_] = columnUpper_[bestSequence2];
        else
          columnUpper[firstAvailable_] = COIN_DBL_MAX;
        if (status == atLowerBound) {
          solution[firstAvailable_] = columnLower[firstAvailable_];
          model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
        } else {
          solution[firstAvailable_] = columnUpper[firstAvailable_];
          model->setStatus(firstAvailable_, ClpSimplex::atUpperBound);
        }
      }
      model->setObjectiveOffset(model->objectiveOffset() + cost_[bestSequence2] * solution[firstAvailable_]);
      model->nonLinearCost()->setOne(firstAvailable_, solution[firstAvailable_],
        columnLower[firstAvailable_],
        columnUpper[firstAvailable_], cost_[bestSequence2]);
      bestSequence = firstAvailable_;
      // firstAvailable_ only updated if good pivot (in updatePivot)
      startColumn[firstAvailable_ + 1] = numberElements;
      //printf("price struct %d - dj %g gubpi %g\n",bestSequence,value,savedBestGubDual_);
      reducedCost[bestSequence] = value;
    } else {
      // slack - row must just have been created
      assert(toIndex_[savedBestSet_] == numberActiveSets_ - 1);
      int newRow = numberStaticRows_ + numberActiveSets_ - 1;
      bestSequence = lastDynamic_ + newRow;
      reducedCost[bestSequence] = savedBestGubDual_;
    }
  }
  // clear for next iteration
  savedBestSequence_ = -1;
}
// Returns reduced cost of a variable
double
ClpDynamicMatrix::reducedCost(ClpSimplex *model, int sequence) const
{
  int numberRows = model->numberRows();
  int slackOffset = lastDynamic_ + numberRows;
  if (sequence < slackOffset)
    return model->djRegion()[sequence];
  else
    return savedBestDj_;
}
// Does gub crash
void ClpDynamicMatrix::gubCrash()
{
  // Do basis - cheapest or slack if feasible
  int longestSet = 0;
  int iSet;
  for (iSet = 0; iSet < numberSets_; iSet++) {
    int n = 0;
    int j = startSet_[iSet];
    while (j >= 0) {
      n++;
      j = next_[j];
    }
    longestSet = CoinMax(longestSet, n);
  }
  double *upper = new double[longestSet + 1];
  double *cost = new double[longestSet + 1];
  double *lower = new double[longestSet + 1];
  double *solution = new double[longestSet + 1];
  int *back = new int[longestSet + 1];
  double tolerance = model_->primalTolerance();
  double objectiveOffset = 0.0;
  for (iSet = 0; iSet < numberSets_; iSet++) {
    int iBasic = -1;
    double value = 0.0;
    // find cheapest
    int numberInSet = 0;
    int j = startSet_[iSet];
    while (j >= 0) {
      if (!columnLower_)
        lower[numberInSet] = 0.0;
      else
        lower[numberInSet] = columnLower_[j];
      if (!columnUpper_)
        upper[numberInSet] = COIN_DBL_MAX;
      else
        upper[numberInSet] = columnUpper_[j];
      back[numberInSet++] = j;
      j = next_[j];
    }
    CoinFillN(solution, numberInSet, 0.0);
    // and slack
    iBasic = numberInSet;
    solution[iBasic] = -value;
    lower[iBasic] = -upperSet_[iSet];
    upper[iBasic] = -lowerSet_[iSet];
    int kphase;
    if (value < lowerSet_[iSet] - tolerance || value > upperSet_[iSet] + tolerance) {
      // infeasible
      kphase = 0;
      // remember bounds are flipped so opposite to natural
      if (value < lowerSet_[iSet] - tolerance)
        cost[iBasic] = 1.0;
      else
        cost[iBasic] = -1.0;
      CoinZeroN(cost, numberInSet);
      double dualTolerance = model_->dualTolerance();
      for (int iphase = kphase; iphase < 2; iphase++) {
        if (iphase) {
          cost[numberInSet] = 0.0;
          for (int j = 0; j < numberInSet; j++)
            cost[j] = cost_[back[j]];
        }
        // now do one row lp
        bool improve = true;
        while (improve) {
          improve = false;
          double dual = cost[iBasic];
          int chosen = -1;
          double best = dualTolerance;
          int way = 0;
          for (int i = 0; i <= numberInSet; i++) {
            double dj = cost[i] - dual;
            double improvement = 0.0;
            if (iphase || i < numberInSet)
              assert(solution[i] >= lower[i] && solution[i] <= upper[i]);
            if (dj > dualTolerance)
              improvement = dj * (solution[i] - lower[i]);
            else if (dj < -dualTolerance)
              improvement = dj * (solution[i] - upper[i]);
            if (improvement > best) {
              best = improvement;
              chosen = i;
              if (dj < 0.0) {
                way = 1;
              } else {
                way = -1;
              }
            }
          }
          if (chosen >= 0) {
            improve = true;
            // now see how far
            if (way > 0) {
              // incoming increasing so basic decreasing
              // if phase 0 then go to nearest bound
              double distance = upper[chosen] - solution[chosen];
              double basicDistance;
              if (!iphase) {
                assert(iBasic == numberInSet);
                assert(solution[iBasic] > upper[iBasic]);
                basicDistance = solution[iBasic] - upper[iBasic];
              } else {
                basicDistance = solution[iBasic] - lower[iBasic];
              }
              // need extra coding for unbounded
              assert(CoinMin(distance, basicDistance) < 1.0e20);
              if (distance > basicDistance) {
                // incoming becomes basic
                solution[chosen] += basicDistance;
                if (!iphase)
                  solution[iBasic] = upper[iBasic];
                else
                  solution[iBasic] = lower[iBasic];
                iBasic = chosen;
              } else {
                // flip
                solution[chosen] = upper[chosen];
                solution[iBasic] -= distance;
              }
            } else {
              // incoming decreasing so basic increasing
              // if phase 0 then go to nearest bound
              double distance = solution[chosen] - lower[chosen];
              double basicDistance;
              if (!iphase) {
                assert(iBasic == numberInSet);
                assert(solution[iBasic] < lower[iBasic]);
                basicDistance = lower[iBasic] - solution[iBasic];
              } else {
                basicDistance = upper[iBasic] - solution[iBasic];
              }
              // need extra coding for unbounded - for now just exit
              if (CoinMin(distance, basicDistance) > 1.0e20) {
                printf("unbounded on set %d\n", iSet);
                iphase = 1;
                iBasic = numberInSet;
                break;
              }
              if (distance > basicDistance) {
                // incoming becomes basic
                solution[chosen] -= basicDistance;
                if (!iphase)
                  solution[iBasic] = lower[iBasic];
                else
                  solution[iBasic] = upper[iBasic];
                iBasic = chosen;
              } else {
                // flip
                solution[chosen] = lower[chosen];
                solution[iBasic] += distance;
              }
            }
            if (!iphase) {
              if (iBasic < numberInSet)
                break; // feasible
              else if (solution[iBasic] >= lower[iBasic] && solution[iBasic] <= upper[iBasic])
                break; // feasible (on flip)
            }
          }
        }
      }
    }
    // do solution i.e. bounds
    if (columnLower_ || columnUpper_) {
      for (int j = 0; j < numberInSet; j++) {
        if (j != iBasic) {
          objectiveOffset += solution[j] * cost[j];
          if (columnLower_ && columnUpper_) {
            if (fabs(solution[j] - columnLower_[back[j]]) > fabs(solution[j] - columnUpper_[back[j]]))
              setDynamicStatus(back[j], atUpperBound);
          } else if (columnUpper_ && solution[j] > 0.0) {
            setDynamicStatus(back[j], atUpperBound);
          } else {
            setDynamicStatus(back[j], atLowerBound);
            assert(!solution[j]);
          }
        }
      }
    }
    // convert iBasic back and do bounds
    if (iBasic == numberInSet) {
      // slack basic
      setStatus(iSet, ClpSimplex::basic);
      iBasic = iSet + maximumGubColumns_;
    } else {
      iBasic = back[iBasic];
      setDynamicStatus(iBasic, soloKey);
      // remember bounds flipped
      if (upper[numberInSet] == lower[numberInSet])
        setStatus(iSet, ClpSimplex::isFixed);
      else if (solution[numberInSet] == upper[numberInSet])
        setStatus(iSet, ClpSimplex::atLowerBound);
      else if (solution[numberInSet] == lower[numberInSet])
        setStatus(iSet, ClpSimplex::atUpperBound);
      else
        abort();
    }
    keyVariable_[iSet] = iBasic;
  }
  model_->setObjectiveOffset(objectiveOffset_ - objectiveOffset);
  delete[] lower;
  delete[] solution;
  delete[] upper;
  delete[] cost;
  delete[] back;
  // make sure matrix is in good shape
  matrix_->orderMatrix();
}
// Populates initial matrix from dynamic status
void ClpDynamicMatrix::initialProblem()
{
  int iSet;
  double *element = matrix_->getMutableElements();
  int *row = matrix_->getMutableIndices();
  CoinBigIndex *startColumn = matrix_->getMutableVectorStarts();
  int *length = matrix_->getMutableVectorLengths();
  double *cost = model_->objective();
  double *solution = model_->primalColumnSolution();
  double *columnLower = model_->columnLower();
  double *columnUpper = model_->columnUpper();
  double *rowSolution = model_->primalRowSolution();
  double *rowLower = model_->rowLower();
  double *rowUpper = model_->rowUpper();
  CoinBigIndex numberElements = startColumn[firstDynamic_];

  firstAvailable_ = firstDynamic_;
  numberActiveSets_ = 0;
  for (iSet = 0; iSet < numberSets_; iSet++) {
    toIndex_[iSet] = -1;
    int numberActive = 0;
    int whichKey = -1;
    if (getStatus(iSet) == ClpSimplex::basic) {
      whichKey = maximumGubColumns_ + iSet;
      numberActive = 1;
    } else {
      whichKey = -1;
    }
    int j = startSet_[iSet];
    while (j >= 0) {
      assert(getDynamicStatus(j) != soloKey || whichKey == -1);
      if (getDynamicStatus(j) == inSmall) {
        numberActive++;
      } else if (getDynamicStatus(j) == soloKey) {
        whichKey = j;
        numberActive++;
      }
      j = next_[j]; //onto next in set
    }
    if (numberActive > 1) {
      int iRow = numberActiveSets_ + numberStaticRows_;
      rowSolution[iRow] = 0.0;
      double lowerValue;
      if (lowerSet_[iSet] > -1.0e20)
        lowerValue = lowerSet_[iSet];
      else
        lowerValue = -COIN_DBL_MAX;
      double upperValue;
      if (upperSet_[iSet] < 1.0e20)
        upperValue = upperSet_[iSet];
      else
        upperValue = COIN_DBL_MAX;
      rowLower[iRow] = lowerValue;
      rowUpper[iRow] = upperValue;
      if (getStatus(iSet) == ClpSimplex::basic) {
        model_->setRowStatus(iRow, ClpSimplex::basic);
        rowSolution[iRow] = 0.0;
      } else if (getStatus(iSet) == ClpSimplex::atLowerBound) {
        model_->setRowStatus(iRow, ClpSimplex::atLowerBound);
        rowSolution[iRow] = lowerValue;
      } else {
        model_->setRowStatus(iRow, ClpSimplex::atUpperBound);
        rowSolution[iRow] = upperValue;
      }
      j = startSet_[iSet];
      while (j >= 0) {
        DynamicStatus status = getDynamicStatus(j);
        if (status == inSmall) {
          int numberThis = startColumn_[j + 1] - startColumn_[j] + 1;
          if (numberElements + numberThis > numberElements_) {
            // need to redo
            numberElements_ = CoinMax(3 * numberElements_ / 2, numberElements + numberThis);
            matrix_->reserve(lastDynamic_, numberElements_);
            element = matrix_->getMutableElements();
            row = matrix_->getMutableIndices();
            // these probably okay but be safe
            startColumn = matrix_->getMutableVectorStarts();
            length = matrix_->getMutableVectorLengths();
          }
          length[firstAvailable_] = numberThis;
          cost[firstAvailable_] = cost_[j];
          CoinBigIndex base = startColumn_[j];
          for (int k = 0; k < numberThis - 1; k++) {
            row[numberElements] = row_[base + k];
            element[numberElements++] = element_[base + k];
          }
          row[numberElements] = iRow;
          element[numberElements++] = 1.0;
          id_[firstAvailable_ - firstDynamic_] = j;
          solution[firstAvailable_] = 0.0;
          model_->setStatus(firstAvailable_, ClpSimplex::basic);
          if (!columnLower_ && !columnUpper_) {
            columnLower[firstAvailable_] = 0.0;
            columnUpper[firstAvailable_] = COIN_DBL_MAX;
          } else {
            if (columnLower_)
              columnLower[firstAvailable_] = columnLower_[j];
            else
              columnLower[firstAvailable_] = 0.0;
            if (columnUpper_)
              columnUpper[firstAvailable_] = columnUpper_[j];
            else
              columnUpper[firstAvailable_] = COIN_DBL_MAX;
            if (status != atUpperBound) {
              solution[firstAvailable_] = columnLower[firstAvailable_];
            } else {
              solution[firstAvailable_] = columnUpper[firstAvailable_];
            }
          }
          firstAvailable_++;
          startColumn[firstAvailable_] = numberElements;
        }
        j = next_[j]; //onto next in set
      }
      model_->setRowStatus(numberActiveSets_ + numberStaticRows_, getStatus(iSet));
      toIndex_[iSet] = numberActiveSets_;
      fromIndex_[numberActiveSets_++] = iSet;
    } else {
      // solo key
      bool needKey = false;
      if (numberActive) {
        if (whichKey < maximumGubColumns_) {
          // structural - assume ok
          needKey = false;
        } else {
          // slack
          keyVariable_[iSet] = maximumGubColumns_ + iSet;
          double value = keyValue(iSet);
          if (value < lowerSet_[iSet] - 1.0e-8 || value > upperSet_[iSet] + 1.0e-8)
            needKey = true;
        }
      } else {
        needKey = true;
      }
      if (needKey) {
        // all to lb then up some (slack/null if possible)
        int length = 99999999;
        int which = -1;
        double sum = 0.0;
        for (int iColumn = startSet_[iSet]; iColumn < startSet_[iSet + 1]; iColumn++) {
          setDynamicStatus(iColumn, atLowerBound);
          sum += columnLower_[iColumn];
          if (length > startColumn_[iColumn + 1] - startColumn_[iColumn]) {
            which = iColumn;
            length = startColumn_[iColumn + 1] - startColumn_[iColumn];
          }
        }
        if (sum > lowerSet_[iSet] - 1.0e-8) {
          // slack can be basic
          setStatus(iSet, ClpSimplex::basic);
          keyVariable_[iSet] = maximumGubColumns_ + iSet;
        } else {
          // use shortest
          setDynamicStatus(which, soloKey);
          keyVariable_[iSet] = which;
          setStatus(iSet, ClpSimplex::atLowerBound);
        }
      }
    }
    assert(toIndex_[iSet] >= 0 || whichKey >= 0);
    keyVariable_[iSet] = whichKey;
  }
  // clean up pivotVariable
  int numberColumns = model_->numberColumns();
  int numberRows = model_->numberRows();
  int *pivotVariable = model_->pivotVariable();
  if (pivotVariable) {
    for (int i = 0; i < numberStaticRows_ + numberActiveSets_; i++) {
      if (model_->getRowStatus(i) != ClpSimplex::basic)
        pivotVariable[i] = -1;
      else
        pivotVariable[i] = numberColumns + i;
    }
    for (int i = numberStaticRows_ + numberActiveSets_; i < numberRows; i++) {
      pivotVariable[i] = i + numberColumns;
    }
    int put = -1;
    for (int i = 0; i < numberColumns; i++) {
      if (model_->getColumnStatus(i) == ClpSimplex::basic) {
        while (put < numberRows) {
          put++;
          if (pivotVariable[put] == -1) {
            pivotVariable[put] = i;
            break;
          }
        }
      }
    }
    for (int i = CoinMax(put, 0); i < numberRows; i++) {
      if (pivotVariable[i] == -1)
        pivotVariable[i] = i + numberColumns;
    }
  }
  if (rhsOffset_ && model_->costRegion()) {
    double *cost = model_->costRegion();
    double *columnLower = model_->lowerRegion();
    double *columnUpper = model_->upperRegion();
    double *solution = model_->solutionRegion();
    int numberRows = model_->numberRows();
    for (int i = numberActiveSets_; i < numberRows - numberStaticRows_; i++) {
      int iSequence = i + numberStaticRows_ + numberColumns;
      solution[iSequence] = 0.0;
      columnLower[iSequence] = -COIN_DBL_MAX;
      columnUpper[iSequence] = COIN_DBL_MAX;
      cost[iSequence] = 0.0;
      model_->nonLinearCost()->setOne(iSequence, solution[iSequence],
        columnLower[iSequence],
        columnUpper[iSequence], 0.0);
      model_->setStatus(iSequence, ClpSimplex::basic);
      rhsOffset_[i + numberStaticRows_] = 0.0;
    }
#if 0
       for (int i=0;i<numberStaticRows_;i++)
	 printf("%d offset %g\n",
		i,rhsOffset_[i]);
#endif
  }
  numberActiveColumns_ = firstAvailable_;
#if 0
     for (iSet = 0; iSet < numberSets_; iSet++) {
       for (int j=startSet_[iSet];j<startSet_[iSet+1];j++) {
	 if (getDynamicStatus(j)==soloKey)
	   printf("%d in set %d is solo key\n",j,iSet);
	 else if (getDynamicStatus(j)==inSmall)
	   printf("%d in set %d is in small\n",j,iSet);
       }
     }
#endif
  return;
}
// Writes out model (without names)
void ClpDynamicMatrix::writeMps(const char *name)
{
  int numberTotalRows = numberStaticRows_ + numberSets_;
  int numberTotalColumns = firstDynamic_ + numberGubColumns_;
  // over estimate
  int numberElements = getNumElements() + startColumn_[numberGubColumns_]
    + numberGubColumns_;
  double *columnLower = new double[numberTotalColumns];
  double *columnUpper = new double[numberTotalColumns];
  double *cost = new double[numberTotalColumns];
  double *rowLower = new double[numberTotalRows];
  double *rowUpper = new double[numberTotalRows];
  CoinBigIndex *start = new CoinBigIndex[numberTotalColumns + 1];
  int *row = new int[numberElements];
  double *element = new double[numberElements];
  // Fill in
  const CoinBigIndex *startA = getVectorStarts();
  const int *lengthA = getVectorLengths();
  const int *rowA = getIndices();
  const double *elementA = getElements();
  const double *columnLowerA = model_->columnLower();
  const double *columnUpperA = model_->columnUpper();
  const double *costA = model_->objective();
  const double *rowLowerA = model_->rowLower();
  const double *rowUpperA = model_->rowUpper();
  start[0] = 0;
  numberElements = 0;
  for (int i = 0; i < firstDynamic_; i++) {
    columnLower[i] = columnLowerA[i];
    columnUpper[i] = columnUpperA[i];
    cost[i] = costA[i];
    for (CoinBigIndex j = startA[i]; j < startA[i] + lengthA[i]; j++) {
      row[numberElements] = rowA[j];
      element[numberElements++] = elementA[j];
    }
    start[i + 1] = numberElements;
  }
  for (int i = 0; i < numberStaticRows_; i++) {
    rowLower[i] = rowLowerA[i];
    rowUpper[i] = rowUpperA[i];
  }
  int putC = firstDynamic_;
  int putR = numberStaticRows_;
  for (int i = 0; i < numberSets_; i++) {
    rowLower[putR] = lowerSet_[i];
    rowUpper[putR] = upperSet_[i];
    for (CoinBigIndex k = startSet_[i]; k < startSet_[i + 1]; k++) {
      columnLower[putC] = columnLower_[k];
      columnUpper[putC] = columnUpper_[k];
      cost[putC] = cost_[k];
      putC++;
      for (CoinBigIndex j = startColumn_[k]; j < startColumn_[k + 1]; j++) {
        row[numberElements] = row_[j];
        element[numberElements++] = element_[j];
      }
      row[numberElements] = putR;
      element[numberElements++] = 1.0;
      start[putC] = numberElements;
    }
    putR++;
  }

  assert(putR == numberTotalRows);
  assert(putC == numberTotalColumns);
  ClpSimplex modelOut;
  modelOut.loadProblem(numberTotalColumns, numberTotalRows,
    start, row, element,
    columnLower, columnUpper, cost,
    rowLower, rowUpper);
  modelOut.writeMps(name);
  delete[] columnLower;
  delete[] columnUpper;
  delete[] cost;
  delete[] rowLower;
  delete[] rowUpper;
  delete[] start;
  delete[] row;
  delete[] element;
}
// Adds in a column to gub structure (called from descendant)
int ClpDynamicMatrix::addColumn(CoinBigIndex numberEntries, const int *row, const double *element,
  double cost, double lower, double upper, int iSet,
  DynamicStatus status)
{
  // check if already in
  int j = startSet_[iSet];
  while (j >= 0) {
    if (startColumn_[j + 1] - startColumn_[j] == numberEntries) {
      const int *row2 = row_ + startColumn_[j];
      const double *element2 = element_ + startColumn_[j];
      bool same = true;
      for (int k = 0; k < numberEntries; k++) {
        if (row[k] != row2[k] || element[k] != element2[k]) {
          same = false;
          break;
        }
      }
      if (same) {
        bool odd = false;
        if (cost != cost_[j])
          odd = true;
        if (columnLower_ && lower != columnLower_[j])
          odd = true;
        if (columnUpper_ && upper != columnUpper_[j])
          odd = true;
        if (odd) {
          printf("seems odd - same els but cost,lo,up are %g,%g,%g and %g,%g,%g\n",
            cost, lower, upper, cost_[j],
            columnLower_ ? columnLower_[j] : 0.0,
            columnUpper_ ? columnUpper_[j] : 1.0e100);
        } else {
          setDynamicStatus(j, status);
          return j;
        }
      }
    }
    j = next_[j];
  }

  if (numberGubColumns_ == maximumGubColumns_ || startColumn_[numberGubColumns_] + numberEntries > maximumElements_) {
    CoinBigIndex j;
    int i;
    int put = 0;
    int numberElements = 0;
    CoinBigIndex start = 0;
    // compress - leave ones at ub and basic
    int *which = new int[numberGubColumns_];
    for (i = 0; i < numberGubColumns_; i++) {
      CoinBigIndex end = startColumn_[i + 1];
      // what about ubs if column generation?
      if (getDynamicStatus(i) != atLowerBound) {
        // keep in
        for (j = start; j < end; j++) {
          row_[numberElements] = row_[j];
          element_[numberElements++] = element_[j];
        }
        startColumn_[put + 1] = numberElements;
        cost_[put] = cost_[i];
        if (columnLower_)
          columnLower_[put] = columnLower_[i];
        if (columnUpper_)
          columnUpper_[put] = columnUpper_[i];
        dynamicStatus_[put] = dynamicStatus_[i];
        id_[put] = id_[i];
        which[i] = put;
        put++;
      } else {
        // out
        which[i] = -1;
      }
      start = end;
    }
    // now redo startSet_ and next_
    int *newNext = new int[maximumGubColumns_];
    for (int jSet = 0; jSet < numberSets_; jSet++) {
      int sequence = startSet_[jSet];
      while (which[sequence] < 0) {
        // out
        assert(next_[sequence] >= 0);
        sequence = next_[sequence];
      }
      startSet_[jSet] = which[sequence];
      int last = which[sequence];
      while (next_[sequence] >= 0) {
        sequence = next_[sequence];
        if (which[sequence] >= 0) {
          // keep
          newNext[last] = which[sequence];
          last = which[sequence];
        }
      }
      newNext[last] = -jSet - 1;
    }
    delete[] next_;
    next_ = newNext;
    delete[] which;
    abort();
  }
  CoinBigIndex start = startColumn_[numberGubColumns_];
  CoinMemcpyN(row, numberEntries, row_ + start);
  CoinMemcpyN(element, numberEntries, element_ + start);
  startColumn_[numberGubColumns_ + 1] = start + numberEntries;
  cost_[numberGubColumns_] = cost;
  if (columnLower_)
    columnLower_[numberGubColumns_] = lower;
  else
    assert(!lower);
  if (columnUpper_)
    columnUpper_[numberGubColumns_] = upper;
  else
    assert(upper > 1.0e20);
  setDynamicStatus(numberGubColumns_, status);
  // Do next_
  j = startSet_[iSet];
  startSet_[iSet] = numberGubColumns_;
  next_[numberGubColumns_] = j;
  numberGubColumns_++;
  return numberGubColumns_ - 1;
}
// Returns which set a variable is in
int ClpDynamicMatrix::whichSet(int sequence) const
{
  while (next_[sequence] >= 0)
    sequence = next_[sequence];
  int iSet = -next_[sequence] - 1;
  return iSet;
}

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