/* $Id: ClpSimplexOther.cpp 2074 2014-12-10 09:43:54Z forrest $ */
// 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 "CoinPragma.hpp"

#include <math.h>

#include "CoinHelperFunctions.hpp"
#include "ClpSimplexOther.hpp"
#include "ClpSimplexDual.hpp"
#include "ClpSimplexPrimal.hpp"
#include "ClpEventHandler.hpp"
#include "ClpHelperFunctions.hpp"
#include "ClpFactorization.hpp"
#include "ClpDualRowDantzig.hpp"
#include "ClpNonLinearCost.hpp"
#include "ClpDynamicMatrix.hpp"
#include "CoinPackedMatrix.hpp"
#include "CoinIndexedVector.hpp"
#include "CoinBuild.hpp"
#include "CoinMpsIO.hpp"
#include "CoinFloatEqual.hpp"
#include "ClpMessage.hpp"
#include <cfloat>
#include <cassert>
#include <string>
#include <stdio.h>
#include <iostream>
#ifdef INT_IS_8
#define COIN_ANY_BITS_PER_INT 64
#define COIN_ANY_SHIFT_PER_INT 6
#define COIN_ANY_MASK_PER_INT 0x3f
#else
#define COIN_ANY_BITS_PER_INT 32
#define COIN_ANY_SHIFT_PER_INT 5
#define COIN_ANY_MASK_PER_INT 0x1f
#endif
/* Dual ranging.
   This computes increase/decrease in cost for each given variable and corresponding
   sequence numbers which would change basis.  Sequence numbers are 0..numberColumns
   and numberColumns.. for artificials/slacks.
   For non-basic variables the sequence number will be that of the non-basic variables.

   Up to user to provide correct length arrays.

*/
void ClpSimplexOther::dualRanging(int numberCheck, const int * which,
                                  double * costIncreased, int * sequenceIncreased,
                                  double * costDecreased, int * sequenceDecreased,
                                  double * valueIncrease, double * valueDecrease)
{
     rowArray_[1]->clear();
     columnArray_[1]->clear();
     // long enough for rows+columns
     assert(rowArray_[3]->capacity() >= numberRows_ + numberColumns_);
     rowArray_[3]->clear();
     int * backPivot = rowArray_[3]->getIndices();
     int i;
     for ( i = 0; i < numberRows_ + numberColumns_; i++) {
          backPivot[i] = -1;
     }
     for (i = 0; i < numberRows_; i++) {
          int iSequence = pivotVariable_[i];
          backPivot[iSequence] = i;
     }
     // dualTolerance may be zero if from CBC.  In fact use that fact
     bool inCBC = !dualTolerance_;
     if (inCBC)
          assert (integerType_);
     dualTolerance_ = dblParam_[ClpDualTolerance];
     double * arrayX = rowArray_[0]->denseVector();
     for ( i = 0; i < numberCheck; i++) {
          rowArray_[0]->clear();
          //rowArray_[0]->checkClear();
          //rowArray_[1]->checkClear();
          //columnArray_[1]->checkClear();
          columnArray_[0]->clear();
          //columnArray_[0]->checkClear();
          int iSequence = which[i];
          if (iSequence < 0) {
               costIncreased[i] = 0.0;
               sequenceIncreased[i] = -1;
               costDecreased[i] = 0.0;
               sequenceDecreased[i] = -1;
               continue;
          }
          double costIncrease = COIN_DBL_MAX;
          double costDecrease = COIN_DBL_MAX;
          int sequenceIncrease = -1;
          int sequenceDecrease = -1;
          if (valueIncrease) {
               assert (valueDecrease);
               valueIncrease[i] = iSequence < numberColumns_ ? columnActivity_[iSequence] : rowActivity_[iSequence-numberColumns_];
               valueDecrease[i] = valueIncrease[i];
          }

          switch(getStatus(iSequence)) {

          case basic: {
               // non-trvial
               // Get pivot row
               int iRow = backPivot[iSequence];
               assert (iRow >= 0);
#ifndef COIN_FAC_NEW
               double plusOne = 1.0;
               rowArray_[0]->createPacked(1, &iRow, &plusOne);
#else
               rowArray_[0]->createOneUnpackedElement( iRow, 1.0);
#endif
               factorization_->updateColumnTranspose(rowArray_[1], rowArray_[0]);
               // put row of tableau in rowArray[0] and columnArray[0]
               matrix_->transposeTimes(this, -1.0,
                                       rowArray_[0], columnArray_[1], columnArray_[0]);
#ifdef COIN_FAC_NEW
	       assert (!rowArray_[0]->packedMode());
#endif
               double alphaIncrease;
               double alphaDecrease;
               // do ratio test up and down
               checkDualRatios(rowArray_[0], columnArray_[0], costIncrease, sequenceIncrease, alphaIncrease,
                               costDecrease, sequenceDecrease, alphaDecrease);
               if (!inCBC) {
                    if (valueIncrease) {
                         if (sequenceIncrease >= 0)
                              valueIncrease[i] = primalRanging1(sequenceIncrease, iSequence);
                         if (sequenceDecrease >= 0)
                              valueDecrease[i] = primalRanging1(sequenceDecrease, iSequence);
                    }
               } else {
                    int number = rowArray_[0]->getNumElements();
#ifdef COIN_FAC_NEW
		    const int * index = rowArray_[0]->getIndices();
#endif
                    double scale2 = 0.0;
                    int j;
                    for (j = 0; j < number; j++) {
#ifndef COIN_FAC_NEW
                         scale2 += arrayX[j] * arrayX[j];
#else
			 int iRow=index[j];
                         scale2 += arrayX[iRow] * arrayX[iRow];
#endif
                    }
                    scale2 = 1.0 / sqrt(scale2);
                    //valueIncrease[i] = scale2;
                    if (sequenceIncrease >= 0) {
                         double djValue = dj_[sequenceIncrease];
                         if (fabs(djValue) > 10.0 * dualTolerance_) {
                              // we are going to use for cutoff so be exact
                              costIncrease = fabs(djValue / alphaIncrease);
                              /* Not sure this is good idea as I don't think correct e.g.
                                 suppose a continuous variable has dj slightly greater. */
                              if(false && sequenceIncrease < numberColumns_ && integerType_[sequenceIncrease]) {
                                   // can improve
                                   double movement = (columnScale_ == NULL) ? 1.0 :
                                                     rhsScale_ * inverseColumnScale_[sequenceIncrease];
                                   costIncrease = CoinMax(fabs(djValue * movement), costIncrease);
                              }
                         } else {
                              costIncrease = 0.0;
                         }
                    }
                    if (sequenceDecrease >= 0) {
                         double djValue = dj_[sequenceDecrease];
                         if (fabs(djValue) > 10.0 * dualTolerance_) {
                              // we are going to use for cutoff so be exact
                              costDecrease = fabs(djValue / alphaDecrease);
                              if(sequenceDecrease < numberColumns_ && integerType_[sequenceDecrease]) {
                                   // can improve
                                   double movement = (columnScale_ == NULL) ? 1.0 :
                                                     rhsScale_ * inverseColumnScale_[sequenceDecrease];
                                   costDecrease = CoinMax(fabs(djValue * movement), costDecrease);
                              }
                         } else {
                              costDecrease = 0.0;
                         }
                    }
                    costIncrease *= scale2;
                    costDecrease *= scale2;
               }
          }
          break;
          case isFixed:
               break;
          case isFree:
          case superBasic:
               costIncrease = 0.0;
               costDecrease = 0.0;
               sequenceIncrease = iSequence;
               sequenceDecrease = iSequence;
               break;
          case atUpperBound:
               costIncrease = CoinMax(0.0, -dj_[iSequence]);
               sequenceIncrease = iSequence;
               if (valueIncrease)
                    valueIncrease[i] = primalRanging1(iSequence, iSequence);
               break;
          case atLowerBound:
               costDecrease = CoinMax(0.0, dj_[iSequence]);
               sequenceDecrease = iSequence;
               if (valueIncrease)
                    valueDecrease[i] = primalRanging1(iSequence, iSequence);
               break;
          }
          double scaleFactor;
          if (rowScale_) {
               if (iSequence < numberColumns_)
                    scaleFactor = 1.0 / (objectiveScale_ * columnScale_[iSequence]);
               else
                    scaleFactor = rowScale_[iSequence-numberColumns_] / objectiveScale_;
          } else {
               scaleFactor = 1.0 / objectiveScale_;
          }
          if (costIncrease < 1.0e30)
               costIncrease *= scaleFactor;
          if (costDecrease < 1.0e30)
               costDecrease *= scaleFactor;
          if (optimizationDirection_ == 1.0) {
               costIncreased[i] = costIncrease;
               sequenceIncreased[i] = sequenceIncrease;
               costDecreased[i] = costDecrease;
               sequenceDecreased[i] = sequenceDecrease;
          } else if (optimizationDirection_ == -1.0) {
               costIncreased[i] = costDecrease;
               sequenceIncreased[i] = sequenceDecrease;
               costDecreased[i] = costIncrease;
               sequenceDecreased[i] = sequenceIncrease;
               if (valueIncrease) {
                    double temp = valueIncrease[i];
                    valueIncrease[i] = valueDecrease[i];
                    valueDecrease[i] = temp;
               }
          } else if (optimizationDirection_ == 0.0) {
               // !!!!!! ???
               costIncreased[i] = COIN_DBL_MAX;
               sequenceIncreased[i] = -1;
               costDecreased[i] = COIN_DBL_MAX;
               sequenceDecreased[i] = -1;
          } else {
               abort();
          }
     }
     rowArray_[0]->clear();
     //rowArray_[1]->clear();
     //columnArray_[1]->clear();
     columnArray_[0]->clear();
     //rowArray_[3]->clear();
     if (!optimizationDirection_)
          printf("*** ????? Ranging with zero optimization costs\n");
}
/*
   Row array has row part of pivot row
   Column array has column part.
   This is used in dual ranging
*/
void
ClpSimplexOther::checkDualRatios(CoinIndexedVector * rowArray,
                                 CoinIndexedVector * columnArray,
                                 double & costIncrease, int & sequenceIncrease, double & alphaIncrease,
                                 double & costDecrease, int & sequenceDecrease, double & alphaDecrease)
{
     double acceptablePivot = 1.0e-9;
     double * work;
     int number;
     int * which;
     int iSection;

     double thetaDown = 1.0e31;
     double thetaUp = 1.0e31;
     int sequenceDown = -1;
     int sequenceUp = -1;
     double alphaDown = 0.0;
     double alphaUp = 0.0;

     int addSequence;

     for (iSection = 0; iSection < 2; iSection++) {

          int i;
          if (!iSection) {
               work = rowArray->denseVector();
               number = rowArray->getNumElements();
               which = rowArray->getIndices();
               addSequence = numberColumns_;
          } else {
               work = columnArray->denseVector();
               number = columnArray->getNumElements();
               which = columnArray->getIndices();
               addSequence = 0;
          }

          for (i = 0; i < number; i++) {
               int iSequence = which[i];
               int iSequence2 = iSequence + addSequence;
#ifndef COIN_FAC_NEW
               double alpha = work[i];
#else
               double alpha = !addSequence ? work[i] : work[iSequence];
#endif
               if (fabs(alpha) < acceptablePivot)
                    continue;
               double oldValue = dj_[iSequence2];

               switch(getStatus(iSequence2)) {

               case basic:
                    break;
               case ClpSimplex::isFixed:
                    break;
               case isFree:
               case superBasic:
                    // treat dj as if zero
                    thetaDown = 0.0;
                    thetaUp = 0.0;
                    sequenceDown = iSequence2;
                    sequenceUp = iSequence2;
                    break;
               case atUpperBound:
                    if (alpha > 0.0) {
                         // test up
                         if (oldValue + thetaUp * alpha > dualTolerance_) {
                              thetaUp = (dualTolerance_ - oldValue) / alpha;
                              sequenceUp = iSequence2;
                              alphaUp = alpha;
                         }
                    } else {
                         // test down
                         if (oldValue - thetaDown * alpha > dualTolerance_) {
                              thetaDown = -(dualTolerance_ - oldValue) / alpha;
                              sequenceDown = iSequence2;
                              alphaDown = alpha;
                         }
                    }
                    break;
               case atLowerBound:
                    if (alpha < 0.0) {
                         // test up
                         if (oldValue + thetaUp * alpha < - dualTolerance_) {
                              thetaUp = -(dualTolerance_ + oldValue) / alpha;
                              sequenceUp = iSequence2;
                              alphaUp = alpha;
                         }
                    } else {
                         // test down
                         if (oldValue - thetaDown * alpha < -dualTolerance_) {
                              thetaDown = (dualTolerance_ + oldValue) / alpha;
                              sequenceDown = iSequence2;
                              alphaDown = alpha;
                         }
                    }
                    break;
               }
          }
     }
     if (sequenceUp >= 0) {
          costIncrease = thetaUp;
          sequenceIncrease = sequenceUp;
          alphaIncrease = alphaUp;
     }
     if (sequenceDown >= 0) {
          costDecrease = thetaDown;
          sequenceDecrease = sequenceDown;
          alphaDecrease = alphaDown;
     }
}
/** Primal ranging.
    This computes increase/decrease in value for each given variable and corresponding
    sequence numbers which would change basis.  Sequence numbers are 0..numberColumns
    and numberColumns.. for artificials/slacks.
    For basic variables the sequence number will be that of the basic variables.

    Up to user to provide correct length arrays.

    When here - guaranteed optimal
*/
void
ClpSimplexOther::primalRanging(int numberCheck, const int * which,
                               double * valueIncreased, int * sequenceIncreased,
                               double * valueDecreased, int * sequenceDecreased)
{
     rowArray_[0]->clear();
     rowArray_[1]->clear();
     lowerIn_ = -COIN_DBL_MAX;
     upperIn_ = COIN_DBL_MAX;
     valueIn_ = 0.0;
     for ( int i = 0; i < numberCheck; i++) {
          int iSequence = which[i];
          double valueIncrease = COIN_DBL_MAX;
          double valueDecrease = COIN_DBL_MAX;
          int sequenceIncrease = -1;
          int sequenceDecrease = -1;

          switch(getStatus(iSequence)) {

          case basic:
          case isFree:
          case superBasic:
               // Easy
               valueDecrease = CoinMax(0.0, upper_[iSequence] - solution_[iSequence]);
               valueIncrease = CoinMax(0.0, solution_[iSequence] - lower_[iSequence]);
               sequenceDecrease = iSequence;
               sequenceIncrease = iSequence;
               break;
          case isFixed:
          case atUpperBound:
          case atLowerBound: {
               // Non trivial
               // Other bound is ignored
#ifndef COIN_FAC_NEW
               unpackPacked(rowArray_[1], iSequence);
#else
               unpack(rowArray_[1], iSequence);
#endif
               factorization_->updateColumn(rowArray_[2], rowArray_[1]);
               // Get extra rows
               matrix_->extendUpdated(this, rowArray_[1], 0);
               // do ratio test
               checkPrimalRatios(rowArray_[1], 1);
               if (pivotRow_ >= 0) {
                    valueIncrease = theta_;
                    sequenceIncrease = pivotVariable_[pivotRow_];
               }
               checkPrimalRatios(rowArray_[1], -1);
               if (pivotRow_ >= 0) {
                    valueDecrease = theta_;
                    sequenceDecrease = pivotVariable_[pivotRow_];
               }
               rowArray_[1]->clear();
          }
          break;
          }
          double scaleFactor;
          if (rowScale_) {
               if (iSequence < numberColumns_)
                    scaleFactor = columnScale_[iSequence] / rhsScale_;
               else
                    scaleFactor = 1.0 / (rowScale_[iSequence-numberColumns_] * rhsScale_);
          } else {
               scaleFactor = 1.0 / rhsScale_;
          }
          if (valueIncrease < 1.0e30)
               valueIncrease *= scaleFactor;
          else
               valueIncrease = COIN_DBL_MAX;
          if (valueDecrease < 1.0e30)
               valueDecrease *= scaleFactor;
          else
               valueDecrease = COIN_DBL_MAX;
          valueIncreased[i] = valueIncrease;
          sequenceIncreased[i] = sequenceIncrease;
          valueDecreased[i] = valueDecrease;
          sequenceDecreased[i] = sequenceDecrease;
     }
}
// Returns new value of whichOther when whichIn enters basis
double
ClpSimplexOther::primalRanging1(int whichIn, int whichOther)
{
     rowArray_[0]->clear();
     rowArray_[1]->clear();
     int iSequence = whichIn;
     double newValue = solution_[whichOther];
     double alphaOther = 0.0;
     Status status = getStatus(iSequence);
     assert (status == atLowerBound || status == atUpperBound);
     int wayIn = (status == atLowerBound) ? 1 : -1;

     switch(getStatus(iSequence)) {

     case basic:
     case isFree:
     case superBasic:
          assert (whichIn == whichOther);
          // Easy
          newValue = wayIn > 0 ? upper_[iSequence] : lower_[iSequence];
          break;
     case isFixed:
     case atUpperBound:
     case atLowerBound:
          // Non trivial
     {
          // Other bound is ignored
#ifndef COIN_FAC_NEW
          unpackPacked(rowArray_[1], iSequence);
#else
          unpack(rowArray_[1], iSequence);
#endif
          factorization_->updateColumn(rowArray_[2], rowArray_[1]);
          // Get extra rows
          matrix_->extendUpdated(this, rowArray_[1], 0);
          // do ratio test
          double acceptablePivot = 1.0e-7;
          double * work = rowArray_[1]->denseVector();
          int number = rowArray_[1]->getNumElements();
          int * which = rowArray_[1]->getIndices();

          // we may need to swap sign
          double way = wayIn;
          double theta = 1.0e30;
          for (int iIndex = 0; iIndex < number; iIndex++) {

               int iRow = which[iIndex];
#ifndef COIN_FAC_NEW
               double alpha = work[iIndex] * way;
#else
               double alpha = work[iRow] * way;
#endif
               int iPivot = pivotVariable_[iRow];
               if (iPivot == whichOther) {
                    alphaOther = alpha;
                    continue;
               }
               double oldValue = solution_[iPivot];
               if (fabs(alpha) > acceptablePivot) {
                    if (alpha > 0.0) {
                         // basic variable going towards lower bound
                         double bound = lower_[iPivot];
                         oldValue -= bound;
                         if (oldValue - theta * alpha < 0.0) {
                              theta = CoinMax(0.0, oldValue / alpha);
                         }
                    } else {
                         // basic variable going towards upper bound
                         double bound = upper_[iPivot];
                         oldValue = oldValue - bound;
                         if (oldValue - theta * alpha > 0.0) {
                              theta = CoinMax(0.0, oldValue / alpha);
                         }
                    }
               }
          }
          if (whichIn != whichOther) {
               if (theta < 1.0e30)
                    newValue -= theta * alphaOther;
               else
                    newValue = alphaOther > 0.0 ? -1.0e30 : 1.0e30;
          } else {
               newValue += theta * wayIn;
          }
     }
     rowArray_[1]->clear();
     break;
     }
     double scaleFactor;
     if (rowScale_) {
          if (whichOther < numberColumns_)
               scaleFactor = columnScale_[whichOther] / rhsScale_;
          else
               scaleFactor = 1.0 / (rowScale_[whichOther-numberColumns_] * rhsScale_);
     } else {
          scaleFactor = 1.0 / rhsScale_;
     }
     if (newValue < 1.0e29)
          if (newValue > -1.0e29)
               newValue *= scaleFactor;
          else
               newValue = -COIN_DBL_MAX;
     else
          newValue = COIN_DBL_MAX;
     return newValue;
}
/*
   Row array has pivot column
   This is used in primal ranging
*/
void
ClpSimplexOther::checkPrimalRatios(CoinIndexedVector * rowArray,
                                   int direction)
{
     // sequence stays as row number until end
     pivotRow_ = -1;
     double acceptablePivot = 1.0e-7;
     double * work = rowArray->denseVector();
     int number = rowArray->getNumElements();
     int * which = rowArray->getIndices();

     // we need to swap sign if going down
     double way = direction;
     theta_ = 1.0e30;
     for (int iIndex = 0; iIndex < number; iIndex++) {

          int iRow = which[iIndex];
#ifndef COIN_FAC_NEW
          double alpha = work[iIndex] * way;
#else
          double alpha = work[iRow] * way;
#endif
          int iPivot = pivotVariable_[iRow];
          double oldValue = solution_[iPivot];
          if (fabs(alpha) > acceptablePivot) {
               if (alpha > 0.0) {
                    // basic variable going towards lower bound
                    double bound = lower_[iPivot];
                    oldValue -= bound;
                    if (oldValue - theta_ * alpha < 0.0) {
                         pivotRow_ = iRow;
                         theta_ = CoinMax(0.0, oldValue / alpha);
                    }
               } else {
                    // basic variable going towards upper bound
                    double bound = upper_[iPivot];
                    oldValue = oldValue - bound;
                    if (oldValue - theta_ * alpha > 0.0) {
                         pivotRow_ = iRow;
                         theta_ = CoinMax(0.0, oldValue / alpha);
                    }
               }
          }
     }
}
/* Write the basis in MPS format to the specified file.
   If writeValues true writes values of structurals
   (and adds VALUES to end of NAME card)

   Row and column names may be null.
   formatType is
   <ul>
   <li> 0 - normal
   <li> 1 - extra accuracy
   <li> 2 - IEEE hex (later)
   </ul>

   Returns non-zero on I/O error

   This is based on code contributed by Thorsten Koch
*/
int
ClpSimplexOther::writeBasis(const char *filename,
                            bool writeValues,
                            int formatType) const
{
     formatType = CoinMax(0, formatType);
     formatType = CoinMin(2, formatType);
     if (!writeValues)
          formatType = 0;
     // See if INTEL if IEEE
     if (formatType == 2) {
          // test intel here and add 1 if not intel
          double value = 1.0;
          char x[8];
          memcpy(x, &value, 8);
          if (x[0] == 63) {
               formatType ++; // not intel
          } else {
               assert (x[0] == 0);
          }
     }

     char number[20];
     FILE * fp = fopen(filename, "w");
     if (!fp)
          return -1;

     // NAME card

     if (strcmp(strParam_[ClpProbName].c_str(), "") == 0) {
          fprintf(fp, "NAME          BLANK      ");
     } else {
          fprintf(fp, "NAME          %s       ", strParam_[ClpProbName].c_str());
     }
     if (formatType >= 2)
          fprintf(fp, "FREEIEEE");
     else if (writeValues)
          fprintf(fp, "VALUES");
     // finish off name
     fprintf(fp, "\n");
     int iRow = 0;
     for(int iColumn = 0; iColumn < numberColumns_; iColumn++) {
          bool printit = false;
          if( getColumnStatus(iColumn) == ClpSimplex::basic) {
               printit = true;
               // Find non basic row
               for(; iRow < numberRows_; iRow++) {
                    if (getRowStatus(iRow) != ClpSimplex::basic)
                         break;
               }
               if (lengthNames_) {
                    if (iRow != numberRows_) {
                         fprintf(fp, " %s %-8s       %s",
                                 getRowStatus(iRow) == ClpSimplex::atUpperBound ? "XU" : "XL",
                                 columnNames_[iColumn].c_str(),
                                 rowNames_[iRow].c_str());
                         iRow++;
                    } else {
                         // Allow for too many basics!
                         fprintf(fp, " BS %-8s       ",
                                 columnNames_[iColumn].c_str());
                         // Dummy row name if values
                         if (writeValues)
                              fprintf(fp, "      _dummy_");
                    }
               } else {
                    // no names
                    if (iRow != numberRows_) {
                         fprintf(fp, " %s C%7.7d     R%7.7d",
                                 getRowStatus(iRow) == ClpSimplex::atUpperBound ? "XU" : "XL",
                                 iColumn, iRow);
                         iRow++;
                    } else {
                         // Allow for too many basics!
                         fprintf(fp, " BS C%7.7d", iColumn);
                         // Dummy row name if values
                         if (writeValues)
                              fprintf(fp, "      _dummy_");
                    }
               }
          } else  {
               if( getColumnStatus(iColumn) == ClpSimplex::atUpperBound) {
                    printit = true;
                    if (lengthNames_)
                         fprintf(fp, " UL %s", columnNames_[iColumn].c_str());
                    else
                         fprintf(fp, " UL C%7.7d", iColumn);
                    // Dummy row name if values
                    if (writeValues)
                         fprintf(fp, "      _dummy_");
               } else if( (getColumnStatus(iColumn) == ClpSimplex::superBasic||
			   getColumnStatus(iColumn) == ClpSimplex::isFree)&&
			  writeValues) {
                    printit = true;
                    if (lengthNames_)
                         fprintf(fp, " BS %s", columnNames_[iColumn].c_str());
                    else
                         fprintf(fp, " BS C%7.7d", iColumn);
                    // Dummy row name if values
                    if (writeValues)
                         fprintf(fp, "      _dummy_");
               }
          }
          if (printit && writeValues) {
               // add value
               CoinConvertDouble(0, formatType, columnActivity_[iColumn], number);
               fprintf(fp, "     %s", number);
          }
          if (printit)
               fprintf(fp, "\n");
     }
     fprintf(fp, "ENDATA\n");
     fclose(fp);
     return 0;
}
// Read a basis from the given filename
int
ClpSimplexOther::readBasis(const char *fileName)
{
     int status = 0;
     if (strcmp(fileName, "-") != 0 && strcmp(fileName, "stdin") != 0) {
          FILE *fp = fopen(fileName, "r");
          if (fp) {
               // can open - lets go for it
               fclose(fp);
          } else {
               handler_->message(CLP_UNABLE_OPEN, messages_)
                         << fileName << CoinMessageEol;
               return -1;
          }
     }
     CoinMpsIO m;
     m.passInMessageHandler(handler_);
     *m.messagesPointer() = coinMessages();
     bool savePrefix = m.messageHandler()->prefix();
     m.messageHandler()->setPrefix(handler_->prefix());
     status = m.readBasis(fileName, "", columnActivity_, status_ + numberColumns_,
                          status_,
                          columnNames_, numberColumns_,
                          rowNames_, numberRows_);
     m.messageHandler()->setPrefix(savePrefix);
     if (status >= 0) {
          if (!status) {
               // set values
               int iColumn, iRow;
               for (iRow = 0; iRow < numberRows_; iRow++) {
                    if (getRowStatus(iRow) == atLowerBound)
                         rowActivity_[iRow] = rowLower_[iRow];
                    else if (getRowStatus(iRow) == atUpperBound)
                         rowActivity_[iRow] = rowUpper_[iRow];
               }
               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
                    if (getColumnStatus(iColumn) == atLowerBound)
                         columnActivity_[iColumn] = columnLower_[iColumn];
                    else if (getColumnStatus(iColumn) == atUpperBound)
                         columnActivity_[iColumn] = columnUpper_[iColumn];
               }
          } else {
               memset(rowActivity_, 0, numberRows_ * sizeof(double));
               matrix_->times(-1.0, columnActivity_, rowActivity_);
          }
     } else {
          // errors
          handler_->message(CLP_IMPORT_ERRORS, messages_)
                    << status << fileName << CoinMessageEol;
     }
     return status;
}
/* Creates dual of a problem if looks plausible
   (defaults will always create model)
   fractionRowRanges is fraction of rows allowed to have ranges
   fractionColumnRanges is fraction of columns allowed to have ranges
*/
ClpSimplex *
ClpSimplexOther::dualOfModel(double fractionRowRanges, double fractionColumnRanges) const
{
     const ClpSimplex * model2 = static_cast<const ClpSimplex *> (this);
     bool changed = false;
     int numberChanged = 0;
     int numberFreeColumnsInPrimal=0;
     int iColumn;
     // check if we need to change bounds to rows
     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
       if (columnUpper_[iColumn] < 1.0e20) {
	 if (columnLower_[iColumn] > -1.0e20) {
               changed = true;
               numberChanged++;
          }
       } else if (columnLower_[iColumn] < -1.0e20) {
	 numberFreeColumnsInPrimal++;
       }
     }
     int iRow;
     int numberExtraRows = 0;
     int numberFreeColumnsInDual=0;
     if (numberChanged <= fractionColumnRanges * numberColumns_) {
          for (iRow = 0; iRow < numberRows_; iRow++) {
               if (rowLower_[iRow] > -1.0e20 &&
                         rowUpper_[iRow] < 1.0e20) {
                    if (rowUpper_[iRow] != rowLower_[iRow])
                         numberExtraRows++;
		    else
		      numberFreeColumnsInDual++;
               }
          }
          if (numberExtraRows > fractionRowRanges * numberRows_)
               return NULL;
     } else {
          return NULL;
     }
     printf("would have %d free columns in primal, %d in dual\n",
	    numberFreeColumnsInPrimal,numberFreeColumnsInDual);
     if (4*(numberFreeColumnsInDual-numberFreeColumnsInPrimal)>
	 numberColumns_&&fractionRowRanges<1.0)
       return NULL; //dangerous (well anyway in dual)
     if (changed) {
          ClpSimplex * model3 = new ClpSimplex(*model2);
          CoinBuild build;
          double one = 1.0;
          int numberColumns = model3->numberColumns();
          const double * columnLower = model3->columnLower();
          const double * columnUpper = model3->columnUpper();
          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
               if (columnUpper[iColumn] < 1.0e20 &&
                         columnLower[iColumn] > -1.0e20) {
                    if (fabs(columnLower[iColumn]) < fabs(columnUpper[iColumn])) {
                         double value = columnUpper[iColumn];
                         model3->setColumnUpper(iColumn, COIN_DBL_MAX);
                         build.addRow(1, &iColumn, &one, -COIN_DBL_MAX, value);
                    } else {
                         double value = columnLower[iColumn];
                         model3->setColumnLower(iColumn, -COIN_DBL_MAX);
                         build.addRow(1, &iColumn, &one, value, COIN_DBL_MAX);
                    }
               }
          }
          model3->addRows(build);
          model2 = model3;
     }
     int numberColumns = model2->numberColumns();
     const double * columnLower = model2->columnLower();
     const double * columnUpper = model2->columnUpper();
     int numberRows = model2->numberRows();
     double * rowLower = CoinCopyOfArray(model2->rowLower(), numberRows);
     double * rowUpper = CoinCopyOfArray(model2->rowUpper(), numberRows);

     const double * objective = model2->objective();
     CoinPackedMatrix * matrix = model2->matrix();
     // get transpose
     CoinPackedMatrix rowCopy = *matrix;
     const int * row = matrix->getIndices();
     const int * columnLength = matrix->getVectorLengths();
     const CoinBigIndex * columnStart = matrix->getVectorStarts();
     const double * elementByColumn = matrix->getElements();
     double objOffset = 0.0;
     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
          double offset = 0.0;
          double objValue = optimizationDirection_ * objective[iColumn];
          if (columnUpper[iColumn] > 1.0e20) {
               if (columnLower[iColumn] > -1.0e20)
                    offset = columnLower[iColumn];
          } else if (columnLower[iColumn] < -1.0e20) {
               offset = columnUpper[iColumn];
          } else {
               // taken care of before
               abort();
          }
          if (offset) {
               objOffset += offset * objValue;
               for (CoinBigIndex j = columnStart[iColumn];
                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                    int iRow = row[j];
                    if (rowLower[iRow] > -1.0e20)
                         rowLower[iRow] -= offset * elementByColumn[j];
                    if (rowUpper[iRow] < 1.0e20)
                         rowUpper[iRow] -= offset * elementByColumn[j];
               }
          }
     }
     int * which = new int[numberRows+numberExtraRows];
     rowCopy.reverseOrdering();
     rowCopy.transpose();
     double * fromRowsLower = new double[numberRows+numberExtraRows];
     double * fromRowsUpper = new double[numberRows+numberExtraRows];
     double * newObjective = new double[numberRows+numberExtraRows];
     double * fromColumnsLower = new double[numberColumns];
     double * fromColumnsUpper = new double[numberColumns];
     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
          double objValue = optimizationDirection_ * objective[iColumn];
          // Offset is already in
          if (columnUpper[iColumn] > 1.0e20) {
               if (columnLower[iColumn] > -1.0e20) {
                    fromColumnsLower[iColumn] = -COIN_DBL_MAX;
                    fromColumnsUpper[iColumn] = objValue;
               } else {
                    // free
                    fromColumnsLower[iColumn] = objValue;
                    fromColumnsUpper[iColumn] = objValue;
               }
          } else if (columnLower[iColumn] < -1.0e20) {
               fromColumnsLower[iColumn] = objValue;
               fromColumnsUpper[iColumn] = COIN_DBL_MAX;
          } else {
               abort();
          }
     }
     int kRow = 0;
     int kExtraRow = numberRows;
     for (iRow = 0; iRow < numberRows; iRow++) {
          if (rowLower[iRow] < -1.0e20) {
               assert (rowUpper[iRow] < 1.0e20);
               newObjective[kRow] = -rowUpper[iRow];
               fromRowsLower[kRow] = -COIN_DBL_MAX;
               fromRowsUpper[kRow] = 0.0;
               which[kRow] = iRow;
               kRow++;
          } else if (rowUpper[iRow] > 1.0e20) {
               newObjective[kRow] = -rowLower[iRow];
               fromRowsLower[kRow] = 0.0;
               fromRowsUpper[kRow] = COIN_DBL_MAX;
               which[kRow] = iRow;
               kRow++;
          } else {
               if (rowUpper[iRow] == rowLower[iRow]) {
                    newObjective[kRow] = -rowLower[iRow];
                    fromRowsLower[kRow] = -COIN_DBL_MAX;;
                    fromRowsUpper[kRow] = COIN_DBL_MAX;
                    which[kRow] = iRow;
                    kRow++;
               } else {
                    // range
                    newObjective[kRow] = -rowUpper[iRow];
                    fromRowsLower[kRow] = -COIN_DBL_MAX;
                    fromRowsUpper[kRow] = 0.0;
                    which[kRow] = iRow;
                    kRow++;
                    newObjective[kExtraRow] = -rowLower[iRow];
                    fromRowsLower[kExtraRow] = 0.0;
                    fromRowsUpper[kExtraRow] = COIN_DBL_MAX;
                    which[kExtraRow] = iRow;
                    kExtraRow++;
               }
          }
     }
     if (numberExtraRows) {
          CoinPackedMatrix newCopy;
          newCopy.setExtraGap(0.0);
          newCopy.setExtraMajor(0.0);
          newCopy.submatrixOfWithDuplicates(rowCopy, kExtraRow, which);
          rowCopy = newCopy;
     }
     ClpSimplex * modelDual = new ClpSimplex();
     modelDual->loadProblem(rowCopy, fromRowsLower, fromRowsUpper, newObjective,
                            fromColumnsLower, fromColumnsUpper);
     modelDual->setObjectiveOffset(objOffset);
     modelDual->setDualBound(model2->dualBound());
     modelDual->setInfeasibilityCost(model2->infeasibilityCost());
     modelDual->setDualTolerance(model2->dualTolerance());
     modelDual->setPrimalTolerance(model2->primalTolerance());
     modelDual->setPerturbation(model2->perturbation());
     modelDual->setSpecialOptions(model2->specialOptions());
     modelDual->setMoreSpecialOptions(model2->moreSpecialOptions());
     modelDual->setMaximumIterations(model2->maximumIterations());
     modelDual->setFactorizationFrequency(model2->factorizationFrequency());
     modelDual->setLogLevel(model2->logLevel());
     delete [] fromRowsLower;
     delete [] fromRowsUpper;
     delete [] fromColumnsLower;
     delete [] fromColumnsUpper;
     delete [] newObjective;
     delete [] which;
     delete [] rowLower;
     delete [] rowUpper;
     if (changed)
          delete model2;
     modelDual->createStatus();
     return modelDual;
}
// Restores solution from dualized problem
int
ClpSimplexOther::restoreFromDual(const ClpSimplex * dualProblem,
				 bool checkAccuracy)
{
     int returnCode = 0;;
     createStatus();
     // Number of rows in dual problem was original number of columns
     assert (numberColumns_ == dualProblem->numberRows());
     // If slack on d-row basic then column at bound otherwise column basic
     // If d-column basic then rhs tight
     int numberBasic = 0;
     int iRow, iColumn = 0;
     // Get number of extra rows from ranges
     int numberExtraRows = 0;
     for (iRow = 0; iRow < numberRows_; iRow++) {
          if (rowLower_[iRow] > -1.0e20 &&
                    rowUpper_[iRow] < 1.0e20) {
               if (rowUpper_[iRow] != rowLower_[iRow])
                    numberExtraRows++;
          }
     }
     const double * objective = this->objective();
     const double * dualDual = dualProblem->dualRowSolution();
     const double * dualDj = dualProblem->dualColumnSolution();
     const double * dualSol = dualProblem->primalColumnSolution();
     const double * dualActs = dualProblem->primalRowSolution();
#if 0
     ClpSimplex thisCopy = *this;
     thisCopy.dual(); // for testing
     const double * primalDual = thisCopy.dualRowSolution();
     const double * primalDj = thisCopy.dualColumnSolution();
     const double * primalSol = thisCopy.primalColumnSolution();
     const double * primalActs = thisCopy.primalRowSolution();
     char ss[] = {'F', 'B', 'U', 'L', 'S', 'F'};
     printf ("Dual problem row info %d rows\n", dualProblem->numberRows());
     for (iRow = 0; iRow < dualProblem->numberRows(); iRow++)
          printf("%d at %c primal %g dual %g\n",
                 iRow, ss[dualProblem->getRowStatus(iRow)],
                 dualActs[iRow], dualDual[iRow]);
     printf ("Dual problem column info %d columns\n", dualProblem->numberColumns());
     for (iColumn = 0; iColumn < dualProblem->numberColumns(); iColumn++)
          printf("%d at %c primal %g dual %g\n",
                 iColumn, ss[dualProblem->getColumnStatus(iColumn)],
                 dualSol[iColumn], dualDj[iColumn]);
     printf ("Primal problem row info %d rows\n", thisCopy.numberRows());
     for (iRow = 0; iRow < thisCopy.numberRows(); iRow++)
          printf("%d at %c primal %g dual %g\n",
                 iRow, ss[thisCopy.getRowStatus(iRow)],
                 primalActs[iRow], primalDual[iRow]);
     printf ("Primal problem column info %d columns\n", thisCopy.numberColumns());
     for (iColumn = 0; iColumn < thisCopy.numberColumns(); iColumn++)
          printf("%d at %c primal %g dual %g\n",
                 iColumn, ss[thisCopy.getColumnStatus(iColumn)],
                 primalSol[iColumn], primalDj[iColumn]);
#endif
     // position at bound information
     int jColumn = numberRows_;
     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
          double objValue = optimizationDirection_ * objective[iColumn];
          Status status = dualProblem->getRowStatus(iColumn);
          double otherValue = COIN_DBL_MAX;
          if (columnUpper_[iColumn] < 1.0e20 &&
                    columnLower_[iColumn] > -1.0e20) {
               if (fabs(columnLower_[iColumn]) < fabs(columnUpper_[iColumn])) {
                    otherValue = columnUpper_[iColumn] + dualDj[jColumn];
               } else {
                    otherValue = columnLower_[iColumn] + dualDj[jColumn];
               }
               jColumn++;
          }
          if (status == basic) {
               // column is at bound
               if (otherValue == COIN_DBL_MAX) {
                    reducedCost_[iColumn] = objValue - dualActs[iColumn];
                    if (columnUpper_[iColumn] > 1.0e20) {
                         if (columnLower_[iColumn] > -1.0e20) {
                              if (columnUpper_[iColumn] > columnLower_[iColumn])
                                   setColumnStatus(iColumn, atLowerBound);
                              else
                                   setColumnStatus(iColumn, isFixed);
                              columnActivity_[iColumn] = columnLower_[iColumn];
                         } else {
                              // free
                              setColumnStatus(iColumn, isFree);
                              columnActivity_[iColumn] = 0.0;
                         }
                    } else {
                         setColumnStatus(iColumn, atUpperBound);
                         columnActivity_[iColumn] = columnUpper_[iColumn];
                    }
               } else {
                    reducedCost_[iColumn] = objValue - dualActs[iColumn];
                    //printf("other dual sol %g\n",otherValue);
                    if (fabs(otherValue - columnLower_[iColumn]) < 1.0e-5) {
                         if (columnUpper_[iColumn] > columnLower_[iColumn])
                              setColumnStatus(iColumn, atLowerBound);
                         else
                              setColumnStatus(iColumn, isFixed);
                         columnActivity_[iColumn] = columnLower_[iColumn];
                    } else if (fabs(otherValue - columnUpper_[iColumn]) < 1.0e-5) {
                         if (columnUpper_[iColumn] > columnLower_[iColumn])
                              setColumnStatus(iColumn, atUpperBound);
                         else
                              setColumnStatus(iColumn, isFixed);
                         columnActivity_[iColumn] = columnUpper_[iColumn];
                    } else {
			 setColumnStatus(iColumn, superBasic);
                         columnActivity_[iColumn] = otherValue;
                    }
               }
          } else {
               if (otherValue == COIN_DBL_MAX) {
                    // column basic
                    setColumnStatus(iColumn, basic);
                    numberBasic++;
                    if (columnLower_[iColumn] > -1.0e20) {
                         columnActivity_[iColumn] = -dualDual[iColumn] + columnLower_[iColumn];
                    } else if (columnUpper_[iColumn] < 1.0e20) {
                         columnActivity_[iColumn] = -dualDual[iColumn] + columnUpper_[iColumn];
                    } else {
                         columnActivity_[iColumn] = -dualDual[iColumn];
                    }
                    reducedCost_[iColumn] = 0.0;
               } else {
                    // may be at other bound
                    //printf("xx %d %g jcol %d\n",iColumn,otherValue,jColumn-1);
                    if (dualProblem->getColumnStatus(jColumn - 1) != basic) {
                         // column basic
                         setColumnStatus(iColumn, basic);
                         numberBasic++;
                         //printf("Col %d otherV %g dualDual %g\n",iColumn,
                         // otherValue,dualDual[iColumn]);
                         columnActivity_[iColumn] = -dualDual[iColumn];
                         columnActivity_[iColumn] = otherValue;
                         reducedCost_[iColumn] = 0.0;
                    } else {
                         reducedCost_[iColumn] = objValue - dualActs[iColumn];
                         if (fabs(otherValue - columnLower_[iColumn]) < 1.0e-5) {
                              if (columnUpper_[iColumn] > columnLower_[iColumn])
                                   setColumnStatus(iColumn, atLowerBound);
                              else
                                   setColumnStatus(iColumn, isFixed);
                              columnActivity_[iColumn] = columnLower_[iColumn];
                         } else if (fabs(otherValue - columnUpper_[iColumn]) < 1.0e-5) {
                              if (columnUpper_[iColumn] > columnLower_[iColumn])
                                   setColumnStatus(iColumn, atUpperBound);
                              else
                                   setColumnStatus(iColumn, isFixed);
                              columnActivity_[iColumn] = columnUpper_[iColumn];
                         } else {
			      setColumnStatus(iColumn, superBasic);
			      columnActivity_[iColumn] = otherValue;
                         }
                    }
               }
          }
     }
     // now rows
     int kExtraRow = jColumn;
     int numberRanges = 0;
     for (iRow = 0; iRow < numberRows_; iRow++) {
          Status status = dualProblem->getColumnStatus(iRow);
          if (status == basic) {
               // row is at bound
               dual_[iRow] = dualSol[iRow];;
          } else {
               // row basic
               setRowStatus(iRow, basic);
               numberBasic++;
               dual_[iRow] = 0.0;
          }
          if (rowLower_[iRow] < -1.0e20) {
               if (status == basic) {
                    rowActivity_[iRow] = rowUpper_[iRow];
                    setRowStatus(iRow, atUpperBound);
               } else {
                    // might be stopped assert (dualDj[iRow] < 1.0e-5);
                    rowActivity_[iRow] = rowUpper_[iRow] + dualDj[iRow];
               }
          } else if (rowUpper_[iRow] > 1.0e20) {
               if (status == basic) {
                    rowActivity_[iRow] = rowLower_[iRow];
                    setRowStatus(iRow, atLowerBound);
               } else {
                    rowActivity_[iRow] = rowLower_[iRow] + dualDj[iRow];
                    // might be stopped assert (dualDj[iRow] > -1.0e-5);
               }
          } else {
               if (rowUpper_[iRow] == rowLower_[iRow]) {
                    rowActivity_[iRow] = rowLower_[iRow];
                    if (status == basic) {
                         setRowStatus(iRow, isFixed);
                    }
               } else {
                    // range
                    numberRanges++;
                    Status statusL = dualProblem->getColumnStatus(kExtraRow);
                    //printf("range row %d (%d), extra %d (%d) - dualSol %g,%g dualDj %g,%g\n",
                    //     iRow,status,kExtraRow,statusL, dualSol[iRow],
                    //     dualSol[kExtraRow],dualDj[iRow],dualDj[kExtraRow]);
                    if (status == basic) {
                         // might be stopped assert (statusL != basic);
                         rowActivity_[iRow] = rowUpper_[iRow];
                         setRowStatus(iRow, atUpperBound);
                    } else if (statusL == basic) {
                         numberBasic--; // already counted
                         rowActivity_[iRow] = rowLower_[iRow];
                         setRowStatus(iRow, atLowerBound);
                         dual_[iRow] = dualSol[kExtraRow];;
                    } else {
                         rowActivity_[iRow] = rowLower_[iRow] - dualDj[iRow];
                         // might be stopped assert (dualDj[iRow] < 1.0e-5);
                         // row basic
                         //setRowStatus(iRow,basic);
                         //numberBasic++;
                         dual_[iRow] = 0.0;
                    }
                    kExtraRow++;
               }
          }
     }
     if (numberBasic != numberRows_) {
          printf("Bad basis - ranges - coding needed\n");
          assert (numberRanges);
          abort();
     }
     if (optimizationDirection_ < 0.0) {
          for (iRow = 0; iRow < numberRows_; iRow++) {
               dual_[iRow] = -dual_[iRow];
          }
     }
     // redo row activities
     memset(rowActivity_, 0, numberRows_ * sizeof(double));
     matrix_->times(1.0, columnActivity_, rowActivity_);
     // redo reduced costs
     memcpy(reducedCost_, this->objective(), numberColumns_ * sizeof(double));
     matrix_->transposeTimes(-1.0, dual_, reducedCost_);
     checkSolutionInternal();
     if (sumDualInfeasibilities_ > 1.0e-5 || sumPrimalInfeasibilities_ > 1.0e-5) {
          returnCode = 1;
#ifdef CLP_INVESTIGATE
          printf("There are %d dual infeasibilities summing to %g ",
                 numberDualInfeasibilities_, sumDualInfeasibilities_);
          printf("and %d primal infeasibilities summing to %g\n",
                 numberPrimalInfeasibilities_, sumPrimalInfeasibilities_);
#endif
     }
     // Below will go to ..DEBUG later
#if 1 //ndef NDEBUG
     if (checkAccuracy) {
       // Check if correct
       double * columnActivity = CoinCopyOfArray(columnActivity_, numberColumns_);
       double * rowActivity = CoinCopyOfArray(rowActivity_, numberRows_);
       double * reducedCost = CoinCopyOfArray(reducedCost_, numberColumns_);
       double * dual = CoinCopyOfArray(dual_, numberRows_);
       this->dual(); //primal();
       CoinRelFltEq eq(1.0e-5);
       for (iRow = 0; iRow < numberRows_; iRow++) {
	 assert(eq(dual[iRow], dual_[iRow]));
       }
       for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
	 assert(eq(columnActivity[iColumn], columnActivity_[iColumn]));
       }
       for (iRow = 0; iRow < numberRows_; iRow++) {
	 assert(eq(rowActivity[iRow], rowActivity_[iRow]));
       }
       for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
	 assert(eq(reducedCost[iColumn], reducedCost_[iColumn]));
       }
       delete [] columnActivity;
       delete [] rowActivity;
       delete [] reducedCost;
       delete [] dual;
     }
#endif
     return returnCode;
}
/* Sets solution in dualized problem
   non-zero return code indicates minor problems
*/
int 
ClpSimplexOther::setInDual(ClpSimplex * dualProblem)
{
  // Number of rows in dual problem was original number of columns
  assert (numberColumns_ == dualProblem->numberRows());
  // out If slack on d-row basic then column at bound otherwise column basic
  // out If d-column basic then rhs tight
  // if column at bound then slack on d-row basic
  // if column basic then slack on d-row at bound
  // if rhs non-basic then d-column basic
  // if rhs basic then d-column ? 
  int numberBasic = 0;
  int iRow, iColumn = 0;
  //int numberExtraRows = dualProblem->numberColumns()-numberRows_;
  //const double * objective = this->objective();
  //double * dualDual = dualProblem->dualRowSolution();
  //double * dualDj = dualProblem->dualColumnSolution();
  double * dualSol = dualProblem->primalColumnSolution();
  //double * dualActs = dualProblem->primalRowSolution();
  const double * lower = dualProblem->columnLower();
  const double * upper = dualProblem->columnUpper();
  // position at bound information
  int jColumn = numberRows_;
  for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
    Status status = getColumnStatus(iColumn);
    Status statusD = dualProblem->getRowStatus(iColumn);
    Status statusDJ = dualProblem->getColumnStatus(jColumn);
    if (status==atLowerBound||
	status==isFixed||
	status==atUpperBound) {
      dualProblem->setRowStatus(iColumn,basic);
      numberBasic++;
      if (columnUpper_[iColumn] < 1.0e20 &&
	  columnLower_[iColumn] > -1.0e20) {
	bool mainLower =(fabs(columnLower_[iColumn]) < fabs(columnUpper_[iColumn]));
	// fix this
	if (mainLower) {
	  if (status==atUpperBound) {
	    dualProblem->setColumnStatus(jColumn,atUpperBound);
	  } else {
	    dualProblem->setColumnStatus(jColumn,atUpperBound);
	  }
	} else {
	  if (status==atUpperBound) {
	    dualProblem->setColumnStatus(jColumn,atLowerBound);
	  } else {
	    dualProblem->setColumnStatus(jColumn,atLowerBound);
	  }
	}
	assert(statusDJ == dualProblem->getColumnStatus(jColumn));
	jColumn++;
      }
    } else if (status==isFree) {
      dualProblem->setRowStatus(iColumn,basic);
      numberBasic++;
    } else {
      assert (status==basic);
      //numberBasic++;
    }
    assert(statusD == dualProblem->getRowStatus(iColumn));
  }
  // now rows (no ranges at first)
  for (iRow = 0; iRow < numberRows_; iRow++) {
    Status status = getRowStatus(iRow);
    Status statusD = dualProblem->getColumnStatus(iRow);
    if (status == basic) {
      // dual variable is at bound
      if (!lower[iRow]) {
	dualProblem->setColumnStatus(iRow,atLowerBound);
      } else if (!upper[iRow]) {
	dualProblem->setColumnStatus(iRow,atUpperBound);
      } else {
	dualProblem->setColumnStatus(iRow,isFree);
	dualSol[iRow]=0.0;
      }
    } else {
      // dual variable is basic
      dualProblem->setColumnStatus(iRow,basic);
      numberBasic++;
    }
    if (rowLower_[iRow] < -1.0e20 &&
	rowUpper_[iRow] > 1.0e20) {
      if (rowUpper_[iRow] != rowLower_[iRow]) {
	printf("can't handle ranges yet\n");
	abort();
      }
    }
    assert(statusD == dualProblem->getColumnStatus(iRow));
  }
  if (numberBasic != numberColumns_) {
    printf("Bad basis - ranges - coding needed ??\n");
    abort();
  }
  return 0;
}
/* Does very cursory presolve.
   rhs is numberRows, whichRows is 3*numberRows and whichColumns is 2*numberColumns
*/
ClpSimplex *
ClpSimplexOther::crunch(double * rhs, int * whichRow, int * whichColumn,
                        int & nBound, bool moreBounds, bool tightenBounds)
{
     //#define CHECK_STATUS
#ifdef CHECK_STATUS
     {
          int n = 0;
          int i;
          for (i = 0; i < numberColumns_; i++)
               if (getColumnStatus(i) == ClpSimplex::basic)
                    n++;
          for (i = 0; i < numberRows_; i++)
               if (getRowStatus(i) == ClpSimplex::basic)
                    n++;
          assert (n == numberRows_);
     }
#endif

     const double * element = matrix_->getElements();
     const int * row = matrix_->getIndices();
     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
     const int * columnLength = matrix_->getVectorLengths();

     CoinZeroN(rhs, numberRows_);
     int iColumn;
     int iRow;
     CoinZeroN(whichRow, numberRows_);
     int * backColumn = whichColumn + numberColumns_;
     int numberRows2 = 0;
     int numberColumns2 = 0;
     double offset = 0.0;
     const double * objective = this->objective();
     double * solution = columnActivity_;
     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
          double lower = columnLower_[iColumn];
          double upper = columnUpper_[iColumn];
          if (upper > lower || getColumnStatus(iColumn) == ClpSimplex::basic) {
               backColumn[iColumn] = numberColumns2;
               whichColumn[numberColumns2++] = iColumn;
               for (CoinBigIndex j = columnStart[iColumn];
                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                    int iRow = row[j];
                    int n = whichRow[iRow];
                    if (n == 0 && element[j])
                         whichRow[iRow] = -iColumn - 1;
                    else if (n < 0)
                         whichRow[iRow] = 2;
               }
          } else {
               // fixed
               backColumn[iColumn] = -1;
               solution[iColumn] = upper;
               if (upper) {
                    offset += objective[iColumn] * upper;
                    for (CoinBigIndex j = columnStart[iColumn];
                              j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                         int iRow = row[j];
                         double value = element[j];
                         rhs[iRow] += upper * value;
                    }
               }
          }
     }
     int returnCode = 0;
     double tolerance = primalTolerance();
     nBound = 2 * numberRows_;
     for (iRow = 0; iRow < numberRows_; iRow++) {
          int n = whichRow[iRow];
          if (n > 0) {
               whichRow[numberRows2++] = iRow;
          } else if (n < 0) {
               //whichRow[numberRows2++]=iRow;
               //continue;
               // Can only do in certain circumstances as we don't know current value
               if (rowLower_[iRow] == rowUpper_[iRow] || getRowStatus(iRow) == ClpSimplex::basic) {
                    // save row and column for bound
                    whichRow[--nBound] = iRow;
                    whichRow[nBound+numberRows_] = -n - 1;
               } else if (moreBounds) {
                    // save row and column for bound
                    whichRow[--nBound] = iRow;
                    whichRow[nBound+numberRows_] = -n - 1;
               } else {
                    whichRow[numberRows2++] = iRow;
               }
          } else {
               // empty
               double rhsValue = rhs[iRow];
               if (rhsValue < rowLower_[iRow] - tolerance || rhsValue > rowUpper_[iRow] + tolerance) {
                    returnCode = 1; // infeasible
               }
          }
     }
     ClpSimplex * small = NULL;
     if (!returnCode) {
       //printf("CRUNCH from (%d,%d) to (%d,%d)\n",
       //     numberRows_,numberColumns_,numberRows2,numberColumns2);
          small = new ClpSimplex(this, numberRows2, whichRow,
                                 numberColumns2, whichColumn, true, false);
#if 0
          ClpPackedMatrix * rowCopy = dynamic_cast<ClpPackedMatrix *>(rowCopy_);
          if (rowCopy) {
               assert(!small->rowCopy());
               small->setNewRowCopy(new ClpPackedMatrix(*rowCopy, numberRows2, whichRow,
                                    numberColumns2, whichColumn));
          }
#endif
          // Set some stuff
          small->setDualBound(dualBound_);
          small->setInfeasibilityCost(infeasibilityCost_);
          small->setSpecialOptions(specialOptions_);
          small->setPerturbation(perturbation_);
          small->defaultFactorizationFrequency();
          small->setAlphaAccuracy(alphaAccuracy_);
          // If no rows left then no tightening!
          if (!numberRows2 || !numberColumns2)
               tightenBounds = false;

          int numberElements = getNumElements();
          int numberElements2 = small->getNumElements();
          small->setObjectiveOffset(objectiveOffset() - offset);
          handler_->message(CLP_CRUNCH_STATS, messages_)
                    << numberRows2 << -(numberRows_ - numberRows2)
                    << numberColumns2 << -(numberColumns_ - numberColumns2)
                    << numberElements2 << -(numberElements - numberElements2)
                    << CoinMessageEol;
          // And set objective value to match
          small->setObjectiveValue(this->objectiveValue());
          double * rowLower2 = small->rowLower();
          double * rowUpper2 = small->rowUpper();
          int jRow;
          for (jRow = 0; jRow < numberRows2; jRow++) {
               iRow = whichRow[jRow];
               if (rowLower2[jRow] > -1.0e20)
                    rowLower2[jRow] -= rhs[iRow];
               if (rowUpper2[jRow] < 1.0e20)
                    rowUpper2[jRow] -= rhs[iRow];
          }
          // and bounds
          double * columnLower2 = small->columnLower();
          double * columnUpper2 = small->columnUpper();
          const char * integerInformation = integerType_;
          for (jRow = nBound; jRow < 2 * numberRows_; jRow++) {
               iRow = whichRow[jRow];
               iColumn = whichRow[jRow+numberRows_];
               double lowerRow = rowLower_[iRow];
               if (lowerRow > -1.0e20)
                    lowerRow -= rhs[iRow];
               double upperRow = rowUpper_[iRow];
               if (upperRow < 1.0e20)
                    upperRow -= rhs[iRow];
               int jColumn = backColumn[iColumn];
               double lower = columnLower2[jColumn];
               double upper = columnUpper2[jColumn];
               double value = 0.0;
               for (CoinBigIndex j = columnStart[iColumn];
                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                    if (iRow == row[j]) {
                         value = element[j];
                         break;
                    }
               }
               assert (value);
               // convert rowLower and Upper to implied bounds on column
               double newLower = -COIN_DBL_MAX;
               double newUpper = COIN_DBL_MAX;
               if (value > 0.0) {
                    if (lowerRow > -1.0e20)
                         newLower = lowerRow / value;
                    if (upperRow < 1.0e20)
                         newUpper = upperRow / value;
               } else {
                    if (upperRow < 1.0e20)
                         newLower = upperRow / value;
                    if (lowerRow > -1.0e20)
                         newUpper = lowerRow / value;
               }
               if (integerInformation && integerInformation[iColumn]) {
                    if (newLower - floor(newLower) < 10.0 * tolerance)
                         newLower = floor(newLower);
                    else
                         newLower = ceil(newLower);
                    if (ceil(newUpper) - newUpper < 10.0 * tolerance)
                         newUpper = ceil(newUpper);
                    else
                         newUpper = floor(newUpper);
               }
               newLower = CoinMax(lower, newLower);
               newUpper = CoinMin(upper, newUpper);
               if (newLower > newUpper + tolerance) {
                    //printf("XXYY inf on bound\n");
                    returnCode = 1;
               }
               columnLower2[jColumn] = newLower;
               columnUpper2[jColumn] = CoinMax(newLower, newUpper);
               if (getRowStatus(iRow) != ClpSimplex::basic) {
                    if (getColumnStatus(iColumn) == ClpSimplex::basic) {
                         if (columnLower2[jColumn] == columnUpper2[jColumn]) {
                              // can only get here if will be fixed
                              small->setColumnStatus(jColumn, ClpSimplex::isFixed);
                         } else {
                              // solution is valid
                              if (fabs(columnActivity_[iColumn] - columnLower2[jColumn]) <
                                        fabs(columnActivity_[iColumn] - columnUpper2[jColumn]))
                                   small->setColumnStatus(jColumn, ClpSimplex::atLowerBound);
                              else
                                   small->setColumnStatus(jColumn, ClpSimplex::atUpperBound);
                         }
                    } else {
                         //printf("what now neither basic\n");
                    }
               }
          }
          if (returnCode) {
               delete small;
               small = NULL;
          } else if (tightenBounds && integerInformation) {
               // See if we can tighten any bounds
               // use rhs for upper and small duals for lower
               double * up = rhs;
               double * lo = small->dualRowSolution();
               const double * element = small->clpMatrix()->getElements();
               const int * row = small->clpMatrix()->getIndices();
               const CoinBigIndex * columnStart = small->clpMatrix()->getVectorStarts();
               //const int * columnLength = small->clpMatrix()->getVectorLengths();
               CoinZeroN(lo, numberRows2);
               CoinZeroN(up, numberRows2);
               for (int iColumn = 0; iColumn < numberColumns2; iColumn++) {
                    double upper = columnUpper2[iColumn];
                    double lower = columnLower2[iColumn];
                    //assert (columnLength[iColumn]==columnStart[iColumn+1]-columnStart[iColumn]);
                    for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn+1]; j++) {
                         int iRow = row[j];
                         double value = element[j];
                         if (value > 0.0) {
                              if (upper < 1.0e20)
                                   up[iRow] += upper * value;
                              else
                                   up[iRow] = COIN_DBL_MAX;
                              if (lower > -1.0e20)
                                   lo[iRow] += lower * value;
                              else
                                   lo[iRow] = -COIN_DBL_MAX;
                         } else {
                              if (upper < 1.0e20)
                                   lo[iRow] += upper * value;
                              else
                                   lo[iRow] = -COIN_DBL_MAX;
                              if (lower > -1.0e20)
                                   up[iRow] += lower * value;
                              else
                                   up[iRow] = COIN_DBL_MAX;
                         }
                    }
               }
               double * rowLower2 = small->rowLower();
               double * rowUpper2 = small->rowUpper();
               bool feasible = true;
               // make safer
               for (int iRow = 0; iRow < numberRows2; iRow++) {
                    double lower = lo[iRow];
                    if (lower > rowUpper2[iRow] + tolerance) {
                         feasible = false;
                         break;
                    } else {
                         lo[iRow] = CoinMin(lower - rowUpper2[iRow], 0.0) - tolerance;
                    }
                    double upper = up[iRow];
                    if (upper < rowLower2[iRow] - tolerance) {
                         feasible = false;
                         break;
                    } else {
                         up[iRow] = CoinMax(upper - rowLower2[iRow], 0.0) + tolerance;
                    }
		    // tighten row bounds
		    if (lower>-1.0e10)
		      rowLower2[iRow] = CoinMax(rowLower2[iRow],
						lower - 1.0e-6*(1.0+fabs(lower))); 
		    if (upper<1.0e10)
		      rowUpper2[iRow] = CoinMin(rowUpper2[iRow],
						upper + 1.0e-6*(1.0+fabs(upper))); 
               }
               if (!feasible) {
                    delete small;
                    small = NULL;
               } else {
                    // and tighten
                    for (int iColumn = 0; iColumn < numberColumns2; iColumn++) {
                         if (integerInformation[whichColumn[iColumn]]) {
                              double upper = columnUpper2[iColumn];
                              double lower = columnLower2[iColumn];
                              double newUpper = upper;
                              double newLower = lower;
                              double difference = upper - lower;
                              if (lower > -1000.0 && upper < 1000.0) {
                                   for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn+1]; j++) {
                                        int iRow = row[j];
                                        double value = element[j];
                                        if (value > 0.0) {
                                             double upWithOut = up[iRow] - value * difference;
                                             if (upWithOut < 0.0) {
                                                  newLower = CoinMax(newLower, lower - (upWithOut + tolerance) / value);
                                             }
                                             double lowWithOut = lo[iRow] + value * difference;
                                             if (lowWithOut > 0.0) {
                                                  newUpper = CoinMin(newUpper, upper - (lowWithOut - tolerance) / value);
                                             }
                                        } else {
                                             double upWithOut = up[iRow] + value * difference;
                                             if (upWithOut < 0.0) {
                                                  newUpper = CoinMin(newUpper, upper - (upWithOut + tolerance) / value);
                                             }
                                             double lowWithOut = lo[iRow] - value * difference;
                                             if (lowWithOut > 0.0) {
                                                  newLower = CoinMax(newLower, lower - (lowWithOut - tolerance) / value);
                                             }
                                        }
                                   }
                                   if (newLower > lower || newUpper < upper) {
                                        if (fabs(newUpper - floor(newUpper + 0.5)) > 1.0e-6)
                                             newUpper = floor(newUpper);
                                        else
                                             newUpper = floor(newUpper + 0.5);
                                        if (fabs(newLower - ceil(newLower - 0.5)) > 1.0e-6)
                                             newLower = ceil(newLower);
                                        else
                                             newLower = ceil(newLower - 0.5);
                                        // change may be too small - check
                                        if (newLower > lower || newUpper < upper) {
                                             if (newUpper >= newLower) {
                                                  // Could also tighten in this
                                                  //printf("%d bounds %g %g tightened to %g %g\n",
                                                  //     iColumn,columnLower2[iColumn],columnUpper2[iColumn],
                                                  //     newLower,newUpper);
#if 1
                                                  columnUpper2[iColumn] = newUpper;
                                                  columnLower2[iColumn] = newLower;
                                                  columnUpper_[whichColumn[iColumn]] = newUpper;
                                                  columnLower_[whichColumn[iColumn]] = newLower;
#endif
                                                  // and adjust bounds on rows
                                                  newUpper -= upper;
                                                  newLower -= lower;
                                                  for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn+1]; j++) {
                                                       int iRow = row[j];
                                                       double value = element[j];
                                                       if (value > 0.0) {
                                                            up[iRow] += newUpper * value;
                                                            lo[iRow] += newLower * value;
                                                       } else {
                                                            lo[iRow] += newUpper * value;
                                                            up[iRow] += newLower * value;
                                                       }
                                                  }
                                             } else {
                                                  // infeasible
                                                  //printf("%d bounds infeasible %g %g tightened to %g %g\n",
                                                  //     iColumn,columnLower2[iColumn],columnUpper2[iColumn],
                                                  //     newLower,newUpper);
#if 1
                                                  delete small;
                                                  small = NULL;
                                                  break;
#endif
                                             }
                                        }
                                   }
                              }
                         }
                    }
               }
          }
     }
#if 0
     if (small) {
          static int which = 0;
          which++;
          char xxxx[20];
          sprintf(xxxx, "bad%d.mps", which);
          small->writeMps(xxxx, 0, 1);
          sprintf(xxxx, "largebad%d.mps", which);
          writeMps(xxxx, 0, 1);
          printf("bad%d %x old size %d %d new %d %d\n", which, small,
                 numberRows_, numberColumns_, small->numberRows(), small->numberColumns());
#if 0
          for (int i = 0; i < numberColumns_; i++)
               printf("Bound %d %g %g\n", i, columnLower_[i], columnUpper_[i]);
          for (int i = 0; i < numberRows_; i++)
               printf("Row bound %d %g %g\n", i, rowLower_[i], rowUpper_[i]);
#endif
     }
#endif
#ifdef CHECK_STATUS
     {
          int n = 0;
          int i;
          for (i = 0; i < small->numberColumns(); i++)
               if (small->getColumnStatus(i) == ClpSimplex::basic)
                    n++;
          for (i = 0; i < small->numberRows(); i++)
               if (small->getRowStatus(i) == ClpSimplex::basic)
                    n++;
          assert (n == small->numberRows());
     }
#endif
     return small;
}
/* After very cursory presolve.
   rhs is numberRows, whichRows is 3*numberRows and whichColumns is 2*numberColumns.
*/
void
ClpSimplexOther::afterCrunch(const ClpSimplex & small,
                             const int * whichRow,
                             const int * whichColumn, int nBound)
{
#ifndef NDEBUG
     for (int i = 0; i < small.numberRows(); i++)
          assert (whichRow[i] >= 0 && whichRow[i] < numberRows_);
     for (int i = 0; i < small.numberColumns(); i++)
          assert (whichColumn[i] >= 0 && whichColumn[i] < numberColumns_);
#endif
     getbackSolution(small, whichRow, whichColumn);
     // and deal with status for bounds
     const double * element = matrix_->getElements();
     const int * row = matrix_->getIndices();
     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
     const int * columnLength = matrix_->getVectorLengths();
     double tolerance = primalTolerance();
     double djTolerance = dualTolerance();
     for (int jRow = nBound; jRow < 2 * numberRows_; jRow++) {
          int iRow = whichRow[jRow];
          int iColumn = whichRow[jRow+numberRows_];
          if (getColumnStatus(iColumn) != ClpSimplex::basic) {
               double lower = columnLower_[iColumn];
               double upper = columnUpper_[iColumn];
               double value = columnActivity_[iColumn];
               double djValue = reducedCost_[iColumn];
               dual_[iRow] = 0.0;
               if (upper > lower) {
                    if (value < lower + tolerance && djValue > -djTolerance) {
                         setColumnStatus(iColumn, ClpSimplex::atLowerBound);
                         setRowStatus(iRow, ClpSimplex::basic);
                    } else if (value > upper - tolerance && djValue < djTolerance) {
                         setColumnStatus(iColumn, ClpSimplex::atUpperBound);
                         setRowStatus(iRow, ClpSimplex::basic);
                    } else {
                         // has to be basic
                         setColumnStatus(iColumn, ClpSimplex::basic);
                         reducedCost_[iColumn] = 0.0;
                         double value = 0.0;
                         for (CoinBigIndex j = columnStart[iColumn];
                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                              if (iRow == row[j]) {
                                   value = element[j];
                                   break;
                              }
                         }
                         dual_[iRow] = djValue / value;
                         if (rowUpper_[iRow] > rowLower_[iRow]) {
                              if (fabs(rowActivity_[iRow] - rowLower_[iRow]) <
                                        fabs(rowActivity_[iRow] - rowUpper_[iRow]))
                                   setRowStatus(iRow, ClpSimplex::atLowerBound);
                              else
                                   setRowStatus(iRow, ClpSimplex::atUpperBound);
                         } else {
                              setRowStatus(iRow, ClpSimplex::isFixed);
                         }
                    }
               } else {
                    // row can always be basic
                    setRowStatus(iRow, ClpSimplex::basic);
               }
          } else {
               // row can always be basic
               setRowStatus(iRow, ClpSimplex::basic);
          }
     }
     //#ifndef NDEBUG
#if 0
     if  (small.status() == 0) {
          int n = 0;
          int i;
          for (i = 0; i < numberColumns; i++)
               if (getColumnStatus(i) == ClpSimplex::basic)
                    n++;
          for (i = 0; i < numberRows; i++)
               if (getRowStatus(i) == ClpSimplex::basic)
                    n++;
          assert (n == numberRows);
     }
#endif
}
/* Tightens integer bounds - returns number tightened or -1 if infeasible
 */
int
ClpSimplexOther::tightenIntegerBounds(double * rhsSpace)
{
     // See if we can tighten any bounds
     // use rhs for upper and small duals for lower
     double * up = rhsSpace;
     double * lo = dual_;
     const double * element = matrix_->getElements();
     const int * row = matrix_->getIndices();
     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
     const int * columnLength = matrix_->getVectorLengths();
     CoinZeroN(lo, numberRows_);
     CoinZeroN(up, numberRows_);
     for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
          double upper = columnUpper_[iColumn];
          double lower = columnLower_[iColumn];
          //assert (columnLength[iColumn]==columnStart[iColumn+1]-columnStart[iColumn]);
          for (CoinBigIndex j = columnStart[iColumn];
                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
               int iRow = row[j];
               double value = element[j];
               if (value > 0.0) {
                    if (upper < 1.0e20)
                         up[iRow] += upper * value;
                    else
                         up[iRow] = COIN_DBL_MAX;
                    if (lower > -1.0e20)
                         lo[iRow] += lower * value;
                    else
                         lo[iRow] = -COIN_DBL_MAX;
               } else {
                    if (upper < 1.0e20)
                         lo[iRow] += upper * value;
                    else
                         lo[iRow] = -COIN_DBL_MAX;
                    if (lower > -1.0e20)
                         up[iRow] += lower * value;
                    else
                         up[iRow] = COIN_DBL_MAX;
               }
          }
     }
     bool feasible = true;
     // make safer
     double tolerance = primalTolerance();
     for (int iRow = 0; iRow < numberRows_; iRow++) {
          double lower = lo[iRow];
          if (lower > rowUpper_[iRow] + tolerance) {
               feasible = false;
               break;
          } else {
               lo[iRow] = CoinMin(lower - rowUpper_[iRow], 0.0) - tolerance;
          }
          double upper = up[iRow];
          if (upper < rowLower_[iRow] - tolerance) {
               feasible = false;
               break;
          } else {
               up[iRow] = CoinMax(upper - rowLower_[iRow], 0.0) + tolerance;
          }
     }
     int numberTightened = 0;
     if (!feasible) {
          return -1;
     } else if (integerType_) {
          // and tighten
          for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
               if (integerType_[iColumn]) {
                    double upper = columnUpper_[iColumn];
                    double lower = columnLower_[iColumn];
                    double newUpper = upper;
                    double newLower = lower;
                    double difference = upper - lower;
                    if (lower > -1000.0 && upper < 1000.0) {
                         for (CoinBigIndex j = columnStart[iColumn];
                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                              int iRow = row[j];
                              double value = element[j];
                              if (value > 0.0) {
                                   double upWithOut = up[iRow] - value * difference;
                                   if (upWithOut < 0.0) {
                                        newLower = CoinMax(newLower, lower - (upWithOut + tolerance) / value);
                                   }
                                   double lowWithOut = lo[iRow] + value * difference;
                                   if (lowWithOut > 0.0) {
                                        newUpper = CoinMin(newUpper, upper - (lowWithOut - tolerance) / value);
                                   }
                              } else {
                                   double upWithOut = up[iRow] + value * difference;
                                   if (upWithOut < 0.0) {
                                        newUpper = CoinMin(newUpper, upper - (upWithOut + tolerance) / value);
                                   }
                                   double lowWithOut = lo[iRow] - value * difference;
                                   if (lowWithOut > 0.0) {
                                        newLower = CoinMax(newLower, lower - (lowWithOut - tolerance) / value);
                                   }
                              }
                         }
                         if (newLower > lower || newUpper < upper) {
                              if (fabs(newUpper - floor(newUpper + 0.5)) > 1.0e-6)
                                   newUpper = floor(newUpper);
                              else
                                   newUpper = floor(newUpper + 0.5);
                              if (fabs(newLower - ceil(newLower - 0.5)) > 1.0e-6)
                                   newLower = ceil(newLower);
                              else
                                   newLower = ceil(newLower - 0.5);
                              // change may be too small - check
                              if (newLower > lower || newUpper < upper) {
                                   if (newUpper >= newLower) {
                                        numberTightened++;
                                        //printf("%d bounds %g %g tightened to %g %g\n",
                                        //     iColumn,columnLower_[iColumn],columnUpper_[iColumn],
                                        //     newLower,newUpper);
                                        columnUpper_[iColumn] = newUpper;
                                        columnLower_[iColumn] = newLower;
                                        // and adjust bounds on rows
                                        newUpper -= upper;
                                        newLower -= lower;
                                        for (CoinBigIndex j = columnStart[iColumn];
                                                  j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                                             int iRow = row[j];
                                             double value = element[j];
                                             if (value > 0.0) {
                                                  up[iRow] += newUpper * value;
                                                  lo[iRow] += newLower * value;
                                             } else {
                                                  lo[iRow] += newUpper * value;
                                                  up[iRow] += newLower * value;
                                             }
                                        }
                                   } else {
                                        // infeasible
                                        //printf("%d bounds infeasible %g %g tightened to %g %g\n",
                                        //     iColumn,columnLower_[iColumn],columnUpper_[iColumn],
                                        //     newLower,newUpper);
                                        return -1;
                                   }
                              }
                         }
                    }
               }
          }
     }
     return numberTightened;
}
/* Parametrics
   This is an initial slow version.
   The code uses current bounds + theta * change (if change array not NULL)
   and similarly for objective.
   It starts at startingTheta and returns ending theta in endingTheta.
   If reportIncrement 0.0 it will report on any movement
   If reportIncrement >0.0 it will report at startingTheta+k*reportIncrement.
   If it can not reach input endingTheta return code will be 1 for infeasible,
   2 for unbounded, if error on ranges -1,  otherwise 0.
   Normal report is just theta and objective but
   if event handler exists it may do more
   On exit endingTheta is maximum reached (can be used for next startingTheta)
*/
int
ClpSimplexOther::parametrics(double startingTheta, double & endingTheta, double reportIncrement,
                             const double * lowerChangeBound, const double * upperChangeBound,
                             const double * lowerChangeRhs, const double * upperChangeRhs,
                             const double * changeObjective)
{
     bool needToDoSomething = true;
     bool canTryQuick = (reportIncrement) ? true : false;
     // Save copy of model
     ClpSimplex copyModel = *this;
     int savePerturbation = perturbation_;
     perturbation_ = 102; // switch off
     while (needToDoSomething) {
          needToDoSomething = false;
          algorithm_ = -1;

          // save data
          ClpDataSave data = saveData();
	  // Dantzig 
	  ClpDualRowPivot * savePivot = dualRowPivot_;
	  dualRowPivot_ = new ClpDualRowDantzig();
	  dualRowPivot_->setModel(this);
          int returnCode = reinterpret_cast<ClpSimplexDual *> (this)->startupSolve(0, NULL, 0);
          int iRow, iColumn;
          double * chgUpper = NULL;
          double * chgLower = NULL;
          double * chgObjective = NULL;


          if (!returnCode) {
               // Find theta when bounds will cross over and create arrays
               int numberTotal = numberRows_ + numberColumns_;
               chgLower = new double[numberTotal];
               memset(chgLower, 0, numberTotal * sizeof(double));
               chgUpper = new double[numberTotal];
               memset(chgUpper, 0, numberTotal * sizeof(double));
               chgObjective = new double[numberTotal];
               memset(chgObjective, 0, numberTotal * sizeof(double));
               assert (!rowScale_);
               double maxTheta = 1.0e50;
               if (lowerChangeRhs || upperChangeRhs) {
                    for (iRow = 0; iRow < numberRows_; iRow++) {
                         double lower = rowLower_[iRow];
                         double upper = rowUpper_[iRow];
                         if (lower > upper) {
                              maxTheta = -1.0;
                              break;
                         }
                         double lowerChange = (lowerChangeRhs) ? lowerChangeRhs[iRow] : 0.0;
                         double upperChange = (upperChangeRhs) ? upperChangeRhs[iRow] : 0.0;
                         if (lower > -1.0e20 && upper < 1.0e20) {
                              if (lower + maxTheta * lowerChange > upper + maxTheta * upperChange) {
                                   maxTheta = (upper - lower) / (lowerChange - upperChange);
                              }
                         }
                         if (lower > -1.0e20) {
                              lower_[numberColumns_+iRow] += startingTheta * lowerChange;
                              chgLower[numberColumns_+iRow] = lowerChange;
                         }
                         if (upper < 1.0e20) {
                              upper_[numberColumns_+iRow] += startingTheta * upperChange;
                              chgUpper[numberColumns_+iRow] = upperChange;
                         }
                    }
               }
               if (maxTheta > 0.0) {
                    if (lowerChangeBound || upperChangeBound) {
                         for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
                              double lower = columnLower_[iColumn];
                              double upper = columnUpper_[iColumn];
                              if (lower > upper) {
                                   maxTheta = -1.0;
                                   break;
                              }
                              double lowerChange = (lowerChangeBound) ? lowerChangeBound[iColumn] : 0.0;
                              double upperChange = (upperChangeBound) ? upperChangeBound[iColumn] : 0.0;
                              if (lower > -1.0e20 && upper < 1.0e20) {
                                   if (lower + maxTheta * lowerChange > upper + maxTheta * upperChange) {
                                        maxTheta = (upper - lower) / (lowerChange - upperChange);
                                   }
                              }
                              if (lower > -1.0e20) {
                                   lower_[iColumn] += startingTheta * lowerChange;
                                   chgLower[iColumn] = lowerChange;
                              }
                              if (upper < 1.0e20) {
                                   upper_[iColumn] += startingTheta * upperChange;
                                   chgUpper[iColumn] = upperChange;
                              }
                         }
                    }
                    if (maxTheta == 1.0e50)
                         maxTheta = COIN_DBL_MAX;
               }
               if (maxTheta < 0.0) {
                    // bad ranges or initial
                    returnCode = -1;
               }
	       if (maxTheta < endingTheta) {
		 char line[100];
		 sprintf(line,"Crossover considerations reduce ending  theta from %g to %g\n", 
			 endingTheta,maxTheta);
		 handler_->message(CLP_GENERAL,messages_)
		   << line << CoinMessageEol;
		 endingTheta = maxTheta;
	       }
               if (endingTheta < startingTheta) {
                    // bad initial
                    returnCode = -2;
               }
          }
          double saveEndingTheta = endingTheta;
          if (!returnCode) {
               if (changeObjective) {
                    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
                         chgObjective[iColumn] = changeObjective[iColumn];
                         cost_[iColumn] += startingTheta * changeObjective[iColumn];
                    }
               }
               double * saveDuals = NULL;
               reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(0, saveDuals, -1, data);
               assert (!problemStatus_);
	       for (int i=0;i<numberRows_+numberColumns_;i++)
		 setFakeBound(i, noFake);
               // Now do parametrics
	       handler_->message(CLP_PARAMETRICS_STATS, messages_)
		 << startingTheta << objectiveValue() << CoinMessageEol;
               while (!returnCode) {
		    //assert (reportIncrement);
		 parametricsData paramData;
		 paramData.startingTheta=startingTheta;
		 paramData.endingTheta=endingTheta;
		 paramData.maxTheta=COIN_DBL_MAX;
		 paramData.lowerChange = chgLower;
		 paramData.upperChange = chgUpper;
                    returnCode = parametricsLoop(paramData, reportIncrement,
                                                 chgLower, chgUpper, chgObjective, data,
                                                 canTryQuick);
		 startingTheta=paramData.startingTheta;
		 endingTheta=paramData.endingTheta;
                    if (!returnCode) {
                         //double change = endingTheta-startingTheta;
                         startingTheta = endingTheta;
                         endingTheta = saveEndingTheta;
                         //for (int i=0;i<numberTotal;i++) {
                         //lower_[i] += change*chgLower[i];
                         //upper_[i] += change*chgUpper[i];
                         //cost_[i] += change*chgObjective[i];
                         //}
			 handler_->message(CLP_PARAMETRICS_STATS, messages_)
			   << startingTheta << objectiveValue() << CoinMessageEol;
                         if (startingTheta >= endingTheta)
                              break;
                    } else if (returnCode == -1) {
                         // trouble - do external solve
                         needToDoSomething = true;
		    } else if (problemStatus_==1) {
		      // can't move any further
		      if (!canTryQuick) {
			handler_->message(CLP_PARAMETRICS_STATS, messages_)
			  << endingTheta << objectiveValue() << CoinMessageEol;
			problemStatus_=0;
		      }
                    } else {
                         abort();
                    }
               }
          }
          reinterpret_cast<ClpSimplexDual *> (this)->finishSolve(0);

          delete dualRowPivot_;
          dualRowPivot_ = savePivot;
          // Restore any saved stuff
          restoreData(data);
          if (needToDoSomething) {
               double saveStartingTheta = startingTheta; // known to be feasible
               int cleanedUp = 1;
               while (cleanedUp) {
                    // tweak
                    if (cleanedUp == 1) {
                         if (!reportIncrement)
                              startingTheta = CoinMin(startingTheta + 1.0e-5, saveEndingTheta);
                         else
                              startingTheta = CoinMin(startingTheta + reportIncrement, saveEndingTheta);
                    } else {
                         // restoring to go slowly
                         startingTheta = saveStartingTheta;
                    }
                    // only works if not scaled
                    int i;
                    const double * obj1 = objective();
                    double * obj2 = copyModel.objective();
                    const double * lower1 = columnLower_;
                    double * lower2 = copyModel.columnLower();
                    const double * upper1 = columnUpper_;
                    double * upper2 = copyModel.columnUpper();
                    for (i = 0; i < numberColumns_; i++) {
                         obj2[i] = obj1[i] + startingTheta * chgObjective[i];
                         lower2[i] = lower1[i] + startingTheta * chgLower[i];
                         upper2[i] = upper1[i] + startingTheta * chgUpper[i];
                    }
                    lower1 = rowLower_;
                    lower2 = copyModel.rowLower();
                    upper1 = rowUpper_;
                    upper2 = copyModel.rowUpper();
                    for (i = 0; i < numberRows_; i++) {
                         lower2[i] = lower1[i] + startingTheta * chgLower[i+numberColumns_];
                         upper2[i] = upper1[i] + startingTheta * chgUpper[i+numberColumns_];
                    }
                    copyModel.dual();
                    if (copyModel.problemStatus()) {
		      char line[100];
		      sprintf(line,"Can not get to theta of %g\n", startingTheta);
		      handler_->message(CLP_GENERAL,messages_)
			<< line << CoinMessageEol;
                         canTryQuick = false; // do slowly to get exact amount
                         // back to last known good
                         if (cleanedUp == 1)
                              cleanedUp = 2;
                         else
                              abort();
                    } else {
                         // and move stuff back
                         int numberTotal = numberRows_ + numberColumns_;
                         CoinMemcpyN(copyModel.statusArray(), numberTotal, status_);
                         CoinMemcpyN(copyModel.primalColumnSolution(), numberColumns_, columnActivity_);
                         CoinMemcpyN(copyModel.primalRowSolution(), numberRows_, rowActivity_);
                         cleanedUp = 0;
                    }
               }
          }
          delete [] chgLower;
          delete [] chgUpper;
          delete [] chgObjective;
     }
     perturbation_ = savePerturbation;
     char line[100];
     sprintf(line,"Ending theta %g\n", endingTheta);
     handler_->message(CLP_GENERAL,messages_)
       << line << CoinMessageEol;
     return problemStatus_;
}
/* Version of parametrics which reads from file
   See CbcClpParam.cpp for details of format
   Returns -2 if unable to open file */
int 
ClpSimplexOther::parametrics(const char * dataFile)
{
  int returnCode=-2;
  FILE *fp = fopen(dataFile, "r");
  char line[200];
  if (!fp) {
    handler_->message(CLP_UNABLE_OPEN, messages_)
      << dataFile << CoinMessageEol;
    return -2;
  }

  if (!fgets(line, 200, fp)) {
    sprintf(line,"Empty parametrics file %s?",dataFile);
    handler_->message(CLP_GENERAL,messages_)
      << line << CoinMessageEol;
    fclose(fp);
    return -2;
  }
  char * pos = line;
  char * put = line;
  while (*pos >= ' ' && *pos != '\n') {
    if (*pos != ' ' && *pos != '\t') {
      *put = static_cast<char>(tolower(*pos));
      put++;
    }
    pos++;
  }
  *put = '\0';
  pos = line;
  double startTheta=0.0;
  double endTheta=0.0;
  double intervalTheta=COIN_DBL_MAX;
  int detail=0;
  bool good = true;
  while (good) {
    good=false;
    // check ROWS
    char * comma = strchr(pos, ',');
    if (!comma)
      break;
    *comma = '\0';
    if (strcmp(pos,"rows"))
      break;
    *comma = ',';
    pos = comma+1;
    // check lower theta
    comma = strchr(pos, ',');
    if (!comma)
      break;
    *comma = '\0';
    startTheta = atof(pos);
    *comma = ',';
    pos = comma+1;
    // check upper theta
    comma = strchr(pos, ',');
    good=true;
    if (comma)
      *comma = '\0';
    endTheta = atof(pos);
    if (comma) {
      *comma = ',';
      pos = comma+1;
      comma = strchr(pos, ',');
      if (comma)
	*comma = '\0';
      intervalTheta = atof(pos);
      if (comma) {
	*comma = ',';
	pos = comma+1;
	comma = strchr(pos, ',');
	if (comma)
	  *comma = '\0';
	detail = atoi(pos);
	if (comma) 
	*comma = ',';
      }
    }
    break;
  }
  if (good) {
    if (startTheta<0.0||
	startTheta>endTheta||
	intervalTheta<0.0)
      good=false;
    if (detail<0||detail>1)
      good=false;
  }
  if (intervalTheta>=endTheta)
    intervalTheta=0.0;
  if (!good) {
    sprintf(line,"Odd first line %s on file %s?",line,dataFile);
    handler_->message(CLP_GENERAL,messages_)
      << line << CoinMessageEol;
    fclose(fp);
    return -2;
  }
  if (!fgets(line, 200, fp)) {
    sprintf(line,"Not enough records on parametrics file %s?",dataFile);
    handler_->message(CLP_GENERAL,messages_)
      << line << CoinMessageEol;
    fclose(fp);
    return -2;
  }
  double * lowerRowMove = NULL;
  double * upperRowMove = NULL;
  double * lowerColumnMove = NULL;
  double * upperColumnMove = NULL;
  double * objectiveMove = NULL;
  char saveLine[200];
  saveLine[0]='\0';
  std::string headingsRow[] = {"name", "number", "lower", "upper", "rhs"};
  int gotRow[] = { -1, -1, -1, -1, -1};
  int orderRow[5];
  assert(sizeof(gotRow) == sizeof(orderRow));
  int nAcross = 0;
  pos = line;
  put = line;
  while (*pos >= ' ' && *pos != '\n') {
    if (*pos != ' ' && *pos != '\t') {
      *put = static_cast<char>(tolower(*pos));
      put++;
    }
    pos++;
  }
  *put = '\0';
  pos = line;
  int i;
  good = true;
  if (strncmp(line,"column",6)) {
    while (pos) {
      char * comma = strchr(pos, ',');
      if (comma)
	*comma = '\0';
      for (i = 0; i < static_cast<int> (sizeof(gotRow) / sizeof(int)); i++) {
	if (headingsRow[i] == pos) {
	  if (gotRow[i] < 0) {
	    orderRow[nAcross] = i;
	    gotRow[i] = nAcross++;
	  } else {
	    // duplicate
	    good = false;
	  }
	  break;
	}
      }
      if (i == static_cast<int> (sizeof(gotRow) / sizeof(int)))
	good = false;
      if (comma) {
	*comma = ',';
	pos = comma + 1;
      } else {
	break;
      }
    }
    if (gotRow[0] < 0 && gotRow[1] < 0)
      good = false;
    if (gotRow[0] >= 0 && gotRow[1] >= 0)
      good = false;
    if (gotRow[0] >= 0 && !lengthNames())
      good = false;
    if (gotRow[4]<0) {
      if (gotRow[2] < 0 && gotRow[3] >= 0)
	good = false;
      else if (gotRow[3] < 0 && gotRow[2] >= 0)
	good = false;
    } else if (gotRow[2]>=0||gotRow[3]>=0) {
      good = false;
    }
    if (good) {
      char ** rowNames = new char * [numberRows_];
      int iRow;
      for (iRow = 0; iRow < numberRows_; iRow++) {
	rowNames[iRow] =
	  CoinStrdup(rowName(iRow).c_str());
      }
      lowerRowMove = new double [numberRows_];
      memset(lowerRowMove,0,numberRows_*sizeof(double));
      upperRowMove = new double [numberRows_];
      memset(upperRowMove,0,numberRows_*sizeof(double));
      int nLine = 0;
      int nBadLine = 0;
      int nBadName = 0;
      while (fgets(line, 200, fp)) {
	if (!strncmp(line, "ENDATA", 6)||
	    !strncmp(line, "COLUMN",6))
	  break;
	nLine++;
	iRow = -1;
	double upper = 0.0;
	double lower = 0.0;
	char * pos = line;
	char * put = line;
	while (*pos >= ' ' && *pos != '\n') {
	  if (*pos != ' ' && *pos != '\t') {
	    *put = *pos;
	    put++;
	  }
	  pos++;
	}
	*put = '\0';
	pos = line;
	for (int i = 0; i < nAcross; i++) {
	  char * comma = strchr(pos, ',');
	  if (comma) {
	    *comma = '\0';
	  } else if (i < nAcross - 1) {
	    nBadLine++;
	    break;
	  }
	  switch (orderRow[i]) {
	    // name
	  case 0:
	    // For large problems this could be slow
	    for (iRow = 0; iRow < numberRows_; iRow++) {
	      if (!strcmp(rowNames[iRow], pos))
		break;
	    }
	    if (iRow == numberRows_)
	      iRow = -1;
	    break;
	    // number
	  case 1:
	    iRow = atoi(pos);
	    if (iRow < 0 || iRow >= numberRows_)
	      iRow = -1;
	    break;
	    // lower
	  case 2:
	    upper = atof(pos);
	    break;
	    // upper
	  case 3:
	    lower = atof(pos);
	    break;
	    // rhs
	  case 4:
	    lower = atof(pos);
	    upper = lower;
	    break;
	  }
	  if (comma) {
	    *comma = ',';
	    pos = comma + 1;
	  }
	}
	if (iRow >= 0) {
	  if (rowLower_[iRow]>-1.0e20)
	    lowerRowMove[iRow] = lower;
	  else
	    lowerRowMove[iRow]=0.0;
	  if (rowUpper_[iRow]<1.0e20)
	    upperRowMove[iRow] = upper;
	  else
	    upperRowMove[iRow] = lower;
	} else {
	  nBadName++;
	  if(saveLine[0]=='\0')
	    strcpy(saveLine,line);
	}
      }
      sprintf(line,"%d Row fields and %d records", nAcross, nLine);
      handler_->message(CLP_GENERAL,messages_)
	<< line << CoinMessageEol;
      if (nBadName) {
	sprintf(line," ** %d records did not match on name/sequence, first bad %s", nBadName,saveLine);
	handler_->message(CLP_GENERAL,messages_)
	  << line << CoinMessageEol;
	returnCode=-1;
	good=false;
      }
      for (iRow = 0; iRow < numberRows_; iRow++) {
	free(rowNames[iRow]);
      }
      delete [] rowNames;
    } else {
      sprintf(line,"Duplicate or unknown keyword - or name/number fields wrong");
      handler_->message(CLP_GENERAL,messages_)
	<< line << CoinMessageEol;
      returnCode=-1;
      good=false;
    }
  }
  if (good&&(!strncmp(line, "COLUMN",6)||!strncmp(line, "column",6))) {
    if (!fgets(line, 200, fp)) {
      sprintf(line,"Not enough records on parametrics file %s after COLUMNS?",dataFile);
      handler_->message(CLP_GENERAL,messages_)
	<< line << CoinMessageEol;
      fclose(fp);
      return -2;
    }
    std::string headingsColumn[] = {"name", "number", "lower", "upper", "objective"};
    saveLine[0]='\0';
    int gotColumn[] = { -1, -1, -1, -1, -1};
    int orderColumn[5];
    assert(sizeof(gotColumn) == sizeof(orderColumn));
    nAcross = 0;
    pos = line;
    put = line;
    while (*pos >= ' ' && *pos != '\n') {
      if (*pos != ' ' && *pos != '\t') {
	*put = static_cast<char>(tolower(*pos));
	put++;
      }
      pos++;
    }
    *put = '\0';
    pos = line;
    int i;
    if (strncmp(line,"endata",6)&&good) {
      while (pos) {
	char * comma = strchr(pos, ',');
	if (comma)
	  *comma = '\0';
	for (i = 0; i < static_cast<int> (sizeof(gotColumn) / sizeof(int)); i++) {
	  if (headingsColumn[i] == pos) {
	    if (gotColumn[i] < 0) {
	      orderColumn[nAcross] = i;
	      gotColumn[i] = nAcross++;
	    } else {
	      // duplicate
	      good = false;
	    }
	    break;
	  }
	}
	if (i == static_cast<int> (sizeof(gotColumn) / sizeof(int)))
	  good = false;
	if (comma) {
	  *comma = ',';
	  pos = comma + 1;
	} else {
	  break;
	}
      }
      if (gotColumn[0] < 0 && gotColumn[1] < 0)
	good = false;
      if (gotColumn[0] >= 0 && gotColumn[1] >= 0)
	good = false;
      if (gotColumn[0] >= 0 && !lengthNames())
	good = false;
      if (good) {
	char ** columnNames = new char * [numberColumns_];
	int iColumn;
	for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
	  columnNames[iColumn] =
	    CoinStrdup(columnName(iColumn).c_str());
	}
	lowerColumnMove = reinterpret_cast<double *> (malloc(numberColumns_ * sizeof(double)));
	memset(lowerColumnMove,0,numberColumns_*sizeof(double));
	upperColumnMove = reinterpret_cast<double *> (malloc(numberColumns_ * sizeof(double)));
	memset(upperColumnMove,0,numberColumns_*sizeof(double));
	objectiveMove = reinterpret_cast<double *> (malloc(numberColumns_ * sizeof(double)));
	memset(objectiveMove,0,numberColumns_*sizeof(double));
	int nLine = 0;
	int nBadLine = 0;
	int nBadName = 0;
	while (fgets(line, 200, fp)) {
	  if (!strncmp(line, "ENDATA", 6))
	    break;
	  nLine++;
	  iColumn = -1;
	  double upper = 0.0;
	  double lower = 0.0;
	  double obj =0.0;
	  char * pos = line;
	  char * put = line;
	  while (*pos >= ' ' && *pos != '\n') {
	    if (*pos != ' ' && *pos != '\t') {
	      *put = *pos;
	      put++;
	    }
	    pos++;
	  }
	  *put = '\0';
	  pos = line;
	  for (int i = 0; i < nAcross; i++) {
	    char * comma = strchr(pos, ',');
	    if (comma) {
	      *comma = '\0';
	    } else if (i < nAcross - 1) {
	      nBadLine++;
	      break;
	    }
	    switch (orderColumn[i]) {
	      // name
	    case 0:
	      // For large problems this could be slow
	      for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
		if (!strcmp(columnNames[iColumn], pos))
		  break;
	      }
	      if (iColumn == numberColumns_)
		iColumn = -1;
	      break;
	      // number
	    case 1:
	      iColumn = atoi(pos);
	      if (iColumn < 0 || iColumn >= numberColumns_)
		iColumn = -1;
	      break;
	      // lower
	    case 2:
	      upper = atof(pos);
	      break;
	      // upper
	    case 3:
	      lower = atof(pos);
	      break;
	      // objective
	    case 4:
	      obj = atof(pos);
	      upper = lower;
	      break;
	    }
	    if (comma) {
	      *comma = ',';
	      pos = comma + 1;
	    }
	  }
	  if (iColumn >= 0) {
	    if (columnLower_[iColumn]>-1.0e20)
	      lowerColumnMove[iColumn] = lower;
	    else
	      lowerColumnMove[iColumn]=0.0;
	    if (columnUpper_[iColumn]<1.0e20)
	      upperColumnMove[iColumn] = upper;
	    else
	      upperColumnMove[iColumn] = lower;
	    objectiveMove[iColumn] = obj;
	  } else {
	    nBadName++;
	    if(saveLine[0]=='\0')
	      strcpy(saveLine,line);
	  }
	}
	sprintf(line,"%d Column fields and %d records", nAcross, nLine);
	handler_->message(CLP_GENERAL,messages_)
	  << line << CoinMessageEol;
	if (nBadName) {
	  sprintf(line," ** %d records did not match on name/sequence, first bad %s", nBadName,saveLine);
	  handler_->message(CLP_GENERAL,messages_)
	    << line << CoinMessageEol;
	  returnCode=-1;
	  good=false;
	}
	for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
	  free(columnNames[iColumn]);
	}
	delete [] columnNames;
      } else {
	sprintf(line,"Duplicate or unknown keyword - or name/number fields wrong");
	handler_->message(CLP_GENERAL,messages_)
	  << line << CoinMessageEol;
	returnCode=-1;
	good=false;
      }
    }
  }
  returnCode=-1;
  if (good) {
    // clean arrays
    if (lowerRowMove) {
      bool empty=true;
      for (int i=0;i<numberRows_;i++) {
	if (lowerRowMove[i]) {
	  empty=false;
	break;
	}
      }
      if (empty) {
	delete [] lowerRowMove;
	lowerRowMove=NULL;
      }
    }
    if (upperRowMove) {
      bool empty=true;
      for (int i=0;i<numberRows_;i++) {
	if (upperRowMove[i]) {
	  empty=false;
	break;
	}
      }
      if (empty) {
	delete [] upperRowMove;
	upperRowMove=NULL;
      }
    }
    if (lowerColumnMove) {
      bool empty=true;
      for (int i=0;i<numberColumns_;i++) {
	if (lowerColumnMove[i]) {
	  empty=false;
	break;
	}
      }
      if (empty) {
	delete [] lowerColumnMove;
	lowerColumnMove=NULL;
      }
    }
    if (upperColumnMove) {
      bool empty=true;
      for (int i=0;i<numberColumns_;i++) {
	if (upperColumnMove[i]) {
	  empty=false;
	break;
	}
      }
      if (empty) {
	delete [] upperColumnMove;
	upperColumnMove=NULL;
      }
    }
    if (objectiveMove) {
      bool empty=true;
      for (int i=0;i<numberColumns_;i++) {
	if (objectiveMove[i]) {
	  empty=false;
	break;
	}
      }
      if (empty) {
	delete [] objectiveMove;
	objectiveMove=NULL;
      }
    }
    int saveScaling = scalingFlag_;
    scalingFlag_ = 0;
    int saveLogLevel = handler_->logLevel();
    if (detail>0&&!intervalTheta)
      handler_->setLogLevel(3);
    else
      handler_->setLogLevel(1);
    returnCode = parametrics(startTheta,endTheta,intervalTheta,
			     lowerColumnMove,upperColumnMove,
			     lowerRowMove,upperRowMove,
			     objectiveMove);
    scalingFlag_ = saveScaling;
    handler_->setLogLevel(saveLogLevel);
  }
  delete [] lowerRowMove;
  delete [] upperRowMove;
  delete [] lowerColumnMove;
  delete [] upperColumnMove;
  delete [] objectiveMove;
  fclose(fp);
  return returnCode;
}
int
ClpSimplexOther::parametricsLoop(parametricsData & paramData,double reportIncrement,
                                 const double * lowerChange, const double * upperChange,
                                 const double * changeObjective, ClpDataSave & data,
                                 bool canTryQuick)
{
  double startingTheta = paramData.startingTheta;
  double & endingTheta = paramData.endingTheta;
     // stuff is already at starting
     // For this crude version just try and go to end
     double change = 0.0;
     if (reportIncrement && canTryQuick) {
          endingTheta = CoinMin(endingTheta, startingTheta + reportIncrement);
          change = endingTheta - startingTheta;
     }
     int numberTotal = numberRows_ + numberColumns_;
     int i;
     for ( i = 0; i < numberTotal; i++) {
          lower_[i] += change * lowerChange[i];
          upper_[i] += change * upperChange[i];
          switch(getStatus(i)) {

          case basic:
          case isFree:
          case superBasic:
               break;
          case isFixed:
          case atUpperBound:
               solution_[i] = upper_[i];
               break;
          case atLowerBound:
               solution_[i] = lower_[i];
               break;
          }
          cost_[i] += change * changeObjective[i];
     }
     problemStatus_ = -1;

     // This says whether to restore things etc
     // startup will have factorized so can skip
     int factorType = 0;
     // Start check for cycles
     progress_.startCheck();
     // Say change made on first iteration
     changeMade_ = 1;
     /*
       Status of problem:
       0 - optimal
       1 - infeasible
       2 - unbounded
       -1 - iterating
       -2 - factorization wanted
       -3 - redo checking without factorization
       -4 - looks infeasible
     */
     while (problemStatus_ < 0) {
          int iRow, iColumn;
          // clear
          for (iRow = 0; iRow < 4; iRow++) {
               rowArray_[iRow]->clear();
          }

          for (iColumn = 0; iColumn < 2; iColumn++) {
               columnArray_[iColumn]->clear();
          }

          // give matrix (and model costs and bounds a chance to be
          // refreshed (normally null)
          matrix_->refresh(this);
          // may factorize, checks if problem finished
          statusOfProblemInParametrics(factorType, data);
          // Say good factorization
          factorType = 1;
          if (data.sparseThreshold_) {
               // use default at present
               factorization_->sparseThreshold(0);
               factorization_->goSparse();
          }

          // exit if victory declared
          if (problemStatus_ >= 0 && 
	      (canTryQuick || startingTheta>=endingTheta-1.0e-7) )
               break;

          // test for maximum iterations
          if (hitMaximumIterations()) {
               problemStatus_ = 3;
               break;
          }
          // Check event
          {
               int status = eventHandler_->event(ClpEventHandler::endOfFactorization);
               if (status >= 0) {
                    problemStatus_ = 5;
                    secondaryStatus_ = ClpEventHandler::endOfFactorization;
                    break;
               }
          }
          // Do iterations
	  problemStatus_=-1;
          if (canTryQuick) {
               double * saveDuals = NULL;
               reinterpret_cast<ClpSimplexDual *> (this)->whileIterating(saveDuals, 0);
          } else {
               whileIterating(paramData, reportIncrement,
                              changeObjective);
	       startingTheta = endingTheta;
          }
     }
     if (!problemStatus_) {
          theta_ = change + startingTheta;
          eventHandler_->event(ClpEventHandler::theta);
          return 0;
     } else if (problemStatus_ == 10) {
          return -1;
     } else {
          return problemStatus_;
     }
}
/* Parametrics
   The code uses current bounds + theta * change (if change array not NULL)
   It starts at startingTheta and returns ending theta in endingTheta.
   If it can not reach input endingTheta return code will be 1 for infeasible,
   2 for unbounded, if error on ranges -1,  otherwise 0.
   Event handler may do more
   On exit endingTheta is maximum reached (can be used for next startingTheta)
*/
int
ClpSimplexOther::parametrics(double startingTheta, double & endingTheta,
                             const double * lowerChangeBound, const double * upperChangeBound,
                             const double * lowerChangeRhs, const double * upperChangeRhs)
{
  int savePerturbation = perturbation_;
  perturbation_ = 102; // switch off
  algorithm_ = -1;
  // extra region
  int maximumPivots = factorization_->maximumPivots();
  int numberDense = factorization_->numberDense();
  int length = numberRows_ + numberDense + maximumPivots;
  assert (!rowArray_[4]);
  rowArray_[4]=new CoinIndexedVector(length);
  assert (!rowArray_[5]);
  rowArray_[5]=new CoinIndexedVector(length);

  // save data
  ClpDataSave data = saveData();
  int numberTotal = numberRows_ + numberColumns_;
  int ratio = static_cast<int>((2*sizeof(int))/sizeof(double));
  assert (ratio==1||ratio==2);
  // allow for unscaled - even if not needed
  int lengthArrays = 4*numberTotal+(3*numberTotal+2)*ratio+2*numberRows_+1;
  int unscaledChangesOffset=lengthArrays; // need extra copy of change
  lengthArrays += numberTotal;
  
  /*
    Save information and modify
  */
  double * saveLower = new double [lengthArrays];
  double * saveUpper = new double [lengthArrays];
  double * lowerCopy = saveLower+2*numberTotal;
  double * upperCopy = saveUpper+2*numberTotal;
  double * lowerChange = saveLower+numberTotal;
  double * upperChange = saveUpper+numberTotal;
  double * lowerGap = saveLower+4*numberTotal;
  double * lowerCoefficient = lowerGap+numberRows_;
  double * upperGap = saveUpper+4*numberTotal;
  double * upperCoefficient = upperGap+numberRows_;
  int * lowerList = (reinterpret_cast<int *>(saveLower+4*numberTotal+2*numberRows_))+2;
  int * upperList = (reinterpret_cast<int *>(saveUpper+4*numberTotal+2*numberRows_))+2;
  int * lowerActive = lowerList+numberTotal+1;
  int * upperActive = upperList+numberTotal+1;
  // To mark as odd
  char * markDone = reinterpret_cast<char *>(lowerActive+numberTotal);
  //memset(markDone,0,numberTotal);
  int * backwardBasic = upperActive+numberTotal;
  parametricsData paramData;
  paramData.lowerChange = lowerChange;
  paramData.lowerList=lowerList;
  paramData.upperChange = upperChange;
  paramData.upperList=upperList;
  paramData.markDone=markDone;
  paramData.backwardBasic=backwardBasic;
  paramData.lowerActive = lowerActive;
  paramData.lowerGap = lowerGap;
  paramData.lowerCoefficient = lowerCoefficient;
  paramData.upperActive = upperActive;
  paramData.upperGap = upperGap;
  paramData.upperCoefficient = upperCoefficient;
  paramData.unscaledChangesOffset = unscaledChangesOffset-numberTotal;
  paramData.firstIteration=true;
  // Find theta when bounds will cross over and create arrays
  memset(lowerChange, 0, numberTotal * sizeof(double));
  memset(upperChange, 0, numberTotal * sizeof(double));
  if (lowerChangeBound)
    memcpy(lowerChange,lowerChangeBound,numberColumns_*sizeof(double));
  if (upperChangeBound)
    memcpy(upperChange,upperChangeBound,numberColumns_*sizeof(double));
  if (lowerChangeRhs)
    memcpy(lowerChange+numberColumns_,
	   lowerChangeRhs,numberRows_*sizeof(double));
  if (upperChangeRhs)
    memcpy(upperChange+numberColumns_,
	   upperChangeRhs,numberRows_*sizeof(double));
  // clean
  for (int iRow = 0; iRow < numberRows_; iRow++) {
    double lower = rowLower_[iRow];
    double upper = rowUpper_[iRow];
    if (lower<-1.0e30)
      lowerChange[numberColumns_+iRow]=0.0;
    if (upper>1.0e30)
      upperChange[numberColumns_+iRow]=0.0;
  }
  for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
    double lower = columnLower_[iColumn];
    double upper = columnUpper_[iColumn];
    if (lower<-1.0e30)
      lowerChange[iColumn]=0.0;
    if (upper>1.0e30)
      upperChange[iColumn]=0.0;
  }
  // save unscaled version of changes
  memcpy(saveLower+unscaledChangesOffset,lowerChange,numberTotal*sizeof(double));
  memcpy(saveUpper+unscaledChangesOffset,upperChange,numberTotal*sizeof(double));
  int nLowerChange=0;
  int nUpperChange=0;
  for (int i=0;i<numberColumns_;i++) {
    if (lowerChange[i]) { 
      lowerList[nLowerChange++]=i;
    }
    if (upperChange[i]) { 
      upperList[nUpperChange++]=i;
    }
  }
  lowerList[-2]=nLowerChange;
  upperList[-2]=nUpperChange;
  for (int i=numberColumns_;i<numberTotal;i++) {
    if (lowerChange[i]) { 
      lowerList[nLowerChange++]=i;
    }
    if (upperChange[i]) { 
      upperList[nUpperChange++]=i;
    }
  }
  lowerList[-1]=nLowerChange;
  upperList[-1]=nUpperChange;
  memcpy(lowerCopy,columnLower_,numberColumns_*sizeof(double));
  memcpy(upperCopy,columnUpper_,numberColumns_*sizeof(double));
  memcpy(lowerCopy+numberColumns_,
	 rowLower_,numberRows_*sizeof(double));
  memcpy(upperCopy+numberColumns_,
	 rowUpper_,numberRows_*sizeof(double));
  {
    //  extra for unscaled
    double * unscaledCopy;
    unscaledCopy = lowerCopy + numberTotal; 
    memcpy(unscaledCopy,columnLower_,numberColumns_*sizeof(double));
    memcpy(unscaledCopy+numberColumns_,
	   rowLower_,numberRows_*sizeof(double));
    unscaledCopy = upperCopy + numberTotal; 
    memcpy(unscaledCopy,columnUpper_,numberColumns_*sizeof(double));
    memcpy(unscaledCopy+numberColumns_,
	   rowUpper_,numberRows_*sizeof(double));
  }
  int returnCode=0;
  paramData.startingTheta=startingTheta;
  paramData.endingTheta=endingTheta;
  paramData.maxTheta=endingTheta;
  computeRhsEtc(paramData);
  bool swapped=false;
  // Dantzig 
#define ALL_DANTZIG
#ifdef ALL_DANTZIG
  ClpDualRowPivot * savePivot = dualRowPivot_;
  dualRowPivot_ = new ClpDualRowDantzig();
  dualRowPivot_->setModel(this);
#else
  ClpDualRowPivot * savePivot = NULL;
#endif
  if (!returnCode) {
    assert (objective_->type()==1);
    objective_->setType(2); // in case matrix empty
    returnCode = reinterpret_cast<ClpSimplexDual *> (this)->startupSolve(0, NULL, 0);
    objective_->setType(1);
    if (!returnCode) {
      double saveDualBound=dualBound_;
      dualBound_=CoinMax(dualBound_,1.0e15);
      swapped=true;
      double * temp;
      memcpy(saveLower,lower_,numberTotal*sizeof(double));
      temp=saveLower;
      saveLower=lower_;
      lower_=temp;
      //columnLowerWork_ = lower_;
      //rowLowerWork_ = lower_ + numberColumns_;
      memcpy(saveUpper,upper_,numberTotal*sizeof(double));
      temp=saveUpper;
      saveUpper=upper_;
      upper_=temp;
      //columnUpperWork_ = upper_;
      //rowUpperWork_ = upper_ + numberColumns_;
      if (rowScale_) {
	// scale saved and change arrays
	double * lowerChange = lower_+numberTotal;
	double * upperChange = upper_+numberTotal;
	double * lowerSave = lowerChange+numberTotal;
	double * upperSave = upperChange+numberTotal;
	for (int i=0;i<numberColumns_;i++) {
	  double multiplier = inverseColumnScale_[i];
	  if (lowerSave[i]>-1.0e20)
	    lowerSave[i] *= multiplier;
	  if (upperSave[i]<1.0e20)
	    upperSave[i] *= multiplier;
	  lowerChange[i] *= multiplier;
	  upperChange[i] *= multiplier;
	}
	lowerChange += numberColumns_;
	upperChange += numberColumns_;
	lowerSave += numberColumns_;
	upperSave += numberColumns_;
	for (int i=0;i<numberRows_;i++) {
	  double multiplier = rowScale_[i];
	  if (lowerSave[i]>-1.0e20)
	    lowerSave[i] *= multiplier;
	  if (upperSave[i]<1.0e20)
	    upperSave[i] *= multiplier;
	  lowerChange[i] *= multiplier;
	  upperChange[i] *= multiplier;
	}
      }
      //double saveEndingTheta = endingTheta;
      double * saveDuals = NULL;
      reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(0, saveDuals, -1, data);
      if (numberPrimalInfeasibilities_&&sumPrimalInfeasibilities_<1.0e-4) {
	// probably can get rid of this if we adjust every change in theta
	//printf("INFEAS_A %d %g\n",numberPrimalInfeasibilities_,
	//   sumPrimalInfeasibilities_);
	int pass=100;
	while(sumPrimalInfeasibilities_) {
	  pass--;
	  if (!pass)
	    break;
	  problemStatus_=-1;
	  for (int iSequence=numberColumns_;iSequence<numberTotal;iSequence++) {
	    double value=solution_[iSequence];
	    // remember scaling
	    if (value<lower_[iSequence]-1.0e-9) {
	      lowerCopy[iSequence]+=value-lower_[iSequence];
	      lower_[iSequence]=value;
	    } else if (value>upper_[iSequence]+1.0e-9) {
	      upperCopy[iSequence]+=value-upper_[iSequence];
	      upper_[iSequence]=value;
	    }
	  }
	  reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(1, saveDuals, -1, data);
	}
      }
      if (!problemStatus_) {
	if (nLowerChange||nUpperChange) {
#ifndef ALL_DANTZIG
	  // Dantzig 
	  savePivot = dualRowPivot_;
	  dualRowPivot_ = new ClpDualRowDantzig();
	  dualRowPivot_->setModel(this);
#endif
	  //for (int i=0;i<numberRows_+numberColumns_;i++)
	  //setFakeBound(i, noFake);
	  // Now do parametrics
	  handler_->message(CLP_PARAMETRICS_STATS, messages_)
	    << startingTheta << objectiveValue() << CoinMessageEol;
	  bool canSkipFactorization=true;
	  while (!returnCode) {
	    paramData.startingTheta=startingTheta;
	    paramData.endingTheta=endingTheta;
	    returnCode = parametricsLoop(paramData,
					 data,canSkipFactorization);
	    startingTheta=paramData.startingTheta;
	    endingTheta=paramData.endingTheta;
	    canSkipFactorization=false;
	    if (!returnCode) {
	      //startingTheta = endingTheta;
	      //endingTheta = saveEndingTheta;
	      handler_->message(CLP_PARAMETRICS_STATS, messages_)
		<< startingTheta << objectiveValue() << CoinMessageEol;
	      if (startingTheta >= endingTheta-primalTolerance_
		  ||problemStatus_==2)
		break;
	    } else if (returnCode == -1) {
	      // trouble - do external solve
	      abort(); //needToDoSomething = true;
	    } else if (problemStatus_==1) {
	      // can't move any further
	      handler_->message(CLP_PARAMETRICS_STATS, messages_)
		<< endingTheta << objectiveValue() << CoinMessageEol;
	      problemStatus_=0;
	    }
	  }
	}
	dualBound_ = saveDualBound;
	//reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(0, saveDuals, -1, data);
      } else {
	// check if empty
	//if (!numberRows_||!matrix_->getNumElements()) {
	// success
#ifdef CLP_USER_DRIVEN
	//theta_ = endingTheta;
	//eventHandler_->event(ClpEventHandler::theta);
#endif
	//}
      }
    }
    if (problemStatus_==2) {
      delete [] ray_;
      ray_ = new double [numberColumns_];
    }
    if (swapped&&lower_) {
      double * temp=saveLower;
      saveLower=lower_;
      lower_=temp;
      temp=saveUpper;
      saveUpper=upper_;
      upper_=temp;
    }
    reinterpret_cast<ClpSimplexDual *> (this)->finishSolve(0);
  }    
  if (!scalingFlag_) {
    memcpy(columnLower_,lowerCopy,numberColumns_*sizeof(double));
    memcpy(columnUpper_,upperCopy,numberColumns_*sizeof(double));
    memcpy(rowLower_,lowerCopy+numberColumns_,
	   numberRows_*sizeof(double));
    memcpy(rowUpper_,upperCopy+numberColumns_,
	   numberRows_*sizeof(double));
  } else {
    //  extra for unscaled
    double * unscaledCopy;
    unscaledCopy = lowerCopy + numberTotal; 
    memcpy(columnLower_,unscaledCopy,numberColumns_*sizeof(double));
    memcpy(rowLower_,unscaledCopy+numberColumns_,
	   numberRows_*sizeof(double));
    unscaledCopy = upperCopy + numberTotal; 
    memcpy(columnUpper_,unscaledCopy,numberColumns_*sizeof(double));
    memcpy(rowUpper_,unscaledCopy+numberColumns_,
	   numberRows_*sizeof(double));
  }
  delete [] saveLower;
  delete [] saveUpper;
#ifdef ALL_DANTZIG
  if (savePivot) {
#endif
    delete dualRowPivot_;
    dualRowPivot_ = savePivot;
#ifdef ALL_DANTZIG
  }
#endif
  // Restore any saved stuff
  restoreData(data);
  perturbation_ = savePerturbation;
  delete rowArray_[4];
  rowArray_[4]=NULL;
  delete rowArray_[5];
  rowArray_[5]=NULL;
  char line[100];
  sprintf(line,"Ending theta %g\n", endingTheta);
  handler_->message(CLP_GENERAL,messages_)
    << line << CoinMessageEol;
  return problemStatus_;
}
int
ClpSimplexOther::parametricsLoop(parametricsData & paramData,
                                 ClpDataSave & data,bool canSkipFactorization)
{
  double & startingTheta = paramData.startingTheta;
  double & endingTheta = paramData.endingTheta;
  int numberTotal = numberRows_+numberColumns_;
  // stuff is already at starting
  const int * lowerList = paramData.lowerList;
  const int * upperList = paramData.upperList;
  problemStatus_ = -1;
  //double saveEndingTheta=endingTheta;

  // This says whether to restore things etc
  // startup will have factorized so can skip
  int factorType = 0;
  // Start check for cycles
  progress_.startCheck();
  // Say change made on first iteration
  changeMade_ = 1;
  /*
    Status of problem:
    0 - optimal
    1 - infeasible
    2 - unbounded
    -1 - iterating
    -2 - factorization wanted
    -3 - redo checking without factorization
    -4 - looks infeasible
  */
  while (problemStatus_ < 0) {
    int iRow, iColumn;
    // clear
    for (iRow = 0; iRow < 6; iRow++) {
      rowArray_[iRow]->clear();
    }
    
    for (iColumn = 0; iColumn < 2; iColumn++) {
      columnArray_[iColumn]->clear();
    }
    
    // give matrix (and model costs and bounds a chance to be
    // refreshed (normally null)
    matrix_->refresh(this);
    // may factorize, checks if problem finished
    if (!canSkipFactorization)
      statusOfProblemInParametrics(factorType, data);
    canSkipFactorization=false;
    if (numberPrimalInfeasibilities_) {
      if (largestPrimalError_>1.0e3&&startingTheta>1.0e10) {
	// treat as success
	problemStatus_=0;
	endingTheta=startingTheta;
	break;
      }
      // probably can get rid of this if we adjust every change in theta
      //printf("INFEAS %d %g\n",numberPrimalInfeasibilities_,
      //     sumPrimalInfeasibilities_);
      const double * lowerChange = lower_+numberTotal;
      const double * upperChange = upper_+numberTotal;
      const double * startLower = lowerChange+numberTotal;
      const double * startUpper = upperChange+numberTotal;
      //startingTheta -= 1.0e-7;
      int nLowerChange = lowerList[-1];
      for (int i = 0; i < nLowerChange; i++) {
	int iSequence = lowerList[i];
	lower_[iSequence] = startLower[iSequence] + startingTheta * lowerChange[iSequence];
      }
      int nUpperChange = upperList[-1];
      for (int i = 0; i < nUpperChange; i++) {
	int iSequence = upperList[i];
	upper_[iSequence] = startUpper[iSequence] + startingTheta * upperChange[iSequence];
      }
      // adjust rhs in case dual uses
      memcpy(columnLower_,lower_,numberColumns_*sizeof(double));
      memcpy(rowLower_,lower_+numberColumns_,numberRows_*sizeof(double));
      memcpy(columnUpper_,upper_,numberColumns_*sizeof(double));
      memcpy(rowUpper_,upper_+numberColumns_,numberRows_*sizeof(double));
      if (rowScale_) {
	for (int i=0;i<numberColumns_;i++) {
	  double multiplier = columnScale_[i];
	  if (columnLower_[i]>-1.0e20)
	    columnLower_[i] *= multiplier;
	  if (columnUpper_[i]<1.0e20)
	    columnUpper_[i] *= multiplier;
	}
	for (int i=0;i<numberRows_;i++) {
	  double multiplier = inverseRowScale_[i];
	  if (rowLower_[i]>-1.0e20)
	    rowLower_[i] *= multiplier;
	  if (rowUpper_[i]<1.0e20)
	    rowUpper_[i] *= multiplier;
	}
      }
      double * saveDuals = NULL;
      problemStatus_=-1;
      ClpObjective * saveObjective = objective_;
      reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(0, saveDuals, -1, data);
      if (saveObjective!=objective_) {
	delete objective_;
	objective_=saveObjective;
      }
      int pass=100;
      double moved=0.0;
      while(sumPrimalInfeasibilities_) {
	//printf("INFEAS pass %d %d %g\n",100-pass,numberPrimalInfeasibilities_,
	//     sumPrimalInfeasibilities_);
	pass--;
	if (!pass)
	  break;
	problemStatus_=-1;
	for (int iSequence=numberColumns_;iSequence<numberTotal;iSequence++) {
	  double value=solution_[iSequence];
	  if (value<lower_[iSequence]-1.0e-9) {
	    moved += lower_[iSequence]-value;
	    lower_[iSequence]=value;
	  } else if (value>upper_[iSequence]+1.0e-9) {
	    moved += upper_[iSequence]-value;
	    upper_[iSequence]=value;
	  }
	}
	if (!moved) {
	  for (int iSequence=0;iSequence<numberColumns_;iSequence++) {
	    double value=solution_[iSequence];
	    if (value<lower_[iSequence]-1.0e-9) {
	      moved += lower_[iSequence]-value;
	      lower_[iSequence]=value;
	    } else if (value>upper_[iSequence]+1.0e-9) {
	      moved += upper_[iSequence]-value;
	      upper_[iSequence]=value;
	    }
	  }
	}
	assert (moved);
	reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(1, saveDuals, -1, data);
      }
      // adjust
      //printf("Should adjust - moved %g\n",moved);
    }
    // Say good factorization
    factorType = 1;
    if (data.sparseThreshold_) {
      // use default at present
      factorization_->sparseThreshold(0);
      factorization_->goSparse();
    }
    
    // exit if victory declared
    if (problemStatus_ >= 0 && startingTheta>=endingTheta-1.0e-7 )
      break;
    
    // test for maximum iterations
    if (hitMaximumIterations()) {
      problemStatus_ = 3;
      break;
    }
#ifdef CLP_USER_DRIVEN
    // Check event
    {
      int status = eventHandler_->event(ClpEventHandler::endOfFactorization);
      if (status >= 0) {
	problemStatus_ = 5;
	secondaryStatus_ = ClpEventHandler::endOfFactorization;
	break;
      }
    }
#endif
    // Do iterations
    problemStatus_=-1;
    whileIterating(paramData, 0.0,
		   NULL);
    //startingTheta = endingTheta;
    //endingTheta = saveEndingTheta;
  }
  if (!problemStatus_/*||problemStatus_==2*/) {
    theta_ = endingTheta;
#ifdef CLP_USER_DRIVEN
    {
      double saveTheta=theta_;
      theta_ = endingTheta;
      int status=eventHandler_->event(ClpEventHandler::theta);
      if (status>=0&&status<10) {
	endingTheta=theta_;
	theta_=saveTheta;
	problemStatus_=-1;
      } else {
	if (status>=10) {
	  problemStatus_=status-10;
	  startingTheta=endingTheta;
	}
	theta_=saveTheta;
      }
    }
#endif
    return 0;
  } else if (problemStatus_ == 10) {
    return -1;
  } else {
    return problemStatus_;
  }
}
/* Checks if finished.  Updates status */
void
ClpSimplexOther::statusOfProblemInParametrics(int type, ClpDataSave & saveData)
{
     if (type == 2) {
          // trouble - go to recovery
          problemStatus_ = 10;
          return;
     }
     if (problemStatus_ > -3 || factorization_->pivots()) {
          // factorize
          // later on we will need to recover from singularities
          // also we could skip if first time
          if (type) {
               // is factorization okay?
               if (internalFactorize(1)) {
                    // trouble - go to recovery
                    problemStatus_ = 10;
                    return;
               }
          }
          if (problemStatus_ != -4 || factorization_->pivots() > 10)
               problemStatus_ = -3;
     }
     // at this stage status is -3 or -4 if looks infeasible
     // get primal and dual solutions
     gutsOfSolution(NULL, NULL);
     double realDualInfeasibilities = sumDualInfeasibilities_;
     // If bad accuracy treat as singular
     if ((largestPrimalError_ > 1.0e15 || largestDualError_ > 1.0e15) && numberIterations_) {
          // trouble - go to recovery
          problemStatus_ = 10;
          return;
     } else if (largestPrimalError_ < 1.0e-7 && largestDualError_ < 1.0e-7) {
          // Can reduce tolerance
          double newTolerance = CoinMax(0.99 * factorization_->pivotTolerance(), saveData.pivotTolerance_);
          factorization_->pivotTolerance(newTolerance);
     }
     // Check if looping
     int loop;
     if (type != 2)
          loop = progress_.looping();
     else
          loop = -1;
     if (loop >= 0) {
          problemStatus_ = loop; //exit if in loop
          if (!problemStatus_) {
               // declaring victory
               numberPrimalInfeasibilities_ = 0;
               sumPrimalInfeasibilities_ = 0.0;
          } else {
               problemStatus_ = 10; // instead - try other algorithm
          }
          return;
     } else if (loop < -1) {
          // something may have changed
          gutsOfSolution(NULL, NULL);
     }
     progressFlag_ = 0; //reset progress flag
     if (handler_->detail(CLP_SIMPLEX_STATUS, messages_) < 100) {
          handler_->message(CLP_SIMPLEX_STATUS, messages_)
                    << numberIterations_ << objectiveValue();
          handler_->printing(sumPrimalInfeasibilities_ > 0.0)
                    << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
          handler_->printing(sumDualInfeasibilities_ > 0.0)
                    << sumDualInfeasibilities_ << numberDualInfeasibilities_;
          handler_->printing(numberDualInfeasibilitiesWithoutFree_
                             < numberDualInfeasibilities_)
                    << numberDualInfeasibilitiesWithoutFree_;
          handler_->message() << CoinMessageEol;
     }
#ifdef CLP_USER_DRIVEN
     if (sumPrimalInfeasibilities_&&sumPrimalInfeasibilities_<1.0e-7) {
       int status=eventHandler_->event(ClpEventHandler::slightlyInfeasible);
       if (status>=0) {
	 // fix up
	 for (int iSequence=0;iSequence<numberRows_+numberColumns_;iSequence++) {
	   double value=solution_[iSequence];
	   if (value<=lower_[iSequence]-primalTolerance_) {
	     lower_[iSequence]=value;
	   } else if (value>=upper_[iSequence]+primalTolerance_) {
	     upper_[iSequence]=value;
	   }
	 }
	 numberPrimalInfeasibilities_ = 0;
	 sumPrimalInfeasibilities_ = 0.0;
       }
     }
#endif
     /* If we are primal feasible and any dual infeasibilities are on
        free variables then it is better to go to primal */
     if (!numberPrimalInfeasibilities_ && !numberDualInfeasibilitiesWithoutFree_ &&
               numberDualInfeasibilities_) {
          problemStatus_ = 10;
          return;
     }

     // check optimal
     // give code benefit of doubt
     if (sumOfRelaxedDualInfeasibilities_ == 0.0 &&
               sumOfRelaxedPrimalInfeasibilities_ == 0.0) {
          // say optimal (with these bounds etc)
          numberDualInfeasibilities_ = 0;
          sumDualInfeasibilities_ = 0.0;
          numberPrimalInfeasibilities_ = 0;
          sumPrimalInfeasibilities_ = 0.0;
     }
     if (dualFeasible() || problemStatus_ == -4) {
          progress_.modifyObjective(objectiveValue_
                                    - sumDualInfeasibilities_ * dualBound_);
     }
     if (numberPrimalInfeasibilities_) {
          if (problemStatus_ == -4 || problemStatus_ == -5) {
               problemStatus_ = 1; // infeasible
          }
     } else if (numberDualInfeasibilities_) {
          // clean up
          problemStatus_ = 10;
     } else {
          problemStatus_ = 0;
     }
     lastGoodIteration_ = numberIterations_;
     if (problemStatus_ < 0) {
          sumDualInfeasibilities_ = realDualInfeasibilities; // back to say be careful
          if (sumDualInfeasibilities_)
               numberDualInfeasibilities_ = 1;
     }
     // Allow matrices to be sorted etc
     int fake = -999; // signal sort
     matrix_->correctSequence(this, fake, fake);
}
//static double lastThetaX=0.0;
/* This has the flow between re-factorizations
   Reasons to come out:
   -1 iterations etc
   -2 inaccuracy
   -3 slight inaccuracy (and done iterations)
   +0 looks optimal (might be unbounded - but we will investigate)
   +1 looks infeasible
   +3 max iterations
   +4 accuracy problems
*/
int
ClpSimplexOther::whileIterating(parametricsData & paramData, double /*reportIncrement*/,
                                const double * /*changeObjective*/)
{
  double & startingTheta = paramData.startingTheta;
  double & endingTheta = paramData.endingTheta;
  const double * lowerChange = paramData.lowerChange;
  const double * upperChange = paramData.upperChange;
  int numberTotal = numberColumns_ + numberRows_;
  const int * lowerList = paramData.lowerList;
  const int * upperList = paramData.upperList;
  //#define CLP_PARAMETRIC_DENSE_ARRAYS 2
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
  double * lowerGap = paramData.lowerGap;
  double * upperGap = paramData.upperGap;
  double * lowerCoefficient = paramData.lowerCoefficient;
  double * upperCoefficient = paramData.upperCoefficient;
#endif
  // do basic pointers
  int * backwardBasic = paramData.backwardBasic;
  for (int i=0;i<numberTotal;i++)
    backwardBasic[i]=-1;
  for (int i=0;i<numberRows_;i++) {
    int iPivot=pivotVariable_[i];
    backwardBasic[iPivot]=i;
  }
     {
          int i;
          for (i = 0; i < 4; i++) {
               rowArray_[i]->clear();
          }
          for (i = 0; i < 2; i++) {
               columnArray_[i]->clear();
          }
     }
     // if can't trust much and long way from optimal then relax
     if (largestPrimalError_ > 10.0)
          factorization_->relaxAccuracyCheck(CoinMin(1.0e2, largestPrimalError_ / 10.0));
     else
          factorization_->relaxAccuracyCheck(1.0);
     // status stays at -1 while iterating, >=0 finished, -2 to invert
     // status -3 to go to top without an invert
     int returnCode = -1;
     double lastTheta = startingTheta;
     double useTheta = startingTheta;
     while (problemStatus_ == -1) {
          double increaseTheta = CoinMin(endingTheta - lastTheta, 1.0e50);
          // Get theta for bounds - we know can't crossover
          int pivotType = nextTheta(1, increaseTheta, paramData,
                                     NULL);
	  useTheta += theta_;
	  double change = useTheta - lastTheta;
	  if (paramData.firstIteration) {
	    // redo rhs etc to make as accurate as possible
	    paramData.firstIteration=false;
	    if (change>1.0e-14) {
	      startingTheta=useTheta;
	      lastTheta=startingTheta;
	      change=0.0;
	      // restore rhs
	      const double * saveLower = paramData.lowerChange+2*numberTotal;
	      memcpy(columnLower_,saveLower,numberColumns_*sizeof(double));
	      memcpy(rowLower_,saveLower+numberColumns_,numberRows_*sizeof(double));
	      const double * saveUpper = paramData.upperChange+2*numberTotal;
	      memcpy(columnUpper_,saveUpper,numberColumns_*sizeof(double));
	      memcpy(rowUpper_,saveUpper+numberColumns_,numberRows_*sizeof(double));
	      paramData.startingTheta=startingTheta;
	      computeRhsEtc(paramData);
	      redoInternalArrays();
	      // Update solution
	      rowArray_[4]->clear();
	      for (int i=0;i<numberTotal;i++) {
		if (getStatus(i)==atLowerBound||getStatus(i)==isFixed)
		  solution_[i]=lower_[i];
		else if (getStatus(i)==atUpperBound)
		  solution_[i]=upper_[i];
	      }
	      gutsOfSolution(NULL,NULL);
	    }
	  }
	  if (change>1.0e-14) {
	    int n;
	    n=lowerList[-1];
	    for (int i=0;i<n;i++) {
	      int iSequence = lowerList[i];
	      double thisChange = change * lowerChange[iSequence];
	      double newValue = lower_[iSequence] + thisChange;
	      lower_[iSequence] = newValue;
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
	      if (getStatus(iSequence)==basic) {
		int iRow=backwardBasic[iSequence];
		lowerGap[iRow] -= thisChange;
	      } else if(getStatus(iSequence)==atLowerBound) {
		solution_[iSequence] = newValue;
	      }
#else
	      if(getStatus(iSequence)==atLowerBound) {
		solution_[iSequence] = newValue;
	      }
#endif
#if 0
	      // may have to adjust other bound
	      double otherValue = upper_[iSequence];
	      if (otherValue-newValue<dualBound_) {
		//originalBound(iSequence,useTheta,lowerChange,upperChange);
		//reinterpret_cast<ClpSimplexDual *> ( this)->changeBound(iSequence);
		//ClpTraceDebug (fabs(lower_[iSequence]-newValue)<1.0e-5);
	      }
#endif
	    }
	    n=upperList[-1];
	    for (int i=0;i<n;i++) {
	      int iSequence = upperList[i];
	      double thisChange = change * upperChange[iSequence];
	      double newValue = upper_[iSequence] + thisChange;
	      upper_[iSequence] = newValue;
	      if(getStatus(iSequence)==atUpperBound||
		 getStatus(iSequence)==isFixed) {
		solution_[iSequence] = newValue;
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
	      } else if (getStatus(iSequence)==basic) {
		int iRow=backwardBasic[iSequence];
		upperGap[iRow] += thisChange;
#endif
	      }
	      // may have to adjust other bound
	      double otherValue = lower_[iSequence];
	      if (newValue-otherValue<dualBound_) {
		//originalBound(iSequence,useTheta,lowerChange,upperChange);
		//reinterpret_cast<ClpSimplexDual *> ( this)->changeBound(iSequence);
		//ClpTraceDebug (fabs(upper_[iSequence]-newValue)<1.0e-5);
	      }
	    }
	  }
	  sequenceIn_=-1;
          if (pivotType) {
	    if (useTheta>lastTheta+1.0e-9) {
	      handler_->message(CLP_PARAMETRICS_STATS, messages_)
		<< useTheta << objectiveValue() << CoinMessageEol;
	      lastTheta = useTheta;
	    }
	    problemStatus_ = -2;
	    if (!factorization_->pivots()&&pivotRow_<0)
	      problemStatus_=2;
#ifdef CLP_USER_DRIVEN
	    {
	      double saveTheta=theta_;
	      theta_ = endingTheta;
	      if (problemStatus_==2&&theta_>paramData.acceptableMaxTheta)
		theta_=COIN_DBL_MAX; // we have finished
	      int status=eventHandler_->event(ClpEventHandler::theta);
	      if (status>=0&&status<10) {
		endingTheta=theta_;
		problemStatus_=-1;
		continue;
	      } else {
		if (status>=10)
		  problemStatus_=status-10;
		if (status<0)
		  startingTheta = useTheta;
	      }
	      theta_=saveTheta;
	    }
#else
	    startingTheta = useTheta;
#endif
	    return 4;
	  }
          // choose row to go out
          //reinterpret_cast<ClpSimplexDual *> ( this)->dualRow(-1);
          if (pivotRow_ >= 0) {
               // we found a pivot row
               if (handler_->detail(CLP_SIMPLEX_PIVOTROW, messages_) < 100) {
                    handler_->message(CLP_SIMPLEX_PIVOTROW, messages_)
                              << pivotRow_
                              << CoinMessageEol;
               }
               // check accuracy of weights
               dualRowPivot_->checkAccuracy();
               // do ratio test for normal iteration
               double bestPossiblePivot = bestPivot();
               if (sequenceIn_ >= 0) {
                    // normal iteration
                    // update the incoming column
                    double btranAlpha = -alpha_ * directionOut_; // for check
#ifndef COIN_FAC_NEW
                    unpackPacked(rowArray_[1]);
#else
                    unpack(rowArray_[1]);
#endif
                    // and update dual weights (can do in parallel - with extra array)
		    rowArray_[2]->clear();
                    alpha_ = dualRowPivot_->updateWeights(rowArray_[0],
                                                          rowArray_[2],
                                                          rowArray_[3],
                                                          rowArray_[1]);
                    // see if update stable
#ifdef CLP_DEBUG
                    if ((handler_->logLevel() & 32))
                         printf("btran alpha %g, ftran alpha %g\n", btranAlpha, alpha_);
#endif
                    double checkValue = 1.0e-7;
                    // if can't trust much and long way from optimal then relax
                    if (largestPrimalError_ > 10.0)
                         checkValue = CoinMin(1.0e-4, 1.0e-8 * largestPrimalError_);
                    if (fabs(btranAlpha) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
                              fabs(btranAlpha - alpha_) > checkValue*(1.0 + fabs(alpha_))) {
                         handler_->message(CLP_DUAL_CHECK, messages_)
                                   << btranAlpha
                                   << alpha_
                                   << CoinMessageEol;
			 // clear arrays
			 rowArray_[4]->clear();
                         if (factorization_->pivots()) {
                              dualRowPivot_->unrollWeights();
                              problemStatus_ = -2; // factorize now
                              rowArray_[0]->clear();
                              rowArray_[1]->clear();
                              columnArray_[0]->clear();
                              returnCode = -2;
                              break;
                         } else {
                              // take on more relaxed criterion
                              double test;
                              if (fabs(btranAlpha) < 1.0e-8 || fabs(alpha_) < 1.0e-8)
                                   test = 1.0e-1 * fabs(alpha_);
                              else
                                   test = 1.0e-4 * (1.0 + fabs(alpha_));
                              if (fabs(btranAlpha) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
                                        fabs(btranAlpha - alpha_) > test) {
                                   dualRowPivot_->unrollWeights();
                                   // need to reject something
                                   char x = isColumn(sequenceOut_) ? 'C' : 'R';
                                   handler_->message(CLP_SIMPLEX_FLAG, messages_)
                                             << x << sequenceWithin(sequenceOut_)
                                             << CoinMessageEol;
                                   setFlagged(sequenceOut_);
                                   progress_.clearBadTimes();
                                   lastBadIteration_ = numberIterations_; // say be more cautious
                                   rowArray_[0]->clear();
                                   rowArray_[1]->clear();
                                   columnArray_[0]->clear();
                                   if (fabs(alpha_) < 1.0e-10 && fabs(btranAlpha) < 1.0e-8 && numberIterations_ > 100) {
                                        //printf("I think should declare infeasible\n");
                                        problemStatus_ = 1;
                                        returnCode = 1;
                                        break;
                                   }
                                   continue;
                              }
                         }
                    }
                    // update duals BEFORE replaceColumn so can do updateColumn
                    double objectiveChange = 0.0;
                    // do duals first as variables may flip bounds
                    // rowArray_[0] and columnArray_[0] may have flips
                    // so use rowArray_[3] for work array from here on
                    int nswapped = 0;
                    //rowArray_[0]->cleanAndPackSafe(1.0e-60);
                    //columnArray_[0]->cleanAndPackSafe(1.0e-60);
#if CLP_CAN_HAVE_ZERO_OBJ
		    if ((specialOptions_&2097152)==0) {
#endif
		      nswapped = reinterpret_cast<ClpSimplexDual *> ( this)->updateDualsInDual(rowArray_[0], columnArray_[0],
											       rowArray_[2], theta_,
											       objectiveChange, false);
		      assert (!nswapped);
#if CLP_CAN_HAVE_ZERO_OBJ
		    } else {
		      rowArray_[0]->clear();
		      rowArray_[2]->clear();
		      columnArray_[0]->clear();
		    }
#endif
                    // which will change basic solution
                    if (nswapped) {
		      abort(); //needs testing
                         factorization_->updateColumn(rowArray_[3], rowArray_[2]);
                         dualRowPivot_->updatePrimalSolution(rowArray_[2],
                                                             1.0, objectiveChange);
                         // recompute dualOut_
                         valueOut_ = solution_[sequenceOut_];
                         if (directionOut_ < 0) {
                              dualOut_ = valueOut_ - upperOut_;
                         } else {
                              dualOut_ = lowerOut_ - valueOut_;
                         }
                    }
                    // amount primal will move
                    double movement = -dualOut_ * directionOut_ / alpha_;
                    // so objective should increase by fabs(dj)*movement
                    // but we already have objective change - so check will be good
                    if (objectiveChange + fabs(movement * dualIn_) < -1.0e-5) {
#ifdef CLP_DEBUG
                         if (handler_->logLevel() & 32)
                              printf("movement %g, swap change %g, rest %g  * %g\n",
                                     objectiveChange + fabs(movement * dualIn_),
                                     objectiveChange, movement, dualIn_);
#endif
			 assert (objectiveChange + fabs(movement * dualIn_) >= -1.0e-5);
                         if(factorization_->pivots()) {
                              // going backwards - factorize
                              dualRowPivot_->unrollWeights();
                              problemStatus_ = -2; // factorize now
                              returnCode = -2;
                              break;
                         }
                    }
                    CoinAssert(fabs(dualOut_) < 1.0e50);
                    // if stable replace in basis
                    int updateStatus = factorization_->replaceColumn(this,
                                       rowArray_[2],
                                       rowArray_[1],
                                       pivotRow_,
                                       alpha_);
                    // if no pivots, bad update but reasonable alpha - take and invert
                    if (updateStatus == 2 &&
                              !factorization_->pivots() && fabs(alpha_) > 1.0e-5)
                         updateStatus = 4;
                    if (updateStatus == 1 || updateStatus == 4) {
                         // slight error
                         if (factorization_->pivots() > 5 || updateStatus == 4) {
                              problemStatus_ = -2; // factorize now
                              returnCode = -3;
                         }
                    } else if (updateStatus == 2) {
                         // major error
                         dualRowPivot_->unrollWeights();
                         // later we may need to unwind more e.g. fake bounds
                         if (factorization_->pivots()) {
                              problemStatus_ = -2; // factorize now
                              returnCode = -2;
                              break;
                         } else {
                              // need to reject something
                              char x = isColumn(sequenceOut_) ? 'C' : 'R';
                              handler_->message(CLP_SIMPLEX_FLAG, messages_)
                                        << x << sequenceWithin(sequenceOut_)
                                        << CoinMessageEol;
                              setFlagged(sequenceOut_);
                              progress_.clearBadTimes();
                              lastBadIteration_ = numberIterations_; // say be more cautious
                              rowArray_[0]->clear();
                              rowArray_[1]->clear();
                              columnArray_[0]->clear();
                              // make sure dual feasible
                              // look at all rows and columns
                              double objectiveChange = 0.0;
                              reinterpret_cast<ClpSimplexDual *> ( this)->updateDualsInDual(rowArray_[0], columnArray_[0], rowArray_[1],
                                        0.0, objectiveChange, true);
                              continue;
                         }
                    } else if (updateStatus == 3) {
                         // out of memory
                         // increase space if not many iterations
                         if (factorization_->pivots() <
                                   0.5 * factorization_->maximumPivots() &&
                                   factorization_->pivots() < 200)
                              factorization_->areaFactor(
                                   factorization_->areaFactor() * 1.1);
                         problemStatus_ = -2; // factorize now
                    } else if (updateStatus == 5) {
                         problemStatus_ = -2; // factorize now
                    }
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
		    int * lowerActive = paramData.lowerActive;
		    int * upperActive = paramData.upperActive;
#endif
		    // update change vector
		    {
		      double * work = rowArray_[1]->denseVector();
		      int number = rowArray_[1]->getNumElements();
		      int * which = rowArray_[1]->getIndices();
		      assert (!rowArray_[4]->packedMode());
#ifndef COIN_FAC_NEW
		      assert (rowArray_[1]->packedMode());
#else
		      assert (!rowArray_[1]->packedMode());
#endif
		      double pivotValue = rowArray_[4]->denseVector()[pivotRow_];
		      double multiplier = -pivotValue/alpha_;
		      double * array=rowArray_[4]->denseVector();
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
		      int lowerN=lowerActive[-1];
		      int upperN=upperActive[-1];
#endif
		      if (multiplier) {
			for (int i = 0; i < number; i++) {
			  int iRow = which[i];
#ifndef COIN_FAC_NEW
			  double alpha=multiplier*work[i];
#else
			  double alpha=multiplier*work[iRow];
#endif
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
			  double alpha3 = alpha+array[iRow];
			  int iSequence = pivotVariable_[iRow];
			  double oldLower = lowerCoefficient[iRow];
			  double oldUpper = upperCoefficient[iRow];
			  if (lower_[iSequence]>-1.0e30) {
			    //lowerGap[iRow]=value-lower_[iSequence];
			    double alpha2 = alpha3 + lowerChange[iSequence];
			    if (alpha2>1.0e-8)  {
			      lowerCoefficient[iRow]=alpha2;
			      if (!oldLower)
				lowerActive[lowerN++]=iRow;
			    } else {
			      if (oldLower)
				lowerCoefficient[iRow]=COIN_DBL_MIN;
			    }
			  } else {
			    if (oldLower)
			      lowerCoefficient[iRow]=COIN_DBL_MIN;
			  }
			  if (upper_[iSequence]<1.0e30) {
			    //upperGap[iRow]=-(value-upper_[iSequence]);
			    double alpha2 = -(alpha3+upperChange[iSequence]);
			    if (alpha2>1.0e-8) {
			      upperCoefficient[iRow]=alpha2;
			      if (!oldUpper)
				upperActive[upperN++]=iRow;
			    } else {
			      if (oldUpper)
				upperCoefficient[iRow]=COIN_DBL_MIN;
			    }
			  } else {
			    if (oldUpper)
			      upperCoefficient[iRow]=COIN_DBL_MIN;
			  }
#endif
			  rowArray_[4]->quickAdd(iRow,alpha);
			}
		      }
		      pivotValue = array[pivotRow_];
		      // we want pivot to be -multiplier
		      rowArray_[4]->quickAdd(pivotRow_,-multiplier-pivotValue);
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
		      assert (lowerN>=0&&lowerN<=numberRows_);
		      lowerActive[-1]=lowerN;
		      upperActive[-1]=upperN;
#endif
		    }
                    // update primal solution
#if CLP_CAN_HAVE_ZERO_OBJ
		    if ((specialOptions_&2097152)!=0) 
		      theta_=0.0;
#endif
                    if (theta_ < 0.0) {
#ifdef CLP_DEBUG
                         if (handler_->logLevel() & 32)
                              printf("negative theta %g\n", theta_);
#endif
                         theta_ = 0.0;
                    }
                    // do actual flips
                    reinterpret_cast<ClpSimplexDual *> ( this)->flipBounds(rowArray_[0], columnArray_[0]);
                    //rowArray_[1]->expand();
#ifndef CLP_PARAMETRIC_DENSE_ARRAYS
                    dualRowPivot_->updatePrimalSolution(rowArray_[1],
                                                        movement,
                                                        objectiveChange);
#else
		    // do by hand
		    {
		      double * work = rowArray_[1]->denseVector();
		      int number = rowArray_[1]->getNumElements();
		      int * which = rowArray_[1]->getIndices();
		      int i;
		      if (rowArray_[1]->packedMode()) {
			for (i = 0; i < number; i++) {
			  int iRow = which[i];
			  int iSequence = pivotVariable_[iRow];
			  double value = solution_[iSequence];
			  double change = movement * work[i];
			  value -= change;
			  if (lower_[iSequence]>-1.0e30)
			    lowerGap[iRow]=value-lower_[iSequence];
			  if (upper_[iSequence]<1.0e30)
			    upperGap[iRow]=-(value-upper_[iSequence]);
			  solution_[iSequence] = value;
			  objectiveChange -= change * cost_[iSequence];
			  work[i] = 0.0;
			}
		      } else {
			for (i = 0; i < number; i++) {
			  int iRow = which[i];
			  int iSequence = pivotVariable_[iRow];
			  double value = solution_[iSequence];
			  double change = movement * work[iRow];
			  value -= change;
			  solution_[iSequence] = value;
			  objectiveChange -= change * cost_[iSequence];
			  work[iRow] = 0.0;
			}
		      }
		      rowArray_[1]->setNumElements(0);
		    }
#endif
                    // modify dualout
                    dualOut_ /= alpha_;
                    dualOut_ *= -directionOut_;
                    //setStatus(sequenceIn_,basic);
                    dj_[sequenceIn_] = 0.0;
                    //double oldValue = valueIn_;
                    if (directionIn_ == -1) {
                         // as if from upper bound
                         valueIn_ = upperIn_ + dualOut_;
                    } else {
                         // as if from lower bound
                         valueIn_ = lowerIn_ + dualOut_;
                    }
		    objectiveChange = 0.0;
#if CLP_CAN_HAVE_ZERO_OBJ
		    if ((specialOptions_&2097152)==0) {
#endif
		      for (int i=0;i<numberTotal;i++)
			objectiveChange += solution_[i]*cost_[i];
		      objectiveChange -= objectiveValue_;
#if CLP_CAN_HAVE_ZERO_OBJ
		    }
#endif
                    // outgoing
                    originalBound(sequenceOut_,useTheta,lowerChange,upperChange);
		    lowerOut_=lower_[sequenceOut_];
		    upperOut_=upper_[sequenceOut_];
                    // set dj to zero unless values pass
                    if (directionOut_ > 0) {
                         valueOut_ = lowerOut_;
                         dj_[sequenceOut_] = theta_;
#if CLP_CAN_HAVE_ZERO_OBJ>1
#ifdef COIN_REUSE_RANDOM
			 if ((specialOptions_&2097152)!=0) {
			   dj_[sequenceOut_] = 1.0e-9*(1.0+CoinDrand48());;
			 }
#endif
#endif
                    } else {
                         valueOut_ = upperOut_;
                         dj_[sequenceOut_] = -theta_;
#if CLP_CAN_HAVE_ZERO_OBJ>1
#ifdef COIN_REUSE_RANDOM
			 if ((specialOptions_&2097152)!=0) {
			   dj_[sequenceOut_] = -1.0e-9*(1.0+CoinDrand48());;
			 }
#endif
#endif
                    }
                    solution_[sequenceOut_] = valueOut_;
                    int whatNext = housekeeping(objectiveChange);
		    reinterpret_cast<ClpSimplexDual *>(this)->originalBound(sequenceIn_);
		    assert (backwardBasic[sequenceOut_]==pivotRow_);
		    backwardBasic[sequenceOut_]=-1;
		    backwardBasic[sequenceIn_]=pivotRow_;
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
		    double value = solution_[sequenceIn_];
		    double alpha = rowArray_[4]->denseVector()[pivotRow_];
		    double oldLower = lowerCoefficient[pivotRow_];
		    double oldUpper = upperCoefficient[pivotRow_];
		    if (lower_[sequenceIn_]>-1.0e30) {
		      lowerGap[pivotRow_]=value-lower_[sequenceIn_];
		      double alpha2 = alpha + lowerChange[sequenceIn_];
		      if (alpha2>1.0e-8)  {
			lowerCoefficient[pivotRow_]=alpha2;
			if (!oldLower) {
			  int lowerN=lowerActive[-1];
			  assert (lowerN>=0&&lowerN<numberRows_);
			  lowerActive[lowerN]=pivotRow_;
			  lowerActive[-1]=lowerN+1;
			}
		      } else {
			if (oldLower)
			  lowerCoefficient[pivotRow_]=COIN_DBL_MIN;
		      }
		    } else {
		      if (oldLower)
			lowerCoefficient[pivotRow_]=COIN_DBL_MIN;
		    }
		    if (upper_[sequenceIn_]<1.0e30) {
		      upperGap[pivotRow_]=-(value-upper_[sequenceIn_]);
		      double alpha2 = -(alpha+upperChange[sequenceIn_]);
		      if (alpha2>1.0e-8) {
			upperCoefficient[pivotRow_]=alpha2;
			if (!oldUpper) {
			  int upperN=upperActive[-1];
			  assert (upperN>=0&&upperN<numberRows_);
			  upperActive[upperN]=pivotRow_;
			  upperActive[-1]=upperN+1;
			}
		      } else {
			if (oldUpper)
			  upperCoefficient[pivotRow_]=COIN_DBL_MIN;
		      }
		    } else {
		      if (oldUpper)
			upperCoefficient[pivotRow_]=COIN_DBL_MIN;
		    }
#endif
		    {
		      char in[200],out[200];
		      int iSequence=sequenceIn_;
		      if (iSequence<numberColumns_) {
			if (lengthNames_) 
			  strcpy(in,columnNames_[iSequence].c_str());
			 else 
			  sprintf(in,"C%7.7d",iSequence);
		      } else {
			iSequence -= numberColumns_;
			if (lengthNames_) 
			  strcpy(in,rowNames_[iSequence].c_str());
			 else 
			  sprintf(in,"R%7.7d",iSequence);
		      }
		      iSequence=sequenceOut_;
		      if (iSequence<numberColumns_) {
			if (lengthNames_) 
			  strcpy(out,columnNames_[iSequence].c_str());
			 else 
			  sprintf(out,"C%7.7d",iSequence);
		      } else {
			iSequence -= numberColumns_;
			if (lengthNames_) 
			  strcpy(out,rowNames_[iSequence].c_str());
			 else 
			  sprintf(out,"R%7.7d",iSequence);
		      }
		      handler_->message(CLP_PARAMETRICS_STATS2, messages_)
			<< useTheta << objectiveValue() 
			<< in << out << CoinMessageEol;
		    }
		    if (useTheta>lastTheta+1.0e-9) {
		      handler_->message(CLP_PARAMETRICS_STATS, messages_)
			<< useTheta << objectiveValue() << CoinMessageEol;
		      lastTheta = useTheta;
		    }
                    // and set bounds correctly
                    originalBound(sequenceIn_,useTheta,lowerChange,upperChange);
                    reinterpret_cast<ClpSimplexDual *> ( this)->changeBound(sequenceOut_);
                    if (whatNext == 1) {
                         problemStatus_ = -2; // refactorize
                    } else if (whatNext == 2) {
                         // maximum iterations or equivalent
                         problemStatus_ = 3;
                         returnCode = 3;
                         break;
                    }
#ifdef CLP_USER_DRIVEN
                    // Check event
                    {
                         int status = eventHandler_->event(ClpEventHandler::endOfIteration);
                         if (status >= 0) {
                              problemStatus_ = 5;
                              secondaryStatus_ = ClpEventHandler::endOfIteration;
                              returnCode = 4;
                              break;
                         }
                    }
#endif
               } else {
                    // no incoming column is valid
#ifdef CLP_USER_DRIVEN
		 rowArray_[0]->clear();
		 columnArray_[0]->clear();
		 theta_ = useTheta;
		 lastTheta = useTheta;
		 int action = eventHandler_->event(ClpEventHandler::noTheta);
		 if (action>=0) {
		   endingTheta=theta_;
		   theta_ = 0.0;
		   //adjust [4] from handler - but
		   //rowArray_[4]->clear(); // temp
		   if (action>=0&&action<10)
		     problemStatus_=-1; // carry on
		   else if (action==15)
		     problemStatus_ =5; // say stopped
		   returnCode = 1;
		   if (action==0||action>=10) 
		     break;
		   else
		     continue;
		 } else {
		 theta_ = 0.0;
		 }
#endif
                    pivotRow_ = -1;
#ifdef CLP_DEBUG
                    if (handler_->logLevel() & 32)
                         printf("** no column pivot\n");
#endif
                    if (factorization_->pivots() < 10) { 
                         // If we have just factorized and infeasibility reasonable say infeas
                         if (((specialOptions_ & 4096) != 0 || bestPossiblePivot < 1.0e-11) && dualBound_ > 1.0e8) {
                              if (valueOut_ > upperOut_ + 1.0e-3 || valueOut_ < lowerOut_ - 1.0e-3
                                        || (specialOptions_ & 64) == 0) {
                                   // say infeasible
                                   problemStatus_ = 1;
                                   // unless primal feasible!!!!
                                   //printf("%d %g %d %g\n",numberPrimalInfeasibilities_,sumPrimalInfeasibilities_,
                                   //     numberDualInfeasibilities_,sumDualInfeasibilities_);
                                   if (numberDualInfeasibilities_)
                                        problemStatus_ = 10;
                                   rowArray_[0]->clear();
                                   columnArray_[0]->clear();
                              }
                         }
                         // If special option set - put off as long as possible
                         if ((specialOptions_ & 64) == 0) {
                              problemStatus_ = -4; //say looks infeasible
                         } else {
                              // flag
                              char x = isColumn(sequenceOut_) ? 'C' : 'R';
                              handler_->message(CLP_SIMPLEX_FLAG, messages_)
                                        << x << sequenceWithin(sequenceOut_)
                                        << CoinMessageEol;
                              setFlagged(sequenceOut_);
                              if (!factorization_->pivots()) {
                                   rowArray_[0]->clear();
                                   columnArray_[0]->clear();
                                   continue;
                              }
                         }
                    }
                    rowArray_[0]->clear();
                    columnArray_[0]->clear();
                    returnCode = 1;
                    break;
               }
          } else {
               // no pivot row
#ifdef CLP_USER_DRIVEN
	    {
	      double saveTheta=theta_;
	      theta_ = endingTheta;
	      int status=eventHandler_->event(ClpEventHandler::theta);
	      if (status>=0&&status<10) {
		endingTheta=theta_;
		theta_=saveTheta;
		continue;
	      } else {
		theta_=saveTheta;
	      }
	    }
#endif
#ifdef CLP_DEBUG
               if (handler_->logLevel() & 32)
                    printf("** no row pivot\n");
#endif
               int numberPivots = factorization_->pivots();
               bool specialCase;
               int useNumberFake;
               returnCode = 0;
               if (numberPivots < 20 &&
                         (specialOptions_ & 2048) != 0 && !numberChanged_ && perturbation_ >= 100
                         && dualBound_ > 1.0e8) {
                    specialCase = true;
                    // as dual bound high - should be okay
                    useNumberFake = 0;
               } else {
                    specialCase = false;
                    useNumberFake = numberFake_;
               }
               if (!numberPivots || specialCase) {
                    // may have crept through - so may be optimal
                    // check any flagged variables
                    int iRow;
                    for (iRow = 0; iRow < numberRows_; iRow++) {
                         int iPivot = pivotVariable_[iRow];
                         if (flagged(iPivot))
                              break;
                    }
                    if (iRow < numberRows_ && numberPivots) {
                         // try factorization
                         returnCode = -2;
                    }

                    if (useNumberFake || numberDualInfeasibilities_) {
                         // may be dual infeasible
                         problemStatus_ = -5;
                    } else {
                         if (iRow < numberRows_) {
                              problemStatus_ = -5;
                         } else {
                              if (numberPivots) {
                                   // objective may be wrong
                                   objectiveValue_ = innerProduct(cost_,
                                                                  numberColumns_ + numberRows_,
                                                                  solution_);
                                   objectiveValue_ += objective_->nonlinearOffset();
                                   objectiveValue_ /= (objectiveScale_ * rhsScale_);
                                   if ((specialOptions_ & 16384) == 0) {
                                        // and dual_ may be wrong (i.e. for fixed or basic)
                                        CoinIndexedVector * arrayVector = rowArray_[1];
                                        arrayVector->clear();
                                        int iRow;
                                        double * array = arrayVector->denseVector();
                                        /* Use dual_ instead of array
                                           Even though dual_ is only numberRows_ long this is
                                           okay as gets permuted to longer rowArray_[2]
                                        */
                                        arrayVector->setDenseVector(dual_);
                                        int * index = arrayVector->getIndices();
                                        int number = 0;
                                        for (iRow = 0; iRow < numberRows_; iRow++) {
                                             int iPivot = pivotVariable_[iRow];
                                             double value = cost_[iPivot];
                                             dual_[iRow] = value;
                                             if (value) {
                                                  index[number++] = iRow;
                                             }
                                        }
                                        arrayVector->setNumElements(number);
                                        // Extended duals before "updateTranspose"
                                        matrix_->dualExpanded(this, arrayVector, NULL, 0);
                                        // Btran basic costs
                                        rowArray_[2]->clear();
                                        factorization_->updateColumnTranspose(rowArray_[2], arrayVector);
                                        // and return vector
                                        arrayVector->setDenseVector(array);
                                   }
                              }
                              problemStatus_ = 0;
                              sumPrimalInfeasibilities_ = 0.0;
                              if ((specialOptions_&(1024 + 16384)) != 0) {
                                   CoinIndexedVector * arrayVector = rowArray_[1];
                                   arrayVector->clear();
                                   double * rhs = arrayVector->denseVector();
                                   times(1.0, solution_, rhs);
                                   bool bad2 = false;
                                   int i;
                                   for ( i = 0; i < numberRows_; i++) {
                                        if (rhs[i] < rowLowerWork_[i] - primalTolerance_ ||
                                                  rhs[i] > rowUpperWork_[i] + primalTolerance_) {
                                             bad2 = true;
                                        } else if (fabs(rhs[i] - rowActivityWork_[i]) > 1.0e-3) {
                                        }
                                        rhs[i] = 0.0;
                                   }
                                   for ( i = 0; i < numberColumns_; i++) {
                                        if (solution_[i] < columnLowerWork_[i] - primalTolerance_ ||
                                                  solution_[i] > columnUpperWork_[i] + primalTolerance_) {
                                             bad2 = true;
                                        }
                                   }
                                   if (bad2) {
                                        problemStatus_ = -3;
                                        returnCode = -2;
                                        // Force to re-factorize early next time
                                        int numberPivots = factorization_->pivots();
                                        forceFactorization_ = CoinMin(forceFactorization_, (numberPivots + 1) >> 1);
                                   }
                              }
                         }
                    }
               } else {
                    problemStatus_ = -3;
                    returnCode = -2;
                    // Force to re-factorize early next time
                    int numberPivots = factorization_->pivots();
                    forceFactorization_ = CoinMin(forceFactorization_, (numberPivots + 1) >> 1);
               }
               break;
          }
     }
     startingTheta = lastTheta+theta_;
     return returnCode;
}
// Compute new rowLower_ etc (return negative if infeasible - otherwise largest change)
double 
ClpSimplexOther::computeRhsEtc( parametricsData & paramData)
{
  double maxTheta = COIN_DBL_MAX;
  double largestChange=0.0;
  double startingTheta = paramData.startingTheta;
  const double * lowerChange = paramData.lowerChange+
    paramData.unscaledChangesOffset;
  const double * upperChange = paramData.upperChange+
    paramData.unscaledChangesOffset;
  for (int iRow = 0; iRow < numberRows_; iRow++) {
    double lower = rowLower_[iRow];
    double upper = rowUpper_[iRow];
    double chgLower = lowerChange[numberColumns_+iRow];
    largestChange=CoinMax(largestChange,fabs(chgLower));
    double chgUpper = upperChange[numberColumns_+iRow];
    largestChange=CoinMax(largestChange,fabs(chgUpper));
    if (lower > -1.0e30 && upper < 1.0e30) {
      if (lower + maxTheta * chgLower > upper + maxTheta * chgUpper) {
	maxTheta = (upper - lower) / (chgLower - chgUpper);
      }
    }
    lower+=startingTheta*chgLower;
    upper+=startingTheta*chgUpper;
#ifndef CLP_USER_DRIVEN
    if (lower > upper) {
      maxTheta = -1.0;
      break;
    }
#endif
    rowLower_[iRow]=lower;
    rowUpper_[iRow]=upper;
  }
  for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
    double lower = columnLower_[iColumn];
    double upper = columnUpper_[iColumn];
    double chgLower = lowerChange[iColumn];
    largestChange=CoinMax(largestChange,fabs(chgLower));
    double chgUpper = upperChange[iColumn];
    largestChange=CoinMax(largestChange,fabs(chgUpper));
    if (lower > -1.0e30 && upper < 1.0e30) {
      if (lower + maxTheta * chgLower > upper + maxTheta * chgUpper) {
	maxTheta = (upper - lower) / (chgLower - chgUpper);
      }
    }
    lower+=startingTheta*chgLower;
    upper+=startingTheta*chgUpper;
#ifndef CLP_USER_DRIVEN
    if (lower > upper) {
      maxTheta = -1.0;
      break;
    }
#endif
    columnLower_[iColumn]=lower;
    columnUpper_[iColumn]=upper;
  }
#ifndef CLP_USER_DRIVEN
  paramData.maxTheta=maxTheta;
  if (maxTheta<0)
    largestChange=-1.0; // signal infeasible
#else
  // maxTheta already set
  /* given largest change element choose acceptable end
     be safe and make sure difference < 0.1*tolerance */
  double acceptableDifference=0.1*primalTolerance_/
    CoinMax(largestChange,1.0);
  paramData.acceptableMaxTheta=maxTheta-acceptableDifference;
#endif
  return largestChange;
}
// Redo lower_ from rowLower_ etc
void 
ClpSimplexOther::redoInternalArrays()
{
  double * lowerSave = lower_;
  double * upperSave = upper_;
  memcpy(lowerSave,columnLower_,numberColumns_*sizeof(double));
  memcpy(lowerSave+numberColumns_,rowLower_,numberRows_*sizeof(double));
  memcpy(upperSave,columnUpper_,numberColumns_*sizeof(double));
  memcpy(upperSave+numberColumns_,rowUpper_,numberRows_*sizeof(double));
  if (rowScale_) {
    // scale arrays
    for (int i=0;i<numberColumns_;i++) {
      double multiplier = inverseColumnScale_[i];
      if (lowerSave[i]>-1.0e20)
	lowerSave[i] *= multiplier;
      if (upperSave[i]<1.0e20)
	upperSave[i] *= multiplier;
    }
    lowerSave += numberColumns_;
    upperSave += numberColumns_;
    for (int i=0;i<numberRows_;i++) {
      double multiplier = rowScale_[i];
      if (lowerSave[i]>-1.0e20)
	lowerSave[i] *= multiplier;
      if (upperSave[i]<1.0e20)
	upperSave[i] *= multiplier;
    }
  }
}
#if 0
static int zzzzzz=0;
int zzzzzzOther=0;
#endif
// Finds best possible pivot
double 
ClpSimplexOther::bestPivot(bool justColumns)
{
  // Get good size for pivot
  // Allow first few iterations to take tiny
  double acceptablePivot = 1.0e-9;
  if (numberIterations_ > 100)
    acceptablePivot = 1.0e-8;
  if (factorization_->pivots() > 10 ||
      (factorization_->pivots() && sumDualInfeasibilities_))
    acceptablePivot = 1.0e-5; // if we have iterated be more strict
  else if (factorization_->pivots() > 5)
    acceptablePivot = 1.0e-6; // if we have iterated be slightly more strict
  else if (factorization_->pivots())
    acceptablePivot = 1.0e-8; // relax
  double bestPossiblePivot = 1.0;
  // get sign for finding row of tableau
  // normal iteration
  // create as packed
  double direction = directionOut_;
#ifndef COIN_FAC_NEW
  rowArray_[0]->createPacked(1, &pivotRow_, &direction);
#else
  rowArray_[0]->createOneUnpackedElement(pivotRow_, direction);
#endif
  factorization_->updateColumnTranspose(rowArray_[1], rowArray_[0]);
  // put row of tableau in rowArray[0] and columnArray[0]
  matrix_->transposeTimes(this, -1.0,
			  rowArray_[0], rowArray_[3], columnArray_[0]);
  sequenceIn_=-1;
  if (justColumns)
    rowArray_[0]->clear();
  // do ratio test for normal iteration
  bestPossiblePivot = 
    reinterpret_cast<ClpSimplexDual *> 
    ( this)->dualColumn(rowArray_[0],
			columnArray_[0], columnArray_[1],
			rowArray_[3], acceptablePivot, NULL);
  return bestPossiblePivot;
}
// Computes next theta and says if objective or bounds (0= bounds, 1 objective, -1 none)
int
ClpSimplexOther::nextTheta(int /*type*/, double maxTheta, parametricsData & paramData,
                           const double * /*changeObjective*/)
{
  const double * lowerChange = paramData.lowerChange;
  const double * upperChange = paramData.upperChange;
  const int * lowerList = paramData.lowerList;
  const int * upperList = paramData.upperList;
  int iSequence;
  bool toLower = false;
  //assert (type==1);
  // may need to decide based on model?
  bool needFullUpdate = rowArray_[4]->getNumElements()==0;
  double * array = rowArray_[4]->denseVector();
  //rowArray_[4]->checkClean();
  const int * row = matrix_->getIndices();
  const int * columnLength = matrix_->getVectorLengths();
  const CoinBigIndex * columnStart = matrix_->getVectorStarts();
  const double * elementByColumn = matrix_->getElements();
#if 0
  double tempArray[5000];
  bool checkIt=false;
  if (factorization_->pivots()&&!needFullUpdate&&sequenceIn_<0) {
    memcpy(tempArray,array,numberRows_*sizeof(double));
    checkIt=true;
    needFullUpdate=true;
  }
#endif
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
  double * lowerGap = paramData.lowerGap;
  double * upperGap = paramData.upperGap;
  double * lowerCoefficient = paramData.lowerCoefficient;
  double * upperCoefficient = paramData.upperCoefficient;
  int * lowerActive=paramData.lowerActive;
  int * upperActive=paramData.upperActive;
#endif
  if (!factorization_->pivots()||needFullUpdate) {
    //zzzzzz=0;
    rowArray_[4]->clear();
    // get change
    if (!rowScale_) {
      int n;
      n=lowerList[-2];
      int i;
      for (i=0;i<n;i++) {
	int iSequence = lowerList[i];
	assert (iSequence<numberColumns_);
	if (getColumnStatus(iSequence)==atLowerBound) {
	  double value=lowerChange[iSequence];
	  for (CoinBigIndex j = columnStart[iSequence];
	       j < columnStart[iSequence] + columnLength[iSequence]; j++) {
	    rowArray_[4]->quickAdd(row[j], elementByColumn[j]*value);
	  }
	}
      }
      n=lowerList[-1];
      const double * change = lowerChange+numberColumns_;
      for (;i<n;i++) {
	int iSequence = lowerList[i]-numberColumns_;
	assert (iSequence>=0);
	if (getRowStatus(iSequence)==atLowerBound) {
	  double value=change[iSequence];
	  rowArray_[4]->quickAdd(iSequence, -value);
	}
      }
      n=upperList[-2];
      for (i=0;i<n;i++) {
	int iSequence = upperList[i];
	assert (iSequence<numberColumns_);
	if (getColumnStatus(iSequence)==atUpperBound) {
	  double value=upperChange[iSequence];
	  for (CoinBigIndex j = columnStart[iSequence];
	       j < columnStart[iSequence] + columnLength[iSequence]; j++) {
	    rowArray_[4]->quickAdd(row[j], elementByColumn[j]*value);
	  }
	}
      }
      n=upperList[-1];
      change = upperChange+numberColumns_;
      for (;i<n;i++) {
	int iSequence = upperList[i]-numberColumns_;
	assert (iSequence>=0);
	if (getRowStatus(iSequence)==atUpperBound) {
	  double value=change[iSequence];
	  rowArray_[4]->quickAdd(iSequence, -value);
	}
      }
    } else {
      int n;
      n=lowerList[-2];
      int i;
      for (i=0;i<n;i++) {
	int iSequence = lowerList[i];
	assert (iSequence<numberColumns_);
	if (getColumnStatus(iSequence)==atLowerBound) {
	  double value=lowerChange[iSequence];
	  // apply scaling
	  double scale = columnScale_[iSequence];
	  for (CoinBigIndex j = columnStart[iSequence];
	       j < columnStart[iSequence] + columnLength[iSequence]; j++) {
	    int iRow = row[j];
	    rowArray_[4]->quickAdd(iRow, elementByColumn[j]*scale * rowScale_[iRow]*value);
	  }
	}
      }
      n=lowerList[-1];
      const double * change = lowerChange+numberColumns_;
      for (;i<n;i++) {
	int iSequence = lowerList[i]-numberColumns_;
	assert (iSequence>=0);
	if (getRowStatus(iSequence)==atLowerBound) {
	  double value=change[iSequence];
	  rowArray_[4]->quickAdd(iSequence, -value);
	}
      }
      n=upperList[-2];
      for (i=0;i<n;i++) {
	int iSequence = upperList[i];
	assert (iSequence<numberColumns_);
	if (getColumnStatus(iSequence)==atUpperBound) {
	  double value=upperChange[iSequence];
	  // apply scaling
	  double scale = columnScale_[iSequence];
	  for (CoinBigIndex j = columnStart[iSequence];
	       j < columnStart[iSequence] + columnLength[iSequence]; j++) {
	    int iRow = row[j];
	    rowArray_[4]->quickAdd(iRow, elementByColumn[j]*scale * rowScale_[iRow]*value);
	  }
	}
      }
      n=upperList[-1];
      change = upperChange+numberColumns_;
      for (;i<n;i++) {
	int iSequence = upperList[i]-numberColumns_;
	assert (iSequence>=0);
	if (getRowStatus(iSequence)==atUpperBound) {
	  double value=change[iSequence];
	  rowArray_[4]->quickAdd(iSequence, -value);
	}
      }
    }
    // ftran it
    factorization_->updateColumn(rowArray_[0], rowArray_[4]);
#if 0
    if (checkIt) {
      for (int i=0;i<numberRows_;i++) {
	assert (fabs(tempArray[i]-array[i])<1.0e-8);
      }
    }
#endif
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
    /* later for sparse - keep like CoinIndexedvector
       and just redo here */
    int lowerN=0;
    int upperN=0;
    memset(lowerCoefficient,0,numberRows_*sizeof(double));
    memset(upperCoefficient,0,numberRows_*sizeof(double));
    for (int iRow=0;iRow<numberRows_;iRow++) {
      iSequence = pivotVariable_[iRow];
      double currentSolution = solution_[iSequence];
      double alpha = array[iRow];
      double thetaCoefficientLower = lowerChange[iSequence] + alpha;
      double thetaCoefficientUpper = upperChange[iSequence] + alpha;
      if (thetaCoefficientLower > 1.0e-8&&lower_[iSequence]>-1.0e30) {
	double currentLower = lower_[iSequence];
	ClpTraceDebug (currentSolution >= currentLower - 100.0*primalTolerance_);
	double gap=currentSolution-currentLower;
	lowerGap[iRow]=gap;
	lowerCoefficient[iRow]=thetaCoefficientLower;
	lowerActive[lowerN++]=iRow;
	//} else {
	//lowerCoefficient[iRow]=0.0;
      }
      if (thetaCoefficientUpper < -1.0e-8&&upper_[iSequence]<1.0e30) {
	double currentUpper = upper_[iSequence];
	ClpTraceDebug (currentSolution <= currentUpper + 100.0*primalTolerance_);
	double gap2=-(currentSolution-currentUpper); //positive
	upperGap[iRow]=gap2;
	upperCoefficient[iRow]=-thetaCoefficientUpper;
	upperActive[upperN++]=iRow;
      }
    }
    assert (lowerN>=0&&lowerN<=numberRows_);
    lowerActive[-1]=lowerN;
    upperActive[-1]=upperN;
#endif
  } else if (sequenceIn_>=0) {
    //assert (sequenceIn_>=0);
    assert (sequenceOut_>=0);
    assert (sequenceIn_!=sequenceOut_);
    double change = (directionIn_>0) ? -lowerChange[sequenceIn_] : -upperChange[sequenceIn_];
    int needed=0;
    assert (!rowArray_[5]->getNumElements());
    if (change) {
      if (sequenceIn_<numberColumns_) {
	if (!rowScale_) {
	  for (CoinBigIndex i = columnStart[sequenceIn_];
	       i < columnStart[sequenceIn_] + columnLength[sequenceIn_]; i++) {
	    rowArray_[5]->quickAdd(row[i], elementByColumn[i]*change);
	  }
	} else {
	  // apply scaling
	  double scale = columnScale_[sequenceIn_];
	  for (CoinBigIndex i = columnStart[sequenceIn_];
	       i < columnStart[sequenceIn_] + columnLength[sequenceIn_]; i++) {
	    int iRow = row[i];
	    rowArray_[5]->quickAdd(iRow, elementByColumn[i]*scale * rowScale_[iRow]*change);
	  }
	}
      } else {
	rowArray_[5]->insert(sequenceIn_-numberColumns_,-change);
      }
      needed++;
    }
    if (getStatus(sequenceOut_)==atLowerBound)
      change=lowerChange[sequenceOut_];
    else
      change=upperChange[sequenceOut_];
    if (change) {
      if (sequenceOut_<numberColumns_) {
	if (!rowScale_) {
	  for (CoinBigIndex i = columnStart[sequenceOut_];
	       i < columnStart[sequenceOut_] + columnLength[sequenceOut_]; i++) {
	    rowArray_[5]->quickAdd(row[i], elementByColumn[i]*change);
	  }
	} else {
	  // apply scaling
	  double scale = columnScale_[sequenceOut_];
	  for (CoinBigIndex i = columnStart[sequenceOut_];
	       i < columnStart[sequenceOut_] + columnLength[sequenceOut_]; i++) {
	    int iRow = row[i];
	    rowArray_[5]->quickAdd(iRow, elementByColumn[i]*scale * rowScale_[iRow]*change);
	  }
	}
      } else {
	rowArray_[5]->quickAdd(sequenceOut_-numberColumns_,-change);
      }
      needed++;
    }
    //printf("seqin %d seqout %d needed %d\n",
    //	   sequenceIn_,sequenceOut_,needed);
    if (needed) {
      // ftran it
      factorization_->updateColumn(rowArray_[0], rowArray_[5]);
      // add
      double * array5 = rowArray_[5]->denseVector();
      int * index5 = rowArray_[5]->getIndices();
      int number5 = rowArray_[5]->getNumElements();
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
      int lowerN=lowerActive[-1];
      int upperN=upperActive[-1];
      int nIn4=rowArray_[4]->getNumElements();
      int * index4 = rowArray_[4]->getIndices();
#endif
      for (int i = 0; i < number5; i++) {
	int iPivot = index5[i];
#ifndef CLP_PARAMETRIC_DENSE_ARRAYS
	rowArray_[4]->quickAdd(iPivot,array5[iPivot]);
#else
	/* later for sparse - modify here */
	int iSequence = pivotVariable_[iPivot];
	double currentSolution = solution_[iSequence];
	double currentAlpha = array[iPivot];
	double alpha5 = array5[iPivot];
	double alpha = currentAlpha+alpha5;
	if (currentAlpha) {
	  if (alpha) {
	    array[iPivot] = alpha;
	  } else {
	    array[iPivot] = COIN_DBL_MIN;
	  }
	} else {
	  index4[nIn4++] = iPivot;
	  array[iPivot] = alpha;
	}
	double thetaCoefficientLower = lowerChange[iSequence] + alpha;
	double thetaCoefficientUpper = upperChange[iSequence] + alpha;
	double oldLower = lowerCoefficient[iPivot];
	double oldUpper = upperCoefficient[iPivot];
	if (thetaCoefficientLower > 1.0e-8&&lower_[iSequence]>-1.0e30) {
	  double currentLower = lower_[iSequence];
	  ClpTraceDebug (currentSolution >= currentLower - 100.0*primalTolerance_);
	  double gap=currentSolution-currentLower;
	  lowerGap[iPivot]=gap;
	  lowerCoefficient[iPivot]=thetaCoefficientLower;
	  if (!oldLower)
	    lowerActive[lowerN++]=iPivot;
	} else {
	  if (oldLower)
	    lowerCoefficient[iPivot]=COIN_DBL_MIN;
	}
	if (thetaCoefficientUpper < -1.0e-8&&upper_[iSequence]<1.0e30) {
	  double currentUpper = upper_[iSequence];
	  ClpTraceDebug (currentSolution <= currentUpper + 100.0*primalTolerance_);
	  double gap2=-(currentSolution-currentUpper); //positive
	  upperGap[iPivot]=gap2;
	  upperCoefficient[iPivot]=-thetaCoefficientUpper;
	  if (!oldUpper)
	    upperActive[upperN++]=iPivot;
	} else {
	  if (oldUpper)
	    upperCoefficient[iPivot]=COIN_DBL_MIN;
	}
#endif
	array5[iPivot]=0.0;
      }
      rowArray_[5]->setNumElements(0);
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
      rowArray_[4]->setNumElements(nIn4);
      assert (lowerN>=0&&lowerN<=numberRows_);
      lowerActive[-1]=lowerN;
      upperActive[-1]=upperN;
#endif
    }
  }
  const int * index = rowArray_[4]->getIndices();
  int number = rowArray_[4]->getNumElements();
#define TESTXX 0
#ifndef CLP_PARAMETRIC_DENSE_ARRAYS //TESTXX
  int * markDone = reinterpret_cast<int *>(paramData.markDone);
  int nToZero=(numberRows_+numberColumns_+COIN_ANY_BITS_PER_INT-1)>>COIN_ANY_SHIFT_PER_INT;
  memset(markDone,0,nToZero*sizeof(int));
  const int * backwardBasic = paramData.backwardBasic;
#endif
  // first ones with alpha
  double theta1=maxTheta;
  int pivotRow1=-1;
#ifndef CLP_PARAMETRIC_DENSE_ARRAYS //TESTXX
  int pivotRow2=-1;
  double theta2=maxTheta;
#endif
#ifndef CLP_PARAMETRIC_DENSE_ARRAYS //TESTXX
  for (int i=0;i<number;i++) {
    int iPivot=index[i];
    iSequence = pivotVariable_[iPivot];
    //assert(!markDone[iSequence]);
    int word = iSequence >> COIN_ANY_SHIFT_PER_INT;
    int bit = iSequence & COIN_ANY_MASK_PER_INT;
    markDone[word] |= ( 1 << bit );
    // solution value will be sol - theta*alpha
    // bounds will be bounds + change *theta
    double currentSolution = solution_[iSequence];
    double alpha = array[iPivot];
    double thetaCoefficientLower = lowerChange[iSequence] + alpha;
    double thetaCoefficientUpper = upperChange[iSequence] + alpha;
    if (thetaCoefficientLower > 1.0e-8) {
      double currentLower = lower_[iSequence];
      ClpTraceDebug (currentSolution >= currentLower - 100.0*primalTolerance_);
      assert (currentSolution >= currentLower - 100.0*primalTolerance_);
      double gap=currentSolution-currentLower;
      if (thetaCoefficientLower*theta1>gap) {
	theta1 = gap/thetaCoefficientLower;
	//toLower=true;
	pivotRow1=iPivot;
      }
    }
    if (thetaCoefficientUpper < -1.0e-8) {
      double currentUpper = upper_[iSequence];
      ClpTraceDebug (currentSolution <= currentUpper + 100.0*primalTolerance_);
      assert (currentSolution <= currentUpper + 100.0*primalTolerance_);
      double gap2=currentSolution-currentUpper; //negative
      if (thetaCoefficientUpper*theta2<gap2) {
	theta2 = gap2/thetaCoefficientUpper;
	//toLower=false;
	pivotRow2=iPivot;
      }
    }
  }
  // now others
  int nLook=lowerList[-1];
  for (int i=0;i<nLook;i++) {
    int iSequence = lowerList[i];
    int word = iSequence >> COIN_ANY_SHIFT_PER_INT;
    int bit = iSequence & COIN_ANY_MASK_PER_INT;
    if (getColumnStatus(iSequence)==basic&&(markDone[word]&(1<<bit))==0) {
      double currentSolution = solution_[iSequence];
      double currentLower = lower_[iSequence];
      ClpTraceDebug (currentSolution >= currentLower - 100.0*primalTolerance_);
      double thetaCoefficient = lowerChange[iSequence];
      if (thetaCoefficient > 0.0) {
	double gap=currentSolution-currentLower;
	if (thetaCoefficient*theta1>gap) {
	  theta1 = gap/thetaCoefficient;
	  //toLower=true;
	  pivotRow1 = backwardBasic[iSequence];
	}
      }
    }
  }
  nLook=upperList[-1];
  for (int i=0;i<nLook;i++) {
    int iSequence = upperList[i];
    int word = iSequence >> COIN_ANY_SHIFT_PER_INT;
    int bit = iSequence & COIN_ANY_MASK_PER_INT;
    if (getColumnStatus(iSequence)==basic&&(markDone[word]&(1<<bit))==0) {
      double currentSolution = solution_[iSequence];
      double currentUpper = upper_[iSequence];
      ClpTraceDebug (currentSolution <= currentUpper + 100.0*primalTolerance_);
      double thetaCoefficient = upperChange[iSequence];
      if (thetaCoefficient < 0) {
	double gap=currentSolution-currentUpper; //negative
	if (thetaCoefficient*theta2<gap) {
	  theta2 = gap/thetaCoefficient;
	  //toLower=false;
	  pivotRow2 = backwardBasic[iSequence];
	}
      }
    }
  }
  if (theta2<theta1) {
    theta_=theta2;
    toLower=false;
    pivotRow_=pivotRow2;
  } else {
    theta_=theta1;
    toLower=true;
    pivotRow_=pivotRow1;
  }
#if 0 //TESTXX
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
  {
    double * checkArray = new double[numberRows_];
    memcpy(checkArray,lowerCoefficient,numberRows_*sizeof(double));
    int lowerN=lowerActive[-1];
    for (int i=0;i<lowerN;i++) {
      int iRow=lowerActive[i];
      int iSequence = pivotVariable_[iRow];
      double alpha = array[iRow];
      double thetaCoefficient = lowerChange[iSequence] + alpha;
      if (thetaCoefficient > 1.0e-8&&lower_[iSequence]>-1.0e30) {
	assert(fabs(checkArray[iRow]-thetaCoefficient)<1.0e-5);
	if(fabs(checkArray[iRow]-thetaCoefficient)>1.0e-5) {
	  abort();
	}
      } else {
	assert (fabs(checkArray[iRow])<1.0e-12);
	if (fabs(checkArray[iRow])>1.0e-12) {
	  abort();
	}
      }
      checkArray[iRow]=0.0;
    }
    for (int i=0;i<numberRows_;i++) {
      assert (!checkArray[i]);
      if (checkArray[i])
	abort();
    }
    memcpy(checkArray,upperCoefficient,numberRows_*sizeof(double));
    int upperN=upperActive[-1];
    for (int i=0;i<upperN;i++) {
      int iRow=upperActive[i];
      int iSequence = pivotVariable_[iRow];
      double alpha = array[iRow];
      double thetaCoefficient = -(upperChange[iSequence] + alpha);
      if (thetaCoefficient > 1.0e-8&&upper_[iSequence]<1.0e30) {
	assert(fabs(checkArray[iRow]-thetaCoefficient)<1.0e-5);
	if(fabs(checkArray[iRow]-thetaCoefficient)>1.0e-5) {
	  abort();
	}
      } else {
	assert (fabs(checkArray[iRow])<1.0e-12);
	if (fabs(checkArray[iRow])>1.0e-12) {
	  abort();
	}
      }
      checkArray[iRow]=0.0;
    }
    for (int i=0;i<numberRows_;i++) {
      assert (!checkArray[i]);
      if (checkArray[i])
	abort();
    }
    delete [] checkArray;
  }
  double theta3=maxTheta;
  int pivotRow3=-1;
  int lowerN=lowerActive[-1];
  for (int i=0;i<lowerN;i++) {
    int iRow=lowerActive[i];
    double lowerC = lowerCoefficient[iRow];
    double gap=lowerGap[iRow];
    if (toLower&&iRow==pivotRow_) {
      assert (lowerC*theta3>gap-1.0e-8);
      if (lowerC*theta3<gap-1.0e-8)
	abort();
    }
    if (lowerC*theta3>gap&&lowerC!=COIN_DBL_MIN) {
      theta3 = gap/lowerC;
      pivotRow3=iRow;
    }
  }
  int pivotRow4=pivotRow3;
  double theta4=theta3;
  int upperN=upperActive[-1];
  for (int i=0;i<upperN;i++) {
    int iRow=upperActive[i];
    double upperC = upperCoefficient[iRow];
    double gap=upperGap[iRow];
    if (!toLower&&iRow==pivotRow_) {
      assert (upperC*theta3>gap-1.0e-8);
      if (upperC*theta3<gap-1.0e-8)
	abort();
    }
    if (upperC*theta4>gap&&upperC!=COIN_DBL_MIN) {
      theta4 = gap/upperC;
      pivotRow4=iRow;
    }
  }
  bool toLower3;
  if (theta4<theta3) {
    theta3=theta4;
    toLower3=false;
    pivotRow3=pivotRow4;
  } else {
    toLower3=true;
  }
  if (fabs(theta3-theta_)>1.0e-8)
    abort();
  if (toLower!=toLower3||pivotRow_!=pivotRow3) {
    printf("bad piv - good %d %g %s, bad %d %g %s\n",pivotRow_,theta_,toLower ? "toLower" : "toUpper",
	   pivotRow3,theta3,toLower3 ? "toLower" : "toUpper");
    //zzzzzz++;
    if (true/*zzzzzz>zzzzzzOther*/) {
      printf("Swapping\n");
      pivotRow_=pivotRow3;
      theta_=theta3;
      toLower=toLower3;
    }
  }
#endif
#endif
#else
#if 0 //CLP_PARAMETRIC_DENSE_ARRAYS==2
  {
    double * checkArray = new double[numberRows_];
    memcpy(checkArray,lowerCoefficient,numberRows_*sizeof(double));
    int lowerN=lowerActive[-1];
    for (int i=0;i<lowerN;i++) {
      int iRow=lowerActive[i];
      checkArray[iRow]=0.0;
    }
    for (int i=0;i<numberRows_;i++) {
      assert (!checkArray[i]);
      if (checkArray[i])
	abort();
    }
    memcpy(checkArray,upperCoefficient,numberRows_*sizeof(double));
    int upperN=upperActive[-1];
    for (int i=0;i<upperN;i++) {
      int iRow=upperActive[i];
      checkArray[iRow]=0.0;
    }
    for (int i=0;i<numberRows_;i++) {
      assert (!checkArray[i]);
      if (checkArray[i])
	abort();
    }
    delete [] checkArray;
  }
#endif
  int lowerN=lowerActive[-1];
  for (int i=0;i<lowerN;i++) {
    int iRow=lowerActive[i];
    double lowerC = lowerCoefficient[iRow];
    double gap=lowerGap[iRow];
    if (lowerC*theta1>gap&&lowerC!=COIN_DBL_MIN) {
      theta1 = gap/lowerC;
      pivotRow1=iRow;
    }
  }
  pivotRow_=pivotRow1;
  theta_=theta1;
  int upperN=upperActive[-1];
  for (int i=0;i<upperN;i++) {
    int iRow=upperActive[i];
    double upperC = upperCoefficient[iRow];
    double gap=upperGap[iRow];
    if (upperC*theta1>gap&&upperC!=COIN_DBL_MIN) {
      theta1 = gap/upperC;
      pivotRow1=iRow;
    }
  }
  if (theta1<theta_) {
    theta_=theta1;
    toLower=false;
    pivotRow_=pivotRow1;
  } else {
    toLower=true;
  }
#endif
  theta_ = CoinMax(theta_,0.0);
  if (theta_>1.0e-15) {
    // update solution
    for (int iRow = 0; iRow < number; iRow++) {
      int iPivot = index[iRow];
      iSequence = pivotVariable_[iPivot];
      // solution value will be sol - theta*alpha
      double alpha = array[iPivot];
      double currentSolution = solution_[iSequence] - theta_ * alpha;
      solution_[iSequence] =currentSolution;
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS 
      if (lower_[iSequence]>-1.0e30)
	lowerGap[iPivot]=currentSolution-lower_[iSequence];
      if (upper_[iSequence]<1.0e30)
	upperGap[iPivot]=-(currentSolution-upper_[iSequence]);
#endif
    }
  }
#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
  if (pivotRow_>=0&&false) {
    double oldValue = upperCoefficient[pivotRow_];
    double value = array[pivotRow_];
    if (value) {
      if (!oldValue) {
	int upperN=upperActive[-1];
	assert (upperN>=0&&upperN<numberRows_);
	upperActive[upperN]=pivotRow_;
	upperActive[-1]=upperN+1;
      }
    } else {
      if (oldValue)
	upperCoefficient[pivotRow_]=COIN_DBL_MIN;
    }
  }
#endif
#if 0
  for (int i=0;i<numberTotal;i++)
    assert(!markDone[i]);
#endif
  if (pivotRow_ >= 0) {
    sequenceOut_ = pivotVariable_[pivotRow_];
    valueOut_ = solution_[sequenceOut_];
    lowerOut_ = lower_[sequenceOut_]+theta_*lowerChange[sequenceOut_];
    upperOut_ = upper_[sequenceOut_]+theta_*upperChange[sequenceOut_];
    if (!toLower) {
      directionOut_ = -1;
      dualOut_ = valueOut_ - upperOut_;
    } else {
      directionOut_ = 1;
      dualOut_ = lowerOut_ - valueOut_;
    }
    return 0;
  } else {
    //theta_=0.0;
    return -1;
  }
}
// Restores bound to original bound
void 
ClpSimplexOther::originalBound(int iSequence, double theta, 
			       const double * lowerChange,
			       const double * upperChange)
{
     if (getFakeBound(iSequence) != noFake) {
          numberFake_--;
          setFakeBound(iSequence, noFake);
          if (iSequence >= numberColumns_) {
               // rows
               int iRow = iSequence - numberColumns_;
               rowLowerWork_[iRow] = rowLower_[iRow]+theta*lowerChange[iSequence];
               rowUpperWork_[iRow] = rowUpper_[iRow]+theta*upperChange[iSequence];
               if (rowScale_) {
                    if (rowLowerWork_[iRow] > -1.0e50)
                         rowLowerWork_[iRow] *= rowScale_[iRow] * rhsScale_;
                    if (rowUpperWork_[iRow] < 1.0e50)
                         rowUpperWork_[iRow] *= rowScale_[iRow] * rhsScale_;
               } else if (rhsScale_ != 1.0) {
                    if (rowLowerWork_[iRow] > -1.0e50)
                         rowLowerWork_[iRow] *= rhsScale_;
                    if (rowUpperWork_[iRow] < 1.0e50)
                         rowUpperWork_[iRow] *= rhsScale_;
               }
          } else {
               // columns
               columnLowerWork_[iSequence] = columnLower_[iSequence]+theta*lowerChange[iSequence];
               columnUpperWork_[iSequence] = columnUpper_[iSequence]+theta*upperChange[iSequence];
               if (rowScale_) {
                    double multiplier = 1.0 * inverseColumnScale_[iSequence];
                    if (columnLowerWork_[iSequence] > -1.0e50)
                         columnLowerWork_[iSequence] *= multiplier * rhsScale_;
                    if (columnUpperWork_[iSequence] < 1.0e50)
                         columnUpperWork_[iSequence] *= multiplier * rhsScale_;
               } else if (rhsScale_ != 1.0) {
                    if (columnLowerWork_[iSequence] > -1.0e50)
                         columnLowerWork_[iSequence] *= rhsScale_;
                    if (columnUpperWork_[iSequence] < 1.0e50)
                         columnUpperWork_[iSequence] *= rhsScale_;
               }
          }
     }
}
/* Expands out all possible combinations for a knapsack
   If buildObj NULL then just computes space needed - returns number elements
   On entry numberOutput is maximum allowed, on exit it is number needed or
   -1 (as will be number elements) if maximum exceeded.  numberOutput will have at
   least space to return values which reconstruct input.
   Rows returned will be original rows but no entries will be returned for
   any rows all of whose entries are in knapsack.  So up to user to allow for this.
   If reConstruct >=0 then returns number of entrie which make up item "reConstruct"
   in expanded knapsack.  Values in buildRow and buildElement;
*/
int
ClpSimplexOther::expandKnapsack(int knapsackRow, int & numberOutput,
                                double * buildObj, CoinBigIndex * buildStart,
                                int * buildRow, double * buildElement, int reConstruct) const
{
     int iRow;
     int iColumn;
     // Get column copy
     CoinPackedMatrix * columnCopy = matrix();
     // Get a row copy in standard format
     CoinPackedMatrix matrixByRow;
     matrixByRow.reverseOrderedCopyOf(*columnCopy);
     const double * elementByRow = matrixByRow.getElements();
     const int * column = matrixByRow.getIndices();
     const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
     const int * rowLength = matrixByRow.getVectorLengths();
     CoinBigIndex j;
     int * whichColumn = new int [numberColumns_];
     int * whichRow = new int [numberRows_];
     int numJ = 0;
     // Get what other columns can compensate for
     double * lo = new double [numberRows_];
     double * high = new double [numberRows_];
     {
          // Use to get tight column bounds
          ClpSimplex tempModel(*this);
          tempModel.tightenPrimalBounds(0.0, 0, true);
          // Now another model without knapsacks
          int nCol = 0;
          for (iRow = 0; iRow < numberRows_; iRow++) {
               whichRow[iRow] = iRow;
          }
          for (iColumn = 0; iColumn < numberColumns_; iColumn++)
               whichColumn[iColumn] = -1;
          for (j = rowStart[knapsackRow]; j < rowStart[knapsackRow] + rowLength[knapsackRow]; j++) {
               int iColumn = column[j];
               if (columnUpper_[iColumn] > columnLower_[iColumn]) {
                    whichColumn[iColumn] = 0;
               } else {
                    assert (!columnLower_[iColumn]); // fix later
               }
          }
          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
               if (whichColumn[iColumn] < 0)
                    whichColumn[nCol++] = iColumn;
          }
          ClpSimplex tempModel2(&tempModel, numberRows_, whichRow, nCol, whichColumn, false, false, false);
          // Row copy
          CoinPackedMatrix matrixByRow;
          matrixByRow.reverseOrderedCopyOf(*tempModel2.matrix());
          const double * elementByRow = matrixByRow.getElements();
          const int * column = matrixByRow.getIndices();
          const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
          const int * rowLength = matrixByRow.getVectorLengths();
          const double * columnLower = tempModel2.getColLower();
          const double * columnUpper = tempModel2.getColUpper();
          for (iRow = 0; iRow < numberRows_; iRow++) {
               lo[iRow] = -COIN_DBL_MAX;
               high[iRow] = COIN_DBL_MAX;
               if (rowLower_[iRow] > -1.0e20 || rowUpper_[iRow] < 1.0e20) {

                    // possible row
                    int infiniteUpper = 0;
                    int infiniteLower = 0;
                    double maximumUp = 0.0;
                    double maximumDown = 0.0;
                    CoinBigIndex rStart = rowStart[iRow];
                    CoinBigIndex rEnd = rowStart[iRow] + rowLength[iRow];
                    CoinBigIndex j;
                    // Compute possible lower and upper ranges

                    for (j = rStart; j < rEnd; ++j) {
                         double value = elementByRow[j];
                         iColumn = column[j];
                         if (value > 0.0) {
                              if (columnUpper[iColumn] >= 1.0e20) {
                                   ++infiniteUpper;
                              } else {
                                   maximumUp += columnUpper[iColumn] * value;
                              }
                              if (columnLower[iColumn] <= -1.0e20) {
                                   ++infiniteLower;
                              } else {
                                   maximumDown += columnLower[iColumn] * value;
                              }
                         } else if (value < 0.0) {
                              if (columnUpper[iColumn] >= 1.0e20) {
                                   ++infiniteLower;
                              } else {
                                   maximumDown += columnUpper[iColumn] * value;
                              }
                              if (columnLower[iColumn] <= -1.0e20) {
                                   ++infiniteUpper;
                              } else {
                                   maximumUp += columnLower[iColumn] * value;
                              }
                         }
                    }
                    // Build in a margin of error
                    maximumUp += 1.0e-8 * fabs(maximumUp) + 1.0e-7;
                    maximumDown -= 1.0e-8 * fabs(maximumDown) + 1.0e-7;
                    // we want to save effective rhs
                    double up = (infiniteUpper) ? COIN_DBL_MAX : maximumUp;
                    double down = (infiniteLower) ? -COIN_DBL_MAX : maximumDown;
                    if (up == COIN_DBL_MAX || rowLower_[iRow] == -COIN_DBL_MAX) {
                         // However low we go it doesn't matter
                         lo[iRow] = -COIN_DBL_MAX;
                    } else {
                         // If we go below this then can not be feasible
                         lo[iRow] = rowLower_[iRow] - up;
                    }
                    if (down == -COIN_DBL_MAX || rowUpper_[iRow] == COIN_DBL_MAX) {
                         // However high we go it doesn't matter
                         high[iRow] = COIN_DBL_MAX;
                    } else {
                         // If we go above this then can not be feasible
                         high[iRow] = rowUpper_[iRow] - down;
                    }
               }
          }
     }
     numJ = 0;
     for (iColumn = 0; iColumn < numberColumns_; iColumn++)
          whichColumn[iColumn] = -1;
     int * markRow = new int [numberRows_];
     for (iRow = 0; iRow < numberRows_; iRow++)
          markRow[iRow] = 1;
     for (j = rowStart[knapsackRow]; j < rowStart[knapsackRow] + rowLength[knapsackRow]; j++) {
          int iColumn = column[j];
          if (columnUpper_[iColumn] > columnLower_[iColumn]) {
               whichColumn[iColumn] = numJ;
               numJ++;
          }
     }
     /* mark rows
        -n in knapsack and n other variables
        1 no entries
        n+1000 not involved in knapsack but n entries
        0 only in knapsack
     */
     for (iRow = 0; iRow < numberRows_; iRow++) {
          int type = 1;
          for (j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
               int iColumn = column[j];
               if (whichColumn[iColumn] >= 0) {
                    if (type == 1) {
                         type = 0;
                    } else if (type > 0) {
                         assert (type > 1000);
                         type = -(type - 1000);
                    }
               } else if (type == 1) {
                    type = 1001;
               } else if (type < 0) {
                    type --;
               } else if (type == 0) {
                    type = -1;
               } else {
                    assert (type > 1000);
                    type++;
               }
          }
          markRow[iRow] = type;
          if (type < 0 && type > -30 && false)
               printf("markrow on row %d is %d\n", iRow, markRow[iRow]);
     }
     int * bound = new int [numberColumns_+1];
     int * stack = new int [numberColumns_+1];
     int * flip = new int [numberColumns_+1];
     double * offset = new double[numberColumns_+1];
     double * size = new double [numberColumns_+1];
     double * rhsOffset = new double[numberRows_];
     int * build = new int[numberColumns_];
     int maxNumber = numberOutput;
     numJ = 0;
     double minSize = rowLower_[knapsackRow];
     double maxSize = rowUpper_[knapsackRow];
     double knapsackOffset = 0.0;
     for (j = rowStart[knapsackRow]; j < rowStart[knapsackRow] + rowLength[knapsackRow]; j++) {
          int iColumn = column[j];
          double lowerColumn = columnLower_[iColumn];
          double upperColumn = columnUpper_[iColumn];
          if (lowerColumn == upperColumn)
               continue;
          double gap = upperColumn - lowerColumn;
          if (gap > 1.0e8)
               gap = 1.0e8;
          assert (fabs(floor(gap + 0.5) - gap) < 1.0e-5);
          whichColumn[numJ] = iColumn;
          bound[numJ] = static_cast<int> (gap);
          if (elementByRow[j] > 0.0) {
               flip[numJ] = 1;
               offset[numJ] = lowerColumn;
               size[numJ++] = elementByRow[j];
          } else {
               flip[numJ] = -1;
               offset[numJ] = upperColumn;
               size[numJ++] = -elementByRow[j];
               lowerColumn = upperColumn;
          }
          knapsackOffset += elementByRow[j] * lowerColumn;
     }
     int jRow;
     for (iRow = 0; iRow < numberRows_; iRow++)
          whichRow[iRow] = iRow;
     ClpSimplex smallModel(this, numberRows_, whichRow, numJ, whichColumn, true, true, true);
     // modify rhs to allow for nonzero lower bounds
     //double * rowLower = smallModel.rowLower();
     //double * rowUpper = smallModel.rowUpper();
     //const double * columnLower = smallModel.columnLower();
     //const double * columnUpper = smallModel.columnUpper();
     const CoinPackedMatrix * matrix = smallModel.matrix();
     const double * element = matrix->getElements();
     const int * row = matrix->getIndices();
     const CoinBigIndex * columnStart = matrix->getVectorStarts();
     const int * columnLength = matrix->getVectorLengths();
     const double * objective = smallModel.objective();
     //double objectiveOffset=0.0;
     // would use for fixed?
     CoinZeroN(rhsOffset, numberRows_);
     double * rowActivity = smallModel.primalRowSolution();
     CoinZeroN(rowActivity, numberRows_);
     maxSize -= knapsackOffset;
     minSize -= knapsackOffset;
     // now generate
     int i;
     int iStack = numJ;
     for (i = 0; i < numJ; i++) {
          stack[i] = 0;
     }
     double tooMuch = 10.0 * maxSize + 10000;
     stack[numJ] = 1;
     size[numJ] = tooMuch;
     bound[numJ] = 0;
     double sum = tooMuch;
     // allow for all zero being OK
     stack[numJ-1] = -1;
     sum -= size[numJ-1];
     numberOutput = 0;
     int nelCreate = 0;
     /* typeRun is - 0 for initial sizes
                     1 for build
     	  2 for reconstruct
     */
     int typeRun = buildObj ? 1 : 0;
     if (reConstruct >= 0) {
          assert (buildRow && buildElement);
          typeRun = 2;
     }
     if (typeRun == 1)
          buildStart[0] = 0;
     while (iStack >= 0) {
          if (sum >= minSize && sum <= maxSize) {
               double checkSize = 0.0;
               bool good = true;
               int nRow = 0;
               double obj = 0.0;
               CoinZeroN(rowActivity, numberRows_);
               for (iColumn = 0; iColumn < numJ; iColumn++) {
                    int iValue = stack[iColumn];
                    if (iValue > bound[iColumn]) {
                         good = false;
                         break;
                    } else {
                         double realValue = offset[iColumn] + flip[iColumn] * iValue;
                         if (realValue) {
                              obj += objective[iColumn] * realValue;
                              for (CoinBigIndex j = columnStart[iColumn];
                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                                   double value = element[j] * realValue;
                                   int kRow = row[j];
                                   if (rowActivity[kRow]) {
                                        rowActivity[kRow] += value;
                                        if (!rowActivity[kRow])
                                             rowActivity[kRow] = 1.0e-100;
                                   } else {
                                        build[nRow++] = kRow;
                                        rowActivity[kRow] = value;
                                   }
                              }
                         }
                    }
               }
               if (good) {
                    for (jRow = 0; jRow < nRow; jRow++) {
                         int kRow = build[jRow];
                         double value = rowActivity[kRow];
                         if (value > high[kRow] || value < lo[kRow]) {
                              good = false;
                              break;
                         }
                    }
               }
               if (good) {
                    if (typeRun == 1) {
                         buildObj[numberOutput] = obj;
                         for (jRow = 0; jRow < nRow; jRow++) {
                              int kRow = build[jRow];
                              double value = rowActivity[kRow];
                              if (markRow[kRow] < 0 && fabs(value) > 1.0e-13) {
                                   buildElement[nelCreate] = value;
                                   buildRow[nelCreate++] = kRow;
                              }
                         }
                         buildStart[numberOutput+1] = nelCreate;
                    } else if (!typeRun) {
                         for (jRow = 0; jRow < nRow; jRow++) {
                              int kRow = build[jRow];
                              double value = rowActivity[kRow];
                              if (markRow[kRow] < 0 && fabs(value) > 1.0e-13) {
                                   nelCreate++;
                              }
                         }
                    }
                    if (typeRun == 2 && reConstruct == numberOutput) {
                         // build and exit
                         nelCreate = 0;
                         for (iColumn = 0; iColumn < numJ; iColumn++) {
                              int iValue = stack[iColumn];
                              double realValue = offset[iColumn] + flip[iColumn] * iValue;
                              if (realValue) {
                                   buildRow[nelCreate] = whichColumn[iColumn];
                                   buildElement[nelCreate++] = realValue;
                              }
                         }
                         numberOutput = 1;
                         for (i = 0; i < numJ; i++) {
                              bound[i] = 0;
                         }
                         break;
                    }
                    numberOutput++;
                    if (numberOutput > maxNumber) {
                         nelCreate = -numberOutput;
                         numberOutput = -1;
                         for (i = 0; i < numJ; i++) {
                              bound[i] = 0;
                         }
                         break;
                    } else if (typeRun == 1 && numberOutput == maxNumber) {
                         // On second run
                         for (i = 0; i < numJ; i++) {
                              bound[i] = 0;
                         }
                         break;
                    }
                    for (int j = 0; j < numJ; j++) {
                         checkSize += stack[j] * size[j];
                    }
                    assert (fabs(sum - checkSize) < 1.0e-3);
               }
               for (jRow = 0; jRow < nRow; jRow++) {
                    int kRow = build[jRow];
                    rowActivity[kRow] = 0.0;
               }
          }
          if (sum > maxSize || stack[iStack] > bound[iStack]) {
               sum -= size[iStack] * stack[iStack];
               stack[iStack--] = 0;
               if (iStack >= 0) {
                    stack[iStack] ++;
                    sum += size[iStack];
               }
          } else {
               // must be less
               // add to last possible
               iStack = numJ - 1;
               sum += size[iStack];
               stack[iStack]++;
          }
     }
     //printf("%d will be created\n",numberOutput);
     delete [] whichColumn;
     delete [] whichRow;
     delete [] bound;
     delete [] stack;
     delete [] flip;
     delete [] size;
     delete [] offset;
     delete [] rhsOffset;
     delete [] build;
     delete [] markRow;
     delete [] lo;
     delete [] high;
     return nelCreate;
}
// Quick try at cleaning up duals if postsolve gets wrong
void
ClpSimplexOther::cleanupAfterPostsolve()
{
     // First mark singleton equality rows
     char * mark = new char [ numberRows_];
     memset(mark, 0, numberRows_);
     const int * row = matrix_->getIndices();
     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
     const int * columnLength = matrix_->getVectorLengths();
     const double * element = matrix_->getElements();
     for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
          for (CoinBigIndex j = columnStart[iColumn];
                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
               int iRow = row[j];
               if (mark[iRow])
                    mark[iRow] = 2;
               else
                    mark[iRow] = 1;
          }
     }
     // for now just == rows
     for (int iRow = 0; iRow < numberRows_; iRow++) {
          if (rowUpper_[iRow] > rowLower_[iRow])
               mark[iRow] = 3;
     }
     double dualTolerance = dblParam_[ClpDualTolerance];
     double primalTolerance = dblParam_[ClpPrimalTolerance];
     int numberCleaned = 0;
     double maxmin = optimizationDirection_;
     for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
          double dualValue = reducedCost_[iColumn] * maxmin;
          double primalValue = columnActivity_[iColumn];
          double lower = columnLower_[iColumn];
          double upper = columnUpper_[iColumn];
          int way = 0;
          switch(getColumnStatus(iColumn)) {

          case basic:
               // dual should be zero
               if (dualValue > dualTolerance) {
                    way = -1;
               } else if (dualValue < -dualTolerance) {
                    way = 1;
               }
               break;
          case ClpSimplex::isFixed:
               break;
          case atUpperBound:
               // dual should not be positive
               if (dualValue > dualTolerance) {
                    way = -1;
               }
               break;
          case atLowerBound:
               // dual should not be negative
               if (dualValue < -dualTolerance) {
                    way = 1;
               }
               break;
          case superBasic:
          case isFree:
               if (primalValue < upper - primalTolerance) {
                    // dual should not be negative
                    if (dualValue < -dualTolerance) {
                         way = 1;
                    }
               }
               if (primalValue > lower + primalTolerance) {
                    // dual should not be positive
                    if (dualValue > dualTolerance) {
                         way = -1;
                    }
               }
               break;
          }
          if (way) {
               // see if can find singleton row
               for (CoinBigIndex j = columnStart[iColumn];
                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                    int iRow = row[j];
                    if (mark[iRow] == 1) {
                         double value = element[j];
                         // dj - addDual*value == 0.0
                         double addDual = dualValue / value;
                         dual_[iRow] += addDual;
                         reducedCost_[iColumn] = 0.0;
                         numberCleaned++;
                         break;
                    }
               }
          }
     }
     delete [] mark;
#ifdef CLP_INVESTIGATE
     printf("cleanupAfterPostsolve cleaned up %d columns\n", numberCleaned);
#endif
     // Redo
     memcpy(reducedCost_, this->objective(), numberColumns_ * sizeof(double));
     matrix_->transposeTimes(-1.0, dual_, reducedCost_);
     checkSolutionInternal();
}
// Returns gub version of model or NULL
ClpSimplex * 
ClpSimplexOther::gubVersion(int * whichRows, int * whichColumns,
			    int neededGub,
			    int factorizationFrequency)
{
  // find gub
  int numberRows = this->numberRows();
  int numberColumns = this->numberColumns();
  int iRow, iColumn;
  int * columnIsGub = new int [numberColumns];
  const double * columnLower = this->columnLower();
  const double * columnUpper = this->columnUpper();
  int numberFixed=0;
  for (iColumn = 0; iColumn < numberColumns; iColumn++) {
    if (columnUpper[iColumn] == columnLower[iColumn]) {
      columnIsGub[iColumn]=-2;
      numberFixed++;
    } else if (columnLower[iColumn]>=0) {
      columnIsGub[iColumn]=-1;
    } else {
      columnIsGub[iColumn]=-3;
    }
  }
  CoinPackedMatrix * matrix = this->matrix();
  // get row copy
  CoinPackedMatrix rowCopy = *matrix;
  rowCopy.reverseOrdering();
  const int * column = rowCopy.getIndices();
  const int * rowLength = rowCopy.getVectorLengths();
  const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
  const double * element = rowCopy.getElements();
  int numberNonGub = 0;
  int numberEmpty = numberRows;
  int * rowIsGub = new int [numberRows];
  int smallestGubRow=-1;
  int count=numberColumns+1;
  double * rowLower = this->rowLower();
  double * rowUpper = this->rowUpper();
  // make sure we can get rid of upper bounds
  double * fixedRow = new double [numberRows];
  for (iRow = 0 ; iRow < numberRows ; iRow++) {
    double sumFixed=0.0;
    for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
      int iColumn = column[j];
      double value = columnLower[iColumn];
      if (value) 
	sumFixed += element[j] * value;
    }
    fixedRow[iRow]=rowUpper[iRow]-sumFixed;
  }
  for (iRow = numberRows - 1; iRow >= 0; iRow--) {
    bool gubRow = true;
    int numberInRow=0;
    double sumFixed=0.0;
    double gap = fixedRow[iRow]-1.0e-12;
    for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
      int iColumn = column[j];
      if (columnIsGub[iColumn]!=-2) {
	if (element[j] != 1.0||columnIsGub[iColumn]==-3||
	    columnUpper[iColumn]-columnLower[iColumn]<gap) {
	  gubRow = false;
	  break;
	} else {
	  numberInRow++;
	  if (columnIsGub[iColumn] >= 0) {
	    gubRow = false;
	    break;
	  }
	}
      } else {
	sumFixed += columnLower[iColumn]*element[j];
      }
    }
    if (!gubRow) {
      whichRows[numberNonGub++] = iRow;
      rowIsGub[iRow] = -1;
    } else if (numberInRow) {
      if (numberInRow<count) {
	count = numberInRow;
	smallestGubRow=iRow;
      }
      for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
	int iColumn = column[j];
	if (columnIsGub[iColumn]!=-2) 
	  columnIsGub[iColumn] = iRow;
      }
      rowIsGub[iRow] = 0;
    } else {
      // empty row!
      whichRows[--numberEmpty] = iRow;
      rowIsGub[iRow] = -2;
      if (sumFixed>rowUpper[iRow]+1.0e-4||
	  sumFixed<rowLower[iRow]-1.0e-4) {
	fprintf(stderr,"******** No infeasible empty rows - please!\n");
	abort();
      }
    }
  }
  delete [] fixedRow;
  char message[100];
  int numberGub = numberEmpty - numberNonGub;
  if (numberGub >= neededGub) { 
    sprintf(message,"%d gub rows", numberGub);
    handler_->message(CLP_GENERAL2, messages_)
      << message << CoinMessageEol;
    int numberNormal = 0;
    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
      if (columnIsGub[iColumn] < 0  && columnIsGub[iColumn] !=-2) {
	whichColumns[numberNormal++] = iColumn;
      }
    }
    if (!numberNormal) {
      sprintf(message,"Putting back one gub row to make non-empty");
      handler_->message(CLP_GENERAL2, messages_)
	<< message << CoinMessageEol;
      rowIsGub[smallestGubRow]=-1;
      whichRows[numberNonGub++] = smallestGubRow;
      for (int j = rowStart[smallestGubRow]; 
	   j < rowStart[smallestGubRow] + rowLength[smallestGubRow]; j++) {
	int iColumn = column[j];
	if (columnIsGub[iColumn]>=0) {
	  columnIsGub[iColumn]=-4;
	  whichColumns[numberNormal++] = iColumn;
	}
      }
    }
    std::sort(whichRows,whichRows+numberNonGub);
    std::sort(whichColumns,whichColumns+numberNormal);
    double * lower = CoinCopyOfArray(this->rowLower(),numberRows);
    double * upper = CoinCopyOfArray(this->rowUpper(),numberRows);
    // leave empty rows at end
    numberEmpty = numberRows-numberEmpty;
    const int * row = matrix->getIndices();
    const int * columnLength = matrix->getVectorLengths();
    const CoinBigIndex * columnStart = matrix->getVectorStarts();
    const double * elementByColumn = matrix->getElements();
    // Fixed at end
    int put2 = numberColumns-numberFixed;
    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
      if (columnIsGub[iColumn] ==-2) {
	whichColumns[put2++] = iColumn;
	double value = columnLower[iColumn];
	for (int j = columnStart[iColumn]; 
	     j < columnStart[iColumn] + columnLength[iColumn]; j++) {
	  int iRow = row[j];
	  if (lower[iRow]>-1.0e20)
	    lower[iRow] -= value*element[j];
	  if (upper[iRow]<1.0e20)
	    upper[iRow] -= value*element[j];
	}
      }
    }
    int put = numberNormal;
    ClpSimplex * model2 =
      new ClpSimplex(this, numberNonGub, whichRows , numberNormal, whichColumns);
    // scale
    double * scaleArray = new double [numberRows];
    for (int i=0;i<numberRows;i++) {
      scaleArray[i]=1.0;
      if (rowIsGub[i]==-1) {
	double largest = 1.0e-30;
	double smallest = 1.0e30;
	for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
	  int iColumn = column[j];
	  if (columnIsGub[iColumn]!=-2) {
	    double value =fabs(element[j]);
	    largest = CoinMax(value,largest);
	    smallest = CoinMin(value,smallest);
	  }
	}
	double scale = CoinMax(0.001,1.0/sqrt(largest*smallest));
	scaleArray[i]=scale;
	if (lower[i]>-1.0e30)
	  lower[i] *= scale;
	if (upper[i]<1.0e30)
	  upper[i] *= scale;
      }
    }
    // scale partial matrix
    {
      CoinPackedMatrix * matrix = model2->matrix();
      const int * row = matrix->getIndices();
      const int * columnLength = matrix->getVectorLengths();
      const CoinBigIndex * columnStart = matrix->getVectorStarts();
      double * element = matrix->getMutableElements();
      for (int i=0;i<numberNormal;i++) {
	for (int j = columnStart[i]; 
	     j < columnStart[i] + columnLength[i]; j++) {
	  int iRow = row[j];
	  iRow = whichRows[iRow];
	  double scaleBy = scaleArray[iRow];
	  element[j] *= scaleBy;
	}
      }
    }
    // adjust rhs
    double * rowLower = model2->rowLower();
    double * rowUpper = model2->rowUpper();
    for (int i=0;i<numberNonGub;i++) {
      int iRow = whichRows[i];
      rowLower[i] = lower[iRow];
      rowUpper[i] = upper[iRow];
    }
    int numberGubColumns = numberColumns - put - numberFixed;
    CoinBigIndex numberElements=0;
    int * temp1 = new int [numberRows+1];
    // get counts
    memset(temp1,0,numberRows*sizeof(int));
    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
      int iGub = columnIsGub[iColumn];
      if (iGub>=0) {
	numberElements += columnLength[iColumn]-1;
	temp1[iGub]++;
      }
    }
    /* Optional but means can eventually simplify coding
       could even add in fixed slacks to deal with
       singularities - but should not be necessary */
    int numberSlacks=0;
    for (int i = 0; i < numberRows; i++) {
      if (rowIsGub[i]>=0) {
	if (lower[i]<upper[i]) {
	  numberSlacks++;
	  temp1[i]++;
	}
      }
    }
    int * gubStart = new int [numberGub+1];
    numberGub=0;
    gubStart[0]=0;
    for (int i = 0; i < numberRows; i++) {
      if (rowIsGub[i]>=0) {
	rowIsGub[i]=numberGub;
	gubStart[numberGub+1]=gubStart[numberGub]+temp1[i];
	temp1[numberGub]=0;
	lower[numberGub]=lower[i];
	upper[numberGub]=upper[i];
	whichRows[numberNonGub+numberGub]=i;
	numberGub++;
      }
    }
    int numberGubColumnsPlus = numberGubColumns + numberSlacks;
    double * lowerColumn2 = new double [numberGubColumnsPlus];
    CoinFillN(lowerColumn2, numberGubColumnsPlus, 0.0);
    double * upperColumn2 = new double [numberGubColumnsPlus];
    CoinFillN(upperColumn2, numberGubColumnsPlus, COIN_DBL_MAX);
    int * start2 = new int[numberGubColumnsPlus+1];
    int * row2 = new int[numberElements];
    double * element2 = new double[numberElements];
    double * cost2 = new double [numberGubColumnsPlus];
    CoinFillN(cost2, numberGubColumnsPlus, 0.0);
    const double * cost = this->objective();
    put = numberNormal;
    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
      int iGub = columnIsGub[iColumn];
      if (iGub>=0) {
	// TEMP
	//this->setColUpper(iColumn,COIN_DBL_MAX);
	iGub = rowIsGub[iGub];
	assert (iGub>=0);
	int kPut = put+gubStart[iGub]+temp1[iGub];
	temp1[iGub]++;
	whichColumns[kPut]=iColumn;
      }
    }
    for (int i = 0; i < numberRows; i++) {
      if (rowIsGub[i]>=0) {
	int iGub = rowIsGub[i];
	if (lower[iGub]<upper[iGub]) {
	  int kPut = put+gubStart[iGub]+temp1[iGub];
	  temp1[iGub]++;
	  whichColumns[kPut]=iGub+numberColumns;
	}
      }
    }
    //this->primal(1); // TEMP
    // redo rowIsGub to give lookup
    for (int i=0;i<numberRows;i++)
      rowIsGub[i]=-1;
    for (int i=0;i<numberNonGub;i++) 
      rowIsGub[whichRows[i]]=i;
    start2[0]=0;
    numberElements = 0;
    for (int i=0;i<numberGubColumnsPlus;i++) {
      int iColumn = whichColumns[put++];
      if (iColumn<numberColumns) {
	cost2[i] = cost[iColumn];
	lowerColumn2[i] = columnLower[iColumn];
	upperColumn2[i] = columnUpper[iColumn];
	upperColumn2[i] = COIN_DBL_MAX; 
	for (int j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
	  int iRow = row[j];
	  double scaleBy = scaleArray[iRow];
	  iRow = rowIsGub[iRow];
	  if (iRow >= 0) {
	    row2[numberElements] = iRow;
	    element2[numberElements++] = elementByColumn[j]*scaleBy;
	  }
	}
      } else {
	// slack
	int iGub = iColumn-numberColumns;
	double slack = upper[iGub]-lower[iGub];
	assert (upper[iGub]<1.0e20);
	lower[iGub]=upper[iGub];
	cost2[i] = 0;
	lowerColumn2[i] = 0;
	upperColumn2[i] = slack;
	upperColumn2[i] = COIN_DBL_MAX;
      }
      start2[i+1] = numberElements;
    }
    // clean up bounds on variables
    for (int iSet=0;iSet<numberGub;iSet++) {
      double lowerValue=0.0;
      for (int i=gubStart[iSet];i<gubStart[iSet+1];i++) {
	lowerValue += lowerColumn2[i];
      }
      assert (lowerValue<upper[iSet]+1.0e-6);
      double gap = CoinMax(0.0,upper[iSet]-lowerValue);
      for (int i=gubStart[iSet];i<gubStart[iSet+1];i++) {
	if (upperColumn2[i]<1.0e30) {
	  upperColumn2[i] = CoinMin(upperColumn2[i],
				    lowerColumn2[i]+gap);
	}
      }
    }
    sprintf(message,"** Before adding matrix there are %d rows and %d columns",
	   model2->numberRows(), model2->numberColumns());
    handler_->message(CLP_GENERAL2, messages_)
      << message << CoinMessageEol;
    delete [] scaleArray;
    delete [] temp1;
    model2->setFactorizationFrequency(factorizationFrequency);
    ClpDynamicMatrix * newMatrix = 
      new ClpDynamicMatrix(model2, numberGub,
				  numberGubColumnsPlus, gubStart,
				  lower, upper,
				  start2, row2, element2, cost2,
				  lowerColumn2, upperColumn2);
    delete [] gubStart;
    delete [] lowerColumn2;
    delete [] upperColumn2;
    delete [] start2;
    delete [] row2;
    delete [] element2;
    delete [] cost2;
    delete [] lower;
    delete [] upper;
    model2->replaceMatrix(newMatrix,true);
#ifdef EVERY_ITERATION
    {
      ClpDynamicMatrix * gubMatrix =
	dynamic_cast< ClpDynamicMatrix*>(model2->clpMatrix());
      assert(gubMatrix);
      gubMatrix->writeMps("gub.mps");
    }
#endif
    delete [] columnIsGub;
    delete [] rowIsGub;
    newMatrix->switchOffCheck();
#ifdef EVERY_ITERATION
    newMatrix->setRefreshFrequency(1/*000*/);
#else
    newMatrix->setRefreshFrequency(1000);
#endif
    sprintf(message,
	    "** While after adding matrix there are %d rows and %d columns",
	    model2->numberRows(), model2->numberColumns());
    handler_->message(CLP_GENERAL2, messages_)
      << message << CoinMessageEol;
    model2->setSpecialOptions(4);    // exactly to bound
    // Scaling off (done by hand)
    model2->scaling(0);
    return model2;
  } else {
    delete [] columnIsGub;
    delete [] rowIsGub;
    return NULL;
  }
}
// Sets basis from original
void 
ClpSimplexOther::setGubBasis(ClpSimplex &original,const int * whichRows,
			     const int * whichColumns)
{
  ClpDynamicMatrix * gubMatrix =
    dynamic_cast< ClpDynamicMatrix*>(clpMatrix());
  assert(gubMatrix);
  int numberGubColumns = gubMatrix->numberGubColumns();
  int numberNormal = gubMatrix->firstDynamic();
  //int lastOdd = gubMatrix->firstAvailable();
  //int numberTotalColumns = numberNormal + numberGubColumns;
  //assert (numberTotalColumns==numberColumns+numberSlacks);
  int numberRows = original.numberRows();
  int numberColumns = original.numberColumns();
  int * columnIsGub = new int [numberColumns];
  int numberNonGub = gubMatrix->numberStaticRows();
  //assert (firstOdd==numberNormal);
  double * solution = primalColumnSolution();
  double * originalSolution = original.primalColumnSolution();
  const double * upperSet = gubMatrix->upperSet();
  // Column copy of GUB part
  int numberSets = gubMatrix->numberSets();
  const int * startSet = gubMatrix->startSets();
  const CoinBigIndex * columnStart = gubMatrix->startColumn();
  const double * columnLower = gubMatrix->columnLower();
#ifdef TRY_IMPROVE
  const double * columnUpper = gubMatrix->columnUpper();
  const double * lowerSet = gubMatrix->lowerSet();
  const double * element = gubMatrix->element();
  const int * row = gubMatrix->row();
  bool allPositive=true;
  double * rowActivity = new double[numberNonGub];
  memset(rowActivity, 0, numberNonGub*sizeof(double));
  {
    // Non gub contribution
    const double * element = matrix_->getElements();
    const int * row = matrix_->getIndices();
    const CoinBigIndex * columnStart = matrix_->getVectorStarts();
    const int * columnLength = matrix_->getVectorLengths();
    for (int i=0;i<numberNormal;i++) {
      int iColumn = whichColumns[i];
      double value = originalSolution[iColumn];
      if (value) {
	for (CoinBigIndex j = columnStart[i];
	     j < columnStart[i] + columnLength[i]; j++) {
	  int iRow = row[j];
	  rowActivity[iRow] += value*element[j];
	}
      }
    }
  }
  double * newSolution = new double [numberGubColumns];
  int * slacks = new int [numberSets];
  for (int i=0;i<numberSets;i++) {
    double sum=0.0;
    int iSlack=-1;
    for (int j=startSet[i];j<startSet[i+1];j++) {
      gubMatrix->setDynamicStatus(j,ClpDynamicMatrix::atLowerBound);
      int iColumn = whichColumns[j+numberNormal];
      if (iColumn<numberColumns) {
	columnIsGub[iColumn] = whichRows[numberNonGub+i];
	double value = originalSolution[iColumn];
	sum += value;
	newSolution[j]=value;
	for (CoinBigIndex k = columnStart[j]; k < columnStart[j+1] ; k++) {
	  int iRow = row[k];
	  rowActivity[iRow] += value*element[k];
	  if (element[k] < 0.0)
	    allPositive=false;
	}
	if (columnStart[j]==columnStart[j+1])
	  iSlack=j;
      } else {
	newSolution[j]=0.0;
	iSlack=j;
	allPositive=false; // for now
      }
    }
    slacks[i]=iSlack;
    if (sum>upperSet[i]+1.0e-8) {
      double gap = sum-upperSet[i];
      if (iSlack>=0) {
	double value=newSolution[iSlack];
	if (value>0.0) {
	  double down = CoinMin(gap,value);
	  gap -= down;
	  sum -= down;
	  newSolution[iSlack] = value-down;
	}
      }
      if (gap>1.0e-8) {
	for (int j=startSet[i];j<startSet[i+1];j++) {
	  int iColumn = whichColumns[j+numberNormal];
	  if (newSolution[j]>0.0&&iColumn<numberColumns) {
	    double value = newSolution[j];
	    double down = CoinMin(gap,value);
	    gap -= down;
	    sum -= down;
	    newSolution[iSlack] = value-down;
	    for (CoinBigIndex k = columnStart[j]; k < columnStart[j+1] ; k++) {
	      int iRow = row[k];
	      rowActivity[iRow] -= down*element[k];
	    }
	  }
	}
      }
      assert (gap<1.0e-8);
    } else if (sum<lowerSet[i]-1.0e-8) {
      double gap = lowerSet[i]-sum;
      if (iSlack>=0) {
	double value=newSolution[iSlack];
	if (value<columnUpper[iSlack]) {
	  double up = CoinMin(gap,columnUpper[iSlack]-value);
	  gap -= up;
	  sum += up;
	  newSolution[iSlack] = value+up;
	}
      }
      if (gap>1.0e-8) {
	for (int j=startSet[i];j<startSet[i+1];j++) {
	  int iColumn = whichColumns[j+numberNormal];
	  if (newSolution[j]<columnUpper[j]&&iColumn<numberColumns) {
	    double value = newSolution[j];
	    double up = CoinMin(gap,columnUpper[j]-value);
	    gap -= up;
	    sum += up;
	    newSolution[iSlack] = value+up;
	    for (CoinBigIndex k = columnStart[j]; k < columnStart[j+1] ; k++) {
	      int iRow = row[k];
	      rowActivity[iRow] += up*element[k];
	    }
	  }
	}
      }
      assert (gap<1.0e-8);
    } 
    if (fabs(sum-upperSet[i])>1.0e-7)
      printf("Sum for set %d is %g - lower %g, upper %g\n",i,
	     sum,lowerSet[i],upperSet[i]);
  }
  if (allPositive) {
    // See if we can improve solution
    // first reduce if over
    double * gaps = new double [numberNonGub];
    double direction = optimizationDirection_; 
    const double * cost = gubMatrix->cost();
    bool over=false;
    for (int i=0;i<numberNonGub;i++) {
      double activity = rowActivity[i];
      gaps[i]=0.0;
      if (activity>rowUpper_[i]+1.0e-6) {
	gaps[i]=activity-rowUpper_[i];
	over=true;
      }
    }
    double * weights = new double [numberGubColumns];
    int * which = new int [numberGubColumns];
    int * whichSet = new int [numberGubColumns];
    if (over) {
      int n=0;
      for (int i=0;i<numberSets;i++) {
	int iSlack = slacks[i];
	if (iSlack<0||newSolution[iSlack]>upperSet[i]-1.0e-8)
	  continue;
	double slackCost = cost[iSlack]*direction;
	for (int j=startSet[i];j<startSet[i+1];j++) {
	  whichSet[j]=i;
	  double value = newSolution[j];
	  double thisCost = cost[j]*direction;
	  if (value>columnLower[j]&&j!=iSlack) {
	    if(thisCost<slackCost) {
	      double sum = 1.0e-30;
	      for (CoinBigIndex k = columnStart[j]; 
		   k < columnStart[j+1] ; k++) {
		int iRow = row[k];
		sum += gaps[iRow]*element[k];
	      }
	      which[n]=j;
	      // big drop and small difference in cost better
	      weights[n++]=(slackCost-thisCost)/sum;
	    } else {
	      // slack better anyway
	      double move = value-columnLower[j];
	      newSolution[iSlack]=CoinMin(upperSet[i],
					  newSolution[iSlack]+move);
	      newSolution[j]=columnLower[j];
	      for (CoinBigIndex k = columnStart[j]; 
		   k < columnStart[j+1] ; k++) {
		int iRow = row[k];
		rowActivity[iRow] -= move*element[k];
	      }
	    }
	  }
	}
      }
      // sort
      CoinSort_2(weights,weights+n,which);
      for (int i=0;i<n;i++) {
	int j= which[i];
	int iSet = whichSet[j];
	int iSlack = slacks[iSet];
	assert (iSlack>=0);
	double move = 0.0;
	for (CoinBigIndex k = columnStart[j]; 
	     k < columnStart[j+1] ; k++) {
	  int iRow = row[k];
	  if(rowActivity[iRow]-rowUpper_[iRow]>move*element[k]) {
	    move = (rowActivity[iRow]-rowUpper_[iRow])/element[k];
	  }
	}
	move=CoinMin(move,newSolution[j]-columnLower[j]);
	if (move) {
	  newSolution[j] -= move;
	  newSolution[iSlack] += move;
	  for (CoinBigIndex k = columnStart[j]; 
	       k < columnStart[j+1] ; k++) {
	    int iRow = row[k];
	    rowActivity[iRow] -= move*element[k];
	  }
	}
      }
    }
    delete [] whichSet;
    delete [] which;
    delete [] weights;
    delete [] gaps;
    // redo original status!
    for (int i=0;i<numberSets;i++) {
      int numberBasic=0;
      int numberNewBasic=0;
      int j1=-1;
      int j2=-1;
      for (int j=startSet[i];j<startSet[i+1];j++) {
	if (newSolution[j]>columnLower[j]) {
	  numberNewBasic++;
	  j2=j;
	}
	int iOrig = whichColumns[j+numberNormal];
	if (iOrig<numberColumns) {
	  if (original.getColumnStatus(iOrig)!=ClpSimplex::atLowerBound) {
	    numberBasic++;
	    j1=j;
	  }
	} else {
	  int iSet = iOrig - numberColumns;
	  int iRow = whichRows[iSet+numberNonGub];
	  if (original.getRowStatus(iRow)==ClpSimplex::basic) {
	    numberBasic++;
	    j1=j;
	    abort();
	  }
	}
      }
      if (numberBasic==1&&numberNewBasic==1&&
	  j1!=j2) {
	int iOrig1=whichColumns[j1+numberNormal];
	int iOrig2=whichColumns[j2+numberNormal];
	ClpSimplex::Status status1 = original.getColumnStatus(iOrig1);
	ClpSimplex::Status status2 = original.getColumnStatus(iOrig2);
	originalSolution[iOrig1] = newSolution[j1];
	originalSolution[iOrig2] = newSolution[j2];
	original.setColumnStatus(iOrig1,status2);
	original.setColumnStatus(iOrig2,status1);
      }
    }
  }
  delete [] newSolution;
  delete [] slacks;
  delete [] rowActivity;
#else
  for (int i=0;i<numberSets;i++) {
    for (int j=startSet[i];j<startSet[i+1];j++) {
      gubMatrix->setDynamicStatus(j,ClpDynamicMatrix::atLowerBound);
      int iColumn = whichColumns[j+numberNormal];
      if (iColumn<numberColumns) {
	columnIsGub[iColumn] = whichRows[numberNonGub+i];
      }
    }
  }
#endif
  int * numberKey = new int [numberRows];
  memset(numberKey,0,numberRows*sizeof(int));
  for (int i=0;i<numberGubColumns;i++) {
    int iOrig = whichColumns[i+numberNormal];
    if (iOrig<numberColumns) {
      if (original.getColumnStatus(iOrig)==ClpSimplex::basic) {
	int iRow = columnIsGub[iOrig];
	assert (iRow>=0);
	numberKey[iRow]++;
      }
    } else {
      // Set slack
      int iSet = iOrig - numberColumns;
      int iRow = whichRows[iSet+numberNonGub];
      if (original.getRowStatus(iRow)==ClpSimplex::basic) 
	numberKey[iRow]++;
    }
  }
  /* Before going into cleanMatrix we need
     gub status set (inSmall just means basic and active)
     row status set
  */
  for (int i = 0; i < numberSets; i++) {
    gubMatrix->setStatus(i,ClpSimplex::isFixed);
  }
  for (int i = 0; i < numberGubColumns; i++) {
    int iOrig = whichColumns[i+numberNormal];
    if (iOrig<numberColumns) {
      ClpSimplex::Status status = original.getColumnStatus(iOrig);
      if (status==ClpSimplex::atUpperBound) {
	gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::atUpperBound);
      } else if (status==ClpSimplex::atLowerBound) {
	gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::atLowerBound);
      } else if (status==ClpSimplex::basic) {
	int iRow = columnIsGub[iOrig];
	assert (iRow>=0);
	assert(numberKey[iRow]);
	if (numberKey[iRow]==1)
	  gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::soloKey);
	else
	  gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::inSmall);
      }
    } else {
      // slack
      int iSet = iOrig - numberColumns;
      int iRow = whichRows[iSet+numberNonGub];
      if (original.getRowStatus(iRow)==ClpSimplex::basic
#ifdef TRY_IMPROVE
	  ||newSolution[i]>columnLower[i]+1.0e-8
#endif
	  ) {
	assert(numberKey[iRow]);
	if (numberKey[iRow]==1)
	  gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::soloKey);
	else
	  gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::inSmall);
      } else {
	gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::atLowerBound);
      }
    }
  }
  // deal with sets without key
  for (int i = 0; i < numberSets; i++) {
    int iRow = whichRows[numberNonGub+i];
    if (!numberKey[iRow]) {
      double upper = upperSet[i]-1.0e-7;
      if (original.getRowStatus(iRow)==ClpSimplex::basic) 
	gubMatrix->setStatus(i,ClpSimplex::basic);
      // If not at lb make key otherwise one with smallest number els
      double largest=0.0;
      int fewest=numberRows+1;
      int chosen=-1;
      for (int j=startSet[i];j<startSet[i+1];j++) {
	int length=columnStart[j+1]-columnStart[j];
	int iOrig = whichColumns[j+numberNormal];
	double value;
	if (iOrig<numberColumns) {
#ifdef TRY_IMPROVE
	  value=newSolution[j]-columnLower[j];
#else
	  value = originalSolution[iOrig]-columnLower[j];
#endif
	  if (value>upper)
	    gubMatrix->setStatus(i,ClpSimplex::atLowerBound);
	} else {
	  // slack - take value as 0.0 as will win on length
	  value=0.0;
	}
	if (value>largest+1.0e-8) {
	  largest=value;
	  fewest=length;
	  chosen=j;
	} else if (fabs(value-largest)<=1.0e-8&&length<fewest) {
	  largest=value;
	  fewest=length;
	  chosen=j;
	}
      }
      assert(chosen>=0);
      if (gubMatrix->getStatus(i)!=ClpSimplex::basic) {
	// set as key
	for (int j=startSet[i];j<startSet[i+1];j++) {
	  if (j!=chosen)
	    gubMatrix->setDynamicStatus(j,ClpDynamicMatrix::atLowerBound);
	  else
	    gubMatrix->setDynamicStatus(j,ClpDynamicMatrix::soloKey);
	}
      }
    }
  }
  for (int i = 0; i < numberNormal; i++) {
    int iOrig = whichColumns[i];
    setColumnStatus(i,original.getColumnStatus(iOrig));
    solution[i]=originalSolution[iOrig];
  }
  for (int i = 0; i < numberNonGub; i++) {
    int iOrig = whichRows[i];
    setRowStatus(i,original.getRowStatus(iOrig));
  }
  // Fill in current matrix
  gubMatrix->initialProblem();
  delete [] numberKey;
  delete [] columnIsGub;
}
// Restores basis to original
void 
ClpSimplexOther::getGubBasis(ClpSimplex &original,const int * whichRows,
			     const int * whichColumns) const
{
  ClpDynamicMatrix * gubMatrix =
    dynamic_cast< ClpDynamicMatrix*>(clpMatrix());
  assert(gubMatrix);
  int numberGubColumns = gubMatrix->numberGubColumns();
  int numberNormal = gubMatrix->firstDynamic();
  //int lastOdd = gubMatrix->firstAvailable();
  //int numberRows = original.numberRows();
  int numberColumns = original.numberColumns();
  int numberNonGub = gubMatrix->numberStaticRows();
  //assert (firstOdd==numberNormal);
  double * solution = primalColumnSolution();
  double * originalSolution = original.primalColumnSolution();
  int numberSets = gubMatrix->numberSets();
  const double * cost = original.objective();
  int lastOdd = gubMatrix->firstAvailable();
  //assert (numberTotalColumns==numberColumns+numberSlacks);
  int numberRows = original.numberRows();
  //int numberStaticRows = gubMatrix->numberStaticRows();
  const int * startSet = gubMatrix->startSets();
  unsigned char * status = original.statusArray();
  unsigned char * rowStatus = status+numberColumns;
  //assert (firstOdd==numberNormal);
  for (int i=0;i<numberSets;i++) {
    int iRow = whichRows[i+numberNonGub];
    original.setRowStatus(iRow,ClpSimplex::atLowerBound);
  }
  const int * id = gubMatrix->id();
  const double * columnLower = gubMatrix->columnLower();
  const double * columnUpper = gubMatrix->columnUpper();
  for (int i = 0; i < numberGubColumns; i++) {
    int iOrig = whichColumns[i+numberNormal];
    if (iOrig<numberColumns) {
      if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atUpperBound) {
	originalSolution[iOrig] = columnUpper[i];
	status[iOrig] = 2;
      } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atLowerBound && columnLower) {
	originalSolution[iOrig] = columnLower[i];
	status[iOrig] = 3;
      } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::soloKey) {
	int iSet = gubMatrix->whichSet(i);
	originalSolution[iOrig] = gubMatrix->keyValue(iSet);
	status[iOrig] = 1;
      } else {
	originalSolution[iOrig] = 0.0;
	status[iOrig] = 4;
      }
    } else {
      // slack
      int iSet = iOrig - numberColumns;
      int iRow = whichRows[iSet+numberNonGub];
      if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atUpperBound) {
	original.setRowStatus(iRow,ClpSimplex::atLowerBound);
      } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atLowerBound) {
	original.setRowStatus(iRow,ClpSimplex::atUpperBound);
      } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::soloKey) {
	original.setRowStatus(iRow,ClpSimplex::basic);
      }
    }
  }
  for (int i = 0; i < numberNormal; i++) {
    int iOrig = whichColumns[i];
    ClpSimplex::Status thisStatus = getStatus(i);
    if (thisStatus == ClpSimplex::basic)
      status[iOrig] = 1;
    else if (thisStatus == ClpSimplex::atLowerBound)
      status[iOrig] = 3;
    else if (thisStatus == ClpSimplex::atUpperBound)
      status[iOrig] = 2;
    else if (thisStatus == ClpSimplex::isFixed)
      status[iOrig] = 5;
    else
      abort();
    originalSolution[iOrig] = solution[i];
  }
  for (int i = numberNormal; i < lastOdd; i++) {
    int iOrig = whichColumns[id[i-numberNormal] + numberNormal];
    if (iOrig<numberColumns) {
      ClpSimplex::Status thisStatus = getStatus(i);
      if (thisStatus == ClpSimplex::basic)
	status[iOrig] = 1;
      else if (thisStatus == ClpSimplex::atLowerBound)
	status[iOrig] = 3;
      else if (thisStatus == ClpSimplex::atUpperBound)
	status[iOrig] = 2;
      else if (thisStatus == ClpSimplex::isFixed)
	status[iOrig] = 5;
      else
	abort();
      originalSolution[iOrig] = solution[i];
    } else {
      // slack (basic probably)
      int iSet = iOrig - numberColumns;
      int iRow = whichRows[iSet+numberNonGub];
      ClpSimplex::Status thisStatus = getStatus(i);
      if (thisStatus == ClpSimplex::atLowerBound)
	thisStatus = ClpSimplex::atUpperBound;
      else if (thisStatus == ClpSimplex::atUpperBound)
	thisStatus = ClpSimplex::atLowerBound;
      original.setRowStatus(iRow,thisStatus);
    }
  }
  for (int i = 0; i < numberNonGub; i++) {
    int iOrig = whichRows[i];
    ClpSimplex::Status thisStatus = getRowStatus(i);
    if (thisStatus == ClpSimplex::basic)
      rowStatus[iOrig] = 1;
    else if (thisStatus == ClpSimplex::atLowerBound)
      rowStatus[iOrig] = 3;
    else if (thisStatus == ClpSimplex::atUpperBound)
      rowStatus[iOrig] = 2;
    else if (thisStatus == ClpSimplex::isFixed)
      rowStatus[iOrig] = 5;
    else
      abort();
  }
  int * numberKey = new int [numberRows];
  memset(numberKey,0,numberRows*sizeof(int));
  for (int i=0;i<numberSets;i++) {
    int iRow = whichRows[i+numberNonGub];
    for (int j=startSet[i];j<startSet[i+1];j++) {
      int iOrig = whichColumns[j+numberNormal];
      if (iOrig<numberColumns) {
	if (original.getColumnStatus(iOrig)==ClpSimplex::basic) {
	  numberKey[iRow]++;
	}
      } else {
	// slack
	if (original.getRowStatus(iRow)==ClpSimplex::basic) 
	  numberKey[iRow]++;
      }
    }
  }
  for (int i=0;i<numberSets;i++) {
    int iRow = whichRows[i+numberNonGub];
    if (!numberKey[iRow]) {
      original.setRowStatus(iRow,ClpSimplex::basic);
    }
  }
  delete [] numberKey;
  double objValue = 0.0;
  for (int i = 0; i < numberColumns; i++)
    objValue += cost[i] * originalSolution[i];
  //printf("objective value is %g\n", objValue);
}
/*
  Modifies coefficients etc and if necessary pivots in and out.
  All at same status will be done (basis may go singular).
  User can tell which others have been done (i.e. if status matches).
  If called from outside will change status and return 0 (-1 if not ClpPacked)
  If called from event handler returns non-zero if user has to take action.
  -1 - not ClpPackedMatrix
  0 - no pivots
  1 - pivoted
  2 - pivoted and optimal
  3 - refactorize
  4 - worse than that
  indices>=numberColumns are slacks (obviously no coefficients)
  status array is (char) Status enum
*/
int 
ClpSimplex::modifyCoefficientsAndPivot(int number,
				       const int * which,
				       const CoinBigIndex * start,
				       const int * row,
				       const double * newCoefficient,
				       const unsigned char * newStatus,
				       const double * newLower,
				       const double * newUpper,
				       const double * newObjective)
{
  ClpPackedMatrix* clpMatrix =
    dynamic_cast< ClpPackedMatrix*>(matrix_);
  bool canPivot = lower_!=NULL && factorization_!=NULL;
  int returnCode=0;
  if (!clpMatrix) {
    canPivot=false;
    returnCode=-1;
    // very slow
    for (int i=0;i<number;i++) {
      int iSequence=which[i];
      if (iSequence<numberColumns_) {
	for (CoinBigIndex j=start[i];j<start[i+1];j++) {
 	  matrix_->modifyCoefficient(row[j],iSequence,newCoefficient[j]);
	}
      } else {
	assert (start[i]==start[i+1]);
      }
    }
  } else {
#if 0
    // when in stable
    CoinPackedMatrix * matrix = clpMatrix->getPackedMatrix();
    matrix->modifyCoefficients(number,which,start,
			       row,newCoefficient);
#else
    // Copy and sort which
    int * which2 = new int [2*number+2];
    int * sort = which2+number+1;
    int n=0;
    for (int i=0;i<number;i++) {
      int iSequence=which[i];
      if (iSequence<numberColumns_) {
	which2[n]=iSequence;
	sort[n++]=i;
      } else {
	assert (start[i]==start[i+1]);
      }
    }
    if (n) {
      CoinIndexedVector * rowVector=NULL;
      for (int i=0;i<4;i++) {
	if (rowArray_[i]&&!rowArray_[i]->getNumElements()) {
	  rowVector = rowArray_[i];
	  break;
	}
      }
      bool tempVector=false;
      if (!rowVector) {
	tempVector=true;
	rowVector=new CoinIndexedVector(numberRows_);
      }
      CoinSort_2(which2,which2+n,sort);
      // Stop at end
      which2[n]=numberColumns_;
      sort[n]=n;
      CoinPackedMatrix * matrix = clpMatrix->getPackedMatrix();
      int * rowNow = matrix->getMutableIndices();
      CoinBigIndex * columnStart = matrix->getMutableVectorStarts();
      int * columnLength = matrix->getMutableVectorLengths();
      double * elementByColumn = matrix->getMutableElements();
      double * array = rowVector->denseVector();
      //int * index = rowVector->getIndices();
      int needed=0;
      bool moveUp=false;
      for (int i=0;i<n;i++) {
	int inWhich=sort[i];
	int iSequence=which2[inWhich];
	int nZeroNew=0;
	int nZeroOld=0;
	for (CoinBigIndex j=start[inWhich];j<start[inWhich+1];j++) {
	  int iRow=row[j];
	  double newValue=newCoefficient[j];
	  if (!newValue) {
	    newValue = COIN_INDEXED_REALLY_TINY_ELEMENT;
	    nZeroNew++;
	  }
	  array[iRow]=newValue;
	}
	for (CoinBigIndex j=columnStart[iSequence];
	     j<columnStart[iSequence]+columnLength[iSequence];j++) {
	  int iRow=rowNow[j];
	  double oldValue=elementByColumn[j];
	  if (fabs(oldValue)>COIN_INDEXED_REALLY_TINY_ELEMENT) {
	    double newValue=array[iRow];
	    if (oldValue!=newValue) {
	      if (newValue) {
		array[iRow]=0.0;
		if (newValue==COIN_INDEXED_REALLY_TINY_ELEMENT) {
		  needed--;
		}
	      }
	    }
	  } else {
	    nZeroOld++;
	  }
	}
	assert (!nZeroOld);
	for (CoinBigIndex j=start[inWhich];j<start[inWhich+1];j++) {
	  int iRow=row[j];
	  double newValue=array[iRow];
	  if (newValue) {
	    array[iRow]=0.0;
	    needed++;
	    if (needed>0)
	      moveUp=true;
	  }
	}
      }
      int numberElements = matrix->getNumElements();
      assert (numberElements==columnStart[numberColumns_]);
      if (needed>0) {
	// need more space
	matrix->reserve(numberColumns_, numberElements+needed);
	rowNow = matrix->getMutableIndices();
	elementByColumn = matrix->getMutableElements();
      }
      if (moveUp) {
	// move up from top
	CoinBigIndex top = numberElements+needed;
	for (int iColumn=numberColumns_-1;iColumn>=0;iColumn--) {
	  CoinBigIndex end = columnStart[iColumn+1];
	  columnStart[iColumn+1]=top;
	  CoinBigIndex startThis = columnStart[iColumn];
	  for (CoinBigIndex j=end-1;j>=startThis;j--) {
	    if (elementByColumn[j]) {
	      top--;
	      elementByColumn[top]=elementByColumn[j];
	      rowNow[top]=rowNow[j];
	    }
	  }
	}
	columnStart[0]=top;
      }
      // now move down and insert
      CoinBigIndex put=0;
      int iColumn=0;
      for (int i=0;i<n+1;i++) {
	int inWhich=sort[i];
	int nextMod=which2[inWhich];
	for (;iColumn<nextMod;iColumn++) {
	  CoinBigIndex startThis = columnStart[iColumn];
	  columnStart[iColumn]=put;
	  for (CoinBigIndex j=startThis;
	       j<columnStart[iColumn+1];j++) {
	    int iRow=rowNow[j];
	    double oldValue=elementByColumn[j];
	    if (oldValue) {
	      rowNow[put]=iRow;
	      elementByColumn[put++]=oldValue;
	    }
	  }
	}
	if (i==n) {
	  columnStart[iColumn]=put;
	  break;
	}
	// Now 
	for (CoinBigIndex j=start[inWhich];j<start[inWhich+1];j++) {
	  int iRow=row[j];
	  double newValue=newCoefficient[j];
	  if (!newValue) {
	    newValue = COIN_INDEXED_REALLY_TINY_ELEMENT;
	  }
	  array[iRow]=newValue;
	}
	CoinBigIndex startThis = columnStart[iColumn];
	columnStart[iColumn]=put;
	for (CoinBigIndex j=startThis;
	     j<columnStart[iColumn+1];j++) {
	  int iRow=rowNow[j];
	  double oldValue=elementByColumn[j];
	  if (array[iRow]) {
	    oldValue=array[iRow];
	    if (oldValue==COIN_INDEXED_REALLY_TINY_ELEMENT) 
	      oldValue=0.0;
	    array[iRow]=0.0;
	  }
	  if (fabs(oldValue)>COIN_INDEXED_REALLY_TINY_ELEMENT) {
	    rowNow[put]=iRow;
	    elementByColumn[put++]=oldValue;
	  }
	}
	for (CoinBigIndex j=start[inWhich];j<start[inWhich+1];j++) {
	  int iRow=row[j];
	  double newValue=array[iRow];
	  if (newValue) {
	    array[iRow]=0.0;
	    rowNow[put]=iRow;
	    elementByColumn[put++]=newValue;
	  }
	}
	iColumn++;
      }
      matrix->setNumElements(put);
      if (tempVector)
	delete rowVector;
      for (int i=0;i<numberColumns_;i++) {
	columnLength[i]=columnStart[i+1]-columnStart[i];
      }
    }
#endif
    if (canPivot) {
      // ? faster to modify row copy??
      if (rowCopy_&&start[number]) {
	delete rowCopy_;
	rowCopy_ = clpMatrix->reverseOrderedCopy();
      }
      assert (!newStatus); // do later
      int numberPivots = factorization_->pivots();
      int needed=0;
      for (int i=0;i<number;i++) {
	int iSequence=which[i];
	if (start[i+1]>start[i]&&getStatus(iSequence)==basic)
	  needed++;
      }
      if (needed&&numberPivots+needed<20&&needed<-2) {
	// update factorization
	int saveIn = sequenceIn_;
	int savePivot = pivotRow_;
	int nArray=0;
	CoinIndexedVector * vec[2];
	for (int i=0;i<4;i++) {
	  if (!rowArray_[i]->getNumElements()) {
	    vec[nArray++]=rowArray_[i];
	    if (nArray==2)
	      break;
	  }
	}
	assert (nArray==2); // could use temp array
	for (int i=0;i<number;i++) {
	  int sequenceIn_=which[i];
	  if (start[i+1]>start[i]&&getStatus(sequenceIn_)==basic) {
	    // find pivot row
	    for (pivotRow_=0;pivotRow_<numberRows_;pivotRow_++) {
	      if (pivotVariable_[pivotRow_]==sequenceIn_) 
		break;
	    }
	    assert(pivotRow_<numberRows_);
	    // unpack column
	    assert(!vec[0]->getNumElements());
#ifndef COIN_FAC_NEW
	    unpackPacked(vec[0]);
#else
	    unpack(vec[0]);
#endif
	    // update
	    assert(!vec[1]->getNumElements());
	    factorization_->updateColumnFT(vec[1], vec[0]);
	    const double * array = vec[0]->denseVector();
#ifndef COIN_FAC_NEW
	    // Find alpha
	    const int * indices = vec[0]->getIndices();
	    int n=vec[0]->getNumElements();
	    alpha_=0.0;
	    for (int i=0;i<n;i++) {
	      if (indices[i]==pivotRow_) {
		alpha_ = array[i];
		break;
	      }
	    }
#else
	    alpha_ = array[pivotRow_];
#endif
	    int updateStatus=2;
	    if (fabs(alpha_)>1.0e-7) 
	      updateStatus = factorization_->replaceColumn(this,
							   vec[1],
							   vec[0],
							   pivotRow_,
							   alpha_);
	    assert(!vec[1]->getNumElements());
	    vec[0]->clear();
	    if (updateStatus) {
	      returnCode=3;
	      break;
	    }
	  }
	}
	sequenceIn_=saveIn;
	pivotRow_ = savePivot;
	if (!returnCode)
	  returnCode=100; // say can do more
      } else if (needed) {
	returnCode=3; // refactorize
      }
    }
  }
  if (newStatus) {
    for (int i=0;i<number;i++) {
      int iSequence=which[i];
      status_[iSequence]=newStatus[i];
    }
  }
  if (newLower) {
    for (int i=0;i<number;i++) {
      int iSequence=which[i];
      if (iSequence<numberColumns_) {
	if (columnLower_[iSequence]!=newLower[i]) {
	  columnLower_[iSequence]=newLower[i];
	}
      } else {
	iSequence -= numberColumns_;
	if (rowLower_[iSequence]!=newLower[i]) {
	  rowLower_[iSequence]=newLower[i];
	}
      }
    }
  }
  if (newLower) {
    for (int i=0;i<number;i++) {
      int iSequence=which[i];
      if (iSequence<numberColumns_) {
	if (columnLower_[iSequence]!=newLower[i]) {
	  columnLower_[iSequence]=newLower[i];
	}
      } else {
	iSequence -= numberColumns_;
	if (rowLower_[iSequence]!=newLower[i]) {
	  rowLower_[iSequence]=newLower[i];
	}
      }
    }
  }
  if (newUpper) {
    for (int i=0;i<number;i++) {
      int iSequence=which[i];
      if (iSequence<numberColumns_) {
	if (columnUpper_[iSequence]!=newUpper[i]) {
	  columnUpper_[iSequence]=newUpper[i];
	}
      } else {
	iSequence -= numberColumns_;
	if (rowUpper_[iSequence]!=newUpper[i]) {
	  rowUpper_[iSequence]=newUpper[i];
	}
      }
    }
  }
  if (newObjective) {
    double * obj = objective();
    for (int i=0;i<number;i++) {
      int iSequence=which[i];
      if (iSequence<numberColumns_) {
	if (obj[iSequence]!=newObjective[i]) {
	  obj[iSequence]=newObjective[i];
	}
      } else {
	  assert (!newObjective[i]);
      }
    }
  }
  if (canPivot) {
    // update lower, upper, objective and nonLinearCost
    assert (!rowScale_); // for now
    memcpy(lower_,columnLower_,numberColumns_*sizeof(double));
    memcpy(lower_+numberColumns_,rowLower_,numberRows_*sizeof(double));
    memcpy(upper_,columnUpper_,numberColumns_*sizeof(double));
    memcpy(upper_+numberColumns_,rowUpper_,numberRows_*sizeof(double));
    memcpy(cost_,objective(),numberColumns_*sizeof(double));
    memset(cost_+numberColumns_,0,numberRows_*sizeof(double));
    // ? parameter to say no gutsOfSolution needed
    // make sure slacks have correct value
    // see if still optimal
    if (returnCode==100) {
      // is this needed
      if (nonLinearCost_) {
	// speed up later
	//nonLinearCost_->checkInfeasibilities(oldTolerance);
	delete nonLinearCost_;
	nonLinearCost_ = new ClpNonLinearCost(this);
      }
      gutsOfSolution(NULL,NULL,false);
      assert (!newStatus);
      printf("%d primal %d dual\n",numberPrimalInfeasibilities_,
	     numberDualInfeasibilities_);
      returnCode=3;
    } else {
      // is this needed
      if (nonLinearCost_) {
	// speed up later
#if 1
	for (int i=0;i<number;i++) {
	  int iSequence=which[i];
	  nonLinearCost_->setOne(iSequence,solution_[iSequence],
				 lower_[iSequence],upper_[iSequence],
				 cost_[iSequence]);
	}
#else	
	//nonLinearCost_->checkInfeasibilities(oldTolerance);
	delete nonLinearCost_;
	nonLinearCost_ = new ClpNonLinearCost(this);
	//nonLinearCost_->checkInfeasibilities(0.0);
#endif
	//gutsOfSolution(NULL,NULL,false);
	assert (!newStatus);
      }
    }
  }
  return returnCode;
}

/* Pivot out a variable and choose an incoing one.  Assumes dual
   feasible - will not go through a reduced cost.
   Returns step length in theta
   Return codes as before but -1 means no acceptable pivot
*/
int
ClpSimplex::dualPivotResultPart1()
{
     return static_cast<ClpSimplexDual *> (this)->pivotResultPart1();
}
/* Do actual pivot
   state is 1,3 if got tableau column in rowArray_[1]
   2,3 if got tableau row in rowArray_[0] and columnArray_[0]
*/
int 
ClpSimplex::pivotResultPart2(int algorithm,int state)
{
  if (!(state&1)) {
    // update the incoming column
#ifndef COIN_FAC_NEW
    unpackPacked(rowArray_[1]);
#else
    unpack(rowArray_[1]);
#endif
    factorization_->updateColumnFT(rowArray_[2], rowArray_[1]);
  }
#define CHECK_TABLEAU 0
  if (!(state&2)||CHECK_TABLEAU) {
    // get tableau row
    // create as packed
    double direction = directionOut_;
    assert (!rowArray_[2]->getNumElements());
    assert (!columnArray_[1]->getNumElements());
#if CHECK_TABLEAU
    printf("rowArray0 old\n");
    rowArray_[0]->print();
    rowArray_[0]->clear();
    printf("columnArray0 old\n");
    columnArray_[0]->print();
    columnArray_[0]->clear();
#else
    assert (!columnArray_[0]->getNumElements());
    assert (!rowArray_[0]->getNumElements());
#endif
#ifndef COIN_FAC_NEW
    rowArray_[0]->createPacked(1, &pivotRow_, &direction);
#else
    rowArray_[0]->createOneUnpackedElement(pivotRow_, direction);
#endif
    factorization_->updateColumnTranspose(rowArray_[2], rowArray_[0]);
    rowArray_[3]->clear();
    // put row of tableau in rowArray[0] and columnArray[0]
    assert (!rowArray_[2]->getNumElements());
    matrix_->transposeTimes(this, -1.0,
			    rowArray_[0], rowArray_[2], columnArray_[0]);
#if CHECK_TABLEAU
    printf("rowArray0 new\n");
    rowArray_[0]->print();
    printf("columnArray0 new\n");
    columnArray_[0]->print();
#endif
  }
  assert (pivotRow_>=0);
  assert (sequenceIn_>=0);
  assert (sequenceOut_>=0);
  int returnCode=-1;
  if (algorithm>0) {
    // replace in basis
    int updateStatus = factorization_->replaceColumn(this,
						     rowArray_[2],
						     rowArray_[1],
						     pivotRow_,
						     alpha_);
    if (!updateStatus) {
      dualIn_ = cost_[sequenceIn_];
      double * work = rowArray_[1]->denseVector();
      int number = rowArray_[1]->getNumElements();
      int * which = rowArray_[1]->getIndices();
      for (int i = 0; i < number; i++) {
	int iRow = which[i];
#ifndef COIN_FAC_NEW
	double alpha = work[i];
#else
	double alpha = work[iRow];
#endif
	int iPivot = pivotVariable_[iRow];
	dualIn_ -= alpha * cost_[iPivot];
      }
      returnCode=0;
      double multiplier = dualIn_ / alpha_;
      // update column djs
      int i;
      int * index = columnArray_[0]->getIndices();
      number = columnArray_[0]->getNumElements();
      double * element = columnArray_[0]->denseVector();
      assert (columnArray_[0]->packedMode());
      for (i = 0; i < number; i++) {
	int iSequence = index[i];
	dj_[iSequence] += multiplier*element[i];
	reducedCost_[iSequence] = dj_[iSequence];
	element[i] = 0.0;
      }
      columnArray_[0]->setNumElements(0);
      // and row djs
      index = rowArray_[0]->getIndices();
      number = rowArray_[0]->getNumElements();
      element = rowArray_[0]->denseVector();
#ifndef COIN_FAC_NEW
      assert (rowArray_[0]->packedMode());
      for (i = 0; i < number; i++) {
	int iSequence = index[i];
	dj_[iSequence+numberColumns_] += multiplier*element[i];
	dual_[iSequence] = dj_[iSequence+numberColumns_];
	element[i] = 0.0;
      }
#else
      assert (!rowArray_[0]->packedMode());
      for (i = 0; i < number; i++) {
	int iSequence = index[i];
	dj_[iSequence+numberColumns_] += multiplier*element[iSequence];
	dual_[iSequence] = dj_[iSequence+numberColumns_];
	element[iSequence] = 0.0;
      }
#endif
      rowArray_[0]->setNumElements(0);
      double oldCost = cost_[sequenceOut_];
      // update primal solution
      
      double objectiveChange = 0.0;
      // after this rowArray_[1] is not empty - used to update djs
      static_cast<ClpSimplexPrimal *>(this)->updatePrimalsInPrimal(rowArray_[1], theta_, objectiveChange, 0);
      double oldValue = valueIn_;
      if (directionIn_ == -1) {
	// as if from upper bound
	if (sequenceIn_ != sequenceOut_) {
	  // variable becoming basic
	  valueIn_ -= fabs(theta_);
	} else {
	  valueIn_ = lowerIn_;
	}
      } else {
	// as if from lower bound
	if (sequenceIn_ != sequenceOut_) {
	  // variable becoming basic
	  valueIn_ += fabs(theta_);
	} else {
	  valueIn_ = upperIn_;
	}
      }
      objectiveChange += dualIn_ * (valueIn_ - oldValue);
      // outgoing
      if (sequenceIn_ != sequenceOut_) {
	if (directionOut_ > 0) {
	  valueOut_ = lowerOut_;
	} else {
	  valueOut_ = upperOut_;
	}
	if(valueOut_ < lower_[sequenceOut_] - primalTolerance_)
	  valueOut_ = lower_[sequenceOut_] - 0.9 * primalTolerance_;
	else if (valueOut_ > upper_[sequenceOut_] + primalTolerance_)
	  valueOut_ = upper_[sequenceOut_] + 0.9 * primalTolerance_;
	// may not be exactly at bound and bounds may have changed
	// Make sure outgoing looks feasible
	directionOut_ = nonLinearCost_->setOneOutgoing(sequenceOut_, valueOut_);
	// May have got inaccurate
	//if (oldCost!=cost_[sequenceOut_])
	//printf("costchange on %d from %g to %g\n",sequenceOut_,
	//       oldCost,cost_[sequenceOut_]);
	dj_[sequenceOut_] = cost_[sequenceOut_] - oldCost; // normally updated next iteration
	solution_[sequenceOut_] = valueOut_;
      }
      // change cost and bounds on incoming if primal
      nonLinearCost_->setOne(sequenceIn_, valueIn_);
      progress_.startCheck(); // make sure won't worry about cycling
      int whatNext = housekeeping(objectiveChange);
      if (whatNext == 1) {
	returnCode = -2; // refactorize
      } else if (whatNext == 2) {
	// maximum iterations or equivalent
	returnCode = 3;
      } else if(numberIterations_ == lastGoodIteration_
		+ 2 * factorization_->maximumPivots()) {
	// done a lot of flips - be safe
	returnCode = -2; // refactorize
      }
    } else {
      // ?
      abort();
    }
  } else {
    // dual
    // recompute dualOut_
    if (directionOut_ < 0) {
      dualOut_ = valueOut_ - upperOut_;
    } else {
      dualOut_ = lowerOut_ - valueOut_;
    }
    // update the incoming column
    double btranAlpha = -alpha_ * directionOut_; // for check
    rowArray_[1]->clear();
#ifndef COIN_FAC_NEW
    unpackPacked(rowArray_[1]);
#else
    unpack(rowArray_[1]);
#endif
    // moved into updateWeights - factorization_->updateColumnFT(rowArray_[2],rowArray_[1]);
    // and update dual weights (can do in parallel - with extra array)
    alpha_ = dualRowPivot_->updateWeights(rowArray_[0],
					  rowArray_[2],
					  rowArray_[3],
					  rowArray_[1]);
    // see if update stable
#ifdef CLP_DEBUG
    if ((handler_->logLevel() & 32))
      printf("btran alpha %g, ftran alpha %g\n", btranAlpha, alpha_);
#endif
    double checkValue = 1.0e-7;
    // if can't trust much and long way from optimal then relax
    if (largestPrimalError_ > 10.0)
      checkValue = CoinMin(1.0e-4, 1.0e-8 * largestPrimalError_);
    if (fabs(btranAlpha) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
	fabs(btranAlpha - alpha_) > checkValue*(1.0 + fabs(alpha_))) {
      handler_->message(CLP_DUAL_CHECK, messages_)
	<< btranAlpha
	<< alpha_
	<< CoinMessageEol;
      if (factorization_->pivots()) {
	dualRowPivot_->unrollWeights();
	problemStatus_ = -2; // factorize now
	rowArray_[0]->clear();
	rowArray_[1]->clear();
	columnArray_[0]->clear();
	returnCode = -2;
	abort();
	return returnCode;
      } else {
	// take on more relaxed criterion
	double test;
	if (fabs(btranAlpha) < 1.0e-8 || fabs(alpha_) < 1.0e-8)
	  test = 1.0e-1 * fabs(alpha_);
	else
	  test = 1.0e-4 * (1.0 + fabs(alpha_));
	if (fabs(btranAlpha) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
	    fabs(btranAlpha - alpha_) > test) {
	  abort();
	}
      }
    }
    // update duals BEFORE replaceColumn so can do updateColumn
    double objectiveChange = 0.0;
    // do duals first as variables may flip bounds
    // rowArray_[0] and columnArray_[0] may have flips
    // so use rowArray_[3] for work array from here on
    int nswapped = 0;
    //rowArray_[0]->cleanAndPackSafe(1.0e-60);
    //columnArray_[0]->cleanAndPackSafe(1.0e-60);
    // make sure incoming doesn't count
    Status saveStatus = getStatus(sequenceIn_);
    setStatus(sequenceIn_, basic);
    nswapped = 
      static_cast<ClpSimplexDual *>(this)->updateDualsInDual(rowArray_[0], columnArray_[0],
				 rowArray_[2], theta_,
				 objectiveChange, false);
    assert (!nswapped);
    setStatus(sequenceIn_, saveStatus);
    double oldDualOut = dualOut_;
    // which will change basic solution
    if (nswapped) {
      if (rowArray_[2]->getNumElements()) {
	factorization_->updateColumn(rowArray_[3], rowArray_[2]);
	dualRowPivot_->updatePrimalSolution(rowArray_[2],
					    1.0, objectiveChange);
      }
      // recompute dualOut_
      valueOut_ = solution_[sequenceOut_];
      if (directionOut_ < 0) {
	dualOut_ = valueOut_ - upperOut_;
      } else {
	dualOut_ = lowerOut_ - valueOut_;
      }
    }
    // amount primal will move
    double movement = -dualOut_ * directionOut_ / alpha_;
    double movementOld = oldDualOut * directionOut_ / alpha_;
    // so objective should increase by fabs(dj)*movement
    // but we already have objective change - so check will be good
    if (objectiveChange + fabs(movementOld * dualIn_) < -CoinMax(1.0e-5, 1.0e-12 * fabs(objectiveValue_))) {
      if (handler_->logLevel() & 32)
	printf("movement %g, swap change %g, rest %g  * %g\n",
	       objectiveChange + fabs(movement * dualIn_),
	       objectiveChange, movement, dualIn_);
    }
    // if stable replace in basis
    int updateStatus = factorization_->replaceColumn(this,
						     rowArray_[2],
						     rowArray_[1],
						     pivotRow_,
						     alpha_);
    // If looks like bad pivot - refactorize
    if (fabs(dualOut_) > 1.0e50)
      updateStatus = 2;
    // if no pivots, bad update but reasonable alpha - take and invert
    if (updateStatus == 2 &&
	!factorization_->pivots() && fabs(alpha_) > 1.0e-5)
      updateStatus = 4;
    if (updateStatus == 1 || updateStatus == 4) {
      // slight error
      if (factorization_->pivots() > 5 || updateStatus == 4) {
	problemStatus_ = -2; // factorize now
	returnCode = -3;
      }
    } else if (updateStatus == 2) {
      // major error
      dualRowPivot_->unrollWeights();
      // later we may need to unwind more e.g. fake bounds
      if (factorization_->pivots() &&
	  ((moreSpecialOptions_ & 16) == 0 || factorization_->pivots() > 4)) {
	problemStatus_ = -2; // factorize now
	returnCode = -2;
	moreSpecialOptions_ |= 16;
	return returnCode;
      } else {
	// need to reject something
	abort();
      }
    } else if (updateStatus == 3) {
      // out of memory
      // increase space if not many iterations
      if (factorization_->pivots() <
	  0.5 * factorization_->maximumPivots() &&
	  factorization_->pivots() < 200)
	factorization_->areaFactor(
				   factorization_->areaFactor() * 1.1);
      problemStatus_ = -2; // factorize now
    } else if (updateStatus == 5) {
      problemStatus_ = -2; // factorize now
    }
    // update primal solution
    if (theta_ < 0.0) {
      if (handler_->logLevel() & 32)
	printf("negative theta %g\n", theta_);
      theta_ = 0.0;
    }
    // do actual flips (should not be any?)
    static_cast<ClpSimplexDual *>(this)->flipBounds(rowArray_[0], columnArray_[0]);
      //rowArray_[1]->expand();
    dualRowPivot_->updatePrimalSolution(rowArray_[1],
					movement,
					objectiveChange);
    // modify dualout
    dualOut_ /= alpha_;
    dualOut_ *= -directionOut_;
    //setStatus(sequenceIn_,basic);
    dj_[sequenceIn_] = 0.0;
    double oldValue = valueIn_;
    if (directionIn_ == -1) {
      // as if from upper bound
      valueIn_ = upperIn_ + dualOut_;
    } else {
      // as if from lower bound
      valueIn_ = lowerIn_ + dualOut_;
    }
    objectiveChange += cost_[sequenceIn_] * (valueIn_ - oldValue);
    // outgoing
    // set dj to zero unless values pass
    if (directionOut_ > 0) {
      valueOut_ = lowerOut_;
      dj_[sequenceOut_] = theta_;
    } else {
      valueOut_ = upperOut_;
      dj_[sequenceOut_] = -theta_;
    }
    solution_[sequenceOut_] = valueOut_;
    int whatNext = housekeeping(objectiveChange);
    // and set bounds correctly
    static_cast<ClpSimplexDual *>(this)->originalBound(sequenceIn_);
    static_cast<ClpSimplexDual *>(this)->changeBound(sequenceOut_);
    if (whatNext == 1) {
      problemStatus_ = -2; // refactorize
    } else if (whatNext == 2) {
      // maximum iterations or equivalent
      problemStatus_ = 3;
      returnCode = 3;
      abort();
    }
  }
  // Check event
  {
    int status = eventHandler_->event(ClpEventHandler::endOfIteration);
    if (status >= 0) {
      problemStatus_ = 5;
      secondaryStatus_ = ClpEventHandler::endOfIteration;
      returnCode = 3;
    }
  }
  // need to be able to refactoriza
  //printf("return code %d problem status %d\n",
  //	 returnCode,problemStatus_);
  return returnCode;
}
#ifdef COIN_SHORT_SORT
#define USE_HASH 1
#else
#define USE_HASH 0
#endif
#if USE_HASH==2
static const unsigned int mmult[] = {
  262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247};
// Returns a hash value
inline unsigned int 
hashValue(double value, unsigned int maxHash) 
{
  const char * name = reinterpret_cast<char *>(&value);
  unsigned int n = 0;
  for (int j = 0; j < 8; ++j ) {
    n += mmult[j] * name[j];
  }
  return ( n  % maxHash );
}
/*
 */
static int sameTogether(unsigned int nin,int * which, double * weights,
			int * which2, double * weights2, unsigned int * hash)
{
  if (nin<=1)
    return nin;
  // move up and fill hash
  unsigned int maxHash=4*nin;
  memset(hash,0xf0,maxHash*sizeof(int));
  int * spare=which2+maxHash;
  int n2=0;
  unsigned int iNext = hashValue (weights[0],maxHash);
  unsigned int endMarker=0x80000000+maxHash;
  hash[iNext]=endMarker;
  unsigned int iLast=iNext;
  weights2[iNext]=weights[0];
  which2[iNext]=which[0];
  for (unsigned int i=1;i<nin;i++) {
    double value = weights[i];
    unsigned int ipos = hashValue (value,maxHash);
    if ( hash[ipos] == 0xf0f0f0f0 ) {
      hash[iLast] = ipos+0x80000000;
      hash[ipos]=endMarker;
      weights2[ipos]=value;
      which2[ipos]=which[i];
      iLast=ipos;
    } else {
      spare[n2++]=i;
    }
  }
  unsigned int lastSlot = 0;
  for (int j = 0; j < n2; ++j ) {
    int i = spare[j];
    double value=weights[i];
    unsigned int ipos = hashValue ( value , maxHash);
    iLast=ipos;
    while ( hash[ipos] <= 0x80000000) {
      iLast=ipos;
      ipos=hash[ipos];
    }
    while (hash[lastSlot]!=0xf0f0f0f0)
      lastSlot++;
    assert (lastSlot<maxHash);
    hash[lastSlot] = hash[ipos];
    hash[iLast] = lastSlot;
    weights2[lastSlot]=value;
    which2[lastSlot]=which[i];
  }
  int put=0;
  //unsigned int iNext=0;
  int savePut=0;
  while (iNext!=maxHash) {
    weights[put]=weights2[iNext];
    assert (iNext<maxHash);
    which[put++]=which2[iNext];
    iNext = hash[iNext];
    if (iNext>0x7fffffff) {
      // end 
      if (put>savePut+1) {
	CoinShortSort_2(weights+savePut,weights+put,which+savePut);
	// keep
#if 0
	printf("DUP2 value %g ",weights[savePut]);
	for (int i=savePut;i<put;i++)
	  printf("%d (%g) ",which[i],weights[i]);
	printf("\n");
#endif
	savePut=put;
      } else {
	// no
	put=savePut;
      }
      iNext -= 0x80000000;
    }
  }
  return savePut;
}
#endif
#include "CoinPresolveMatrix.hpp"
/* Take out duplicate rows (includes scaled rows and intersections).
   On exit whichRows has rows to delete - return code is number can be deleted 
   or -1 if would be infeasible.
   If tolerance is -1.0 use primalTolerance for equality rows and infeasibility
   If cleanUp not zero then spend more time trying to leave more stable row
   and make row bounds exact multiple of cleanUp if close enough
   moves status to try and delete a basic slack
*/
int 
ClpSimplex::outDuplicateRows(int numberLook,int * whichRows, bool noOverlaps,
			     double tolerance,double cleanUp) 
{
#if USE_HASH<2
  double * weights = new double [numberLook+numberColumns_];
#else
  int numberAlloc=5*numberLook+numberColumns_+((9*numberLook+1)/(sizeof(double)/sizeof(int)));
  double * weights = new double [numberAlloc];
  double * weights2=weights+numberLook+numberColumns_;
#endif
  double * columnWeights = weights+numberLook;
#ifndef COIN_REUSE_RANDOM
  coin_init_random_vec(columnWeights,numberColumns_);
#else
  for (int i=0;i<numberColumns_;i++)
    columnWeights[i]=CoinDrand48();
#endif
#if USE_HASH==1
  typedef struct {
#define INTEL // need way to find out at compile time
#ifdef INTEL
    int which;
    float value;
#else
    float value;
    int which;
#endif
  } hash_1;
  typedef struct {
    union {
      double d;
      hash_1 hash;
    } item;
  } hash;
  assert (sizeof(double) == 8);
  hash * hashWeights = reinterpret_cast<hash *>(weights);
#endif
#if 0
  int counts[5]={0,0,0,0,0};
  int countsEq[5]={0,0,0,0,0};
#endif
  // get row copy
  CoinPackedMatrix rowCopy = *matrix();
  rowCopy.reverseOrdering();
  int * column = rowCopy.getMutableIndices();
  CoinBigIndex * rowStart = rowCopy.getMutableVectorStarts();
  int * rowLength = rowCopy.getMutableVectorLengths();
  double * element = rowCopy.getMutableElements();
  //double wwww[200];
  //assert (numberLook<=200);
  //int iiii[200];
  for (int i=0;i<numberLook;i++) {
    int iRow=whichRows[i];
    double value = 0.0;
    CoinBigIndex start=rowStart[iRow];
    CoinBigIndex end = start+rowLength[iRow];
    // sort (probably in order anyway)
#ifdef COIN_SHORT_SORT
    CoinShortSort_2(column+start,column+end,element+start);
#else
    CoinSort_2(column+start,column+end,element+start);
#endif
    for (CoinBigIndex j=start;j<end;j++) {
      int iColumn = column[j];
      value += columnWeights[iColumn];
    }
#if USE_HASH ==1
    //printf("iLook %d weight %g (before)\n",i,value);
    hash temp;
    temp.item.d=value;
    temp.item.hash.which=iRow;
    hashWeights[i]=temp;
    //wwww[i]=value;
    //iiii[i]=iRow;
#else
    weights[i]=value;
#endif
  }
  //#define PRINT_DUP
#if USE_HASH == 0
#if 0
  if (false) {
    double * w =CoinCopyOfArray(weights,numberLook);
    int * ind = CoinCopyOfArray(whichRows,numberLook);
    double * weights2=new double[50000];
    int * which2 = reinterpret_cast<int *>(weights2+4*numberLook);
    unsigned int * hash = reinterpret_cast<unsigned int *>(which2+5*numberLook);
    int n=sameTogether(numberLook,ind,w,which2,weights2,hash);
    printf("Reduced length of %d\n",n);
    delete [] weights2;
    delete [] w;
    delete [] ind;
  }
#endif
  CoinSort_2(weights,weights+numberLook,whichRows);
#if 0
  {
    double value = weights[0];
    int firstSame=-1;
    int lastSame=-1;
    for (int iLook = 1; iLook < numberLook; iLook++) {
      if (weights[iLook]==value) {
	if (firstSame<0) {
	  /* see how many same - if >2 but < ? may be 
	     worth looking at all combinations
	  */
	  firstSame=iLook-1;
	  printf("DUPS weight %g first row %d ",value,whichRows[firstSame]);
	  for (lastSame=iLook;lastSame<numberLook;lastSame++) {
	    if (weights[lastSame]!=value)
	      break;
	    else
	      printf(", %d ",whichRows[lastSame]);
	  }
	  printf("\n");
	  //printf("dupsame %d rows have same weight",lastSame-firstSame);
	}
      } else {
	firstSame=-1;
	value=weights[iLook];
      }
    }
  }
#endif
#elif USE_HASH==1
  std::sort(weights,weights+numberLook);
#ifdef PRINT_DUP
  //CoinSort_2(wwww,wwww+numberLook,iiii);
  for (int i=0;i<numberLook;i++) {
    hash * temp = reinterpret_cast<hash *>(weights+i);
    whichRows[i]=temp->item.hash.which;
    weights[i]=temp->item.hash.value;
    //printf("iLook %d weight %g (after) - true %d %g\n",
    //	   whichRows[i],weights[i],iiii[i],wwww[i]);
  }
#undef USE_HASH
#define USE_HASH 0
#endif
#else
  int * which2 = reinterpret_cast<int *>(weights2+4*numberLook);
  unsigned int * hash = reinterpret_cast<unsigned int *>(which2+5*numberLook);
  numberLook=sameTogether(numberLook,whichRows,weights,which2,weights2,hash);
  printf("Reduced length of %d\n",numberLook);
#endif
  if (tolerance<0.0)
    tolerance = primalTolerance_;
  int nPossible=0;
  int nDelete=0;
#if USE_HASH==1
  hash * temp = reinterpret_cast<hash *>(weights);
  int iLast=temp->item.hash.which;
  float value=temp->item.hash.value;
#else
  double value = weights[0];
  int iLast = whichRows[0];
#endif
  double inverseCleanup = (cleanUp>0.0) ? 1.0/cleanUp : 0.0;
  //#define PRINT_DUP
#ifdef PRINT_DUP
  int firstSame=-1;
  int lastSame=-1;
#endif
  for (int iLook = 1; iLook < numberLook; iLook++) {
#if USE_HASH==1
    hash * temp = reinterpret_cast<hash *>(weights+iLook);
    int iThis=temp->item.hash.which;
    float valueThis=temp->item.hash.value;
#else
    int iThis=whichRows[iLook];
    double valueThis=weights[iLook];
#endif
    if (valueThis==value) {
#ifdef PRINT_DUP
      if (firstSame<0) {
	/* see how many same - if >2 but < ? may be 
	   worth looking at all combinations
	*/
	firstSame=iLook-1;
	printf("DUPS weight %g first row %d ",value,whichRows[firstSame]);
	for (lastSame=iLook;lastSame<numberLook;lastSame++) {
	  if (weights[lastSame]!=value)
	    break;
	  else
	    printf(", %d ",whichRows[lastSame]);
	}
	printf("\n");
#endif
      CoinBigIndex start = rowStart[iThis];
      CoinBigIndex end = start + rowLength[iThis];
      if (rowLength[iThis] == rowLength[iLast]) {
	nPossible++;
#ifdef PRINT_DUP
	char line[520],temp[50];
#endif
	int ishift = rowStart[iLast] - start;
	CoinBigIndex k;
#ifdef PRINT_DUP
	sprintf(line,"dupj %d,%d %d els ",
		iThis,iLast,rowLength[iLast]);
	int n=strlen(line);
#endif
	bool bad=false;
	double multiplier=0.0;
	for (k=start;k<end;k++) {
	  if (column[k] != column[k+ishift]) {
	    bad=true;
	    break;
	  } else {
#ifdef PRINT_DUP
	    sprintf(temp,"(%g,%g) ",element[k],element[k+ishift]);
#endif
	    if (!multiplier) {
	      multiplier = element[k]/element[k+ishift];
	    } else if(fabs(element[k+ishift]*multiplier-element[k])>1.0e-8) {
	      bad=true;
	    }
#ifdef PRINT_DUP
	    int n2=strlen(temp);
	    if (n+n2<500) {
	      strcat(line,temp);
	      n += n2;
	    } else {
	      strcat(line,"...");
	      break;
	    }
#endif
	  }
	}
	if (!bad) {
#ifdef PRINT_DUP
	  printf("%s lo (%g,%g) up (%g,%g) - multiplier %g\n",line,rowLower_[iThis],rowUpper_[iThis],
		 rowLower_[iLast],rowUpper_[iLast],multiplier);
#endif
	  double rlo1=rowLower_[iLast];
	  double rup1=rowUpper_[iLast];
	  double rlo2=rowLower_[iThis];
	  double rup2=rowUpper_[iThis];
	  // scale
	  rlo1 *= multiplier;
	  rup1 *= multiplier;
	  //swap bounds if neg
	  if (multiplier<0.0) {
	    double temp = rup1;
	    rup1=rlo1;
	    rlo1=temp;
	  }
	  /* now check rhs to see what is what */
#ifdef PRINT_DUP
	  printf("duplicate row %g %g, %g %g\n",
		 rlo1,rup1,rlo2,rup2);
#endif
	  if (!noOverlaps) {
	    /* we always keep this and delete last 
	       later maybe keep better formed one */
	    rlo2 = CoinMax(rlo1,rlo2);
	    if (rlo2<-1.0e30)
	      rlo2=-COIN_DBL_MAX;
	    rup2 = CoinMin(rup1,rup2);
	    if (rup2>1.0e30)
	      rup2=COIN_DBL_MAX;
	  } else {
	    /* keep better formed one */
	    if (rlo2>=rlo1-1.0e-8&&rup2<=rup1+1.0e-8) {
	      // ok
	      rlo2 = CoinMax(rlo1,rlo2);
	      if (rlo2<-1.0e30)
		rlo2=-COIN_DBL_MAX;
	      rup2 = CoinMin(rup1,rup2);
	      if (rup2>1.0e30)
		rup2=COIN_DBL_MAX;
	    } else if (rlo1>=rlo2-1.0e-8&&rup1<=rup2+1.0e-8) {
	      rlo2 = CoinMax(rlo1,rlo2);
	      if (rlo2<-1.0e30)
		rlo2=-COIN_DBL_MAX;
	      rup2 = CoinMin(rup1,rup2);
	      if (rup2>1.0e30)
		rup2=COIN_DBL_MAX;
	      // swap
	      int temp=iLast;
	      iLast=iThis;
	      iThis=temp;
	    } else {
	      // leave (for now)
#if DEBUG_SOME>0
	      printf("row %d %g %g row %d %g %g\n",iLast,rlo1,rup1,iThis,rlo2,rup2);
#endif
	      iLast=iThis;
	      continue;
	    }
	  }
#ifdef PRINT_DUP
	  printf("pre_duprow %dR %dR keep this\n",iLast,iThis);
#endif
#if 0
	  if (rowLength[iThis]<4)
	    counts[rowLength[iThis]]++;
	  else
	    counts[4]++;
#endif
	  if (rup2<rlo2-tolerance) {
	    // infeasible
	    nDelete=-1;
	    break;
	  } else if (fabs(rup2-rlo2)<=tolerance) {
	    // equal - choose closer to zero
	    if (fabs(rup2)<fabs(rlo2))
	      rlo2=rup2;
	    else
	      rup2=rlo2;
#if 0
	  if (rowLength[iThis]<4)
	    countsEq[rowLength[iThis]]++;
	  else
	    countsEq[4]++;
#endif
#ifdef PRINT_DUP
	    printf("Row %d has %d elements == %g\n",
		   iThis,end-start,rlo2);
#endif
	  }
	  if (cleanUp>0.0) {
	    /* see if close to multiple
	       always allow integer values */
	    if (rlo2>-1.0e30) {
	      double value = rlo2;
	      double value2 = floor(value+0.5);
	      if (fabs(value-value2)<1.0e-9) {
		rlo2=value2;
	      } else {
		value = rlo2*inverseCleanup;
		value2 = floor(value+0.5);
		if (fabs(value-value2)<1.0e-9)
		  rlo2=value2*cleanUp;
	      }
	    }
	    if (rup2<1.0e30) {
	      double value = rup2;
	      double value2 = floor(value+0.5);
	      if (fabs(value-value2)<1.0e-9) {
		rup2=value2;
	      } else {
		value = rup2*inverseCleanup;
		value2 = floor(value+0.5);
		if (fabs(value-value2)<1.0e-9)
		  rup2=value2*cleanUp;
	      }
	    }
	  }
	  rowLower_[iThis]=rlo2;
	  rowUpper_[iThis]=rup2;
	  whichRows[nDelete++]=iLast;
	  if (getRowStatus(iLast)!=basic) {
	    if (getRowStatus(iThis)==basic) {
	      setRowStatus(iThis,superBasic);
	      setRowStatus(iLast,basic);
	    }
	  }
	} else {
#ifdef PRINT_DUP
	  printf("%s lo (%g,%g) up (%g,%g) - ODD\n",line,rowLower_[iThis],rowUpper_[iThis],
		 rowLower_[iLast],rowUpper_[iLast]);
#endif
	}
      }
    } else {
#ifdef PRINT_DUP
      // say no match
      firstSame=-1;
#endif
      value=valueThis;
    }
    iLast=iThis;
  }
#ifdef PRINT_DUP
  printf("%d possible duplicate rows - deleting %d\n",
	 nPossible,nDelete);
#endif
#if 0
  for (int i=0;i<5;i++) {
    if (counts[i])
      printf("CC counts %d %d times of which %d were equalities\n",i,counts[i],countsEq[i]);
  }
#endif
  delete [] weights;
  return nDelete;
}
/* Try simple crash like techniques to get closer to primal feasibility
   returns final sum of infeasibilities */
double 
ClpSimplex::moveTowardsPrimalFeasible()
{
  memset (rowActivity_,0,numberRows_*sizeof(double));
  matrix()->times(columnActivity_,rowActivity_);
  double sum=0.0;
  int * which = new int[numberRows_];
  int numberLook=0;
  for (int iRow=0;iRow<numberRows_;iRow++) {
    double value = rowActivity_[iRow];
    double infeasibility = 0.0;
    if (value<rowLower_[iRow]-primalTolerance_) 
      infeasibility = rowLower_[iRow]-value;
    else if (value>rowUpper_[iRow]+primalTolerance_) 
      infeasibility = value-rowUpper_[iRow];
    if (infeasibility) {
      sum += infeasibility;
      which[numberLook++]=iRow;
    }
  }
  if (numberLook) {
    const int * row = matrix_->getIndices();
    const CoinBigIndex * columnStart = matrix_->getVectorStarts();
    const int * columnLength = matrix_->getVectorLengths();
    const double * element = matrix_->getElements();
    // get row copy
    CoinPackedMatrix rowCopy = *matrix();
    rowCopy.reverseOrdering();
    const int * column = rowCopy.getIndices();
    const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
    const int * rowLength = rowCopy.getVectorLengths();
    const double * elementByRow = rowCopy.getElements();
    double lastSum=COIN_DBL_MAX;
    while (sum>primalTolerance_&&numberLook) {
      sum =0.0;
      double worst=primalTolerance_;
      int iWorst=-1;
      int n=numberLook;
      numberLook=0;
      for (int iLook=0;iLook<n;iLook++) {
	int iRow=which[iLook];
	double value = rowActivity_[iRow];
	double infeasibility = 0.0;
	if (value<rowLower_[iRow]-primalTolerance_) 
	  infeasibility = rowLower_[iRow]-value;
	else if (value>rowUpper_[iRow]+primalTolerance_) 
	  infeasibility = value-rowUpper_[iRow];
	if (infeasibility) {
	  sum += infeasibility;
	  which[numberLook++]=iRow;
	  if (infeasibility>worst) {
	    worst = infeasibility;
	    iWorst=iRow;
	  }
	}
      }
      if (sum==0.0||sum>=lastSum-1.0e-8)
	break;
      lastSum=sum;
      double direction;
      if (rowActivity_[iWorst]<rowLower_[iWorst])
	direction=1.0; // increase
      else
	direction=-1.0;
      for (CoinBigIndex k=rowStart[iWorst];
	   k<rowStart[iWorst]+rowLength[iWorst];k++) {
	if (worst<primalTolerance_) 
	  break;
	int iColumn = column[k];
	double value=elementByRow[k]*direction;
	double distance=worst;
	double multiplier = (value>0.0) ? 1.0 : -1.0;
	// but allow for column bounds
	double currentValue = columnActivity_[iColumn];
	if (multiplier>0.0)
	  distance = CoinMin(worst,columnUpper_[iColumn]-currentValue);
	else
	  distance = CoinMin(worst,currentValue-columnLower_[iColumn]);
	distance /= fabs(value);
	for (CoinBigIndex i=columnStart[iColumn];
	     i<columnStart[iColumn]+columnLength[iColumn];i++) {
	  int iRow=row[i];
	  if (iRow!=iWorst) {
	    double value2=element[i]*multiplier;
	    if (value2>0.0) {
	      double distance2 = rowUpper_[iRow]-rowActivity_[iRow]; 
	      if (value2*distance>distance2)
		distance = distance2/value2;
	    } else {
	      double distance2 = rowLower_[iRow]-rowActivity_[iRow]; 
	      if (value2*distance<distance2)
		distance = distance2/value2;
	    }
	  }
	}
	if (distance>1.0e-12) {
	  worst-=distance*fabs(value);
	  distance *= multiplier;
	  columnActivity_[iColumn] = currentValue+distance;
	  for (CoinBigIndex i=columnStart[iColumn];
	       i<columnStart[iColumn]+columnLength[iColumn];i++) {
	    int iRow=row[i];
	    rowActivity_[iRow] += distance*element[i];
	  }
	}
      }
    }
  }
  delete [] which;
  return sum;
}
/* Try simple crash like techniques to remove super basic slacks
   but only if > threshold */
void 
ClpSimplex::removeSuperBasicSlacks(int threshold)
{
  // could try going both ways - for first attempt to nearer bound
  memset (rowActivity_,0,numberRows_*sizeof(double));
  matrix()->times(columnActivity_,rowActivity_);
  double * distance = new double [numberRows_];
  int * whichRows = new int [numberRows_];
  int numberLook=0;
  for (int iRow=0;iRow<numberRows_;iRow++) {
    if (getRowStatus(iRow)!=basic) {
      double value = rowActivity_[iRow];
      if (value>rowLower_[iRow]+primalTolerance_&&
	  value<rowUpper_[iRow]-primalTolerance_) {
	setRowStatus(iRow,superBasic);
	distance[numberLook]=CoinMin(value-rowLower_[iRow],
				      rowUpper_[iRow]-value);
	whichRows[numberLook++]=iRow;
      }
    }
  }
  if (numberLook>threshold) {
    CoinSort_2(distance,distance+numberLook,whichRows);
    const int * row = matrix_->getIndices();
    const CoinBigIndex * columnStart = matrix_->getVectorStarts();
    const int * columnLength = matrix_->getVectorLengths();
    const double * element = matrix_->getElements();
    // get row copy
    CoinPackedMatrix rowCopy = *matrix();
    rowCopy.reverseOrdering();
    const int * column = rowCopy.getIndices();
    const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
    const int * rowLength = rowCopy.getVectorLengths();
    const double * elementByRow = rowCopy.getElements();
    int nMoved=0;
    for (int iLook=0;iLook<numberLook;iLook++) {
      int kRow = whichRows[iLook];
      double direction;
      double needed;
      if (rowUpper_[kRow]-rowActivity_[kRow]<rowActivity_[kRow]-rowLower_[kRow]) {
	direction=1.0; // increase
	needed = rowUpper_[kRow]-rowActivity_[kRow];
      } else {
	direction=-1.0;
	needed = rowActivity_[kRow]-rowLower_[kRow];
      }
      for (CoinBigIndex k=rowStart[kRow];
	 k<rowStart[kRow]+rowLength[kRow];k++) {
	if (needed<primalTolerance_) 
	  break;
	int iColumn = column[k];
	if (getColumnStatus(iColumn)!=basic)
	  continue;
	double value=elementByRow[k]*direction;
	double distance;
	double multiplier = (value>0.0) ? 1.0 : -1.0;
	// but allow for column bounds
	double currentValue = columnActivity_[iColumn];
	if (multiplier>0.0)
	  distance = columnUpper_[iColumn]-currentValue;
	else
	  distance = currentValue-columnLower_[iColumn];
	for (CoinBigIndex i=columnStart[iColumn];
	     i<columnStart[iColumn]+columnLength[iColumn];i++) {
	  int iRow=row[i];
	  double value2=element[i]*multiplier;
	  if (value2>0.0) {
	    double distance2 = rowUpper_[iRow]-rowActivity_[iRow]; 
	    if (value2*distance>distance2)
	      distance = distance2/value2;
	  } else {
	    double distance2 = rowLower_[iRow]-rowActivity_[iRow]; 
	    if (value2*distance<distance2)
	      distance = distance2/value2;
	  }
	}
	if (distance>1.0e-12) {
	  distance *= multiplier;
	  columnActivity_[iColumn] = currentValue+distance;
	  for (CoinBigIndex i=columnStart[iColumn];
	       i<columnStart[iColumn]+columnLength[iColumn];i++) {
	    int iRow=row[i];
	    rowActivity_[iRow] += distance*element[i];
	  }
	  if (direction>0.0) {
	    needed = rowUpper_[kRow]-rowActivity_[kRow];
	  } else {
	    needed = rowActivity_[kRow]-rowLower_[kRow];
	  }
	}
      }
      if (needed<primalTolerance_) {
	nMoved++;
	if (rowUpper_[kRow]-rowActivity_[kRow]<primalTolerance_) 
	  setRowStatus(kRow,atUpperBound);
	else if (rowActivity_[kRow]-rowLower_[kRow]<primalTolerance_)
	  setRowStatus(kRow,atLowerBound);
	else
	  assert (rowUpper_[kRow]-rowActivity_[kRow]<primalTolerance_||
		  rowActivity_[kRow]-rowLower_[kRow]<primalTolerance_);
      }
    }
    char line[100];
    sprintf(line,"Threshold %d found %d fixed %d",threshold,numberLook,nMoved);
    handler_->message(CLP_GENERAL,messages_)
      << line << CoinMessageEol;
  }
  delete [] distance;
  delete [] whichRows;
}
/*
  1 (and 4) redundant (and 8 is user)
  2 sub
  11 movable column
  13 empty (or initially fixed) column
  14 doubleton
*/
typedef struct {
  double oldRowLower;
  double oldRowUpper;
  int row;
  int lengthRow;
} clpPresolveInfo1_4_8;
// can be used instead of 1_4_8
typedef struct {
  double oldRowLower;
  double oldRowUpper;
  int row;
  int lengthRow;
  double * rowLowerX;
  double * rowUpperX;
  double * tempElement;
  int * tempIndex;
  int otherRow;
} clpPresolveInfo8;
typedef struct {
  double oldRowLower;
  double oldRowUpper;
  double oldColumnLower;
  double oldColumnUpper;
  double coefficient;
  // 2 is upper
  double oldRowLower2;
  double oldRowUpper2;
  double coefficient2;
  int row;
  int row2;
  int column;
} clpPresolveInfo2;
typedef struct {
  double oldColumnLower;
  double oldColumnUpper;
  double fixedTo;
  int column;
  int lengthColumn;
} clpPresolveInfo11;
typedef struct {
  double oldColumnLower;
  double oldColumnUpper;
  int column;
} clpPresolveInfo13;
typedef struct {
  double oldColumnLower;
  double oldColumnUpper;
  double oldColumnLower2;
  double oldColumnUpper2;
  double oldObjective2;
  double value1;
  double rhs;
  int type;
  int row;
  int column;
  int column2;
  int lengthColumn2;
} clpPresolveInfo14;
typedef struct {
  int infoOffset;
  int type;
} clpPresolveInfo;
typedef struct {
  int numberEntries;
  int maximumEntries;
  int numberInitial;
  clpPresolveInfo * start; 
} listInfo;
typedef struct {
  char * putStuff;
  char * startStuff;
  CoinBigIndex maxStuff;
} saveInfo;
typedef struct {
  double * elements;
  int * indices;
  char * startStuff;
} restoreInfo;
// struct must match in handler
typedef struct {
  ClpSimplex * model;
  CoinPackedMatrix * rowCopy;
  char * rowType;
  char * columnType;
  saveInfo * stuff;
  clpPresolveInfo * info;
  int * nActions;
} clpPresolveMore;
void ClpCopyToMiniSave(saveInfo & where, const char * info, unsigned int sizeInfo,int numberElements,
			 const int * indices, const double * elements)
{
  char * put = where.putStuff;
  int n = numberElements*static_cast<int>(sizeof(int)+sizeof(double))+static_cast<int>(sizeInfo);
  if (n+(put-where.startStuff)>where.maxStuff) {
    where.maxStuff += CoinMax(where.maxStuff/2 + 10000, 2*n);
    char * temp = new char[where.maxStuff];
    long k = put-where.startStuff;
    memcpy(temp,where.startStuff,k);
    delete [] where.startStuff;
    where.startStuff=temp;
    put = temp+k;
  }
  memcpy(put,info,sizeInfo);
  put += sizeInfo;
  memcpy(put,indices,numberElements*sizeof(int));
  put += numberElements*sizeof(int);
  memcpy(put,elements,numberElements*sizeof(double));
  put += numberElements*sizeof(double);
  where.putStuff=put;
}
static void copyFromSave(restoreInfo & where, clpPresolveInfo & info, void * thisInfoX)
{
  char * get = where.startStuff+info.infoOffset;
  int type = info.type;
  int n=0;
  switch(type) {
    case 1:
    case 4:
      // redundant
      {
	clpPresolveInfo1_4_8  thisInfo;
	memcpy(&thisInfo,get,sizeof(clpPresolveInfo1_4_8));
	memcpy(thisInfoX,get,sizeof(clpPresolveInfo1_4_8));
	get += sizeof(clpPresolveInfo1_4_8);
	n = thisInfo.lengthRow;
      }
      break;
    case 8:
    case 9:
      // redundant
      {
	clpPresolveInfo8  thisInfo;
	memcpy(&thisInfo,get,sizeof(clpPresolveInfo8));
	memcpy(thisInfoX,get,sizeof(clpPresolveInfo8));
	get += sizeof(clpPresolveInfo8);
	n = thisInfo.lengthRow;
      }
      break;
    case 2: 
      // sub
      {
	clpPresolveInfo2 thisInfo;
	memcpy(&thisInfo,get,sizeof(clpPresolveInfo2));
	memcpy(thisInfoX,get,sizeof(clpPresolveInfo2));
	get += sizeof(clpPresolveInfo2);
      }
      break;
    case 11: 
      // movable column
      {
	clpPresolveInfo11 thisInfo;
	memcpy(&thisInfo,get,sizeof(clpPresolveInfo11));
	memcpy(thisInfoX,get,sizeof(clpPresolveInfo11));
	get += sizeof(clpPresolveInfo11);
	n = thisInfo.lengthColumn;
      }
      break;
    case 13: 
      // empty (or initially fixed) column
      {
	clpPresolveInfo13 thisInfo;
	memcpy(&thisInfo,get,sizeof(clpPresolveInfo13));
	memcpy(thisInfoX,get,sizeof(clpPresolveInfo13));
	get += sizeof(clpPresolveInfo13);
      }
      break;
    case 14: 
      // doubleton
      {
	clpPresolveInfo14 thisInfo;
	memcpy(&thisInfo,get,sizeof(clpPresolveInfo14));
	memcpy(thisInfoX,get,sizeof(clpPresolveInfo14));
	get += sizeof(clpPresolveInfo14);
	n = thisInfo.lengthColumn2;
      }
      break;
  }
  if (n) {
    memcpy(where.indices,get,n*sizeof(int));
    get += n*sizeof(int);
    memcpy(where.elements,get,n*sizeof(double));
  }
}
#define DEBUG_SOME 0
// need more space
static
void moveAround(int numberColumns,CoinBigIndex numberElementsOriginal,
		int iColumn,int lengthNeeded,
		int * forward,int * backward,
		CoinBigIndex * columnStart,int * columnLength,
		int * row,double * element)
{
  // we only get here if can't fit so if iColumn is last one need shuffle
  int last=backward[numberColumns];
  bool needCompaction=false;
  CoinBigIndex lastElement=columnStart[numberColumns];
  //assert(lastElement==2*(numberElementsOriginal+numberColumns));
  // save length
  int length=columnLength[iColumn];
  if (iColumn!=last) {
    CoinBigIndex put=columnStart[last]+columnLength[last]+3;
    if (put+lengthNeeded<=lastElement) {
      // copy
      CoinBigIndex start = columnStart[iColumn];
      columnStart[iColumn]=put;
      memcpy(element+put,element+start,length*sizeof(double));
      memcpy(row+put,row+start,length*sizeof(int));
      // forward backward
      int iLast=backward[iColumn];
      int iNext=forward[iColumn];
      forward[iLast]=iNext;
      backward[iNext]=iLast;
      forward[last]=iColumn;
      backward[iColumn]=last;
      forward[iColumn]=numberColumns;
      backward[numberColumns]=iColumn;
    } else {
      needCompaction=true;
    }
  } else {
    needCompaction=true;
  }
  if (needCompaction) {
    printf("compacting\n");
    // size is lastElement+numberElementsOriginal
#ifndef NDEBUG
    CoinBigIndex total=lengthNeeded-columnLength[iColumn];
    for (int i=0;i<numberColumns;i++)
      total += columnLength[i];
    assert (total<=numberElementsOriginal+lengthNeeded);
#endif
    CoinBigIndex put=lastElement;
    for (int i=0;i<numberColumns;i++) {
      CoinBigIndex start = columnStart[i];
      columnStart[i]=put;
      int n=columnLength[i];
      memcpy(element+put,element+start,n*sizeof(double));
      memcpy(row+put,row+start,n*sizeof(int));
      put += n;
    }
    // replace length (may mean copying uninitialized)
    columnLength[iColumn]=lengthNeeded;
    int spare = (2*lastElement-put-(lengthNeeded-length)-numberElementsOriginal)/numberColumns;
    assert (spare>=0);
    // copy back
    put=0;
    for (int i=0;i<numberColumns;i++) {
      CoinBigIndex start = columnStart[i];
      columnStart[i]=put;
      int n=columnLength[i];
      memcpy(element+put,element+start,n*sizeof(double));
      memcpy(row+put,row+start,n*sizeof(int));
      put += n+spare;
    }
    assert (put<=lastElement);
    columnLength[iColumn]=length;
    // redo forward,backward
    for (int i=-1;i<numberColumns;i++)
      forward[i]=i+1;
    forward[numberColumns]=-1;
    for (int i=0;i<=numberColumns;i++)
      backward[i]=i-1;
    backward[-1]=-1;
  }
  //abort();
#if DEBUG_SOME > 0
  printf("moved column %d\n",iColumn);
#endif
}
#if DEBUG_SOME > 0
#ifndef NDEBUG
static void checkBasis(ClpSimplex * model,char * rowType, char * columnType)
{
  int numberRows=model->numberRows();
  int nRowBasic=0;
  int nRows=0;
  for (int i=0;i<numberRows;i++) {
    if (rowType[i]<=0||rowType[i]==55) {
      nRows++;
      if(model->getRowStatus(i)==ClpSimplex::basic)
	nRowBasic++;
    }
  }
  int numberColumns=model->numberColumns();
  int nColumnBasic=0;
  for (int i=0;i<numberColumns;i++) {
    if ((columnType[i]<11||columnType[i]==55)&&model->getColumnStatus(i)==ClpSimplex::basic)
      nColumnBasic++;
  }
  ClpTraceDebug (nRowBasic+nColumnBasic==nRows);
} 
#endif
#endif
#if DEBUG_SOME > 0
static int xxxxxx=2999999;
#endif
/* Mini presolve (faster)
   Char arrays must be numberRows and numberColumns long
   on entry second part must be filled in as follows -
   0 - possible
   >0 - take out and do something (depending on value - TBD)
	       1 - redundant row
	       2 - sub
	       11 - column can be moved to bound
	       4 - row redundant (duplicate)
	       13 - empty (or initially fixed) column
	       14 - == row (also column deleted by row)
	       3 - column altered by a 14
	       5 - temporary marker for truly redundant sub row
	       8 - other
   -1 row/column can't vanish but can have entries removed/changed
   -2 don't touch at all
   on exit <=0 ones will be in presolved problem
   struct will be created and will be long enough
   (information on length etc in first entry)
   user must delete struct
*/
ClpSimplex * 
ClpSimplex::miniPresolve(char * rowType, char * columnType,void ** infoOut)
{
  // Big enough structure
  int numberTotal=numberRows_+numberColumns_;
  CoinBigIndex lastElement = matrix_->getNumElements();
  int maxInfoStuff = 5*lastElement*static_cast<int>(sizeof(double))+numberTotal*static_cast<int>(sizeof(clpPresolveInfo2));
  clpPresolveInfo * infoA = new clpPresolveInfo[numberTotal];
  char * startStuff = new char [maxInfoStuff];
  memset(infoA,'B',numberTotal*sizeof(clpPresolveInfo));
  memset(startStuff,'B',maxInfoStuff);
  int nActions=0;
  int * whichRows = new int [2*numberRows_+numberColumns_];
  int * whichColumns = whichRows + numberRows_;
  int * whichRows2 = whichColumns + numberColumns_;
  double * array = new double [numberRows_];
  memset(array,0,numberRows_*sizeof(double));
  // New model (put in modification to increase size of matrix) and pack
  bool needExtension=numberColumns_>matrix_->getNumCols();
  if (needExtension) {
    matrix()->reserve(numberColumns_,lastElement,true);
    CoinBigIndex * columnStart = matrix()->getMutableVectorStarts();
    for (int i=numberColumns_;i>=0;i--) {
      if (columnStart[i]==0)
	columnStart[i]=lastElement;
      else
	break;
    }
    assert (lastElement==columnStart[numberColumns_]);
  }
#define TWOFER
#ifdef TWOFER
  ClpSimplex * newModel = NULL;
  CoinBigIndex lastPossible=3*lastElement;
  CoinBigIndex lastGood=2*lastElement;
  clpPresolveMore moreInfo;
  moreInfo.model=NULL;
  moreInfo.rowType=rowType;
  moreInfo.columnType=columnType;
  int addColumns = eventHandler_->eventWithInfo(ClpEventHandler::modifyMatrixInMiniPresolve,&moreInfo);
  if (moreInfo.model) {
    newModel = moreInfo.model;
  } else {
    newModel = new ClpSimplex(*this);
    newModel->matrix()->reserve(numberColumns_+addColumns,lastPossible,true);
  }
#else
  ClpSimplex * newModel = new ClpSimplex(*this);
  //newModel->matrix()->reserve(numberColumns_,lastElement,true);
#endif
  newModel->dropNames();
  double * rowLower = newModel->rowLower();
  double * rowUpper = newModel->rowUpper();
  //double * rowActivity = newModel->primalRowSolution();
  unsigned char * rowStatus = newModel->statusArray()+numberColumns_;
  // use top bit of status as marker for whichRows update
  for (int i=0;i<numberRows_;i++)
    rowStatus[i] &= 127;
  double * columnLower = newModel->columnLower();
  double * columnUpper = newModel->columnUpper();
  //double * columnActivity = newModel->primalColumnSolution();
  //unsigned char * columnStatus = newModel->statusArray();
  // Take out marked stuff
  saveInfo stuff;
  stuff.putStuff=startStuff;
  stuff.startStuff=startStuff;
  stuff.maxStuff=maxInfoStuff;
  CoinPackedMatrix * matrix = newModel->matrix();
  int * row = matrix->getMutableIndices();
  CoinBigIndex * columnStart = matrix->getMutableVectorStarts();
  int * columnLength = matrix->getMutableVectorLengths();
  double * element = matrix->getMutableElements();
  // get row copy
  CoinPackedMatrix rowCopy = *matrix;
  rowCopy.reverseOrdering();
  int * column = rowCopy.getMutableIndices();
  CoinBigIndex * rowStart = rowCopy.getMutableVectorStarts();
  double * elementByRow = rowCopy.getMutableElements();
  int * rowLength = rowCopy.getMutableVectorLengths();
  for (int iRow=0;iRow<numberRows_;iRow++) {
    if (rowType[iRow]>0) {
      clpPresolveInfo1_4_8  thisInfo;
      thisInfo.row=iRow;
      thisInfo.oldRowLower=(rowLower_[iRow]>-1.0e30) ? rowLower_[iRow]-rowLower[iRow] : rowLower[iRow];
      thisInfo.oldRowUpper=(rowUpper_[iRow]<1.0e30) ? rowUpper_[iRow]-rowUpper[iRow] : rowUpper[iRow];
      int n=rowLength[iRow];
      CoinBigIndex start=rowStart[iRow];
      thisInfo.lengthRow=n;
      //thisInfo.column=-1;
      infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
      infoA[nActions].type=4; //rowType[iRow];
      nActions++;
      ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo1_4_8),
			  n,column+start,elementByRow+start);
    }
  } 
  CoinBigIndex put=0;
  bool anyDeleted=false;
  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
    CoinBigIndex start=columnStart[iColumn];
    int length = columnLength[iColumn];
    if (columnType[iColumn]>0||(columnType[iColumn]==0&&
				(!length||columnLower_[iColumn]==columnUpper_[iColumn]))) {
      clpPresolveInfo13 thisInfo;
      //thisInfo.row=-1;
      thisInfo.oldColumnLower=columnLower[iColumn];
      thisInfo.oldColumnUpper=columnUpper[iColumn];
      thisInfo.column=iColumn;
      CoinBigIndex start=columnStart[iColumn];
      infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
      infoA[nActions].type=(columnType[iColumn]>0) ? columnType[iColumn] : 13;
      nActions++;
      ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo13),
		 0,NULL,NULL);
      columnType[iColumn]=13;
      if (length) {
	double solValue=columnLower[iColumn];
	if (solValue) {
	  for (int j=start;j<start+length;j++) {
	    int iRow=row[j];
	    double value = element[j]*solValue;
	    double lower = rowLower[iRow];
	    if (lower>-1.0e20)
	      rowLower[iRow]=lower-value;
	    double upper = rowUpper[iRow];
	    if (upper<1.0e20)
	    rowUpper[iRow]=upper-value;
	  }	  
	}
	anyDeleted=true;
	length=0;
      }
    }
    columnStart[iColumn]=put;
    for (CoinBigIndex i=start;i<start+length;i++) {
      int iRow=row[i];
      if (rowType[iRow]<=0) {
	row[put]=iRow;
	element[put++]=element[i];
      }
    }
    columnLength[iColumn]=put-columnStart[iColumn];
  }
  int numberInitial=nActions;
  columnStart[numberColumns_]=put;
  matrix->setNumElements(put);
  // get row copy if changed
  if (anyDeleted) {
    rowCopy = *matrix;
    rowCopy.reverseOrdering();
    column = rowCopy.getMutableIndices();
    rowStart = rowCopy.getMutableVectorStarts();
    elementByRow = rowCopy.getMutableElements();
    rowLength = rowCopy.getMutableVectorLengths();
  }
  double * objective = newModel->objective();
  double offset = objectiveOffset();
  int numberRowsLook=0;
#ifdef TWOFER
  bool orderedMatrix=true;
#endif
  int nChanged = 1;
  bool feasible=true;
  //#define CLP_NO_SUBS
  for (int iRow=0;iRow<numberRows_;iRow++) {
#if DEBUG_SOME>0
#ifndef NDEBUG
    checkBasis(newModel, rowType, columnType);
#endif
#endif
    int nPoss=2;
#if DEBUG_SOME > 0
    xxxxxx--;
    if (xxxxxx<=0)
      nPoss=1;
    if (xxxxxx<-1000)
      nPoss=-1;
    if (xxxxxx==1) {
      printf("bad\n");
    }
#endif
    if (rowLength[iRow]<=nPoss&&!rowType[iRow]) {
      if (rowLength[iRow]<=1) {
	if (rowLength[iRow]==1)  {
#ifndef CLP_NO_SUBS
	  // See if already marked
	  if ((rowStatus[iRow]&128)==0) {
	    rowStatus[iRow] |= 128;
	    whichRows[numberRowsLook++]=iRow;
	    assert (numberRowsLook<=numberRows_);
	  }
#endif
	} else {
#if DEBUG_SOME > 0
	  printf("Dropping null row %d (status %d) - nActions %d\n",
		 iRow,getRowStatus(iRow),nActions);
#endif
	  if (rowLower[iRow] > primalTolerance_ ||
	      rowUpper[iRow] <-primalTolerance_) {
	    feasible=false;
	    nChanged=-1;
	    numberRowsLook=0;
	    break;
	  }
	  rowType[iRow]=1;
	  clpPresolveInfo1_4_8  thisInfo;
	  thisInfo.oldRowLower=(rowLower_[iRow]>-1.0e30) ? rowLower_[iRow]-rowLower[iRow] : rowLower[iRow];
	  thisInfo.oldRowUpper=(rowUpper_[iRow]<1.0e30) ? rowUpper_[iRow]-rowUpper[iRow] : rowUpper[iRow];
	  thisInfo.row=iRow;
	  int n=rowLength[iRow];
	  CoinBigIndex start=rowStart[iRow];
	  thisInfo.lengthRow=n;
	  //thisInfo.column=-1;
	  infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
	  infoA[nActions].type=1;
	  nActions++;
	  ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo1_4_8),
		     n,column+start,elementByRow+start);
	}
#ifdef TWOFER
      } else if (rowLower[iRow]==rowUpper[iRow]) {
#ifndef CLP_NO_SUBS
	// See if already marked
	if ((rowStatus[iRow]&128)==0) {
	  rowStatus[iRow] |= 128;
	  whichRows[numberRowsLook++]=iRow;
	  assert (numberRowsLook<=numberRows_);
	}
#endif
	CoinBigIndex start = rowStart[iRow];
	int iColumn1 = column[start];
	double value1 = elementByRow[start];
	int iColumn2 = column[start+1];
	double value2 = elementByRow[start+1];
	bool swap=false;
	double ratio = fabs(value1/value2);
	if (ratio<0.001||ratio>1000.0) {
	  if (fabs(value1)<fabs(value2)) {
	    swap=true;
	  } 
	} else if (columnLength[iColumn1]<columnLength[iColumn2]) {
	  swap=true;
	}
	if(swap) {
	  iColumn1 = iColumn2;
	  value1 = value2;
	  iColumn2 = column[start];
	  value2 = elementByRow[start];
	}
	// column bounds
	double dropLower = columnLower[iColumn2];
	double dropUpper = columnUpper[iColumn2];
	double newLower;
	double newUpper;
	double rhs = rowLower[iRow]/value1;
	double multiplier = value2/value1;
	if (multiplier>0.0) {
	  newLower = (dropUpper<1.0e30) ? rhs - multiplier*dropUpper : -COIN_DBL_MAX;
	  newUpper = (dropLower>-1.0e30) ? rhs - multiplier*dropLower : COIN_DBL_MAX;
	} else {
	  newUpper = (dropUpper<1.0e30) ? rhs - multiplier*dropUpper : COIN_DBL_MAX;
	  newLower = (dropLower>-1.0e30) ? rhs - multiplier*dropLower : -COIN_DBL_MAX;
	}
	//columnType[iColumn1]=3;
	columnType[iColumn2]=14;
	rowType[iRow]=14;
	rhs = rowLower[iRow]/value2;
	multiplier = value1/value2;
	clpPresolveInfo14 thisInfo;
	thisInfo.oldColumnLower=columnLower[iColumn1];
	thisInfo.oldColumnUpper=columnUpper[iColumn1];
	thisInfo.oldColumnLower2=columnLower[iColumn2];
	thisInfo.oldColumnUpper2=columnUpper[iColumn2];
	thisInfo.oldObjective2=objective[iColumn2];
	thisInfo.value1=value1;
	thisInfo.rhs=rowLower[iRow];
	thisInfo.row=iRow;
	thisInfo.column=iColumn1;
	thisInfo.column2=iColumn2;
	int nel=columnLength[iColumn2];
	CoinBigIndex startCol=columnStart[iColumn2];
	thisInfo.lengthColumn2=nel;
	infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
	infoA[nActions].type=14;
	nActions++;
	ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo14),
			  nel,row+startCol,element+startCol);
	newLower = CoinMax(newLower,columnLower[iColumn1]);
	newUpper = CoinMin(newUpper,columnUpper[iColumn1]);
	if (newLower>newUpper+primalTolerance_) {
	  feasible=false;
	  nChanged=-1;
	  numberRowsLook=0;
	  break;
	}
	columnLower[iColumn1]=newLower;
	columnUpper[iColumn1]=newUpper;
#if DEBUG_SOME > 0
	printf("Dropping doubleton row %d (status %d) keeping column %d (status %d) dropping %d (status %d) (mult,rhs %g %g) - nActions %d\n",
	       iRow,getRowStatus(iRow),iColumn1,getColumnStatus(iColumn1),iColumn2,getColumnStatus(iColumn2),multiplier,rhs,nActions);
#endif
	objective[iColumn1] -= objective[iColumn2]*multiplier;
	offset -= rowLower[iRow]*(objective[iColumn2]*multiplier);
	bool needDrop=false;
	if (newModel->getRowStatus(iRow)!=basic) {
	  if (newModel->getColumnStatus(iColumn2)!=basic) {
	    // On way back may as well have column basic
	    newModel->setColumnStatus(iColumn2,basic);
	    // need to drop basic
	    if (newModel->getColumnStatus(iColumn1)==basic) { 
	      //setColumnStatus(iColumn1,superBasic);
	      newModel->setColumnStatus(iColumn1,superBasic);
	    } else {
	      // not much we can do
#if DEBUG_SOME > 0
	      printf("dropping but no basic a\n");
#endif
	    }
	  } else {
	    // looks good
	  }
	} else {
	  if (newModel->getColumnStatus(iColumn2)!=basic) {
	    // looks good
	  } else {
	    // need to keep a basic
	    if (newModel->getColumnStatus(iColumn1)!=basic) { 
	      //setColumnStatus(iColumn2,superBasic);
	      //setColumnStatus(iColumn1,basic);
	      newModel->setColumnStatus(iColumn1,basic);
	    } else {
	      // not much we can do
#if DEBUG_SOME > 0
	      printf("dropping but all basic a\n");
#endif
	      needDrop=true;
	      //setColumnStatus(iColumn2,superBasic);
	    }
	  }
	}
	int n=0;
	start = columnStart[iColumn1];
	for (int i=start;i<start+columnLength[iColumn1];
	     i++) {
	  int jRow=row[i];
	  if (jRow!=iRow) {
	    array[jRow]=element[i];
	    whichRows2[n++]=jRow;
	  }
	}
	rowLength[iRow]=0;
	start = columnStart[iColumn2];
	for (int i=start;i<start+columnLength[iColumn2];
	     i++) {
	  int jRow=row[i];
	  if (jRow!=iRow) {
	    double value = array[jRow];
	    double valueNew = value -multiplier*element[i];
	    double rhsMod = rhs*element[i];
	    if (rowLower[jRow]>-1.0e30)
	      rowLower[jRow] -= rhsMod;
	    if (rowUpper[jRow]<1.0e30)
	      rowUpper[jRow] -= rhsMod;
	    if (!value) {
	      array[jRow]=valueNew;
	      whichRows2[n++]=jRow;
	    } else {
	      if (!valueNew)
		valueNew=1.0e-100;
	      array[jRow]=valueNew;
	    }
	  }
	}
	columnLength[iColumn2]=0;
	start = columnStart[iColumn1];
	if (n>columnLength[iColumn1]) {
	  orderedMatrix=false;
	  if (lastElement+n>lastGood) {
	    // pack down
	    CoinBigIndex put=lastElement;
	    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
	      CoinBigIndex start = columnStart[iColumn];
	      columnStart[iColumn]=put-lastElement;
	      int length=columnLength[iColumn];
	      for (CoinBigIndex j=start;j<start+length;j++) {
		row[put]=row[j];
		element[put++]=element[j];
	      }
	    }
	    int numberElements = put-lastElement;
	    columnStart[numberColumns_]=numberElements;
	    memcpy(row,row+lastElement,numberElements*sizeof(int));
	    memcpy(element,element+lastElement,numberElements*sizeof(double));
	    lastElement=numberElements;
	  }
	  start=lastElement;
	  columnStart[iColumn1]=start;
	}
	CoinBigIndex put = start;
	for (int i=0;i<n;i++) {
	  int jRow = whichRows2[i];
	  double value = array[jRow];
	  //#define FUNNY_CHECK
#ifdef FUNNY_CHECK
	  if (rowType[jRow]==-2)
	    printf("iColumn1 %d iColumn2 %d row %d value %g\n",
		   iColumn1,iColumn2,jRow,value);
#endif
	  array[jRow]=0.0;
	  if (fabs(value)<1.0e-13) 
	    value=0.0;
	  if (value) {
	    row[put] = jRow;
	    element[put++]=value;
	    if(needDrop&&newModel->getRowStatus(jRow)!=basic) {
	      newModel->setRowStatus(jRow,basic);
	      needDrop=false;
	    }
	  }
	  // take out of row copy
	  int startR = rowStart[jRow];
	  int putR=startR;
	  for (int i=startR;i<startR+rowLength[jRow];i++) {
	    int iColumn = column[i];
	    if (iColumn!=iColumn1&&iColumn!=iColumn2) {
	      column[putR]=iColumn;
	      elementByRow[putR++]=elementByRow[i];
	    } else if (value) {
	      column[putR]=iColumn1;
	      elementByRow[putR++]=value;
	      value=0.0;
	    }
	  }
	  int rowLength2=putR-startR;
#ifndef CLP_NO_SUBS
	  if (rowLength2<=1&&rowLength[jRow]>1&&jRow<iRow) {
	    // may be interesting
	    // See if already marked
	    if ((rowStatus[jRow]&128)==0) {
	      rowStatus[jRow] |= 128;
	      whichRows[numberRowsLook++]=jRow;
	      assert (numberRowsLook<=numberRows_);
	    }
	  }
#endif
	  rowLength[jRow]=rowLength2;
	}
	columnLength[iColumn1]=put-start;
	lastElement=CoinMax(lastElement,put);
#endif
      }
    } else if (true&&rowLower[iRow]==-COIN_DBL_MAX&&rowUpper[iRow]==COIN_DBL_MAX) {
#if DEBUG_SOME > 0
      printf("Dropping null free row %d (status %d) - nActions %d\n",
	     iRow,getRowStatus(iRow),nActions);
#endif
      rowType[iRow]=1;
      clpPresolveInfo1_4_8  thisInfo;
      thisInfo.oldRowLower=(rowLower_[iRow]>-1.0e30) ? rowLower_[iRow]-rowLower[iRow] : rowLower[iRow];
      thisInfo.oldRowUpper=(rowUpper_[iRow]<1.0e30) ? rowUpper_[iRow]-rowUpper[iRow] : rowUpper[iRow];
      thisInfo.row=iRow;
      int n=rowLength[iRow];
      CoinBigIndex start=rowStart[iRow];
      thisInfo.lengthRow=n;
      //thisInfo.column=-1;
      infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
      infoA[nActions].type=1;
      nActions++;
      ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo1_4_8),
			n,column+start,elementByRow+start);
      // need to take out row
      CoinBigIndex end=start+n;
      rowLength[iRow]=0;
      for (CoinBigIndex k=start;k<end;k++) {
	int iColumn=column[k];
	CoinBigIndex startColumn=columnStart[iColumn];
	int n=columnLength[iColumn];
	CoinBigIndex endColumn=startColumn+n;
	columnLength[iColumn]=n-1;
	for (CoinBigIndex j=startColumn;j<endColumn;j++) {
	  int jRow=row[j];
	  if (jRow==iRow) {
	    endColumn--;
	    row[j]=row[endColumn];
	    element[j]=element[endColumn];
	    break;
	  }
	}
	assert (endColumn==startColumn+n-1);
      }
    }
  }
#if DEBUG_SOME>0
  if (xxxxxx<-1000)
    nChanged=-1;
#endif
  while (nChanged>0) {
    nChanged=0;
    int numberColumnsLook=0;
    for (int i=0;i<numberRowsLook;i++) {
#if DEBUG_SOME>0
#ifndef NDEBUG
      checkBasis(newModel, rowType, columnType);
#endif
#endif
      int iRow = whichRows[i];
      // unmark
      assert ((rowStatus[iRow]&128)!=0);
      rowStatus[iRow] &= 127;
      if (rowLength[iRow]==1) {
	//rowType[iRow]=55;
	int iColumn =  column[rowStart[iRow]];
	if (/*columnType[iColumn]==14||*/columnType[iColumn]<-1) 
	  continue;
	if (!columnType[iColumn]) {
	  columnType[iColumn]=55;
	  whichColumns[numberColumnsLook++]=iColumn;
	  nChanged++;
	}
#if 0
      } else if (rowLength[iRow]==2) {
	if (rowLower[iRow]==rowUpper[iRow]) {
	  CoinBigIndex start = rowStart[iRow];
	  int iColumn1 =  column[start];
	  int iColumn2 =  column[start+1];
	  if (!columnType[iColumn1]&&!columnType[iColumn2]) {
	    if (fabs(elementByRow[start])<fabs(elementByRow[start+1])) {
	      iColumn1 = iColumn2;
	      iColumn2 = column[start];
	    }
	    // iColumn2 will be deleted
	    columnType[iColumn1]=56;
	    columnType[iColumn2]=56;
	  }
	} else {
	  printf("why here in miniPresolve row %d\n",iRow);
	}
#endif
      }
    }
    // mark one row as ub and take out row in column copy
    numberRowsLook=0;
    for (int iLook=0;iLook<numberColumnsLook;iLook++) {
#if DEBUG_SOME>0
#ifndef NDEBUG
      checkBasis(newModel, rowType, columnType);
#endif
#endif
      nChanged++;
      int iColumn = whichColumns[iLook];
      if (columnType[iColumn]!=55&&columnType[iColumn]>10)
	continue;
      if (columnType[iColumn]==55)
	columnType[iColumn]=0;
      CoinBigIndex start=columnStart[iColumn];
      int jRowLower=-1;
      double newLower=columnLower[iColumn];
      int jRowUpper=-1;
      double newUpper=columnUpper[iColumn];
      double coefficientLower=0.0;
      double coefficientUpper=0.0;
      for (CoinBigIndex i=start;i<start+columnLength[iColumn];
	   i++) {
	int iRow=row[i];
	if (rowLength[iRow]==1&&rowType[iRow]==0) {
	  rowType[iRow]=1;
	  assert(columnType[iColumn]>=0);
	  // adjust bounds
	  double value = elementByRow[rowStart[iRow]];
	  double lower = newLower;
	  double upper = newUpper;
	  if (value>0.0) {
	    if (rowUpper[iRow]<1.0e30)
	      upper = rowUpper[iRow]/value;
	    if (rowLower[iRow]>-1.0e30)
	      lower = rowLower[iRow]/value;
	  } else {
	    if (rowUpper[iRow]<1.0e30)
	      lower = rowUpper[iRow]/value;
	    if (rowLower[iRow]>-1.0e30)
	      upper = rowLower[iRow]/value;
	  }
	  if (lower>newLower+primalTolerance_) {
	    if (lower>newUpper+primalTolerance_) {
	      feasible=false;
	      nChanged=-1;
	      numberColumnsLook=0;
	      break;
	    } else if (lower>newUpper-primalTolerance_) {
	      newLower=newUpper;
	    } else {
	      newLower = CoinMax(lower,newLower);
	    }
	    jRowLower=iRow;
	    coefficientLower=value;
	  } 
	  if (upper<newUpper-primalTolerance_) {
	    if (upper<newLower-primalTolerance_) {
	      feasible=false;
	      nChanged=-1;
	      numberColumnsLook=0;
	      break;
	    } else if (upper<newLower+primalTolerance_) {
	      newUpper = newLower;
	    } else {
	      newUpper = CoinMin(upper,newUpper);
	    }
	    jRowUpper=iRow;
	    coefficientUpper=value;
	  }
	}
      }
      int put=start;
      int iFlag=0;
      int nonFree=0;
      int numberNonBasicSlacksOut=0;
      if (jRowLower>=0||jRowUpper>=0) {
	clpPresolveInfo2 thisInfo;
	if (jRowLower>=0) {
	  thisInfo.oldRowLower=(rowLower_[jRowLower]>-1.0e30) ? rowLower_[jRowLower]-rowLower[jRowLower] : rowLower[jRowLower];
	  thisInfo.oldRowUpper=(rowUpper_[jRowLower]<1.0e30) ? rowUpper_[jRowLower]-rowUpper[jRowLower] : rowUpper[jRowLower];
	  thisInfo.row=jRowLower;
	  thisInfo.coefficient=coefficientLower;
	} else {
	  thisInfo.row=-1;
#ifndef NDEBUG
	  thisInfo.oldRowLower=COIN_DBL_MAX;
	  thisInfo.oldRowUpper=-COIN_DBL_MAX;
	  thisInfo.coefficient=0.0;
#endif
	}
	if (jRowUpper>=0&&jRowLower!=jRowUpper) {
	  thisInfo.oldRowLower2=(rowLower_[jRowUpper]>-1.0e30) ? rowLower_[jRowUpper]-rowLower[jRowUpper] : rowLower[jRowUpper];
	  thisInfo.oldRowUpper2=(rowUpper_[jRowUpper]<1.0e30) ? rowUpper_[jRowUpper]-rowUpper[jRowUpper] : rowUpper[jRowUpper];
	  thisInfo.row2=jRowUpper;
	  thisInfo.coefficient2=coefficientUpper;
	} else {
	  thisInfo.row2=-1;
#ifndef NDEBUG
	  thisInfo.oldRowLower2=COIN_DBL_MAX;
	  thisInfo.oldRowUpper2=-COIN_DBL_MAX;
	  thisInfo.coefficient2=0.0;
#endif
	}
	thisInfo.oldColumnLower=columnLower[iColumn];
	thisInfo.oldColumnUpper=columnUpper[iColumn];
	columnLower[iColumn]=newLower;
	columnUpper[iColumn]=newUpper;
	thisInfo.column=iColumn;
	infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
	ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo2),
		   0,NULL,NULL);
	infoA[nActions].type=2;
	nActions++;
      }
      for (CoinBigIndex i=start;i<start+columnLength[iColumn];
	   i++) {
	int iRow=row[i];
	if (rowLength[iRow]==1&&rowType[iRow]>=0&&rowType[iRow]!=5) {
#if DEBUG_SOME > 0
	  printf("Dropping singleton row %d (status %d) because of column %d (status %d) - jRow lower/upper %d/%d - nActions %d\n",
		 iRow,getRowStatus(iRow),iColumn,
		 getColumnStatus(iColumn),jRowLower,jRowUpper,nActions);
#endif
	  if (newModel->getRowStatus(iRow)!=basic) {
	    //newModel->setRowStatus(iRow,basic);
	    numberNonBasicSlacksOut++;
	  }
	  rowType[iRow]=1;
	  if (iRow!=jRowLower&&iRow!=jRowUpper) {
	    // mark as redundant
	    infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
	    clpPresolveInfo1_4_8 thisInfo;
	    thisInfo.oldRowLower=(rowLower_[iRow]>-1.0e30) ? rowLower_[iRow]-rowLower[iRow] : rowLower[iRow];
	    thisInfo.oldRowUpper=(rowUpper_[iRow]<1.0e30) ? rowUpper_[iRow]-rowUpper[iRow] : rowUpper[iRow];
	    thisInfo.row=iRow;
	    int n=rowLength[iRow];
	    CoinBigIndex start=rowStart[iRow];
	    thisInfo.lengthRow=n;
	    ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo1_4_8),
		       n,column+start,elementByRow+start);
	    infoA[nActions].type=1;
	    nActions++;
	  }
	  rowLength[iRow]=0;
	} else if (rowType[iRow]<=0) {
	  row[put]=iRow;
	  double value = element[i];
	  element[put++]=value;
	  if (rowType[iRow]>=0&&iFlag<3) {
	    assert(rowType[iRow]==0);
	    double lower = rowLower[iRow];
	    double upper = rowUpper[iRow];
	    if (-1.0e20 < lower && upper < 1.0e20) {
	      // bounded - we lose
	      iFlag=-1;
	      //break;
	    } else if (-1.0e20 < lower || upper < 1.0e20) {
	      nonFree++;
	    }
	    // see what this particular row says
	    // jFlag == 2 ==> up is towards feasibility
	    int jFlag = (value > 0.0
			 ? (upper >  1.0e20 ? 2 : 1)
			 : (lower < -1.0e20 ? 2 : 1));
	    
	    if (iFlag) {
	      // check that it agrees with iFlag.
	      if (iFlag!=jFlag) {
		iFlag=-1;
	      }
	    } else {
	      // first row -- initialize iFlag
	      iFlag=jFlag;
	    }
	  } else if (rowType[iRow]<0) {
	    iFlag=-1; // be safe
	  }
	}
      }
      // Do we need to switch status of iColumn?
      if (numberNonBasicSlacksOut>0) {
	// make iColumn non basic if possible
	if (newModel->getColumnStatus(iColumn)==basic) {
	  newModel->setColumnStatus(iColumn,superBasic);
	}
      }
      double cost = objective[iColumn]*optimizationDirection_;
      int length = put-columnStart[iColumn];
      if (!length) {
	if (!cost) {
	  // put to closest to zero
	  if (fabs(columnLower[iColumn])<fabs(columnUpper[iColumn]))
	    iFlag=1;
	  else
	    iFlag=2;
	} else if (cost>0.0) {
	  iFlag=1;
	} else {
	  iFlag=2;
	}
      } else {
	if (cost>0.0&&iFlag==2)
	  iFlag=-1;
	else if (cost<0.0&&iFlag==1)
	  iFlag=-1;
      }
      columnLength[iColumn]=length;
      //#define NO_MOVABLE
#ifdef NO_MOVABLE
      iFlag=-1;
#endif
      if (iFlag>0&&nonFree) {
	double newValue;
	if (iFlag==2) {
	  // fix to upper
	  newValue =CoinMin(columnUpper[iColumn],1.0e20);
	} else {
	  // fix to lower 
	  newValue =CoinMax(columnLower[iColumn],-1.0e20);
	}
	columnActivity_[iColumn]=newValue;
#if DEBUG_SOME > 0
	if (newModel->getColumnStatus(iColumn)==
	    basic) {
	  // ? move basic back onto sub if can?
	  iFlag += 2;
	}
	printf("Dropping movable column %d - iFlag %d - jRow lower/upper %d/%d - nActions %d\n",
	       iColumn,iFlag,jRowLower,jRowUpper,nActions);
#endif
	columnType[iColumn]=11;
	if (newModel->getColumnStatus(iColumn)==
	    basic) {
	  // need to put status somewhere else
	  int shortestNumber=numberColumns_;
	  int shortest=-1;
	  for (int j=start;j<start+length;j++) {
	    int iRow=row[j];
	    if (rowLength[iRow]<shortestNumber&&
		newModel->getRowStatus(iRow)!=
		basic) {
	      shortest=iRow;
	      shortestNumber = rowLength[iRow];
	    }
	  }
	  if (shortest>=0) {
	    // make basic
	    newModel->setRowStatus(shortest,basic);
	    newModel->setColumnStatus(iColumn,superBasic);
	  } else {
	    // put on a column
	    shortestNumber=numberColumns_;
	    shortest=-1;
	    for (int j=start;j<start+length;j++) {
	      int iRow=row[j];
	      if (rowLength[iRow]<shortestNumber) {
		int start = rowStart[iRow];
		for (int i=start;i<start+rowLength[iRow];i++) {
		  int jColumn = column[i];
		  if (iColumn!=jColumn&&
		      newModel->getColumnStatus(jColumn)!=
		      basic) {
		    shortest=jColumn;
		    shortestNumber = rowLength[iRow];
		  }
		}
	      }
	    }
	    if (shortest>=0) {
	      // make basic
	      newModel->setColumnStatus(shortest,basic);
	    } else {
#if DEBUG_SOME > 0
	      printf("what now - dropping - basic\n");
#endif
	    }
	  }
	}
	clpPresolveInfo11 thisInfo;
	thisInfo.oldColumnLower=columnLower[iColumn];
	thisInfo.oldColumnUpper=columnUpper[iColumn];
	thisInfo.fixedTo=newValue;
	columnLower[iColumn]=newValue;
	columnUpper[iColumn]=newValue;
	thisInfo.column=iColumn;
	int n=columnLength[iColumn];
	CoinBigIndex start=columnStart[iColumn];
	thisInfo.lengthColumn=n;
	infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
	infoA[nActions].type=11;
	nActions++;
	ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo11),
			  n,row+start,element+start);
	// adjust rhs and take out of rows
	columnLength[iColumn]=0;
	nChanged++;
	for (int j=start;j<start+length;j++) {
	  int iRow=row[j];
	  double value = element[j]*newValue;
	  double lower = rowLower[iRow];
	  if (lower>-1.0e20)
	    rowLower[iRow]=lower-value;
	  double upper = rowUpper[iRow];
	  if (upper<1.0e20)
	    rowUpper[iRow]=upper-value;
	  // take out of row copy (and put on list)
	  assert (rowType[iRow]<=0&&rowType[iRow]>-2);
	  // See if already marked (will get to row later in loop
	  if ((rowStatus[iRow]&128)==0) {
	    rowStatus[iRow] |= 128;
	    whichRows[numberRowsLook++]=iRow;
	    assert (numberRowsLook<=numberRows_);
	  }
	  int start = rowStart[iRow];
	  int put=start;
	  for (int i=start;i<start+rowLength[iRow];i++) {
	    int jColumn = column[i];
	    if (iColumn!=jColumn) {
	      column[put]=jColumn;
	      elementByRow[put++]=elementByRow[i];
	    }
	  }
	  rowLength[iRow]=put-start;
	}
      }
    }
  }
  if (feasible) {
    clpPresolveMore moreInfo;
    moreInfo.model=newModel;
    moreInfo.rowCopy=&rowCopy;
    moreInfo.rowType=rowType;
    moreInfo.columnType=columnType;
    moreInfo.stuff=&stuff;
    moreInfo.info=infoA;
    moreInfo.nActions=&nActions;
    eventHandler_->eventWithInfo(ClpEventHandler::moreMiniPresolve,&moreInfo);
    newModel->setObjectiveOffset(offset);
    int nChar2 = nActions*static_cast<int>(sizeof(clpPresolveInfo))+static_cast<int>(stuff.putStuff-startStuff);
    clpPresolveInfo * infoData = reinterpret_cast<clpPresolveInfo *>(new char[nChar2]);
    memcpy(infoData,infoA,nActions*sizeof(clpPresolveInfo));
    char * info2 = reinterpret_cast<char *>(infoData+nActions);
    memcpy(info2,startStuff,stuff.putStuff-startStuff);
    listInfo * infoNew = new listInfo; 
    infoNew->numberEntries=nActions;
    infoNew->maximumEntries=nActions;
    infoNew->start=infoData;
    infoNew->numberInitial=numberInitial;
    *infoOut=infoNew;
    int nRows=0;
    for (int iRow=0;iRow<numberRows_;iRow++) {
      if (rowType[iRow]>0) 
	whichRows[nRows++]=iRow;
    }
    int nColumns=0;
    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
      if (columnType[iColumn]>10) 
	whichColumns[nColumns++]=iColumn;
    }
#ifdef FUNNY_CHECK
    {
      CoinPackedMatrix rowCopy2 = *this->matrix();
      rowCopy2.reverseOrdering();
      int * column2 = rowCopy2.getMutableIndices();
      CoinBigIndex * rowStart2 = rowCopy2.getMutableVectorStarts();
      double * elementByRow2 = rowCopy2.getMutableElements();
      int * rowLength2 = rowCopy2.getMutableVectorLengths();
      printf("Odd rows\n");
      for (int iRow=0;iRow<numberRows_;iRow++) {
	if (rowType[iRow]==-2) {
	  CoinBigIndex start = rowStart[iRow];
	  int length=rowLength[iRow];
	  printf("Odd row %d -> ",iRow);
	  for (CoinBigIndex j=start;j<start+length;j++) {
	    int iColumn=column[j];
	    printf("(%d %g) ",iColumn,elementByRow[j]);
	  }
	  printf("Original ");
	  start = rowStart2[iRow];
	  length=rowLength2[iRow];
	  for (CoinBigIndex j=start;j<start+length;j++) {
	    int iColumn=column2[j];
	    printf("(%d %g) ",iColumn,elementByRow2[j]);
	  }
	  printf(">= %g/%g\n",rowLower[iRow],rowLower_[iRow]);
	}
      }
      printf("now columns\n");
      for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
	CoinBigIndex start = columnStart[iColumn];
	int length=columnLength[iColumn];
	for (CoinBigIndex j=start;j<start+length;j++) {
	  int iRow=row[j];
	  if (rowType[iRow]==-2)
	    printf("Column %d row %d value %g\n",
		   iColumn,iRow,element[j]);
	}
      }
    }
#endif
#ifdef TWOFER
    if (!orderedMatrix) {
      //lastElement;
      // move up
      CoinBigIndex put=lastElement;
      for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
	CoinBigIndex start = columnStart[iColumn];
	columnStart[iColumn]=put-lastElement;
	int length=columnLength[iColumn];
	for (CoinBigIndex j=start;j<start+length;j++) {
	  row[put]=row[j];
	  element[put++]=element[j];
	}
      }
      int numberElements = put-lastElement;
      columnStart[numberColumns_]=numberElements;
      memcpy(row,row+lastElement,numberElements*sizeof(int));
      memcpy(element,element+lastElement,numberElements*sizeof(double));
    }
#endif
    // could just shrink - would be faster
#if DEBUG_SOME > 0
    printf("%d Row types and lookup\n",nRows);
    int nBNew=0;
    int iNew=0;
    for (int iRow=0;iRow<numberRows_;iRow++) {
      int type=rowType[iRow];
      char xNew='O';
      if (type<=0) {
	xNew='N';
	if (newModel->getRowStatus(iRow)==basic) {
	  nBNew++;
	  xNew='B';
	} 
	printf("%d -> %d type %d - new status %c\n",iRow,iNew,rowType[iRow],xNew);
	iNew++;
      }
    }
    printf("%d Column types and lookup\n",nColumns);
    iNew=0;
    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
      int type=columnType[iColumn];
      char xNew='O';
      if (type<=10) {
	xNew='N';
	if (newModel->getColumnStatus(iColumn)==basic) {
	  nBNew++;
	  xNew='B';
	} 
	printf("%d -> %d type %d - new status %c\n",iColumn,iNew,columnType[iColumn],xNew);
	iNew++;
      }
    }
    printf("Deleting %d rows (now %d) and %d columns (%d basic)\n",nRows,numberRows_-nRows,
	   nColumns,nBNew);
#else
#if DEBUG_SOME >0
    printf("Deleting %d rows (now %d) and %d columns\n",nRows,numberRows_-nRows,
	   nColumns);
#endif
#endif
#if 0
    newModel->deleteRows(nRows,whichRows);
    newModel->deleteColumns(nColumns,whichColumns);
#else
    newModel->deleteRowsAndColumns(nRows,whichRows,nColumns,whichColumns);
#endif
  } else {
    delete newModel;
    newModel=NULL;
    *infoOut=NULL;
  }
  delete [] whichRows;
  delete [] infoA;
  delete [] startStuff;
  delete [] array;
  return newModel;
}
// After mini presolve
void 
ClpSimplex::miniPostsolve(const ClpSimplex * presolvedModel, void * infoIn)
{
  int numberTotal=numberRows_+numberColumns_;
  listInfo * infoX = reinterpret_cast<listInfo *>(infoIn);
  int nActions=infoX->numberEntries;
#if DEBUG_SOME > 0
#ifndef NDEBUG
  int numberInitial=infoX->numberInitial;
#endif
#endif
  clpPresolveInfo * infoA = infoX->start;
  char * startStuff = reinterpret_cast<char *>(infoA+nActions);
  // move status and solution across
  int numberColumns2=presolvedModel->numberColumns();
  const double * solution2 = presolvedModel->primalColumnSolution();
  unsigned char * rowStatus2 = presolvedModel->statusArray()+numberColumns2;
  unsigned char * columnStatus2 = presolvedModel->statusArray();
  unsigned char * rowStatus = status_+numberColumns_;
  unsigned char * columnStatus = status_;
  char * rowType = new char [numberTotal];
  memset(rowType,0,numberTotal);
  char * columnType = rowType+numberRows_;
  double * rowLowerX = new double [3*numberRows_+3*numberColumns_+CoinMax(numberRows_,numberColumns_)];
  double * rowUpperX = rowLowerX+numberRows_;
  double * columnLowerX = rowUpperX+numberRows_;
  double * columnUpperX = columnLowerX+numberColumns_;
  double * objectiveX = columnUpperX+numberColumns_;
  double * tempElement = objectiveX+numberColumns_;
  double * array = tempElement+CoinMax(numberRows_,numberColumns_);
  memset(array,0,numberRows_*sizeof(double));
  int * tempIndex = new int [CoinMax(numberRows_,numberColumns_)+4+2*numberColumns_+numberRows_];
  int * forward = tempIndex+CoinMax(numberRows_,numberColumns_)+1;
  int * backward = forward + numberColumns_+2;
  int * whichRows2 = backward + numberColumns_+1;
  for (int i=-1;i<numberColumns_;i++)
    forward[i]=i+1;
  forward[numberColumns_]=-1;
  for (int i=0;i<=numberColumns_;i++)
    backward[i]=i-1;
  backward[-1]=-1;
  restoreInfo restore;
  restore.elements=tempElement;
  restore.indices=tempIndex;
  restore.startStuff=startStuff;
#ifndef NDEBUG
  for (int i=0;i<numberRows_;i++) {
    rowLowerX[i]=COIN_DBL_MAX;
    rowUpperX[i]=-COIN_DBL_MAX;
  }
  for (int i=0;i<numberColumns_;i++) {
    columnLowerX[i]=COIN_DBL_MAX;
    columnUpperX[i]=-COIN_DBL_MAX;
  }
#endif
  memset(rowActivity_,0,numberRows_*sizeof(double));
  memset(dual_,0,numberRows_*sizeof(double));
  // Get presolved contribution
  const int * row = matrix()->getIndices();
  const CoinBigIndex * columnStart = matrix()->getVectorStarts();
  const int * columnLength = matrix()->getVectorLengths();
  const double * element = matrix()->getElements();
  // forwards so dropped column at end
  for (int i=0;i<nActions;i++) {
    int type=infoA[i].type;
    char * getStuff = startStuff+infoA[i].infoOffset;
    int iRow=-1;
    int iColumn=-1;
    switch (type) {
    case 1:
    case 4:
    case 8:
    case 9:
      // redundant
      {
	clpPresolveInfo1_4_8  thisInfo;
	memcpy(&thisInfo,getStuff,sizeof(clpPresolveInfo1_4_8));
	iRow = thisInfo.row;
	rowType[iRow]=static_cast<char>(type);
      }
      break;
    case 2: 
      // sub
      {
	clpPresolveInfo2 thisInfo;
	memcpy(&thisInfo,getStuff,sizeof(clpPresolveInfo2));
	iRow = thisInfo.row;
	if (iRow>=0)
	  rowType[iRow]=2;
	iRow = thisInfo.row2;
	if (iRow>=0)
	  rowType[iRow]=2;
	iColumn = thisInfo.column;
	columnType[iColumn]=2;
      }
      break;
    case 11: 
      // movable column
      {
	clpPresolveInfo11 thisInfo;
	memcpy(&thisInfo,getStuff,sizeof(clpPresolveInfo11));
	iColumn = thisInfo.column;
	columnType[iColumn]=11;
      }
      break;
    case 13: 
      // empty column
      {
	clpPresolveInfo13 thisInfo;
	memcpy(&thisInfo,getStuff,sizeof(clpPresolveInfo13));
	iColumn = thisInfo.column;
	columnType[iColumn]=13;
      }
      break;
    case 14: 
      // doubleton
      {
	clpPresolveInfo14 thisInfo;
	memcpy(&thisInfo,getStuff,sizeof(clpPresolveInfo14));
	iRow = thisInfo.row;
	iColumn = thisInfo.column;
	int iColumn2 = thisInfo.column2;
	columnType[iColumn]=3;
	columnType[iColumn2]=14;
	rowType[iRow]=3;
      }
      break;
    }
#if DEBUG_SOME > 0
    printf("Action %d type %d row %d column %d\n",
	   i,type,iRow,iColumn);
#endif
  }
  int iGet=0;
  const double * rowLowerY = presolvedModel->rowLower();
  const double * rowUpperY = presolvedModel->rowUpper();
  for (int iRow=0;iRow<numberRows_;iRow++) {
    if (!rowType[iRow]) {
      rowStatus[iRow]=rowStatus2[iGet];
      rowActivity_[iRow]=presolvedModel->rowActivity_[iGet];
      dual_[iRow]=presolvedModel->dual_[iGet];
      rowLowerX[iRow]=rowLowerY[iGet];
      rowUpperX[iRow]=rowUpperY[iGet];
      tempIndex[iGet]=iRow;
      iGet++;
    } else {
      setRowStatus(iRow,basic);
    } 
  }
  assert (iGet==presolvedModel->numberRows());
  CoinPackedMatrix matrixX;
  int numberElementsOriginal=matrix_->getNumElements();
  const int * rowY = presolvedModel->matrix()->getIndices();
  const CoinBigIndex * columnStartY = presolvedModel->matrix()->getVectorStarts();
  const int * columnLengthY = presolvedModel->matrix()->getVectorLengths();
  const double * elementY = presolvedModel->matrix()->getElements();
  iGet=0;
  CoinBigIndex put=0;
  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
    if (columnType[iColumn]<11) {
      put += CoinMax(columnLength[iColumn],columnLengthY[iGet]);
      iGet++;
    } else {
      put += columnLength[iColumn];
    }
  }
  int lastElement=2*(put+numberColumns_)+1000;
  int spare = (lastElement-put)/numberColumns_;
  //printf("spare %d\n",spare);
  matrixX.reserve(numberColumns_,lastElement+2*numberElementsOriginal);
  int * rowX = matrixX.getMutableIndices();
  CoinBigIndex * columnStartX = matrixX.getMutableVectorStarts();
  int * columnLengthX = matrixX.getMutableVectorLengths();
  double * elementX = matrixX.getMutableElements();
  const double * columnLowerY = presolvedModel->columnLower();
  const double * columnUpperY = presolvedModel->columnUpper();
  iGet=0;
  put=0;
  memcpy(objectiveX,this->objective(),numberColumns_*sizeof(double));
  const double * objectiveY=presolvedModel->objective();
  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
    columnStartX[iColumn]=put;
    if (columnType[iColumn]<11) {
      CoinBigIndex next=put+columnLengthY[iGet];
      if (spare>=0) 
	next += CoinMax(columnLength[iColumn]-columnLengthY[iGet],0)+spare;
      columnStatus[iColumn]=columnStatus2[iGet];
      columnActivity_[iColumn]=solution2[iGet];
      columnLowerX[iColumn]=columnLowerY[iGet];
      columnUpperX[iColumn]=columnUpperY[iGet];
      columnLengthX[iColumn]=columnLengthY[iGet];
      objectiveX[iColumn]=objectiveY[iGet];
      for (CoinBigIndex j=columnStartY[iGet];j<columnStartY[iGet]+columnLengthY[iGet];j++) {
	rowX[put]=tempIndex[rowY[j]];
	elementX[put++]=elementY[j];
      }
      columnActivity_[iColumn]=presolvedModel->columnActivity_[iGet];
      iGet++;
      columnType[iColumn]=0;
      put = next;
    } else {
      put += CoinMax(columnLength[iColumn]+spare,0);
      columnActivity_[iColumn]=0.0;
      columnType[iColumn]=1;
      columnLengthX[iColumn]=0;
      setColumnStatus(iColumn,superBasic);
    }
  }
  assert (put<=lastElement);
  columnStartX[numberColumns_]=lastElement+numberElementsOriginal;
  assert (put<=lastElement);
  assert (iGet==numberColumns2);
  matrixX.times(columnActivity_,rowActivity_);
  if (optimizationDirection_<0) {
    for (int i=0;i<numberColumns_;i++)
      objectiveX[i]=-objectiveX[i];
  }
#if 0
  // get row copy
  CoinPackedMatrix rowCopy = *matrix();
  rowCopy.reverseOrdering();
  const int * column = rowCopy.getIndices();
  const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
  const int * rowLength = rowCopy.getVectorLengths();
  const double * elementByRow = rowCopy.getElements();
#endif
#if 1 //DEBUG_SOME > 0
  double * tempRhs=new double[numberRows_];
#endif
#ifndef NDEBUG
  bool checkMatrixAtEnd=true;
#endif
  for (int i=nActions-1;i>=0;i--) {
#if DEBUG_SOME > 0
#if 1 //ndef NDEBUG
    memset(tempRhs,0,numberRows_*sizeof(double));
    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
      //if (columnActivity_[iColumn]<columnLower_[iColumn]-1.0e-5||
      //      columnActivity_[iColumn]>columnUpper_[iColumn]+1.0e-5)
      //printf ("Bad column %d %g <= %g <= %g\n",iColumn,
      //	columnLower_[iColumn],columnActivity_[iColumn],columnUpper_[iColumn]);
      double value=columnActivity_[iColumn];
      for (CoinBigIndex j=columnStartX[iColumn];
	   j<columnStartX[iColumn]+columnLengthX[iColumn];j++) {
	int jRow=rowX[j];
	tempRhs[jRow] += value*elementX[j];
      }
    }
    int nBadRow=0;
    for (int iRow=0;iRow<numberRows_;iRow++) {
      if (rowLowerX[iRow]==COIN_DBL_MAX)
	continue;
      if (fabs(tempRhs[iRow]-rowActivity_[iRow])>1.0e-4)
	printf("Row %d temprhs %g rowActivity_ %g\n",iRow,tempRhs[iRow],
	       rowActivity_[iRow]);
      if (tempRhs[iRow]<rowLowerX[iRow]-1.0e-4||
	  tempRhs[iRow]>rowUpperX[iRow]+1.0e-4) {
	printf("Row %d %g %g %g\n",iRow,rowLowerX[iRow],
	       tempRhs[iRow],rowUpperX[iRow]);
	nBadRow++;
      }
    }
    assert (!nBadRow);
#endif
#ifndef NDEBUG
    if (i>=numberInitial&&true) {
      for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
	if (columnLengthX[iColumn]) {
	  double djValue = objectiveX[iColumn];
	  for (CoinBigIndex j=columnStartX[iColumn];
	       j<columnStartX[iColumn]+columnLengthX[iColumn];j++) {
	    int jRow=rowX[j];
	    djValue -= dual_[jRow]*elementX[j];
	  }
	  char inOut=columnType[iColumn] ? 'O' : 'I';
	  if (djValue>10.0*dualTolerance_&&
	      columnActivity_[iColumn]>columnLowerX[iColumn]+primalTolerance_)
	    printf("bad dj on column %d lb dj %g in/out %c\n",iColumn,djValue,inOut);
	  else if (djValue<-10.0*dualTolerance_&&
		   columnActivity_[iColumn]<columnUpperX[iColumn]-primalTolerance_)
	    printf("bad dj on column %d ub dj %g in/out %c\n",iColumn,djValue,inOut);
	}
      }
    }
#endif
#endif
    int type=infoA[i].type;
    int iRow=-1;
    int iColumn=-1;
#if DEBUG_SOME>0
    printf("Action %d type %d\n",i,type);
#ifndef NDEBUG
      checkBasis(this, rowType, columnType);
#endif
#endif
    switch (type) {
    case 1:
    case 4:
    case 8:
    case 9:
      // redundant
      {
#ifndef NDEBUG
	if (type==4)
	  checkMatrixAtEnd=false;
#endif
	clpPresolveInfo8  thisInfo;
	copyFromSave(restore,infoA[i],&thisInfo);
	iRow = thisInfo.row;
	// Insert row and modify RHS
#ifdef CLP_USER_DRIVEN
	if (type>=8) {
	  thisInfo.tempElement=tempElement;
	  thisInfo.tempIndex=tempIndex;
	  thisInfo.rowLowerX=rowLowerX;
	  thisInfo.rowUpperX=rowUpperX;
	  eventHandler_->eventWithInfo(ClpEventHandler::modifyMatrixInMiniPostsolve,&thisInfo);
	} else {
#endif
	if (rowLower_[iRow]>-1.0e30)
	  rowLowerX[iRow]=rowLower_[iRow]-thisInfo.oldRowLower;
	else
	  rowLowerX[iRow]=thisInfo.oldRowLower;
	if (rowUpper_[iRow]<1.0e30)
	  rowUpperX[iRow]=rowUpper_[iRow]-thisInfo.oldRowUpper;
	else
	  rowUpperX[iRow]=thisInfo.oldRowUpper;
#ifdef CLP_USER_DRIVEN
	}
#endif
	int n=thisInfo.lengthRow;
	double rhs=0.0;
	for (int i=0;i<n;i++) {
	  int iColumn = tempIndex[i];
	  double value = tempElement[i];
	  rhs += value*columnActivity_[iColumn];
	  int length=columnLengthX[iColumn];
	  CoinBigIndex start=columnStartX[iColumn];
	  int nextColumn=forward[iColumn];
	  CoinBigIndex startNext=columnStartX[nextColumn];
	  if (start+length==startNext) {
	    // need more
	    moveAround(numberColumns_,numberElementsOriginal,
		       iColumn,length+1,
		       forward,backward,columnStartX,columnLengthX,
		       rowX,elementX);
	    start=columnStartX[iColumn];
	  }
	  columnLengthX[iColumn]++;
	  rowX[start+length]=iRow;
	  elementX[start+length]=value;
	}
	rowActivity_[iRow]=rhs;
	rowType[iRow]=0;
	assert (getRowStatus(iRow)==basic);
      }
      break;
    case 2: 
      // sub
      {
	clpPresolveInfo2 thisInfo;
	copyFromSave(restore,infoA[i],&thisInfo);
	iColumn = thisInfo.column;
	columnType[iColumn]=0;
	int jRowLower=thisInfo.row;
	int jRowUpper=thisInfo.row2;
	int length=columnLengthX[iColumn];
	CoinBigIndex start=columnStartX[iColumn];
	int nextColumn=forward[iColumn];
	CoinBigIndex startNext=columnStartX[nextColumn];
	if (start+length==startNext) {
	  // need more
	  moveAround(numberColumns_,numberElementsOriginal,
		     iColumn,length+(jRowLower<0||jRowUpper<0) ? 1 : 2,
		     forward,backward,columnStartX,columnLengthX,
		     rowX,elementX);
	  start=columnStartX[iColumn];
	}
	// modify
	double valueLower=thisInfo.coefficient;
	double valueUpper=thisInfo.coefficient2;
	if (jRowLower>=0) {
	  rowType[jRowLower]=0;
	  if (rowLower_[jRowLower]>-1.0e30)
	    rowLowerX[jRowLower]=rowLower_[jRowLower]-thisInfo.oldRowLower;
	  else
	    rowLowerX[jRowLower]=thisInfo.oldRowLower;
	  if (rowUpper_[jRowLower]<1.0e30)
	    rowUpperX[jRowLower]=rowUpper_[jRowLower]-thisInfo.oldRowUpper;
	  else
	    rowUpperX[jRowLower]=thisInfo.oldRowUpper;
	  columnLengthX[iColumn]++;
	  rowX[start+length]=jRowLower;
	  elementX[start+length]=valueLower;
	  rowActivity_[jRowLower]=valueLower*columnActivity_[iColumn];
	  // start off with slack basic
	  setRowStatus(jRowLower,basic);
	  length++;
	}
	if (jRowUpper>=0) {
	  rowType[jRowUpper]=0;
	  if (rowLower_[jRowUpper]>-1.0e30)
	    rowLowerX[jRowUpper]=rowLower_[jRowUpper]-thisInfo.oldRowLower2;
	  else
	    rowLowerX[jRowUpper]=thisInfo.oldRowLower2;
	  if (rowUpper_[jRowUpper]<1.0e30)
	    rowUpperX[jRowUpper]=rowUpper_[jRowUpper]-thisInfo.oldRowUpper2;
	  else
	    rowUpperX[jRowUpper]=thisInfo.oldRowUpper2;
	  columnLengthX[iColumn]++;
	  rowX[start+length]=jRowUpper;
	  elementX[start+length]=valueUpper;
	  rowActivity_[jRowUpper]=valueUpper*columnActivity_[iColumn];
	  // start off with slack basic
	  setRowStatus(jRowUpper,basic);
	  length++;
	}
	double djValue = objectiveX[iColumn];
	for (CoinBigIndex j=columnStartX[iColumn];
	     j<columnStartX[iColumn]+columnLengthX[iColumn];j++) {
	  int jRow=rowX[j];
	  djValue -= dual_[jRow]*elementX[j];
	}
	if (thisInfo.oldColumnLower==thisInfo.oldColumnUpper)
	  djValue=0.0;
	if (getColumnStatus(iColumn)!=basic) {
	  setColumnStatus(iColumn,superBasic);
	  double solValue = columnActivity_[iColumn];
	  bool hasToBeBasic=false;
	  if (getColumnStatus(iColumn)!=isFree) {
	    if (solValue>thisInfo.oldColumnLower+primalTolerance_&&
		solValue<thisInfo.oldColumnUpper-primalTolerance_)
	      hasToBeBasic=true;
	  } else {
	    hasToBeBasic=fabs(djValue)>dualTolerance_;
	  }
	  if (solValue<=thisInfo.oldColumnLower+primalTolerance_&&djValue<-dualTolerance_) {
#if DEBUG_SOME > 1
	    printf("odd column %d at lb of %g has dj of %g\n",
		   iColumn,thisInfo.oldColumnLower,djValue);
#endif
	    hasToBeBasic=true;
	  } else if (solValue>=thisInfo.oldColumnUpper-primalTolerance_&&djValue>dualTolerance_) {
#if DEBUG_SOME > 1
	    printf("odd column %d at ub of %g has dj of %g\n",
		   iColumn,thisInfo.oldColumnUpper,djValue);
#endif
	    hasToBeBasic=true;
	  }
	  if (hasToBeBasic) {
	    if (jRowLower>=0&&jRowUpper>=0) {
	      // choose
#if DEBUG_SOME > 1
	      printf("lower row %d %g <= %g <= %g\n",
		     jRowLower,rowLowerX[jRowLower],rowActivity_[jRowLower],
		     rowUpperX[jRowLower]);
#endif
	      double awayLower = CoinMin(rowActivity_[jRowLower]-rowLowerX[jRowLower],
					 rowUpperX[jRowLower]-rowActivity_[jRowLower]);
#if DEBUG_SOME > 1
	      printf("upper row %d %g <= %g <= %g\n",
		     jRowUpper,rowLowerX[jRowUpper],rowActivity_[jRowUpper],
		     rowUpperX[jRowUpper]);
#endif
	      double awayUpper = CoinMin(rowActivity_[jRowUpper]-rowLowerX[jRowUpper],
					 rowUpperX[jRowUpper]-rowActivity_[jRowUpper]);
	      if (awayLower>awayUpper)
		jRowLower=-1;
	    }
	    if (jRowLower<0) {
	      setRowStatus(jRowUpper,superBasic);
	      setColumnStatus(iColumn,basic);
	      dual_[jRowUpper]=djValue/valueUpper;
	    } else {
	      setRowStatus(jRowLower,superBasic);
	      setColumnStatus(iColumn,basic);
	      dual_[jRowLower]=djValue/valueLower;
	    }
	  }
	}
	columnLowerX[iColumn]=thisInfo.oldColumnLower;
	columnUpperX[iColumn]=thisInfo.oldColumnUpper;
      }
      break;
    case 11: 
      // movable column
      {
	clpPresolveInfo11 thisInfo;
	copyFromSave(restore,infoA[i],&thisInfo);
	iColumn = thisInfo.column;
	columnType[iColumn]=0;
	assert (!columnLengthX[iColumn]);
	int newLength=thisInfo.lengthColumn;
	CoinBigIndex start=columnStartX[iColumn];
	int nextColumn=forward[iColumn];
	CoinBigIndex startNext=columnStartX[nextColumn];
	if (start+newLength>startNext) {
	  // need more
	  moveAround(numberColumns_,numberElementsOriginal,
		     iColumn,newLength,
		     forward,backward,columnStartX,columnLengthX,
		     rowX,elementX);
	  start=columnStartX[iColumn];
	}
	columnLengthX[iColumn]=newLength;
	memcpy(rowX+start,tempIndex,newLength*sizeof(int));
	memcpy(elementX+start,tempElement,newLength*sizeof(double));
	double solValue=thisInfo.fixedTo;
	columnActivity_[iColumn]=solValue;
	if (solValue) { 
	  for (int j=columnStartX[iColumn];
	       j<columnStartX[iColumn]+columnLengthX[iColumn];j++) {
	    int jRow=rowX[j];
	    double value=elementX[j]*solValue;
	    rowActivity_[jRow] += value;
	    if (rowLowerX[jRow]>-1.0e30)
	      rowLowerX[jRow] += value;
	    if (rowUpperX[jRow]<1.0e30)
	      rowUpperX[jRow] += value;
	  }
	}
	double djValue = objectiveX[iColumn];
	for (CoinBigIndex j=columnStartX[iColumn];
	     j<columnStartX[iColumn]+columnLengthX[iColumn];j++) {
	  int jRow=rowX[j];
	  djValue -= dual_[jRow]*elementX[j];
	}
	if (thisInfo.oldColumnLower==thisInfo.oldColumnUpper)
	  djValue=0.0;
	if (getColumnStatus(iColumn)!=basic) {
	  setColumnStatus(iColumn,superBasic);
	  bool hasToBeBasic=false;
	  if (getColumnStatus(iColumn)!=isFree) {
	    if (solValue>thisInfo.oldColumnLower+primalTolerance_&&
		solValue<thisInfo.oldColumnUpper-primalTolerance_)
	      hasToBeBasic=true;
	  } else {
	    hasToBeBasic=fabs(djValue)>dualTolerance_;
	  }
	  if (solValue<=thisInfo.oldColumnLower+primalTolerance_&&djValue<-dualTolerance_) {
#if DEBUG_SOME > 1
	    printf("odd column %d at lb of %g has dj of %g\n",
		   iColumn,thisInfo.oldColumnLower,djValue);
#endif
	    hasToBeBasic=true;
	  } else if (solValue>=thisInfo.oldColumnUpper-primalTolerance_&&djValue>dualTolerance_) {
#if DEBUG_SOME > 1
	    printf("odd column %d at ub of %g has dj of %g\n",
		   iColumn,thisInfo.oldColumnUpper,djValue);
#endif
	    hasToBeBasic=true;
	  }
	  if (hasToBeBasic) {
	    //abort();
	    //setRowStatus(iRow,superBasic);
	    setColumnStatus(iColumn,basic);
	    //dual_[iRow]=djValue/value;
	  }
	}
	columnLowerX[iColumn]=thisInfo.oldColumnLower;
	columnUpperX[iColumn]=thisInfo.oldColumnUpper;
      }
      break;
    case 13: 
      // empty (or initially fixed) column
      {
	clpPresolveInfo13 thisInfo;
	copyFromSave(restore,infoA[i],&thisInfo);
	iColumn = thisInfo.column;
	columnType[iColumn]=0;
	columnLowerX[iColumn]=thisInfo.oldColumnLower;
	columnUpperX[iColumn]=thisInfo.oldColumnUpper;
	assert (!columnLengthX[iColumn]);
	int newLength=columnLength[iColumn];
	CoinBigIndex startOriginal = columnStart[iColumn];
	double solValue=columnLower_[iColumn];
	columnActivity_[iColumn]=solValue;
	if (newLength&&solValue) {
	  for (int j=startOriginal;j<startOriginal+newLength;j++) {
	    int iRow=row[j];
	    double value = element[j]*solValue;
	    rowActivity_[iRow] += value;
	    double lower = rowLowerX[iRow];
	    if (lower>-1.0e20)
	      rowLowerX[iRow]=lower+value;
	    double upper = rowUpperX[iRow];
	    if (upper<1.0e20)
	      rowUpperX[iRow]=upper+value;
	  }	  
	}
#ifndef NDEBUG
	// copy from original
	CoinBigIndex start=columnStartX[iColumn];
	int nextColumn=forward[iColumn];
	CoinBigIndex startNext=columnStartX[nextColumn];
	if (start+newLength>startNext) {
	  // need more
	  moveAround(numberColumns_,numberElementsOriginal,
		     iColumn,newLength,
		     forward,backward,columnStartX,columnLengthX,
		     rowX,elementX);
	  start=columnStartX[iColumn];
	}
	columnLengthX[iColumn]=newLength;
	memcpy(rowX+start,row+startOriginal,newLength*sizeof(int));
	memcpy(elementX+start,element+startOriginal,newLength*sizeof(double));
#endif
      }
      break;
    case 14: 
      // doubleton
      {
	clpPresolveInfo14 thisInfo;
	copyFromSave(restore,infoA[i],&thisInfo);
	iRow = thisInfo.row;
	rowType[iRow]=0;
	int iColumn1 = thisInfo.column;
	int iColumn2 = thisInfo.column2;
	columnType[iColumn2]=0;
	double value1=thisInfo.value1;
	int length=columnLengthX[iColumn1];
	CoinBigIndex start=columnStartX[iColumn1];
	for (int i=0;i<length;i++) {
	  int jRow=rowX[i+start];
	  array[jRow]=elementX[i+start];
	  whichRows2[i]=jRow;
	}
	int n=length;
	length=columnLengthX[iColumn2];
	assert (!length);
	int newLength=thisInfo.lengthColumn2;
	start=columnStartX[iColumn2];
	int nextColumn=forward[iColumn2];
	CoinBigIndex startNext=columnStartX[nextColumn];
	if (start+newLength>startNext) {
	  // need more
	  moveAround(numberColumns_,numberElementsOriginal,
		     iColumn2,newLength,
		     forward,backward,columnStartX,columnLengthX,
		     rowX,elementX);
	  start=columnStartX[iColumn2];
	}
	columnLengthX[iColumn2]=newLength;
	memcpy(rowX+start,tempIndex,newLength*sizeof(int));
	memcpy(elementX+start,tempElement,newLength*sizeof(double));
	double value2=0.0;
	for (int i=0;i<newLength;i++) {
	  int jRow=tempIndex[i];
	  double value=tempElement[i];
	  if (jRow==iRow) {
	    value2=value;
	    break;
	  }
	}
	assert (value2);
	double rhs=thisInfo.rhs;
	double multiplier1 = rhs/value2;
	double multiplier = value1/value2;
	for (int i=0;i<newLength;i++) {
	  int jRow=tempIndex[i];
	  double value = array[jRow];
	  double valueNew = value + multiplier*tempElement[i];
	  double rhsMod = multiplier1*tempElement[i];
	  if (rowLowerX[jRow]>-1.0e30)
	    rowLowerX[jRow] += rhsMod;
	  if (rowUpperX[jRow]<1.0e30)
	    rowUpperX[jRow] += rhsMod;
	  rowActivity_[jRow] += rhsMod;
	  if (!value) {
	    array[jRow]=valueNew;
	    whichRows2[n++]=jRow;
	  } else {
	    if (!valueNew)
	      valueNew=1.0e-100;
	    array[jRow]=valueNew;
	  }
	}
	length=0;
	for (int i=0;i<n;i++) {
	  int jRow = whichRows2[i];
	  double value = array[jRow];
	  array[jRow]=0.0;
	  if (fabs(value)<1.0e-13) 
	    value=0.0;
	  if (value) {
	    tempIndex[length] = jRow;
	    tempElement[length++]=value;
	  }
	}
	start=columnStartX[iColumn1];
	nextColumn=forward[iColumn1];
	startNext=columnStartX[nextColumn];
	if (start+length>startNext) {
	  // need more
	  moveAround(numberColumns_,numberElementsOriginal,
		     iColumn1,length,
		     forward,backward,columnStartX,columnLengthX,
		     rowX,elementX);
	  start=columnStartX[iColumn1];
	}
	columnLengthX[iColumn1]=length;
	memcpy(rowX+start,tempIndex,length*sizeof(int));
	memcpy(elementX+start,tempElement,length*sizeof(double));
	objectiveX[iColumn2]=thisInfo.oldObjective2;
	objectiveX[iColumn1] += objectiveX[iColumn2]*multiplier;
	//offset += rhs*(objectiveX[iColumn2]*multiplier);
	double value = multiplier1-columnActivity_[iColumn1]*multiplier;
#if DEBUG_SOME > 0
	printf("type14 column2 %d rhs %g value1 %g - value %g\n",
	       iColumn2,thisInfo.rhs,thisInfo.value1,value);
#endif
	columnActivity_[iColumn2]=value;
	double djValue1 = objectiveX[iColumn1];
	for (CoinBigIndex j=columnStartX[iColumn1];
	     j<columnStartX[iColumn1]+columnLengthX[iColumn1];j++) {
	  int jRow=rowX[j];
	  djValue1 -= dual_[jRow]*elementX[j];
	}
	bool fixed = (thisInfo.oldColumnLower==thisInfo.oldColumnUpper);
	columnLowerX[iColumn1]=thisInfo.oldColumnLower;
	columnUpperX[iColumn1]=thisInfo.oldColumnUpper;
	double djValue2 = objectiveX[iColumn2];
	for (CoinBigIndex j=columnStartX[iColumn2];
	     j<columnStartX[iColumn2]+columnLengthX[iColumn2];j++) {
	  int jRow=rowX[j];
	  djValue2 -= dual_[jRow]*elementX[j];
	}
	bool fixed2 = (thisInfo.oldColumnLower2==thisInfo.oldColumnUpper2);
	columnLowerX[iColumn2]=thisInfo.oldColumnLower2;
	columnUpperX[iColumn2]=thisInfo.oldColumnUpper2;
	if (getColumnStatus(iColumn1)!=basic) {
	  setColumnStatus(iColumn1,superBasic);
	  double solValue = columnActivity_[iColumn1];
	  double lowerValue = columnLowerX[iColumn1];
	  double upperValue = columnUpperX[iColumn1];
	  setColumnStatus(iColumn2,superBasic);
	  double solValue2 = columnActivity_[iColumn2];
	  double lowerValue2 = columnLowerX[iColumn2];
	  double upperValue2 = columnUpperX[iColumn2];
	  int choice=-1;
	  double best=COIN_DBL_MAX;
	  for (int iTry=0;iTry<3;iTry++) {
	    double pi=0.0;
	    switch (iTry) {
	      // leave
	    case 0:
	      break;
	      // iColumn1 basic
	    case 1:
	      pi=djValue1/value1;
	      break;
	      // iColumn2 basic
	    case 2:
	      pi=djValue2/value2;
	      break;
	    }
	    // djs
	    double dj1 = djValue1-value1*pi;;
	    double bad1=0.0;
	    if (!fixed) {
	      if (dj1<-dualTolerance_&&solValue<=lowerValue+primalTolerance_)
		bad1=-dj1;
	      else if (dj1>dualTolerance_&&solValue>=upperValue-primalTolerance_)
		bad1=dj1;
	    }
	    double dj2 = djValue2-value2*pi;
	    double bad2=0.0;
	    if (!fixed2) {
	      if (dj2<-dualTolerance_&&solValue2<=lowerValue2+primalTolerance_)
		bad2=-dj2;
	      else if (dj2>dualTolerance_&&solValue2>=upperValue2-primalTolerance_)
		bad2=dj2;
	    }
	    if (CoinMax(bad1,bad2)<best) {
	      best=CoinMax(bad1,bad2);
	      choice=iTry;
	    }
	  }
	  // but values override
	  if (solValue>lowerValue+primalTolerance_&&
	      solValue<upperValue-primalTolerance_) {
	    if (getColumnStatus(iColumn1)!=isFree||
		fabs(djValue1)>dualTolerance_)
	      choice=1;
	  } else if (solValue2>lowerValue2+primalTolerance_&&
	      solValue2<upperValue2-primalTolerance_) {
	    if (getColumnStatus(iColumn2)!=isFree||
		fabs(djValue2)>dualTolerance_)
	      choice=2;
	  }
	  if (choice==1) {
	    // iColumn1 in basis
	    setRowStatus(iRow,superBasic);
	    setColumnStatus(iColumn1,basic);
	    dual_[iRow]=djValue1/value1;
	  } else if (choice==2) {
	    // iColumn2 in basis
	    setRowStatus(iRow,superBasic);
	    setColumnStatus(iColumn2,basic);
	    dual_[iRow]=djValue2/value2;
	  }
	} else {
	  if (fabs(djValue1)>10.0*dualTolerance_) {
	    // iColumn2 in basis
	    setRowStatus(iRow,superBasic);
	    setColumnStatus(iColumn2,basic);
	    dual_[iRow]=djValue2/value2;
	  } else {
	    // do we need iColumn2 in basis
	    double solValue2 = columnActivity_[iColumn2];
	    double lowerValue2 = columnLowerX[iColumn2];
	    double upperValue2 = columnUpperX[iColumn2];
	    if (solValue2>lowerValue2+primalTolerance_&&
		solValue2<upperValue2-primalTolerance_&&
		getColumnStatus(iColumn2)!=isFree) {
	      // iColumn2 in basis
	      setRowStatus(iRow,superBasic);
	      setColumnStatus(iColumn2,basic);
	      dual_[iRow]=djValue2/value2;
	    }
	  }
	}
	rowLowerX[iRow]=rhs;
	rowUpperX[iRow]=rhs;
	//abort();
      }
      break;
    }
  }
#ifndef NDEBUG
#ifndef CLP_USER_DRIVEN
      // otherwise user may be fudging rhs
  for (int iRow=0;iRow<numberRows_;iRow++) {
#ifndef CLP_USER_DRIVEN
    assert (fabs(rowLower_[iRow]-rowLowerX[iRow])<1.0e-4);
    assert (fabs(rowUpper_[iRow]-rowUpperX[iRow])<1.0e-4);
#else
    if (fabs(rowLower_[iRow]-rowLowerX[iRow])>1.0e-4||
	fabs(rowUpper_[iRow]-rowUpperX[iRow])>1.0e-4)
      printf("USER row %d lower,x %g %g upper,x %g %g\n",iRow,rowLower_[iRow],rowLowerX[iRow],
	     rowUpper_[iRow],rowUpperX[iRow]);
      
#endif
  }
  double * objective = this->objective();
  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
    assert (columnLower_[iColumn]==columnLowerX[iColumn]);
    assert (columnUpper_[iColumn]==columnUpperX[iColumn]);
    assert (fabs(objective[iColumn]-objectiveX[iColumn]*optimizationDirection_)<1.0e-3);
  }
#endif
  if (checkMatrixAtEnd) {
    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
      assert (columnLength[iColumn]==columnLengthX[iColumn]);
      int length=columnLengthX[iColumn];
      CoinBigIndex startX=columnStartX[iColumn];
      CoinSort_2(rowX+startX,rowX+startX+length,elementX+startX);
      CoinBigIndex start=columnStart[iColumn];
      memcpy(tempIndex,row+start,length*sizeof(int));
      memcpy(tempElement,element+start,length*sizeof(double));
      CoinSort_2(tempIndex,tempIndex+length,tempElement);
      for (int i=0;i<length;i++) {
	assert (rowX[i+startX]==tempIndex[i]);
	assert (fabs(elementX[i+startX]-tempElement[i])<1.0e-5);
      }
    }
  }
#endif
  delete [] rowType;
  delete [] tempIndex;
  // use temp matrix and do this every action
#if DEBUG_SOME>0
  matrix()->times(columnActivity_,rowActivity_);
  for (int i=0;i<numberColumns_;i++)
    assert (columnActivity_[i]>=columnLower_[i]-1.0e-5&&
	    columnActivity_[i]<=columnUpper_[i]+1.0e-5);
  int nBad=0;
  for (int i=0;i<numberRows_;i++) {
    if (rowActivity_[i]<rowLower_[i]-1.0e-5||
	rowActivity_[i]>rowUpper_[i]+1.0e-5) {
      printf("Row %d %g %g %g\n",i,rowLower_[i],
	     rowActivity_[i],rowUpper_[i]);
      nBad++;
    }
  }
  ClpTraceDebug (!nBad);
#endif
#if 1 //DEBUG_SOME > 0
  delete [] tempRhs;
#endif
  delete infoX;
  delete [] infoA;
  delete [] rowLowerX;
}
// mini presolve and solve
void 
ClpSimplex::miniSolve(char * rowType, char *columnType,int algorithm, int startUp)
{
  listInfo * info = NULL;
  ClpSimplex * small2 = miniPresolve(rowType,columnType,reinterpret_cast<void **>(&info));
  if (algorithm<0)
    small2->dual(startUp);
  else 
    small2->primal(startUp);
  miniPostsolve(small2,info);
  delete info;
}
