Example #1
0
//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpCholeskyTaucs::ClpCholeskyTaucs (const ClpCholeskyTaucs & rhs)
     : ClpCholeskyBase(rhs)
{
     type_ = rhs.type_;
     // For Taucs stuff is done by malloc
     matrix_ = rhs.matrix_;
     sizeFactorT_ = rhs.sizeFactorT_;
     if (matrix_) {
          choleskyStartT_ = (int *) malloc((numberRows_ + 1) * sizeof(int));
          CoinMemcpyN(rhs.choleskyStartT_, (numberRows_ + 1), choleskyStartT_);
          choleskyRowT_ = (int *) malloc(sizeFactorT_ * sizeof(int));
          CoinMemcpyN(rhs.choleskyRowT_, sizeFactorT_, choleskyRowT_);
          sparseFactorT_ = (double *) malloc(sizeFactorT_ * sizeof(double));
          CoinMemcpyN(rhs.sparseFactorT_, sizeFactorT_, sparseFactorT_);
          matrix_->colptr = choleskyStartT_;
          matrix_->rowind = choleskyRowT_;
          matrix_->values.d = sparseFactorT_;
     } else {
          sparseFactorT_ = NULL;
          choleskyStartT_ = NULL;
          choleskyRowT_ = NULL;
     }
     factorization_ = NULL,
     rowCopyT_ = rhs.rowCopyT_->clone();
}
Example #2
0
void
CoinWarmStartBasis::assignBasisStatus(int ns, int na, char*& sStat,
				     char*& aStat) {
  // Round all so arrays multiple of 4
  int nintS = (ns+15) >> 4;
  int nintA = (na+15) >> 4;
  int size = nintS+nintA;
  if (size) {
    if (size>maxSize_) {
      delete[] structuralStatus_;
      maxSize_ = size+10;
      structuralStatus_ = new char[4*maxSize_];
    }
    CoinMemcpyN( sStat,(4*nintS), structuralStatus_);
    artificialStatus_ = structuralStatus_+4*nintS;
    CoinMemcpyN( aStat,(4*nintA), artificialStatus_);
  } else {
    artificialStatus_ = NULL;
  }
  numStructural_ = ns;
  numArtificial_ = na;
  delete [] sStat;
  delete [] aStat;
  sStat = NULL;
  aStat = NULL;
}
Example #3
0
//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpCholeskyTaucs &
ClpCholeskyTaucs::operator=(const ClpCholeskyTaucs& rhs)
{
     if (this != &rhs) {
          ClpCholeskyBase::operator=(rhs);
          taucs_ccs_free(matrix_);
          if (factorization_)
               taucs_supernodal_factor_free(factorization_);
          factorization_ = NULL;
          sizeFactorT_ = rhs.sizeFactorT_;
          matrix_ = rhs.matrix_;
          if (matrix_) {
               choleskyStartT_ = (int *) malloc((numberRows_ + 1) * sizeof(int));
               CoinMemcpyN(rhs.choleskyStartT_, (numberRows_ + 1), choleskyStartT_);
               choleskyRowT_ = (int *) malloc(sizeFactorT_ * sizeof(int));
               CoinMemcpyN(rhs.choleskyRowT_, sizeFactorT_, choleskyRowT_);
               sparseFactorT_ = (double *) malloc(sizeFactorT_ * sizeof(double));
               CoinMemcpyN(rhs.sparseFactorT_, sizeFactorT_, sparseFactorT_);
               matrix_->colptr = choleskyStartT_;
               matrix_->rowind = choleskyRowT_;
               matrix_->values.d = sparseFactorT_;
          } else {
               sparseFactorT_ = NULL;
               choleskyStartT_ = NULL;
               choleskyRowT_ = NULL;
          }
          delete rowCopyT_;
          rowCopyT_ = rhs.rowCopyT_->clone();
     }
     return *this;
}
Example #4
0
// Load up quadratic objective
void ClpQuadraticObjective::loadQuadraticObjective(const int numberColumns, const CoinBigIndex *start,
  const int *column, const double *element, int numberExtended)
{
  fullMatrix_ = false;
  delete quadraticObjective_;
  quadraticObjective_ = new CoinPackedMatrix(true, numberColumns, numberColumns,
    start[numberColumns], element, column, start, NULL);
  numberColumns_ = numberColumns;
  if (numberExtended > numberExtendedColumns_) {
    if (objective_) {
      // make correct size
      double *newArray = new double[numberExtended];
      CoinMemcpyN(objective_, numberColumns_, newArray);
      delete[] objective_;
      objective_ = newArray;
      memset(objective_ + numberColumns_, 0, (numberExtended - numberColumns_) * sizeof(double));
    }
    if (gradient_) {
      // make correct size
      double *newArray = new double[numberExtended];
      CoinMemcpyN(gradient_, numberColumns_, newArray);
      delete[] gradient_;
      gradient_ = newArray;
      memset(gradient_ + numberColumns_, 0, (numberExtended - numberColumns_) * sizeof(double));
    }
    numberExtendedColumns_ = numberExtended;
  } else {
    numberExtendedColumns_ = numberColumns_;
  }
}
Example #5
0
CoinWarmStartBasis::CoinWarmStartBasis(int ns, int na,
				     const char* sStat, const char* aStat) :
  numStructural_(ns), numArtificial_(na),
  structuralStatus_(NULL), artificialStatus_(NULL) {
  // Round all so arrays multiple of 4
  int nintS = ((ns+15) >> 4);
  int nintA = ((na+15) >> 4);
  maxSize_ = nintS+nintA;
  if (maxSize_ > 0) {
    structuralStatus_ = new char[4*maxSize_];
    if (nintS>0) {
      structuralStatus_[4*nintS-3]=0;
      structuralStatus_[4*nintS-2]=0;
      structuralStatus_[4*nintS-1]=0;
      CoinMemcpyN( sStat,((ns+3)/4), structuralStatus_);
    }
    artificialStatus_ = structuralStatus_+4*nintS;
    if (nintA > 0) {
      artificialStatus_[4*nintA-3]=0;
      artificialStatus_[4*nintA-2]=0;
      artificialStatus_[4*nintA-1]=0;
      CoinMemcpyN( aStat,((na+3)/4), artificialStatus_);
    }
  }
}
Example #6
0
//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpQuadraticObjective &
ClpQuadraticObjective::operator=(const ClpQuadraticObjective &rhs)
{
  if (this != &rhs) {
    fullMatrix_ = rhs.fullMatrix_;
    delete quadraticObjective_;
    quadraticObjective_ = NULL;
    delete[] objective_;
    delete[] gradient_;
    ClpObjective::operator=(rhs);
    numberColumns_ = rhs.numberColumns_;
    numberExtendedColumns_ = rhs.numberExtendedColumns_;
    if (rhs.objective_) {
      objective_ = new double[numberExtendedColumns_];
      CoinMemcpyN(rhs.objective_, numberExtendedColumns_, objective_);
    } else {
      objective_ = NULL;
    }
    if (rhs.gradient_) {
      gradient_ = new double[numberExtendedColumns_];
      CoinMemcpyN(rhs.gradient_, numberExtendedColumns_, gradient_);
    } else {
      gradient_ = NULL;
    }
    if (rhs.quadraticObjective_) {
      quadraticObjective_ = new CoinPackedMatrix(*rhs.quadraticObjective_);
    } else {
      quadraticObjective_ = NULL;
    }
  }
  return *this;
}
Example #7
0
/* Uses factorization to solve. */
void
ClpCholeskyUfl::solve (double * region)
{
     cholmod_dense *x, *b;
     b = cholmod_allocate_dense (numberRows_, 1, numberRows_, CHOLMOD_REAL, c_) ;
     CoinMemcpyN(region, numberRows_, (double *) b->x);
     x = cholmod_solve (CHOLMOD_A, L_, b, c_) ;
     CoinMemcpyN((double *) x->x, numberRows_, region);
     cholmod_free_dense (&x, c_) ;
     cholmod_free_dense (&b, c_) ;
}
/* Uses factorization to solve. */
void
ClpCholeskyWssmpKKT::solveKKT (double * region1, double * region2, const double * diagonal,
                               double diagonalScaleFactor)
{
    int numberRowsModel = model_->numberRows();
    int numberColumns = model_->numberColumns();
    int numberTotal = numberColumns + numberRowsModel;
    double * array = new double [numberRows_];
    CoinMemcpyN(region1, numberTotal, array);
    CoinMemcpyN(region2, numberRowsModel, array + numberTotal);
    int i1 = 1;
    int i0 = 0;
    integerParameters_[1] = 4;
    integerParameters_[2] = 4;
#if 0
    integerParameters_[5] = 3;
    doubleParameters_[5] = 1.0e-10;
    integerParameters_[6] = 6;
#endif
    F77_FUNC(wssmp,WSSMP)(&numberRows_, choleskyStart_, choleskyRow_, sparseFactor_,
                          NULL, permute_, permuteInverse_, array, &numberRows_, &i1,
                          NULL, &i0, NULL, integerParameters_, doubleParameters_);
#if 0
    int iRow;
    for (iRow = 0; iRow < numberTotal; iRow++) {
        if (rowsDropped_[iRow] && fabs(array[iRow]) > 1.0e-8) {
            printf("row region1 %d dropped %g\n", iRow, array[iRow]);
        }
    }
    for (; iRow < numberRows_; iRow++) {
        if (rowsDropped_[iRow] && fabs(array[iRow]) > 1.0e-8) {
            printf("row region2 %d dropped %g\n", iRow, array[iRow]);
        }
    }
#endif
    CoinMemcpyN(array + numberTotal, numberRowsModel, region2);
#if 1
    CoinMemcpyN(array, numberTotal, region1);
#else
    multiplyAdd(region2, numberRowsModel, -1.0, array + numberColumns, 0.0);
    CoinZeroN(array, numberColumns);
    model_->clpMatrix()->transposeTimes(1.0, region2, array);
    for (int iColumn = 0; iColumn < numberTotal; iColumn++)
        region1[iColumn] = diagonal[iColumn] * (array[iColumn] - region1[iColumn]);
#endif
    delete [] array;
#if 0
    if (integerParameters_[5]) {
        std::cout << integerParameters_[5] << " refinements ";
    }
    std::cout << doubleParameters_[6] << std::endl;
#endif
}
Example #9
0
CoinWarmStartBasis::CoinWarmStartBasis(const CoinWarmStartBasis& ws) :
  numStructural_(ws.numStructural_), numArtificial_(ws.numArtificial_),
  structuralStatus_(NULL), artificialStatus_(NULL) {
  // Round all so arrays multiple of 4
  int nintS = (numStructural_+15) >> 4;
  int nintA = (numArtificial_+15) >> 4;
  maxSize_ = nintS+nintA;
  if (maxSize_ > 0) {
    structuralStatus_ = new char[4*maxSize_];
    CoinMemcpyN( ws.structuralStatus_,	(4*nintS), structuralStatus_);
    artificialStatus_ = structuralStatus_+4*nintS;
    CoinMemcpyN( ws.artificialStatus_,	(4*nintA), artificialStatus_);
  }
}
Example #10
0
//-------------------------------------------------------------------
// Useful Constructor
//-------------------------------------------------------------------
ClpQuadraticObjective::ClpQuadraticObjective(const double *objective,
  int numberColumns,
  const CoinBigIndex *start,
  const int *column, const double *element,
  int numberExtendedColumns)
  : ClpObjective()
{
  type_ = 2;
  numberColumns_ = numberColumns;
  if (numberExtendedColumns >= 0)
    numberExtendedColumns_ = CoinMax(numberColumns_, numberExtendedColumns);
  else
    numberExtendedColumns_ = numberColumns_;
  if (objective) {
    objective_ = new double[numberExtendedColumns_];
    CoinMemcpyN(objective, numberColumns_, objective_);
    memset(objective_ + numberColumns_, 0, (numberExtendedColumns_ - numberColumns_) * sizeof(double));
  } else {
    objective_ = new double[numberExtendedColumns_];
    memset(objective_, 0, numberExtendedColumns_ * sizeof(double));
  }
  if (start)
    quadraticObjective_ = new CoinPackedMatrix(true, numberColumns, numberColumns,
      start[numberColumns], element, column, start, NULL);
  else
    quadraticObjective_ = NULL;
  gradient_ = NULL;
  activated_ = 1;
  fullMatrix_ = false;
}
Example #11
0
  virtual int read (void *buffer, int size) override
  {
    if (size <= 0)
      return 0;

    // return value
    int r = 0;

    // treat destination as char *
    char *dest = static_cast<char *>(buffer);

    // First consume data from buffer if available.
    if (dataStart_ < dataEnd_)
      {
	int amount = static_cast<int>(dataEnd_ - dataStart_);
	if (amount > size)
	  amount = size;

 CoinMemcpyN( dataStart_, amount, dest);

	dest += amount;
	size -= amount;

	dataStart_ += amount;

	r = amount;
      }

    // If we require more data, use readRaw.
    // We don't use the buffer here, as readRaw is ecpected to be efficient.
    if (size > 0)
      r += readRaw (dest, size);

    return r;
  }
Example #12
0
char* 
CoinMempool::alloc()
{
  lock_mutex();
  if (first_free_ == NULL) {
    unlock_mutex();
    char* block = allocate_new_block();
    lock_mutex();
#if (COIN_MEMPOOL_SAVE_BLOCKHEADS==1)
    // see if we can record another block head. If not, then resize
    // block_heads
    if (max_block_num_ == block_num_) {
      max_block_num_ = 2 * block_num_ + 10;
      char** old_block_heads = block_heads_;
      block_heads_ = (char**)malloc(max_block_num_ * sizeof(char*));
      CoinMemcpyN( old_block_heads,block_num_,block_heads_);
      free(old_block_heads);
    }
    // save the new block
    block_heads_[block_num_++] = block;
#endif
    // link in the new block
    *(char**)(block+((last_block_size_-1)*entry_size_)) = first_free_;
    first_free_ = block;
  }
  char* p = first_free_;
  first_free_ = *(char**)p;
  unlock_mutex();
  return p;
}
Example #13
0
// For debug check vector is clean i.e. elements match indices
void CoinIndexedVector::checkClean()
{
    int i;
    if (packedMode_) {
        for (i=0; i<nElements_; i++)
            assert(elements_[i]);
        for (; i<capacity_; i++)
            assert(!elements_[i]);
    } else {
        double * copy = new double[capacity_];
        CoinMemcpyN(elements_,capacity_,copy);
        for (i=0; i<nElements_; i++) {
            int indexValue = indices_[i];
            copy[indexValue]=0.0;
        }
        for (i=0; i<capacity_; i++)
            assert(!copy[i]);
        delete [] copy;
    }
#ifndef NDEBUG
    // check mark array zeroed
    char * mark = reinterpret_cast<char *> (indices_+capacity_);
    for (i=0; i<capacity_; i++) {
        assert(!mark[i]);
    }
#endif
}
Example #14
0
/* Subset constructor.  Duplicates are allowed
   and order is as given.
*/
ClpQuadraticObjective::ClpQuadraticObjective(const ClpQuadraticObjective &rhs,
  int numberColumns,
  const int *whichColumn)
  : ClpObjective(rhs)
{
  fullMatrix_ = rhs.fullMatrix_;
  objective_ = NULL;
  int extra = rhs.numberExtendedColumns_ - rhs.numberColumns_;
  numberColumns_ = 0;
  numberExtendedColumns_ = numberColumns + extra;
  if (numberColumns > 0) {
    // check valid lists
    int numberBad = 0;
    int i;
    for (i = 0; i < numberColumns; i++)
      if (whichColumn[i] < 0 || whichColumn[i] >= rhs.numberColumns_)
        numberBad++;
    if (numberBad)
      throw CoinError("bad column list", "subset constructor",
        "ClpQuadraticObjective");
    numberColumns_ = numberColumns;
    objective_ = new double[numberExtendedColumns_];
    for (i = 0; i < numberColumns_; i++)
      objective_[i] = rhs.objective_[whichColumn[i]];
    CoinMemcpyN(rhs.objective_ + rhs.numberColumns_, (numberExtendedColumns_ - numberColumns_),
      objective_ + numberColumns_);
    if (rhs.gradient_) {
      gradient_ = new double[numberExtendedColumns_];
      for (i = 0; i < numberColumns_; i++)
        gradient_[i] = rhs.gradient_[whichColumn[i]];
      CoinMemcpyN(rhs.gradient_ + rhs.numberColumns_, (numberExtendedColumns_ - numberColumns_),
        gradient_ + numberColumns_);
    } else {
      gradient_ = NULL;
    }
  } else {
    gradient_ = NULL;
    objective_ = NULL;
  }
  if (rhs.quadraticObjective_) {
    quadraticObjective_ = new CoinPackedMatrix(*rhs.quadraticObjective_,
      numberColumns, whichColumn,
      numberColumns, whichColumn);
  } else {
    quadraticObjective_ = NULL;
  }
}
Example #15
0
const CoinPresolveAction
  *drop_zero_coefficients_action::presolve (CoinPresolveMatrix *prob,
					    int *checkcols,
					    int ncheckcols,
					    const CoinPresolveAction *next)
{
  double *colels	= prob->colels_;
  int *hrow		= prob->hrow_;
  CoinBigIndex *mcstrt		= prob->mcstrt_;
  int *hincol		= prob->hincol_;
  presolvehlink *clink	= prob->clink_ ;
  presolvehlink *rlink	= prob->rlink_ ;
 
  //  int i;
  int nzeros;
  if (ncheckcols==prob->ncols_) {
    // can do faster
    nzeros = count_col_zeros2(ncheckcols,checkcols,
                               mcstrt,colels,/*hrow,*/hincol);
  } else {
    nzeros = count_col_zeros(ncheckcols,checkcols,
                               mcstrt,colels,/*hrow,*/hincol);
  }
  if (nzeros == 0) {
    return (next);
  } else {
    dropped_zero * zeros = new dropped_zero[nzeros];

    nzeros=drop_col_zeros((ncheckcols==prob->ncols_) ? nzeros : ncheckcols,
			  checkcols,
			  mcstrt,colels,hrow,hincol,clink,
			  zeros);
    double *rowels	= prob->rowels_;
    int *hcol		= prob->hcol_;
    CoinBigIndex *mrstrt		= prob->mrstrt_;
    int *hinrow		= prob->hinrow_;
    //    int nrows		= prob->nrows_;

#   if PRESOLVE_SUMMARY
    printf("NZEROS:  %d\n", nzeros);
#   endif

    // make the row rep consistent
    drop_row_zeros(nzeros,zeros,mrstrt,rowels,hcol,hinrow,rlink) ;

    dropped_zero *zeros1 = new dropped_zero[nzeros];
    CoinMemcpyN(zeros, nzeros, zeros1);

    delete [] zeros;
    return (new drop_zero_coefficients_action(nzeros, zeros1, next));
  }
}
Example #16
0
// Resize objective
void ClpQuadraticObjective::resize(int newNumberColumns)
{
  if (numberColumns_ != newNumberColumns) {
    int newExtended = newNumberColumns + (numberExtendedColumns_ - numberColumns_);
    int i;
    double *newArray = new double[newExtended];
    if (objective_)
      CoinMemcpyN(objective_, CoinMin(newExtended, numberExtendedColumns_), newArray);
    delete[] objective_;
    objective_ = newArray;
    for (i = numberColumns_; i < newNumberColumns; i++)
      objective_[i] = 0.0;
    if (gradient_) {
      newArray = new double[newExtended];
      if (gradient_)
        CoinMemcpyN(gradient_, CoinMin(newExtended, numberExtendedColumns_), newArray);
      delete[] gradient_;
      gradient_ = newArray;
      for (i = numberColumns_; i < newNumberColumns; i++)
        gradient_[i] = 0.0;
    }
    if (quadraticObjective_) {
      if (newNumberColumns < numberColumns_) {
        int *which = new int[numberColumns_ - newNumberColumns];
        int i;
        for (i = newNumberColumns; i < numberColumns_; i++)
          which[i - newNumberColumns] = i;
        quadraticObjective_->deleteRows(numberColumns_ - newNumberColumns, which);
        quadraticObjective_->deleteCols(numberColumns_ - newNumberColumns, which);
        delete[] which;
      } else {
        quadraticObjective_->setDimensions(newNumberColumns, newNumberColumns);
      }
    }
    numberColumns_ = newNumberColumns;
    numberExtendedColumns_ = newExtended;
  }
}
Example #17
0
CoinWarmStartBasis&
CoinWarmStartBasis::operator=(const CoinWarmStartBasis& rhs)
{
  if (this != &rhs) {
    numStructural_=rhs.numStructural_;
    numArtificial_=rhs.numArtificial_;
    // Round all so arrays multiple of 4
    int nintS = (numStructural_+15) >> 4;
    int nintA = (numArtificial_+15) >> 4;
    int size = nintS+nintA;
    if (size>maxSize_) {
      delete[] structuralStatus_;
      maxSize_ = size+10;
      structuralStatus_ = new char[4*maxSize_];
    }
    if (size > 0) {
      CoinMemcpyN( rhs.structuralStatus_,	(4*nintS), structuralStatus_);
      artificialStatus_ = structuralStatus_+4*nintS;
      CoinMemcpyN( rhs.artificialStatus_,	(4*nintA), artificialStatus_);
    } else {
      artificialStatus_ = NULL;
    }
  }
Example #18
0
template <typename T> void
CoinDenseVector<T>::resize(int newsize, T value)
{
  if (newsize != nElements_){
    assert(newsize > 0);
    T *newarray = new T[newsize];
    int cpysize = CoinMin(newsize, nElements_);
    CoinMemcpyN( elements_,cpysize,newarray);
    delete[] elements_;
    elements_ = newarray;
    nElements_ = newsize;
    for(int i=cpysize; i<newsize; i++)
      elements_[i] = value;
  }
}
Example #19
0
// Resize objective
void
ClpLinearObjective::resize(int newNumberColumns)
{
     if (numberColumns_ != newNumberColumns) {
          int i;
          double * newArray = new double[newNumberColumns];
          if (objective_)
               CoinMemcpyN(objective_, CoinMin(newNumberColumns, numberColumns_), newArray);
          delete [] objective_;
          objective_ = newArray;
          for (i = numberColumns_; i < newNumberColumns; i++)
               objective_[i] = 0.0;
          numberColumns_ = newNumberColumns;
     }

}
Example #20
0
// Returns gradient
int
ClpConstraintLinear::gradient(const ClpSimplex * model,
                              const double * solution,
                              double * gradient,
                              double & functionValue,
                              double & offset,
                              bool useScaling,
                              bool refresh) const
{
     if (refresh || !lastGradient_) {
          functionValue_ = 0.0;
          if (!lastGradient_)
               lastGradient_ = new double[numberColumns_];
          CoinZeroN(lastGradient_, numberColumns_);
          bool scaling = (model && model->rowScale() && useScaling);
          if (!scaling) {
               for (int i = 0; i < numberCoefficients_; i++) {
                    int iColumn = column_[i];
                    double value = solution[iColumn];
                    double coefficient = coefficient_[i];
                    functionValue_ += value * coefficient;
                    lastGradient_[iColumn] = coefficient;
               }
          } else {
               // do scaling
               const double * columnScale = model->columnScale();
               for (int i = 0; i < numberCoefficients_; i++) {
                    int iColumn = column_[i];
                    double value = solution[iColumn]; // already scaled
                    double coefficient = coefficient_[i] * columnScale[iColumn];
                    functionValue_ += value * coefficient;
                    lastGradient_[iColumn] = coefficient;
               }
          }
     }
     functionValue = functionValue_;
     offset = 0.0;
     CoinMemcpyN(lastGradient_, numberColumns_, gradient);
     return 0;
}
Example #21
0
void CoinPresolveMatrix::setMatrix (const CoinPackedMatrix *mtx)

{
/*
  Check to make sure the matrix will fit and is column ordered.
*/
  if (mtx->isColOrdered() == false)
  { throw CoinError("source matrix must be column ordered",
		    "setMatrix","CoinPrePostsolveMatrix") ; }

  int numCols = mtx->getNumCols() ;
  if (numCols > ncols0_)
  { throw CoinError("source matrix exceeds allocated capacity",
		    "setMatrix","CoinPrePostsolveMatrix") ; }
/*
  Acquire the actual size, but allocate the matrix storage to the
  requested capacity. The column-major rep is part of the PrePostsolve
  object, the row-major rep belongs to the Presolve object.
*/
  ncols_ = numCols ;
  nrows_ = mtx->getNumRows() ;
  nelems_ = mtx->getNumElements() ;
  bulk0_ = static_cast<CoinBigIndex> (bulkRatio_*nelems0_) ;

  if (mcstrt_ == 0) mcstrt_ = new CoinBigIndex [ncols0_+1] ;
  if (hincol_ == 0) hincol_ = new int [ncols0_+1] ;
  if (hrow_ == 0) hrow_ = new int [bulk0_] ;
  if (colels_ == 0) colels_ = new double [bulk0_] ;

  if (mrstrt_ == 0) mrstrt_ = new CoinBigIndex [nrows0_+1] ;
  if (hinrow_ == 0) hinrow_ = new int [nrows0_+1] ;
  if (hcol_ == 0) hcol_ = new int [bulk0_] ;
  if (rowels_ == 0) rowels_ = new double [bulk0_] ;
/*
  Grab the corresponding vectors from the source matrix.
*/
  const CoinBigIndex *src_mcstrt = mtx->getVectorStarts() ;
  const int *src_hincol = mtx->getVectorLengths() ;
  const double *src_colels = mtx->getElements() ;
  const int *src_hrow = mtx->getIndices() ;
/*
  Bulk copy the column starts and lengths.
*/
  CoinMemcpyN(src_mcstrt,mtx->getSizeVectorStarts(),mcstrt_) ;
  CoinMemcpyN(src_hincol,mtx->getSizeVectorLengths(),hincol_) ;
/*
  Copy the coefficients column by column in case there are gaps between
  the columns in the bulk storage area. The assert is just in case the
  gaps are *really* big.
*/
  assert(src_mcstrt[ncols_] <= bulk0_) ;
  int j;
  for ( j = 0 ; j < numCols ; j++)
  { int lenj = src_hincol[j] ;
    CoinBigIndex offset = mcstrt_[j] ;
    CoinMemcpyN(src_colels+offset,lenj,colels_+offset) ;
    CoinMemcpyN(src_hrow+offset,lenj,hrow_+offset) ; }
/*
  Now make a row-major copy. Start by counting the number of coefficients in
  each row; we can do this directly in hinrow. Given the number of
  coefficients in a row, we know how to lay out the bulk storage area.
*/
  CoinZeroN(hinrow_,nrows0_+1) ;
  for ( j = 0 ; j < ncols_ ; j++)
  { int *rowIndices = hrow_+mcstrt_[j] ;
    int lenj = hincol_[j] ;
    for (int k = 0 ; k < lenj ; k++)
    { int i = rowIndices[k] ;
      hinrow_[i]++ ; } }
/*
  Initialize mrstrt[i] to the start of row i+1. As we drop each coefficient
  and column index into the bulk storage arrays, we'll decrement and store.
  When we're done, mrstrt[i] will point to the start of row i, as it should.
*/
  int totalCoeffs = 0 ;
  int i;
  for ( i = 0 ; i < nrows_ ; i++)
  { totalCoeffs += hinrow_[i] ;
    mrstrt_[i] = totalCoeffs ; }
  mrstrt_[nrows_] = totalCoeffs ;
  for ( j = ncols_-1 ; j >= 0 ; j--)
  { int lenj = hincol_[j] ;
    double *colCoeffs = colels_+mcstrt_[j] ;
    int *rowIndices = hrow_+mcstrt_[j] ;
    for (int k = 0 ; k < lenj ; k++)
    { int ri;
      ri = rowIndices[k] ;
      double aij = colCoeffs[k] ;
      CoinBigIndex l = --mrstrt_[ri] ;
      rowels_[l] = aij ;
      hcol_[l] = j ; } }
/*
  Now the support structures. The entry for original column j should start
  out as j; similarly for row i. originalColumn_ and originalRow_ belong to
  the PrePostsolve object.
*/
  if (originalColumn_ == 0) originalColumn_ = new int [ncols0_] ;
  if (originalRow_ == 0) originalRow_ = new int [nrows0_] ;

  for ( j = 0 ; j < ncols0_ ; j++) 
    originalColumn_[j] = j ;
  for ( i = 0 ; i < nrows0_ ; i++) 
    originalRow_[i] = i ;
/*
  We have help to set up the clink_ and rlink_ vectors (aids for matrix bulk
  storage management). clink_ and rlink_ belong to the Presolve object.  Once
  this is done, it's safe to set mrstrt_[nrows_] and mcstrt_[ncols_] to the
  full size of the bulk storage area.
*/
  if (clink_ == 0) clink_ = new presolvehlink [ncols0_+1] ;
  if (rlink_ == 0) rlink_ = new presolvehlink [nrows0_+1] ;
  presolve_make_memlists(/*mcstrt_,*/hincol_,clink_,ncols_) ;
  presolve_make_memlists(/*mrstrt_,*/hinrow_,rlink_,nrows_) ;
  mcstrt_[ncols_] = bulk0_ ;
  mrstrt_[nrows_] = bulk0_ ;
/*
  No rows or columns have been changed just yet. colChanged_ and rowChanged_
  belong to the Presolve object.
*/
  if (colChanged_ == 0) colChanged_ = new unsigned char [ncols0_] ;
  CoinZeroN(colChanged_,ncols0_) ;
  if (rowChanged_ == 0) rowChanged_ = new unsigned char [nrows0_] ;
  CoinZeroN(rowChanged_,nrows0_) ;
/*
  Finally, allocate the various *ToDo arrays. These are used to track the rows
  and columns which should be processed in a given round of presolve
  transforms. These belong to the Presolve object. Setting number*ToDo to 0
  is all the initialization that's required here.
*/
  rowsToDo_ = new int [nrows0_] ;
  numberRowsToDo_ = 0 ;
  nextRowsToDo_ = new int [nrows0_] ;
  numberNextRowsToDo_ = 0 ;
  colsToDo_ = new int [ncols0_] ;
  numberColsToDo_ = 0 ;
  nextColsToDo_ = new int [ncols0_] ;
  numberNextColsToDo_ = 0 ;
  initializeStuff();
  return ; }
Example #22
0
template <typename T> void
CoinDenseVector<T>::setVector(int size, const T * elems)
{
   resize(size);
   CoinMemcpyN( elems,size,elements_);
}
Example #23
0
/* Returns effective RHS if it is being used.  This is used for long problems
   or big gub or anywhere where going through full columns is
   expensive.  This may re-compute */
double *
ClpMatrixBase::rhsOffset(ClpSimplex * model, bool forceRefresh, bool
#ifdef CLP_DEBUG
                         check
#endif
                        )
{
     if (rhsOffset_) {
#ifdef CLP_DEBUG
          if (check) {
               // no need - but check anyway
               // zero out basic
               int numberRows = model->numberRows();
               int numberColumns = model->numberColumns();
               double * solution = new double [numberColumns];
               double * rhs = new double[numberRows];
               const double * solutionSlack = model->solutionRegion(0);
               CoinMemcpyN(model->solutionRegion(), numberColumns, solution);
               int iRow;
               for (iRow = 0; iRow < numberRows; iRow++) {
                    if (model->getRowStatus(iRow) != ClpSimplex::basic)
                         rhs[iRow] = solutionSlack[iRow];
                    else
                         rhs[iRow] = 0.0;
               }
               for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
                    if (model->getColumnStatus(iColumn) == ClpSimplex::basic)
                         solution[iColumn] = 0.0;
               }
               times(-1.0, solution, rhs);
               delete [] solution;
               for (iRow = 0; iRow < numberRows; iRow++) {
                    if (fabs(rhs[iRow] - rhsOffset_[iRow]) > 1.0e-3)
                         printf("** bad effective %d - true %g old %g\n", iRow, rhs[iRow], rhsOffset_[iRow]);
               }
          }
#endif
          if (forceRefresh || (refreshFrequency_ && model->numberIterations() >=
                               lastRefresh_ + refreshFrequency_)) {
               // zero out basic
               int numberRows = model->numberRows();
               int numberColumns = model->numberColumns();
               double * solution = new double [numberColumns];
               const double * solutionSlack = model->solutionRegion(0);
               CoinMemcpyN(model->solutionRegion(), numberColumns, solution);
               for (int iRow = 0; iRow < numberRows; iRow++) {
                    if (model->getRowStatus(iRow) != ClpSimplex::basic)
                         rhsOffset_[iRow] = solutionSlack[iRow];
                    else
                         rhsOffset_[iRow] = 0.0;
               }
               for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
                    if (model->getColumnStatus(iColumn) == ClpSimplex::basic)
                         solution[iColumn] = 0.0;
               }
               times(-1.0, solution, rhsOffset_);
               delete [] solution;
               lastRefresh_ = model->numberIterations();
          }
     }
     return rhsOffset_;
}
/* This is the real constructor*/
ClpDynamicExampleMatrix::ClpDynamicExampleMatrix(ClpSimplex * model, int numberSets,
          int numberGubColumns, const int * starts,
          const double * lower, const double * upper,
          const CoinBigIndex * startColumn, const int * row,
          const double * element, const double * cost,
          const double * columnLower, const double * columnUpper,
          const unsigned char * status,
          const unsigned char * dynamicStatus,
          int numberIds, const int *ids)
     : ClpDynamicMatrix(model, numberSets, 0, NULL, lower, upper, NULL, NULL, NULL, NULL, NULL, NULL,
                        NULL, NULL)
{
     setType(25);
     numberColumns_ = numberGubColumns;
     // start with safe values - then experiment
     maximumGubColumns_ = numberColumns_;
     maximumElements_ = startColumn[numberColumns_];
     // delete odd stuff created by ClpDynamicMatrix constructor
     delete [] startSet_;
     startSet_ = new int [numberSets_];
     delete [] next_;
     next_ = new int [maximumGubColumns_];
     delete [] row_;
     delete [] element_;
     delete [] startColumn_;
     delete [] cost_;
     delete [] columnLower_;
     delete [] columnUpper_;
     delete [] dynamicStatus_;
     delete [] status_;
     delete [] id_;
     // and size correctly
     row_ = new int [maximumElements_];
     element_ = new double [maximumElements_];
     startColumn_ = new CoinBigIndex [maximumGubColumns_+1];
     // say no columns yet
     numberGubColumns_ = 0;
     startColumn_[0] = 0;
     cost_ = new double[maximumGubColumns_];
     dynamicStatus_ = new unsigned char [2*maximumGubColumns_];
     memset(dynamicStatus_, 0, maximumGubColumns_);
     id_ = new int[maximumGubColumns_];
     if (columnLower)
          columnLower_ = new double[maximumGubColumns_];
     else
          columnLower_ = NULL;
     if (columnUpper)
          columnUpper_ = new double[maximumGubColumns_];
     else
          columnUpper_ = NULL;
     // space for ids
     idGen_ = new int [maximumGubColumns_];
     int iSet;
     for (iSet = 0; iSet < numberSets_; iSet++)
          startSet_[iSet] = -1;
     // This starts code specific to this storage method
     CoinBigIndex i;
     fullStartGen_ = ClpCopyOfArray(starts, numberSets_ + 1);
     startColumnGen_ = ClpCopyOfArray(startColumn, numberColumns_ + 1);
     CoinBigIndex numberElements = startColumnGen_[numberColumns_];
     rowGen_ = ClpCopyOfArray(row, numberElements);
     elementGen_ = new double[numberElements];
     for (i = 0; i < numberElements; i++)
          elementGen_[i] = element[i];
     costGen_ = new double[numberColumns_];
     for (i = 0; i < numberColumns_; i++) {
          costGen_[i] = cost[i];
          // I don't think I need sorted but ...
          CoinSort_2(rowGen_ + startColumnGen_[i], rowGen_ + startColumnGen_[i+1], elementGen_ + startColumnGen_[i]);
     }
     if (columnLower) {
          columnLowerGen_ = new double[numberColumns_];
          for (i = 0; i < numberColumns_; i++) {
               columnLowerGen_[i] = columnLower[i];
               if (columnLowerGen_[i]) {
                    printf("Non-zero lower bounds not allowed - subtract from model\n");
                    abort();
               }
          }
     } else {
          columnLowerGen_ = NULL;
     }
     if (columnUpper) {
          columnUpperGen_ = new double[numberColumns_];
          for (i = 0; i < numberColumns_; i++)
               columnUpperGen_[i] = columnUpper[i];
     } else {
          columnUpperGen_ = NULL;
     }
     // end specific coding
     if (columnUpper_) {
          // set all upper bounds so we have enough space
          double * columnUpper = model->columnUpper();
          for(i = firstDynamic_; i < lastDynamic_; i++)
               columnUpper[i] = 1.0e10;
     }
     status_ = new unsigned char [2*numberSets_+4];
     if (status) {
          memcpy(status_,status, numberSets_ * sizeof(char));
          assert (dynamicStatus);
          CoinMemcpyN(dynamicStatus, numberIds, dynamicStatus_);
          assert (numberIds);
     } else {
          assert (!numberIds);
          memset(status_, 0, numberSets_);
          for (i = 0; i < numberSets_; i++) {
               // make slack key
               setStatus(i, ClpSimplex::basic);
          }
     }
     dynamicStatusGen_ = new unsigned char [numberColumns_];
     memset(dynamicStatusGen_, 0, numberColumns_); // for clarity
     for (i = 0; i < numberColumns_; i++)
          setDynamicStatusGen(i, atLowerBound);
     // Populate with enough columns
     if (!numberIds) {
          // This could be made more sophisticated
          for (iSet = 0; iSet < numberSets_; iSet++) {
               int sequence = fullStartGen_[iSet];
               CoinBigIndex start = startColumnGen_[sequence];
               addColumn(startColumnGen_[sequence+1] - start,
                         rowGen_ + start,
                         elementGen_ + start,
                         costGen_[sequence],
                         columnLowerGen_ ? columnLowerGen_[sequence] : 0,
                         columnUpperGen_ ? columnUpperGen_[sequence] : 1.0e30,
                         iSet, getDynamicStatusGen(sequence));
               idGen_[iSet] = sequence; // say which one in
               setDynamicStatusGen(sequence, inSmall);
          }
     } else {
          // put back old ones
          int * set = new int[numberColumns_];
          for (iSet = 0; iSet < numberSets_; iSet++) {
               for (CoinBigIndex j = fullStartGen_[iSet]; j < fullStartGen_[iSet+1]; j++)
                    set[j] = iSet;
          }
          for (int i = 0; i < numberIds; i++) {
               int sequence = ids[i];
               CoinBigIndex start = startColumnGen_[sequence];
               addColumn(startColumnGen_[sequence+1] - start,
                         rowGen_ + start,
                         elementGen_ + start,
                         costGen_[sequence],
                         columnLowerGen_ ? columnLowerGen_[sequence] : 0,
                         columnUpperGen_ ? columnUpperGen_[sequence] : 1.0e30,
                         set[sequence], getDynamicStatus(i));
               idGen_[iSet] = sequence; // say which one in
               setDynamicStatusGen(sequence, inSmall);
          }
          delete [] set;
     }
     if (!status) {
          gubCrash();
     } else {
          initialProblem();
     }
}
const CoinPresolveAction *implied_free_action::presolve (
    CoinPresolveMatrix *prob, const CoinPresolveAction *next, int &fill_level)
{
# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
# if PRESOLVE_DEBUG > 0
  std::cout
    << "Entering implied_free_action::presolve, fill level " << fill_level
    << "." << std::endl ;
# endif
  presolve_consistent(prob) ;
  presolve_links_ok(prob) ;
  presolve_check_sol(prob) ;
  presolve_check_nbasic(prob) ;
# endif

# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
  const int startEmptyRows = prob->countEmptyRows() ;
  const int startEmptyColumns = prob->countEmptyCols() ;
# if COIN_PRESOLVE_TUNING > 0
  double startTime = 0.0 ;
  if (prob->tuning_) startTime = CoinCpuTime() ;
# endif
# endif

/*
  Unpack the row- and column-major representations.
*/
  const int m = prob->nrows_ ;
  const int n = prob->ncols_ ;

  const CoinBigIndex *rowStarts = prob->mrstrt_ ;
  int *rowLengths = prob->hinrow_ ;
  const int *colIndices = prob->hcol_ ;
  const double *rowCoeffs = prob->rowels_ ;
  presolvehlink *rlink = prob->rlink_ ;

  CoinBigIndex *colStarts = prob->mcstrt_ ;
  int *colLengths = prob->hincol_ ;
  int *rowIndices = prob->hrow_ ;
  double *colCoeffs = prob->colels_ ;
  presolvehlink *clink = prob->clink_ ;

/*
  Column bounds, row bounds, cost, integrality.
*/
  double *clo = prob->clo_ ;
  double *cup = prob->cup_ ;
  double *rlo = prob->rlo_ ;
  double *rup = prob->rup_ ;
  double *cost = prob->cost_ ;
  const unsigned char *integerType = prob->integerType_ ;

/*
  Documented as `inhibit x+y+z = 1 mods'.  From the code below, it's clear
  that this is intended to avoid removing SOS equalities with length >= 5
  (hardcoded). 
*/
  const bool stopSomeStuff = ((prob->presolveOptions()&0x04) != 0) ;
/*
  Ignore infeasibility. `Fix' is overly optimistic.
*/
  const bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
/*
  Defaults to 0.0.
*/
  const double feasTol = prob->feasibilityTolerance_ ;

# if 0  
/*
  Tentatively moved to be a front-end function for useless_constraint_action,
  much as make_fixed is a front-end for make_fixed_action. This bit of code
  left for possible tuning.
  -- lh, 121127 --

  Original comment: This needs to be made faster.
*/
# ifdef COIN_LIGHTWEIGHT_PRESOLVE
  if (prob->pass_ == 1) {
#else
    if (prob->presolveOptions_&0x10) {
# endif
    next = testRedundant(prob,next) ;
    if (prob->status_&0x01 != 0) {
      if ((prob->presolveOptions_&0x4000) != 0)
        prob->status_ &= !0x01 ;
      else
	return (next) ;
    }
# if 1 //def COIN_LIGHTWEIGHT_PRESOLVE
  }
# endif
# endif

/*
  implied_free and subst take a fair bit of effort to scan for candidates.
  This is a hook to allow a presolve driver to avoid that work.
*/
  if (prob->pass_ > 15 && (prob->presolveOptions_&0x10000) != 0) { 
    fill_level = 2 ;
    return (next) ;
  }

/*
  Set up to collect implied_free actions.
*/
  action *actions = new action [n] ;
# ifdef ZEROFAULT
  CoinZeroN(reinterpret_cast<char *>(actions),n*sizeof(action)) ;
# endif
  int nactions = 0 ;

  int *implied_free = prob->usefulColumnInt_ ;
  int *whichFree = implied_free+n ;
  int numberFree = 0 ;
/*
  Arrays to hold row activity (row lhs) min and max values. Each row lhs bound
  is held as two components: a sum of finite column bounds and a count of
  infinite column bounds.
*/
  int *infiniteDown = new int[m] ;
  int *infiniteUp = new int[m] ;
  double *maxDown = new double[m] ;
  double *maxUp = new double[m] ;
/*
  Overload infiniteUp with row status codes:
  -1: L(i)/U(i) not yet computed,
  -2: do not use (empty or useless row),
  -3: give up (infeasible)
  -4: chosen as implied free row
*/
  for (int i = 0 ; i < m ; i++) {
    if (rowLengths[i] > 1)
      infiniteUp[i] = -1 ;
    else
      infiniteUp[i] = -2 ;
  }
  // Get rid of rows with prohibited columns
  if (prob->anyProhibited_) {
    for (int i = 0 ; i < m ; i++) {
      CoinBigIndex rStart = rowStarts[i];
      CoinBigIndex rEnd = rStart+rowLengths[i];
      bool badRow=false;
      for (CoinBigIndex j = rStart; j < rEnd; ++j) {
	if (prob->colProhibited(colIndices[j])) {
	  badRow=true;
	  break;
	}
      }
      if (badRow)
	infiniteUp[i] = -2 ;
    }
  }

// Can't go on without a suitable finite infinity, can we?
#ifdef USE_SMALL_LARGE
  const double large = 1.0e10 ;
#else
  const double large = 1.0e20 ;
#endif

/*
  Decide which columns we're going to look at. There are columns already queued
  in colsToDo_, but sometimes we want to look at all of them. Don't suck in
  prohibited columns. See comments at the head of the routine for fill_level.

  NOTE the overload on usefulColumnInt_. It was assigned above to whichFree
       (indices of interesting columns). We'll be ok because columns are
       consumed out of look at one per main loop iteration, but not all
       columns are interesting.

  Original comment: if gone from 2 to 3 look at all
*/
  int numberLook = prob->numberColsToDo_ ;
  int iLook ;
  int *look = prob->colsToDo_ ;
  if (fill_level < 0) {
    look = prob->usefulColumnInt_+n ;
    if (!prob->anyProhibited()) {
      CoinIotaN(look,n,0) ;
      numberLook = n ;
    } else {
      numberLook = 0 ;
      for (iLook = 0 ; iLook < n ; iLook++) 
	if (!prob->colProhibited(iLook))
	  look[numberLook++] = iLook ;
    }
  }
/*
  Step through the columns of interest looking for suitable x(tgt).

  Interesting columns are limited by number of nonzeros to minimise fill-in
  during substitution.
*/
  bool infeas = false ;
  const int maxLook = abs(fill_level) ;
  for (iLook = 0 ; iLook < numberLook ; iLook++) {
    const int tgtcol = look[iLook] ;
    const int tgtcol_len = colLengths[tgtcol] ;

    if (tgtcol_len <= 0 || tgtcol_len > maxLook) continue ;
/*
  Set up to reconnoiter the column.

  The initial value for ait_max is chosen to make sure that anything that
  satisfies the stability check is big enough to use (though we'd clearly like
  something better).
*/
    const CoinBigIndex kcs = colStarts[tgtcol] ;
    const CoinBigIndex kce = kcs+tgtcol_len ;
    const bool singletonCol = (tgtcol_len == 1) ;
    bool possibleRow = false ;
    bool singletonRow = false ;
    double ait_max = 20*ZTOLDP2 ;
/*
  If this is a singleton column, the only concern is that the row is not a
  singleton row (that has its own, simpler, transform: slack_doubleton). But
  make sure we're not dealing with some tiny a(it).

  Note that there's no point in marking a singleton row. By definition, we
  won't encounter it again.
*/
    if (singletonCol) {
      const int i = rowIndices[kcs] ;
      singletonRow = (rowLengths[i] == 1) ;
      possibleRow = (fabs(colCoeffs[kcs]) > ZTOLDP2) ;
    } else {
      
/*
  If the column is not a singleton, we'll need a numerically stable
  substitution formula. Check that this is possible.  One of the entangled
  rows must be an equality with a numerically stable coefficient, at least
  .1*MAX{i}a(it).
*/
      for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
	const int i = rowIndices[kcol] ;
	if (rowLengths[i] == 1) {
	  singletonRow = true ;
	  break ;
	}
	const double abs_ait = fabs(colCoeffs[kcol]) ;
	ait_max = CoinMax(ait_max,abs_ait) ;
	if (fabs(rlo[i]-rup[i]) < feasTol && abs_ait > .1*ait_max) {
	  possibleRow = true ;
	}
      }
    }
    if (singletonRow || !possibleRow) continue ;
/*
  The column has possibilities. Walk the column, calculate row activity
  bounds L(i) and U(i) for suitable entangled rows, then calculate the
  improvement (if any) on the column bounds for l(j) and u(j). The goal is to
  satisfy the implied free condition over all entangled rows and find at least
  one row suitable for a substitution formula (if the column is not a natural
  singleton).

  Suitable: If this is a natural singleton, we need to look at the single
  entangled constraint.  If we're attempting to create a singleton by
  substitution, only look at equalities with stable coefficients. If x(t) is
  integral, make sure the scaled rhs will be integral.
*/
#   if PRESOLVE_DEBUG > 2
    std::cout
      << "  Checking x(" << tgtcol << "), " << tgtcol_len << " nonzeros"
      << ", l(" << tgtcol << ") " << clo[tgtcol] << ", u(" << tgtcol
      << ") " << cup[tgtcol] << ", c(" << tgtcol << ") " << cost[tgtcol]
      << "." << std::endl ;
#   endif
    const double lt = clo[tgtcol] ;
    const double ut = cup[tgtcol] ;
    double impliedLow = -COIN_DBL_MAX ;
    double impliedHigh = COIN_DBL_MAX ;
    int subst_ndx = -1 ;
    int subst_len = n ;
    for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
      const int i = rowIndices[kcol] ;

      assert(infiniteUp[i] != -3) ;
      if (infiniteUp[i] <= -2) continue ;

      const double ait = colCoeffs[kcol] ;
      const int leni = rowLengths[i] ;
      const double rloi = rlo[i] ;
      const double rupi = rup[i] ;
/*
  A suitable row for substitution must
    * be an equality;
    * the entangled coefficient must be large enough to be numerically stable;
    * if x(t) is integer, the constant term in the substitution formula must be
      integer.
*/
      bool rowiOK = (fabs(rloi-rupi) < feasTol) && (fabs(ait) > .1*ait_max) ;
      rowiOK = rowiOK && ((integerType[tgtcol] == 0) ||
                          (fabs((rloi/ait)-floor((rloi/ait)+0.5)) < feasTol)) ;
/*
  If we don't already have L(i) and U(i), calculate now. Check for useless and
  infeasible constraints when that's done.
*/
      int infUi = 0 ;
      int infLi = 0 ;
      double maxUi = 0.0 ;
      double maxLi = 0.0 ;
      const CoinBigIndex krs = rowStarts[i] ;
      const CoinBigIndex kre = krs+leni ;

      if (infiniteUp[i] == -1) {
	for (CoinBigIndex krow = krs ; krow < kre ; ++krow) {
	  const double aik = rowCoeffs[krow] ;
	  const int k = colIndices[krow] ;
	  const double lk = clo[k] ;
	  const double uk = cup[k] ;
	  if (aik > 0.0) {
	    if (uk < large) 
	      maxUi += uk*aik ;
	    else
	      ++infUi ;
	    if (lk > -large) 
	      maxLi += lk*aik ;
	    else
	      ++infLi ;
	  } else if (aik < 0.0) {
	    if (uk < large) 
	      maxLi += uk*aik ;
	    else
	      ++infLi ;
	    if (lk > -large) 
	      maxUi += lk*aik ;
	    else
	      ++infUi ;
	  }
	}
	const double maxUinf = maxUi+infUi*1.0e31 ;
	const double maxLinf = maxLi-infLi*1.0e31 ;
	if (maxUinf <= rupi+feasTol && maxLinf >= rloi-feasTol) {
	  infiniteUp[i] = -2 ;
	} else if (maxUinf < rloi-feasTol && !fixInfeasibility) {
	  prob->status_|= 1 ;
	  infeas = true ;
	  prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS,
					  prob->messages())
	    << i << rloi << rupi << CoinMessageEol ;
	  infiniteUp[i] = -3 ;
	} else if (maxLinf > rupi+feasTol && !fixInfeasibility) {
	  prob->status_|= 1 ;
	  infeas = true ;
	  prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS,
					  prob->messages())
	    << i << rloi << rupi << CoinMessageEol ;
	  infiniteUp[i] = -3 ;
	} else {
	  infiniteUp[i] = infUi ;
	  infiniteDown[i] = infLi ;
	  maxUp[i] = maxUi ;
	  maxDown[i] = maxLi ;
	}
      } else {
        infUi = infiniteUp[i] ;
	infLi = infiniteDown[i] ;
	maxUi = maxUp[i] ;
	maxLi = maxDown[i] ;
      }
#     if PRESOLVE_DEBUG > 2
      std::cout
        << "    row(" << i << ") " << leni << " nonzeros, blow " << rloi
	<< ", L (" << infLi << "," << maxLi
	<< "), U (" << infUi << "," << maxUi
	<< "), b " << rupi ;
      if (infeas) std::cout << " infeas" ;
      if (infiniteUp[i] == -2) std::cout << " useless" ;
      std::cout << "." << std::endl ;
#     endif
/*
  If we're infeasible, no sense checking further; escape the implied bound
  loop. The other possibility is that we've just discovered the constraint
  is useless, in which case we just move on to the next one in the column.
*/
      if (infeas) break ;
      if (infiniteUp[i] == -2) continue ;
      assert(infiniteUp[i] >= 0 && infiniteUp[i] <= leni) ;
/*
  At this point we have L(i) and U(i), expressed as finite and infinite
  components, and constraint i is neither useless or infeasible. Calculate
  the implied bounds l'(t) and u'(t) on x(t). The calculation (for a(it) > 0)
  is
    u'(t) <= (b(i) - (L(i)-a(it)l(t)))/a(it) = l(t)+(b(i)-L(i))/a(it)
    l'(t) >= (blow(i) - (U(i)-a(it)u(t)))/a(it) = u(t)+(blow(i)-U(i))/a(it)
  Insert the appropriate flips for a(it) < 0. Notice that if there's exactly
  one infinite contribution to L(i) or U(i) and x(t) is responsible, then the
  finite portion of L(i) or U(i) is already correct.

  Cut some slack for possible numerical inaccuracy if the finite portion of
  L(i) or U(i) is very large. If the new bound is very large, force it to
  infinity.
*/
      double ltprime = -COIN_DBL_MAX ;
      double utprime = COIN_DBL_MAX ;
      if (ait > 0.0) {
	if (rloi > -large) {
	  if (!infUi) {
	    assert(ut < large) ;
	    ltprime = ut+(rloi-maxUi)/ait ;
	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
	      ltprime -= 1.0e-12*fabs(maxUi) ;
	  } else if (infUi == 1 && ut > large) {
	    ltprime = (rloi-maxUi)/ait ;
	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
	      ltprime -= 1.0e-12*fabs(maxUi) ;
	  } else {
	    ltprime = -COIN_DBL_MAX ;
	  }
	  impliedLow = CoinMax(impliedLow,ltprime) ;
	}
	if (rupi < large) {
	  if (!infLi) {
	    assert(lt > -large) ;
	    utprime = lt+(rupi-maxLi)/ait ;
	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
	      utprime += 1.0e-12*fabs(maxLi) ;
	  } else if (infLi == 1 && lt < -large) {
	    utprime = (rupi-maxLi)/ait ;
	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
	      utprime += 1.0e-12*fabs(maxLi) ;
	  } else {
	    utprime = COIN_DBL_MAX ;
	  }
	  impliedHigh = CoinMin(impliedHigh,utprime) ;
	}
      } else {
	if (rloi > -large) {
	  if (!infUi) {
	    assert(lt > -large) ;
	    utprime = lt+(rloi-maxUi)/ait ;
	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
	      utprime += 1.0e-12*fabs(maxUi) ;
	  } else if (infUi == 1 && lt < -large) {
	    utprime = (rloi-maxUi)/ait ;
	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
	      utprime += 1.0e-12*fabs(maxUi) ;
	  } else {
	    utprime = COIN_DBL_MAX ;
	  }
	  impliedHigh = CoinMin(impliedHigh,utprime) ;
	}
	if (rupi < large) {
	  if (!infLi) {
	    assert(ut < large) ;
	    ltprime = ut+(rupi-maxLi)/ait ;
	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
	      ltprime -= 1.0e-12*fabs(maxLi) ;
	  } else if (infLi == 1 && ut > large) {
	    ltprime = (rupi-maxLi)/ait ;
	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
	      ltprime -= 1.0e-12*fabs(maxLi) ;
	  } else {
	    ltprime = -COIN_DBL_MAX ;
	  }
	  impliedLow = CoinMax(impliedLow,ltprime) ;
	}
      }
#     if PRESOLVE_DEBUG > 2
      std::cout
        << "    row(" << i << ") l'(" << tgtcol << ") " << ltprime
	<< ", u'(" << tgtcol << ") " << utprime ;
      if (lt <= impliedLow && impliedHigh <= ut)
	std::cout << "; implied free satisfied" ;
      std::cout << "." << std::endl ;
#     endif
/*
  For x(t) integral, see if a substitution formula based on row i will
  preserve integrality.  The final check in this clause aims to preserve
  SOS equalities (i.e., don't eliminate a non-trivial SOS equality from
  the system using this transform).

  Note that this can't be folded into the L(i)/U(i) loop because the answer
  changes with x(t).

  Original comment: can only accept if good looking row
*/
      if (integerType[tgtcol]) {
	possibleRow = true ;
	bool allOnes = true ;
	for (CoinBigIndex krow = krs ; krow < kre ; ++krow) {
	  const int j = colIndices[krow] ;
	  const double scaled_aij = rowCoeffs[krow]/ait ;
	  if (fabs(scaled_aij) != 1.0)
	    allOnes = false ;
	  if (!integerType[j] ||
	      fabs(scaled_aij-floor(scaled_aij+0.5)) > feasTol) {
	    possibleRow = false ;
	    break ;
	  }
	}
	if (rloi == 1.0 && leni >= 5 && stopSomeStuff && allOnes)
	  possibleRow = false ;
	rowiOK = rowiOK && possibleRow ;
      }
/*
  Do we have a winner? If we have an incumbent, prefer the one with fewer
  coefficients.
*/
      if (rowiOK) {
	if (subst_ndx < 0 || (leni < subst_len)) {
#         if PRESOLVE_DEBUG > 2
          std::cout
	    << "    row(" << i << ") now candidate for x(" << tgtcol << ")."
	    << std::endl ;
#         endif
	  subst_ndx = i ;
	  subst_len = leni ;
	}
      }
    }

    if (infeas) break ;
/*
  Can we do the transform? If so, subst_ndx will have a valid row.
  Record the implied free variable and the equality we'll use to substitute
  it out. Take the row out of the running --- we can't use the same row
  for two substitutions.
*/
    if (lt <= impliedLow && impliedHigh <= ut &&
        (subst_ndx >= 0 || singletonRow)) {
      implied_free[numberFree] = subst_ndx ;
      infiniteUp[subst_ndx] = -4 ;
      whichFree[numberFree++] = tgtcol ;
#     if PRESOLVE_DEBUG > 1
      std::cout
        << "  x(" << tgtcol << ") implied free by row " << subst_ndx
	<< std::endl ;
#     endif
    }
  }

  delete[] infiniteDown ;
  delete[] infiniteUp ;
  delete[] maxDown ;
  delete[] maxUp ;

/*
  If we're infeasible, there's nothing more to be done.
*/
  if (infeas) {
#   if PRESOLVE_SUMMARY > 0 || PRESOLVE_DEBUG > 0
    std::cout << "  IMPLIED_FREE: infeasible." << std::endl ;
#   endif
    return (next) ;
  }

/*
  We have a list of implied free variables, each with a row that can be used
  to substitute the variable to singleton status if the variable is not a
  natural singleton. The loop here will only process natural singletons.
  We'll hand the remainder to subst_constraint_action below, if there is
  a remainder.

  The natural singletons processed here are compressed out of whichFree and
  implied_free.
*/
  int unprocessed = 0 ;
  for (iLook = 0 ; iLook < numberFree ; iLook++) {
    const int tgtcol = whichFree[iLook] ;
    
    if (colLengths[tgtcol] != 1) {
      whichFree[unprocessed] = whichFree[iLook] ;
      implied_free[unprocessed] = implied_free[iLook] ;
      unprocessed++ ;
      continue ;
    }
    
    const int tgtrow = implied_free[iLook] ;
    const int tgtrow_len = rowLengths[tgtrow] ;

    const CoinBigIndex kcs = colStarts[tgtcol] ;
    const double tgtcol_coeff = colCoeffs[kcs] ;
    const double tgtcol_cost = cost[tgtcol] ;

    const CoinBigIndex krs = rowStarts[tgtrow] ;
    const CoinBigIndex kre = krs+tgtrow_len ;
    if (tgtcol_cost != 0.0) {
      // Check costs don't make unstable
      //double minOldCost=COIN_DBL_MAX;
      double maxOldCost=0.0;
      //double minNewCost=COIN_DBL_MAX;
      double maxNewCost=0.0;
      for (CoinBigIndex krow = krs ; krow < kre ; krow++) {
	const int j = colIndices[krow] ;
	if (j != tgtcol) {
	  double oldCost = cost[j] ;
	  double newCost = oldCost - (tgtcol_cost*rowCoeffs[krow])/tgtcol_coeff ;
	  oldCost = fabs(oldCost);
	  newCost = fabs(newCost);
	  //minOldCost=CoinMin(minOldCost,oldCost);
	  maxOldCost=CoinMax(maxOldCost,oldCost);
	  //minNewCost=CoinMin(minNewCost,newCost);
	  maxNewCost=CoinMax(maxNewCost,newCost);
	}
      }
      if (maxNewCost>1000.0*(maxOldCost+1.0) && maxOldCost) {
	//printf("too big %d tgtcost %g maxOld %g maxNew %g\n",
	//   tgtcol,tgtcol_cost,maxOldCost,maxNewCost);
	continue;
      }
    }
/*
  Initialise the postsolve action. We need to remember the row and column.
*/
    action *s = &actions[nactions++] ;
    s->row = tgtrow ;
    s->col = tgtcol ;
    s->clo = clo[tgtcol] ;
    s->cup = cup[tgtcol] ;
    s->rlo = rlo[tgtrow] ;
    s->rup = rup[tgtrow] ;
    s->ninrow = tgtrow_len ;
    s->rowels = presolve_dupmajor(rowCoeffs,colIndices,tgtrow_len,krs) ;
    s->costs = NULL ;
/*
  We're processing a singleton, hence no substitutions in the matrix, but we
  do need to fix up the cost vector. The substitution formula is
    x(t) = (rhs(i) - SUM{j\t}a(ik)x(k))/a(it)
  hence
    c'(k) = c(k)-c(t)a(ik)/a(it)
  and there's a constant offset
    c(t)rhs(i)/a(it).
  where rhs(i) is one of blow(i) or b(i).

  For general constraints where blow(i) != b(i), we need to take a bit
  of care. If only one of blow(i) or b(i) is finite, that's the one to
  use. Where we have two finite but unequal bounds, choose the bound that
  will result in the most favourable value for x(t). For minimisation, if
  c(t) < 0 we want to maximise x(t), so choose b(i) if a(it) > 0, blow(i)
  if a(it) < 0.  A bit of case analysis says choose b(i) when c(t)a(it) <
  0, blow(i) when c(t)a(it) > 0. We shouldn't be here if both row bounds
  are infinite.

  Fortunately, the objective coefficients are not affected by this.
*/
    if (tgtcol_cost != 0.0) {
      double tgtrow_rhs = rup[tgtrow] ;
      if (fabs(rlo[tgtrow]-rup[tgtrow]) > feasTol) {
	const double rlot = rlo[tgtrow] ;
	const double rupt = rup[tgtrow] ;
        if (rlot > -COIN_DBL_MAX && rupt < COIN_DBL_MAX) {
	  if ((tgtcol_cost*tgtcol_coeff) > 0)
	    tgtrow_rhs = rlot ;
	  else
	    tgtrow_rhs = rupt ;
	} else if (rupt >= COIN_DBL_MAX) {
	  tgtrow_rhs = rlot ;
	}
      }
      assert(fabs(tgtrow_rhs) <= large) ;
      double *save_costs = new double[tgtrow_len] ;

      for (CoinBigIndex krow = krs ; krow < kre ; krow++) {
	const int j = colIndices[krow] ;
	save_costs[krow-krs] = cost[j] ;
	cost[j] -= (tgtcol_cost*rowCoeffs[krow])/tgtcol_coeff ;
      }
      prob->change_bias((tgtcol_cost*tgtrow_rhs)/tgtcol_coeff) ;
      cost[tgtcol] = 0.0 ;
      s->costs = save_costs ;
    }
/*
  Remove the row from the column-major representation, queuing up each column
  for reconsideration. Then remove the row from the row-major representation.
*/
    for (CoinBigIndex krow = krs ; krow < kre ; krow++) {
      const int j = colIndices[krow] ;
      presolve_delete_from_col(tgtrow,j,colStarts,colLengths,rowIndices,
      			       colCoeffs) ;
      if (colLengths[j] == 0) {
        PRESOLVE_REMOVE_LINK(prob->clink_,j) ;
      } else {
	prob->addCol(j) ;
      }
    }
    PRESOLVE_REMOVE_LINK(clink,tgtcol) ;
    colLengths[tgtcol] = 0 ;

    PRESOLVE_REMOVE_LINK(rlink,tgtrow) ;
    rowLengths[tgtrow] = 0 ;
    rlo[tgtrow] = 0.0 ;
    rup[tgtrow] = 0.0 ;
  }
/*
  We're done with the natural singletons. Trim actions to length and create
  the postsolve object.
*/
  if (nactions) {
#   if PRESOLVE_SUMMARY > 0 || PRESOLVE_DEBUG > 0
    printf("NIMPLIED FREE:  %d\n", nactions) ;
#   endif
    action *actions1 = new action[nactions] ;
    CoinMemcpyN(actions, nactions, actions1) ;
    next = new implied_free_action(nactions,actions1,next) ;
  } 
  delete [] actions ;
# if PRESOLVE_DEBUG > 0
  std::cout
    << "  IMPLIED_FREE: identified " << numberFree
    << " implied free transforms, processed " << numberFree-unprocessed
    << " natural singletons." << std::endl ;
# endif

/*
  Now take a stab at the columns that aren't natural singletons, if there are
  any left.
*/
  if (unprocessed != 0) {
    // if not integer - don't allow much fill
    if (!prob->anyInteger())
    {
      int numberFree=unprocessed;
      int nBad=0;
      unprocessed=0;
      // Take out ones that make much denser or might lead to instability
      /*
	Unpack the row- and column-major representations.
      */
      CoinBigIndex *rowStarts = prob->mrstrt_ ;
      int *rowLengths = prob->hinrow_ ;
      double *rowCoeffs = prob->rowels_ ;
      int *colIndices = prob->hcol_ ;
      
      CoinBigIndex *colStarts = prob->mcstrt_ ;
      int *colLengths = prob->hincol_ ;
      double *colCoeffs = prob->colels_ ;
      int *rowIndices = prob->hrow_ ;
      
      /*
	This array is used to hold the indices of columns involved in substitutions,
	where we have the potential for cancellation. At the end they'll be
	checked to eliminate any actual zeros that may result.
	
	NOTE that usefulColumnInt_ is already in use for parameters implied_free and
	whichFree when this routine is called from implied_free.
      */
      
      int *rowsUsed = &prob->usefulRowInt_[0] ;
      int nRowsUsed = 0 ;
      /*
	Open a loop to process the (equality r, implied free variable t) pairs
	in whichFree and implied_free.
	
	It can happen that removal of (row, natural singleton) pairs back in
	implied_free will reduce the length of column t. It can also happen
	that previous processing here has resulted in fillin or cancellation. So
	check again for column length and exclude natural singletons and overly
	dense columns.
      */
      for (int iLook = 0 ; iLook < numberFree ; iLook++) {
	const int tgtcol = whichFree[iLook] ;
	const int tgtrow = implied_free[iLook] ;
	
	if (colLengths[tgtcol] < 2 || colLengths[tgtcol] > maxLook) {
#     if PRESOLVE_DEBUG > 3
	  std::cout
	    << "    skipping eqn " << tgtrow << " x(" << tgtcol
	    << "); length now " << colLengths[tgtcol] << "." << std::endl ;
#     endif
	  continue ;
	}
	
	CoinBigIndex tgtcs = colStarts[tgtcol] ;
	CoinBigIndex tgtce = tgtcs+colLengths[tgtcol] ;
	/*
	  A few checks to make sure that the candidate pair is still suitable.
	  Processing candidates earlier in the list can eliminate coefficients.
	  * Don't use this pair if any involved row i has become a row singleton
	  or empty.
	  * Don't use this pair if any involved row has been modified as part of
	  the processing for a previous candidate pair on this call.
	  * Don't use this pair if a(i,tgtcol) has become zero.
	  
	  The checks on a(i,tgtcol) seem superfluous but it's possible that
	  implied_free identified two candidate pairs to eliminate the same column. If
	  we've already processed one of them, we could be in trouble.
	*/
	double tgtcoeff = 0.0 ;
	bool dealBreaker = false ;
	for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) {
	  const int i = rowIndices[kcol] ;
	  if (rowLengths[i] < 2 || prob->rowUsed(i)) {
	    dealBreaker = true ;
	    break ;
	  }
	  const double aij = colCoeffs[kcol] ;
	  if (fabs(aij) <= ZTOLDP2) {
	    dealBreaker = true ;
	    break ;
	  }
	  if (i == tgtrow) tgtcoeff = aij ;
	}
	
	if (dealBreaker == true) {
#     if PRESOLVE_DEBUG > 3
	  std::cout
	    << "    skipping eqn " << tgtrow << " x(" << tgtcol
	    << "); deal breaker (1)." << std::endl ;
#     endif
	  continue ;
	}
	/*
	  Check for numerical stability.A large coeff_factor will inflate the
	  coefficients in the substitution formula.
	*/
	dealBreaker = false ;
	for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) {
	  const double coeff_factor = fabs(colCoeffs[kcol]/tgtcoeff) ;
	  if (coeff_factor > 10.0)
	    dealBreaker = true ;
	}
	if (dealBreaker == true) {
#     if PRESOLVE_DEBUG > 3
	  std::cout
	    << "    skipping eqn " << tgtrow << " x(" << tgtcol
	    << "); deal breaker (2)." << std::endl ;
#     endif
	  continue ;
	}
	/*
	  Count up the total number of coefficients in entangled rows and mark them as
	  contaminated.
	*/
	int ntotels = 0 ;
	for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) {
	  const int i = rowIndices[kcol] ;
	  ntotels += rowLengths[i] ;
	  PRESOLVEASSERT(!prob->rowUsed(i)) ;
	  prob->setRowUsed(i) ;
	  rowsUsed[nRowsUsed++] = i ;
	}
	
	CoinBigIndex tgtrs = rowStarts[tgtrow] ;
	CoinBigIndex tgtre = tgtrs+rowLengths[tgtrow] ;
	
	// kill small if wanted
	int relax= (prob->presolveOptions()&0x60000)>>17;
	double tolerance = 1.0e-12;
	for (int i=0;i<relax;i++)
	  tolerance *= 10.0;
	
	/*
	  Sort the target row for efficiency
	*/
	CoinSort_2(colIndices+tgtrs,colIndices+tgtre,rowCoeffs+tgtrs) ;
	CoinBigIndex start=colStarts[tgtcol];
	CoinBigIndex end = start+colLengths[tgtcol];
	numberBadElements=0;
	int numberFill=-rowLengths[tgtrow];
	for (int colndx = start ; colndx < end ; ++colndx) {
	  int i = rowIndices[colndx] ;
	  if (i == tgtrow) continue ;
	  
	  double ait = colCoeffs[colndx] ;
	  double coeff_factor = -ait/tgtcoeff ;
	  
	  CoinBigIndex krs = rowStarts[i] ;
	  CoinBigIndex kre = krs+rowLengths[i] ;
	  /*
	    Sort the row for efficiency and call add_row to do the actual business of
	    changing coefficients due to substitution. This has the potential to trigger
	    compaction of the row-major bulk store, so update bulk store indices.
	  */
	  CoinSort_2(colIndices+krs,colIndices+kre,rowCoeffs+krs) ;
	  
	  numberFill += check_row(rowStarts,rowCoeffs,colIndices,
				  rowLengths,coeff_factor,tolerance,i,tgtrow);
	}
	if (numberBadElements||3*numberFill>2*(colLengths[tgtcol]+rowLengths[tgtrow])) {
	  //printf("Bad subst col %d row %d - %d small elements, fill %d\n",
	  //	 tgtcol,tgtrow,numberBadElements,numberFill);
	  if (numberBadElements)
	    nBad++;
	} else {
	  whichFree[unprocessed]=tgtcol;
	  implied_free[unprocessed++]=tgtrow;
	  //printf("Good subst col %d row %d - fill %d\n",
	  //	 tgtcol,tgtrow,numberFill);
	}
      }
      /*
	That's it, we've processed all the candidate pairs.
	
	Clear the row used flags.
      */
      for (int i = 0 ; i < nRowsUsed ; i++) prob->unsetRowUsed(rowsUsed[i]) ;
#if CLP_USEFUL_PRINTOUT
      printf("%d allowed through out of %d - %d on coefficient\n",
	     unprocessed,numberFree,nBad);
#endif      
    }
    next = subst_constraint_action::presolve(prob,implied_free,whichFree,
    					     unprocessed,next,maxLook) ;
  }
/*
  Give some feedback to the presolve driver. If we aren't finding enough
  candidates and haven't reached the limit, bump fill_level and return a
  negated value. The presolve driver can tweak this value or simply return
  it on the next call. See the top of the routine for a full explanation.
*/
  if (numberFree < 30 && maxLook < prob->maxSubstLevel_) {
    fill_level = -(maxLook+1) ;
  } else {
    fill_level = maxLook ;
  }

# if COIN_PRESOLVE_TUNING > 0
  double thisTime ;
  if (prob->tuning_) thisTime = CoinCpuTime() ;
# endif
# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
  presolve_consistent(prob) ;
  presolve_links_ok(prob) ;
  presolve_check_sol(prob) ;
  presolve_check_nbasic(prob) ;
# endif
# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
  std::cout
    << "Leaving implied_free_action::presolve, fill level " << fill_level
    << ", " << droppedRows << " rows, "
    << droppedColumns << " columns dropped" ;
# if COIN_PRESOLVE_TUNING > 0
  std::cout << " in " << thisTime-startTime << "s" ;
# endif
  std::cout << "." << std::endl ;
# endif

  return (next) ;
}
Example #26
0
bool
ClpInterior::createWorkingData()
{
     bool goodMatrix = true;
     //check matrix
     if (!matrix_->allElementsInRange(this, 1.0e-12, 1.0e20)) {
          problemStatus_ = 4;
          goodMatrix = false;
     }
     int nTotal = numberRows_ + numberColumns_;
     delete [] solution_;
     solution_ = new CoinWorkDouble[nTotal];
     CoinMemcpyN(columnActivity_,	numberColumns_, solution_);
     CoinMemcpyN(rowActivity_,	numberRows_, solution_ + numberColumns_);
     delete [] cost_;
     cost_ = new CoinWorkDouble[nTotal];
     int i;
     CoinWorkDouble direction = optimizationDirection_ * objectiveScale_;
     // direction is actually scale out not scale in
     if (direction)
          direction = 1.0 / direction;
     const double * obj = objective();
     for (i = 0; i < numberColumns_; i++)
          cost_[i] = direction * obj[i];
     memset(cost_ + numberColumns_, 0, numberRows_ * sizeof(CoinWorkDouble));
     // do scaling if needed
     if (scalingFlag_ > 0 && !rowScale_) {
          if (matrix_->scale(this))
               scalingFlag_ = -scalingFlag_; // not scaled after all
     }
     delete [] lower_;
     delete [] upper_;
     lower_ = new CoinWorkDouble[nTotal];
     upper_ = new CoinWorkDouble[nTotal];
     rowLowerWork_ = lower_ + numberColumns_;
     columnLowerWork_ = lower_;
     rowUpperWork_ = upper_ + numberColumns_;
     columnUpperWork_ = upper_;
     CoinMemcpyN(rowLower_, numberRows_, rowLowerWork_);
     CoinMemcpyN(rowUpper_, numberRows_, rowUpperWork_);
     CoinMemcpyN(columnLower_, numberColumns_, columnLowerWork_);
     CoinMemcpyN(columnUpper_, numberColumns_, columnUpperWork_);
     // clean up any mismatches on infinity
     for (i = 0; i < numberColumns_; i++) {
          if (columnLowerWork_[i] < -1.0e30)
               columnLowerWork_[i] = -COIN_DBL_MAX;
          if (columnUpperWork_[i] > 1.0e30)
               columnUpperWork_[i] = COIN_DBL_MAX;
     }
     // clean up any mismatches on infinity
     for (i = 0; i < numberRows_; i++) {
          if (rowLowerWork_[i] < -1.0e30)
               rowLowerWork_[i] = -COIN_DBL_MAX;
          if (rowUpperWork_[i] > 1.0e30)
               rowUpperWork_[i] = COIN_DBL_MAX;
     }
     // check rim of problem okay
     if (!sanityCheck())
          goodMatrix = false;
     if(rowScale_) {
          for (i = 0; i < numberColumns_; i++) {
               CoinWorkDouble multiplier = rhsScale_ / columnScale_[i];
               cost_[i] *= columnScale_[i];
               if (columnLowerWork_[i] > -1.0e50)
                    columnLowerWork_[i] *= multiplier;
               if (columnUpperWork_[i] < 1.0e50)
                    columnUpperWork_[i] *= multiplier;

          }
          for (i = 0; i < numberRows_; i++) {
               CoinWorkDouble multiplier = rhsScale_ * rowScale_[i];
               if (rowLowerWork_[i] > -1.0e50)
                    rowLowerWork_[i] *= multiplier;
               if (rowUpperWork_[i] < 1.0e50)
                    rowUpperWork_[i] *= multiplier;
          }
     } else if (rhsScale_ != 1.0) {
          for (i = 0; i < numberColumns_ + numberRows_; i++) {
               if (lower_[i] > -1.0e50)
                    lower_[i] *= rhsScale_;
               if (upper_[i] < 1.0e50)
                    upper_[i] *= rhsScale_;

          }
     }
     assert (!errorRegion_);
     errorRegion_ = new CoinWorkDouble [numberRows_];
     assert (!rhsFixRegion_);
     rhsFixRegion_ = new CoinWorkDouble [numberRows_];
     assert (!deltaY_);
     deltaY_ = new CoinWorkDouble [numberRows_];
     CoinZeroN(deltaY_, numberRows_);
     assert (!upperSlack_);
     upperSlack_ = new CoinWorkDouble [nTotal];
     assert (!lowerSlack_);
     lowerSlack_ = new CoinWorkDouble [nTotal];
     assert (!diagonal_);
     diagonal_ = new CoinWorkDouble [nTotal];
     assert (!deltaX_);
     deltaX_ = new CoinWorkDouble [nTotal];
     CoinZeroN(deltaX_, nTotal);
     assert (!deltaZ_);
     deltaZ_ = new CoinWorkDouble [nTotal];
     CoinZeroN(deltaZ_, nTotal);
     assert (!deltaW_);
     deltaW_ = new CoinWorkDouble [nTotal];
     CoinZeroN(deltaW_, nTotal);
     assert (!deltaSU_);
     deltaSU_ = new CoinWorkDouble [nTotal];
     CoinZeroN(deltaSU_, nTotal);
     assert (!deltaSL_);
     deltaSL_ = new CoinWorkDouble [nTotal];
     CoinZeroN(deltaSL_, nTotal);
     assert (!primalR_);
     assert (!dualR_);
     // create arrays if we are doing KKT
     if (cholesky_->type() >= 20) {
          primalR_ = new CoinWorkDouble [nTotal];
          CoinZeroN(primalR_, nTotal);
          dualR_ = new CoinWorkDouble [numberRows_];
          CoinZeroN(dualR_, numberRows_);
     }
     assert (!rhsB_);
     rhsB_ = new CoinWorkDouble [numberRows_];
     CoinZeroN(rhsB_, numberRows_);
     assert (!rhsU_);
     rhsU_ = new CoinWorkDouble [nTotal];
     CoinZeroN(rhsU_, nTotal);
     assert (!rhsL_);
     rhsL_ = new CoinWorkDouble [nTotal];
     CoinZeroN(rhsL_, nTotal);
     assert (!rhsZ_);
     rhsZ_ = new CoinWorkDouble [nTotal];
     CoinZeroN(rhsZ_, nTotal);
     assert (!rhsW_);
     rhsW_ = new CoinWorkDouble [nTotal];
     CoinZeroN(rhsW_, nTotal);
     assert (!rhsC_);
     rhsC_ = new CoinWorkDouble [nTotal];
     CoinZeroN(rhsC_, nTotal);
     assert (!workArray_);
     workArray_ = new CoinWorkDouble [nTotal];
     CoinZeroN(workArray_, nTotal);
     assert (!zVec_);
     zVec_ = new CoinWorkDouble [nTotal];
     CoinZeroN(zVec_, nTotal);
     assert (!wVec_);
     wVec_ = new CoinWorkDouble [nTotal];
     CoinZeroN(wVec_, nTotal);
     assert (!dj_);
     dj_ = new CoinWorkDouble [nTotal];
     if (!status_)
          status_ = new unsigned char [numberRows_+numberColumns_];
     memset(status_, 0, numberRows_ + numberColumns_);
     return goodMatrix;
}
Example #27
0
/* Saves any weights round factorization as pivot rows may change
   1) before factorization
   2) after factorization
   3) just redo infeasibilities
   4) restore weights
*/
void
ClpDualRowSteepest::saveWeights(ClpSimplex * model, int mode)
{
     // alternateWeights_ is defined as indexed but is treated oddly
     model_ = model;
     int numberRows = model_->numberRows();
     int numberColumns = model_->numberColumns();
     const int * pivotVariable = model_->pivotVariable();
     int i;
     if (mode == 1) {
          if(weights_) {
               // Check if size has changed
               if (infeasible_->capacity() == numberRows) {
                    alternateWeights_->clear();
                    // change from row numbers to sequence numbers
                    int * which = alternateWeights_->getIndices();
                    for (i = 0; i < numberRows; i++) {
                         int iPivot = pivotVariable[i];
                         which[i] = iPivot;
                    }
                    state_ = 1;
               } else {
                    // size has changed - clear everything
                    delete [] weights_;
                    weights_ = NULL;
                    delete [] dubiousWeights_;
                    dubiousWeights_ = NULL;
                    delete infeasible_;
                    infeasible_ = NULL;
                    delete alternateWeights_;
                    alternateWeights_ = NULL;
                    delete savedWeights_;
                    savedWeights_ = NULL;
                    state_ = -1;
               }
          }
     } else if (mode == 2 || mode == 4 || mode >= 5) {
          // restore
          if (!weights_ || state_ == -1 || mode == 5) {
               // initialize weights
               delete [] weights_;
               delete alternateWeights_;
               weights_ = new double[numberRows];
               alternateWeights_ = new CoinIndexedVector();
               // enough space so can use it for factorization
               alternateWeights_->reserve(numberRows +
                                          model_->factorization()->maximumPivots());
               if (mode_ != 1 || mode == 5) {
                    // initialize to 1.0 (can we do better?)
                    for (i = 0; i < numberRows; i++) {
                         weights_[i] = 1.0;
                    }
               } else {
                    CoinIndexedVector * temp = new CoinIndexedVector();
                    temp->reserve(numberRows +
                                  model_->factorization()->maximumPivots());
                    double * array = alternateWeights_->denseVector();
                    int * which = alternateWeights_->getIndices();
                    for (i = 0; i < numberRows; i++) {
                         double value = 0.0;
                         array[0] = 1.0;
                         which[0] = i;
                         alternateWeights_->setNumElements(1);
                         alternateWeights_->setPackedMode(true);
                         model_->factorization()->updateColumnTranspose(temp,
                                   alternateWeights_);
                         int number = alternateWeights_->getNumElements();
                         int j;
                         for (j = 0; j < number; j++) {
                              value += array[j] * array[j];
                              array[j] = 0.0;
                         }
                         alternateWeights_->setNumElements(0);
                         weights_[i] = value;
                    }
                    delete temp;
               }
               // create saved weights (not really indexedvector)
               savedWeights_ = new CoinIndexedVector();
               savedWeights_->reserve(numberRows);

               double * array = savedWeights_->denseVector();
               int * which = savedWeights_->getIndices();
               for (i = 0; i < numberRows; i++) {
                    array[i] = weights_[i];
                    which[i] = pivotVariable[i];
               }
          } else if (mode != 6) {
               int * which = alternateWeights_->getIndices();
               CoinIndexedVector * rowArray3 = model_->rowArray(3);
               rowArray3->clear();
               int * back = rowArray3->getIndices();
               // In case something went wrong
               for (i = 0; i < numberRows + numberColumns; i++)
                    back[i] = -1;
               if (mode != 4) {
                    // save
                    CoinMemcpyN(which,	numberRows, savedWeights_->getIndices());
                    CoinMemcpyN(weights_,	numberRows, savedWeights_->denseVector());
               } else {
                    // restore
                    //memcpy(which,savedWeights_->getIndices(),
                    //     numberRows*sizeof(int));
                    //memcpy(weights_,savedWeights_->denseVector(),
                    //     numberRows*sizeof(double));
                    which = savedWeights_->getIndices();
               }
               // restore (a bit slow - but only every re-factorization)
               double * array = savedWeights_->denseVector();
               for (i = 0; i < numberRows; i++) {
                    int iSeq = which[i];
                    back[iSeq] = i;
               }
               for (i = 0; i < numberRows; i++) {
                    int iPivot = pivotVariable[i];
                    iPivot = back[iPivot];
                    if (iPivot >= 0) {
                         weights_[i] = array[iPivot];
                         if (weights_[i] < DEVEX_TRY_NORM)
                              weights_[i] = DEVEX_TRY_NORM; // may need to check more
                    } else {
                         // odd
                         weights_[i] = 1.0;
                    }
               }
          } else {
               // mode 6 - scale back weights as primal errors
               double primalError = model_->largestPrimalError();
               double allowed ;
               if (primalError > 1.0e3)
                    allowed = 10.0;
               else if (primalError > 1.0e2)
                    allowed = 50.0;
               else if (primalError > 1.0e1)
                    allowed = 100.0;
               else
                    allowed = 1000.0;
               double allowedInv = 1.0 / allowed;
               for (i = 0; i < numberRows; i++) {
                    double value = weights_[i];
                    if (value < allowedInv)
                         value = allowedInv;
                    else if (value > allowed)
                         value = allowed;
                    weights_[i] = allowed;
               }
          }
          state_ = 0;
          // set up infeasibilities
          if (!infeasible_) {
               infeasible_ = new CoinIndexedVector();
               infeasible_->reserve(numberRows);
          }
     }
     if (mode >= 2) {
          // Get dubious weights
          //if (!dubiousWeights_)
          //dubiousWeights_=new int[numberRows];
          //model_->factorization()->getWeights(dubiousWeights_);
          infeasible_->clear();
          int iRow;
          const int * pivotVariable = model_->pivotVariable();
          double tolerance = model_->currentPrimalTolerance();
          for (iRow = 0; iRow < numberRows; iRow++) {
               int iPivot = pivotVariable[iRow];
               double value = model_->solution(iPivot);
               double lower = model_->lower(iPivot);
               double upper = model_->upper(iPivot);
               if (value < lower - tolerance) {
                    value -= lower;
                    value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
                    if (iPivot < numberColumns)
                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
                    if (lower == upper)
                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
                    // store square in list
                    infeasible_->quickAdd(iRow, value);
               } else if (value > upper + tolerance) {
                    value -= upper;
                    value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
                    if (iPivot < numberColumns)
                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
                    if (lower == upper)
                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
                    // store square in list
                    infeasible_->quickAdd(iRow, value);
               }
          }
     }
}
Example #28
0
/* Orders rows and saves pointer to matrix.and model */
int
ClpCholeskyTaucs::order(ClpInterior * model)
{
     numberRows_ = model->numberRows();
     rowsDropped_ = new char [numberRows_];
     memset(rowsDropped_, 0, numberRows_);
     numberRowsDropped_ = 0;
     model_ = model;
     rowCopyT_ = model->clpMatrix()->reverseOrderedCopy();
     const CoinBigIndex * columnStart = model_->clpMatrix()->getVectorStarts();
     const int * columnLength = model_->clpMatrix()->getVectorLengths();
     const int * row = model_->clpMatrix()->getIndices();
     const CoinBigIndex * rowStart = rowCopyT_->getVectorStarts();
     const int * rowLength = rowCopyT_->getVectorLengths();
     const int * column = rowCopyT_->getIndices();
     // We need two arrays for counts
     int * which = new int [numberRows_];
     int * used = new int[numberRows_];
     CoinZeroN(used, numberRows_);
     int iRow;
     sizeFactorT_ = 0;
     for (iRow = 0; iRow < numberRows_; iRow++) {
          int number = 1;
          // make sure diagonal exists
          which[0] = iRow;
          used[iRow] = 1;
          if (!rowsDropped_[iRow]) {
               CoinBigIndex startRow = rowStart[iRow];
               CoinBigIndex endRow = rowStart[iRow] + rowLength[iRow];
               for (CoinBigIndex k = startRow; k < endRow; k++) {
                    int iColumn = column[k];
                    CoinBigIndex start = columnStart[iColumn];
                    CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
                    for (CoinBigIndex j = start; j < end; j++) {
                         int jRow = row[j];
                         if (jRow >= iRow && !rowsDropped_[jRow]) {
                              if (!used[jRow]) {
                                   used[jRow] = 1;
                                   which[number++] = jRow;
                              }
                         }
                    }
               }
               sizeFactorT_ += number;
               int j;
               for (j = 0; j < number; j++)
                    used[which[j]] = 0;
          }
     }
     delete [] which;
     // Now we have size - create arrays and fill in
     matrix_ = taucs_ccs_create(numberRows_, numberRows_, sizeFactorT_,
                                TAUCS_DOUBLE | TAUCS_SYMMETRIC | TAUCS_LOWER);
     if (!matrix_)
          return 1;
     // Space for starts
     choleskyStartT_ = matrix_->colptr;
     choleskyRowT_ = matrix_->rowind;
     sparseFactorT_ = matrix_->values.d;
     sizeFactorT_ = 0;
     which = choleskyRowT_;
     for (iRow = 0; iRow < numberRows_; iRow++) {
          int number = 1;
          // make sure diagonal exists
          which[0] = iRow;
          used[iRow] = 1;
          choleskyStartT_[iRow] = sizeFactorT_;
          if (!rowsDropped_[iRow]) {
               CoinBigIndex startRow = rowStart[iRow];
               CoinBigIndex endRow = rowStart[iRow] + rowLength[iRow];
               for (CoinBigIndex k = startRow; k < endRow; k++) {
                    int iColumn = column[k];
                    CoinBigIndex start = columnStart[iColumn];
                    CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
                    for (CoinBigIndex j = start; j < end; j++) {
                         int jRow = row[j];
                         if (jRow >= iRow && !rowsDropped_[jRow]) {
                              if (!used[jRow]) {
                                   used[jRow] = 1;
                                   which[number++] = jRow;
                              }
                         }
                    }
               }
               sizeFactorT_ += number;
               int j;
               for (j = 0; j < number; j++)
                    used[which[j]] = 0;
               // Sort
               std::sort(which, which + number);
               // move which on
               which += number;
          }
     }
     choleskyStartT_[numberRows_] = sizeFactorT_;
     delete [] used;
     permuteInverse_ = new int [numberRows_];
     permute_ = new int[numberRows_];
     int * perm, *invp;
     // There seem to be bugs in ordering if model too small
     if (numberRows_ > 10)
          taucs_ccs_order(matrix_, &perm, &invp, (const char *) "genmmd");
     else
          taucs_ccs_order(matrix_, &perm, &invp, (const char *) "identity");
     CoinMemcpyN(perm, numberRows_, permuteInverse_);
     free(perm);
     CoinMemcpyN(invp, numberRows_, permute_);
     free(invp);
     // need to permute
     taucs_ccs_matrix * permuted = taucs_ccs_permute_symmetrically(matrix_, permuteInverse_, permute_);
     // symbolic
     factorization_ = taucs_ccs_factor_llt_symbolic(permuted);
     taucs_ccs_free(permuted);
     return factorization_ ? 0 : 1;
}
Example #29
0
void
ClpInterior::checkSolution()
{
     int iRow, iColumn;
     CoinWorkDouble * reducedCost = reinterpret_cast<CoinWorkDouble *>(reducedCost_);
     CoinWorkDouble * dual = reinterpret_cast<CoinWorkDouble *>(dual_);
     CoinMemcpyN(cost_, numberColumns_, reducedCost);
     matrix_->transposeTimes(-1.0, dual, reducedCost);
     // Now modify reduced costs for quadratic
     CoinWorkDouble quadraticOffset = quadraticDjs(reducedCost,
                                      solution_, scaleFactor_);

     objectiveValue_ = 0.0;
     // now look at solution
     sumPrimalInfeasibilities_ = 0.0;
     sumDualInfeasibilities_ = 0.0;
     CoinWorkDouble dualTolerance =  10.0 * dblParam_[ClpDualTolerance];
     CoinWorkDouble primalTolerance =  dblParam_[ClpPrimalTolerance];
     CoinWorkDouble primalTolerance2 =  10.0 * dblParam_[ClpPrimalTolerance];
     worstComplementarity_ = 0.0;
     complementarityGap_ = 0.0;

     // Done scaled - use permanent regions for output
     // but internal for bounds
     const CoinWorkDouble * lower = lower_ + numberColumns_;
     const CoinWorkDouble * upper = upper_ + numberColumns_;
     for (iRow = 0; iRow < numberRows_; iRow++) {
          CoinWorkDouble infeasibility = 0.0;
          CoinWorkDouble distanceUp = CoinMin(upper[iRow] -
                                              rowActivity_[iRow], static_cast<CoinWorkDouble>(1.0e10));
          CoinWorkDouble distanceDown = CoinMin(rowActivity_[iRow] -
                                                lower[iRow], static_cast<CoinWorkDouble>(1.0e10));
          if (distanceUp > primalTolerance2) {
               CoinWorkDouble value = dual[iRow];
               // should not be negative
               if (value < -dualTolerance) {
                    sumDualInfeasibilities_ += -dualTolerance - value;
                    value = - value * distanceUp;
                    if (value > worstComplementarity_)
                         worstComplementarity_ = value;
                    complementarityGap_ += value;
               }
          }
          if (distanceDown > primalTolerance2) {
               CoinWorkDouble value = dual[iRow];
               // should not be positive
               if (value > dualTolerance) {
                    sumDualInfeasibilities_ += value - dualTolerance;
                    value =  value * distanceDown;
                    if (value > worstComplementarity_)
                         worstComplementarity_ = value;
                    complementarityGap_ += value;
               }
          }
          if (rowActivity_[iRow] > upper[iRow]) {
               infeasibility = rowActivity_[iRow] - upper[iRow];
          } else if (rowActivity_[iRow] < lower[iRow]) {
               infeasibility = lower[iRow] - rowActivity_[iRow];
          }
          if (infeasibility > primalTolerance) {
               sumPrimalInfeasibilities_ += infeasibility - primalTolerance;
          }
     }
     lower = lower_;
     upper = upper_;
     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
          CoinWorkDouble infeasibility = 0.0;
          objectiveValue_ += cost_[iColumn] * columnActivity_[iColumn];
          CoinWorkDouble distanceUp = CoinMin(upper[iColumn] -
                                              columnActivity_[iColumn], static_cast<CoinWorkDouble>(1.0e10));
          CoinWorkDouble distanceDown = CoinMin(columnActivity_[iColumn] -
                                                lower[iColumn], static_cast<CoinWorkDouble>(1.0e10));
          if (distanceUp > primalTolerance2) {
               CoinWorkDouble value = reducedCost[iColumn];
               // should not be negative
               if (value < -dualTolerance) {
                    sumDualInfeasibilities_ += -dualTolerance - value;
                    value = - value * distanceUp;
                    if (value > worstComplementarity_)
                         worstComplementarity_ = value;
                    complementarityGap_ += value;
               }
          }
          if (distanceDown > primalTolerance2) {
               CoinWorkDouble value = reducedCost[iColumn];
               // should not be positive
               if (value > dualTolerance) {
                    sumDualInfeasibilities_ += value - dualTolerance;
                    value =  value * distanceDown;
                    if (value > worstComplementarity_)
                         worstComplementarity_ = value;
                    complementarityGap_ += value;
               }
          }
          if (columnActivity_[iColumn] > upper[iColumn]) {
               infeasibility = columnActivity_[iColumn] - upper[iColumn];
          } else if (columnActivity_[iColumn] < lower[iColumn]) {
               infeasibility = lower[iColumn] - columnActivity_[iColumn];
          }
          if (infeasibility > primalTolerance) {
               sumPrimalInfeasibilities_ += infeasibility - primalTolerance;
          }
     }
#if COIN_LONG_WORK
     // ok as packs down
     CoinMemcpyN(reducedCost, numberColumns_, reducedCost_);
#endif
     // add in offset
     objectiveValue_ += 0.5 * quadraticOffset;
}
/*
  It is always the case that one of the variables of a doubleton is, or
  can be made, implied free, but neither will necessarily be a singleton.
  Since in the case of a doubleton the number of non-zero entries will never
  increase if one is eliminated, it makes sense to always eliminate them.

  The col rep and row rep must be consistent.
 */
const CoinPresolveAction
  *doubleton_action::presolve (CoinPresolveMatrix *prob,
			      const CoinPresolveAction *next)

{
# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
# if PRESOLVE_DEBUG > 0
  std::cout
    << "Entering doubleton_action::presolve; considering "
    << prob->numberRowsToDo_ << " rows." << std::endl ;
# endif
  presolve_consistent(prob) ;
  presolve_links_ok(prob) ;
  presolve_check_sol(prob) ;
  presolve_check_nbasic(prob) ;
# endif
# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
  int startEmptyRows = 0 ;
  int startEmptyColumns = 0 ;
  startEmptyRows = prob->countEmptyRows() ;
  startEmptyColumns = prob->countEmptyCols() ;
# if COIN_PRESOLVE_TUNING > 0
  double startTime = 0.0 ;
  if (prob->tuning_) startTime = CoinCpuTime() ;
# endif
# endif

  const int n = prob->ncols_ ;
  const int m = prob->nrows_ ;

/*
  Unpack column-major and row-major representations, along with rim vectors.
*/
  CoinBigIndex *colStarts = prob->mcstrt_ ;
  int *colLengths = prob->hincol_ ;
  double *colCoeffs = prob->colels_ ;
  int *rowIndices = prob->hrow_ ;
  presolvehlink *clink = prob->clink_ ;

  double *clo = prob->clo_ ;
  double *cup = prob->cup_ ;

  CoinBigIndex *rowStarts = prob->mrstrt_ ;
  int *rowLengths = prob->hinrow_ ;
  double *rowCoeffs = prob->rowels_ ;
  int *colIndices = prob->hcol_ ;
  presolvehlink *rlink = prob->rlink_ ;

  double *rlo = prob->rlo_ ;
  double *rup = prob->rup_ ;

  const unsigned char *integerType = prob->integerType_ ;

  double *cost = prob->cost_ ;

  int numberLook = prob->numberRowsToDo_ ;
  int *look = prob->rowsToDo_ ;
  const double ztolzb	= prob->ztolzb_ ;
  const double ztolzero = 1.0e-12 ;

  action *actions = new action [m] ;
  int nactions = 0 ;

/*
  zeros will hold columns that should be groomed to remove explicit zeros when
  we're finished.

  fixed will hold columns that have ended up as fixed variables.
*/
  int *zeros = prob->usefulColumnInt_ ;
  int nzeros = 0 ;

  int *fixed = zeros+n ;
  int nfixed = 0 ;

  unsigned char *rowstat = prob->rowstat_ ;
  double *acts	= prob->acts_ ;
  double *sol = prob->sol_ ;
/*
  More like `ignore infeasibility'.
*/
  bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;

/*
  Open the main loop to scan for doubleton candidates.
*/
  for (int iLook = 0 ; iLook < numberLook ; iLook++) {
    const int tgtrow = look[iLook] ;
/*
  We need an equality with two coefficients. Avoid isolated constraints, lest
  both variables vanish.

  Failure of the assert indicates that the row- and column-major
  representations are out of sync.
*/
    if ((rowLengths[tgtrow] != 2) ||
        (fabs(rup[tgtrow]-rlo[tgtrow]) > ZTOLDP)) continue ;

    const CoinBigIndex krs = rowStarts[tgtrow] ;
    int tgtcolx = colIndices[krs] ;
    int tgtcoly = colIndices[krs+1] ;

    PRESOLVEASSERT(colLengths[tgtcolx] > 0 || colLengths[tgtcoly] > 0) ;
    if (colLengths[tgtcolx] == 1 && colLengths[tgtcoly] == 1) continue ;
/*
  Avoid prohibited columns and fixed columns. Make sure the coefficients are
  nonzero.
  JJF - test should allow one to be prohibited as long as you leave that
  one.  I modified earlier code but hope I have got this right.
*/
    if (prob->colProhibited(tgtcolx) && prob->colProhibited(tgtcoly))
      continue ;
    if (fabs(rowCoeffs[krs]) < ZTOLDP2 || fabs(rowCoeffs[krs+1]) < ZTOLDP2)
      continue ;
    if ((fabs(cup[tgtcolx]-clo[tgtcolx]) < ZTOLDP) ||
	(fabs(cup[tgtcoly]-clo[tgtcoly]) < ZTOLDP)) continue ;

#   if PRESOLVE_DEBUG > 2
    std::cout
      << "  row " << tgtrow << " colx " << tgtcolx << " coly " << tgtcoly
      << " passes preliminary eval." << std::endl ;
#   endif

/*
  Find this row in each column. The indices are not const because we may flip
  them below, once we decide which column will be eliminated.
*/
    CoinBigIndex krowx =
        presolve_find_row(tgtrow,colStarts[tgtcolx],
			  colStarts[tgtcolx]+colLengths[tgtcolx],rowIndices) ;
    double coeffx = colCoeffs[krowx] ;
    CoinBigIndex krowy =
        presolve_find_row(tgtrow,colStarts[tgtcoly],
			  colStarts[tgtcoly]+colLengths[tgtcoly],rowIndices) ;
    double coeffy = colCoeffs[krowy] ;
    const double rhs = rlo[tgtrow] ;
/*
  Avoid obscuring a requirement for integrality.

  If only one variable is integer, keep it and substitute for the continuous
  variable.

  If both are integer, substitute only for the forms x = k*y (k integral
  and non-empty intersection on bounds on x) or x = 1-y, where both x and
  y are binary.

  flag bits for integerStatus: 0x01: x integer;  0x02: y integer

  This bit of code works because 0 is continuous, 1 is integer. Make sure
  that's true.
*/
    assert((integerType[tgtcolx] == 0) || (integerType[tgtcolx] == 1)) ;
    assert((integerType[tgtcoly] == 0) || (integerType[tgtcoly] == 1)) ;

    int integerX = integerType[tgtcolx];
    int integerY = integerType[tgtcoly];
    /* if one prohibited then treat that as integer. This
       may be pessimistic - but will catch SOS etc */
    if (prob->colProhibited2(tgtcolx))
      integerX=1;
    if (prob->colProhibited2(tgtcoly))
      integerY=1;
    int integerStatus = (integerY<<1)|integerX ;

    if (integerStatus == 3) {
      int good = 0 ;
      double rhs2 = rhs ;
      if (coeffx < 0.0) {
	coeffx = -coeffx ;
	rhs2 += 1 ;
      }
      if ((cup[tgtcolx] == 1.0) && (clo[tgtcolx] == 0.0) &&
	  (fabs(coeffx-1.0) < 1.0e-7) && !prob->colProhibited2(tgtcoly))
	good = 1 ;
      if (coeffy < 0.0) {
	coeffy = -coeffy ;
	rhs2 += 1 ;
      }
      if ((cup[tgtcoly] == 1.0) && (clo[tgtcoly] == 0.0) &&
	  (fabs(coeffy-1.0) < 1.0e-7) && !prob->colProhibited2(tgtcolx))
	good |= 2 ;
      if (!(good == 3 && fabs(rhs2-1.0) < 1.0e-7))
	integerStatus = -1 ;
/*
  Not x+y = 1. Try for ax+by = 0
*/
      if (integerStatus < 0 && rhs == 0.0) {
	coeffx = colCoeffs[krowx] ;
	coeffy = colCoeffs[krowy] ;
	double ratio ;
	bool swap = false ;
	if (fabs(coeffx) > fabs(coeffy)) {
	  ratio = coeffx/coeffy ;
	} else {
	  ratio = coeffy/coeffx ;
	  swap = true ;
	}
	ratio = fabs(ratio) ;
	if (fabs(ratio-floor(ratio+0.5)) < ztolzero) {
	  integerStatus = swap ? 2 : 1 ;
	}
      }
/*
  One last try --- just require an integral substitution formula.

  But ax+by = 0 above is a subset of ax+by = c below and should pass the
  test below. For that matter, so will x+y = 1. Why separate special cases
  above?  -- lh, 121106 --
*/
      if (integerStatus < 0) {
	bool canDo = false ;
	coeffx = colCoeffs[krowx] ;
	coeffy = colCoeffs[krowy] ;
	double ratio ;
	bool swap = false ;
	double rhsRatio ;
	if (fabs(coeffx) > fabs(coeffy)) {
	  ratio = coeffx/coeffy ;
	  rhsRatio = rhs/coeffx ;
	} else {
	  ratio = coeffy/coeffx ;
	  rhsRatio = rhs/coeffy ;
	  swap = true ;
	}
	ratio = fabs(ratio) ;
	if (fabs(ratio-floor(ratio+0.5)) < ztolzero) {
	  // possible
	  integerStatus = swap ? 2 : 1 ;
	  // but check rhs
	  if (rhsRatio==floor(rhsRatio+0.5))
	    canDo=true ;
	}
#       ifdef COIN_DEVELOP2
	if (canDo)
	  printf("Good CoinPresolveDoubleton tgtcolx %d (%g and bounds %g %g) tgtcoly %d (%g and bound %g %g) - rhs %g\n",
		 tgtcolx,colCoeffs[krowx],clo[tgtcolx],cup[tgtcolx],
		 tgtcoly,colCoeffs[krowy],clo[tgtcoly],cup[tgtcoly],rhs) ;
	else
	printf("Bad CoinPresolveDoubleton tgtcolx %d (%g) tgtcoly %d (%g) - rhs %g\n",
	       tgtcolx,colCoeffs[krowx],tgtcoly,colCoeffs[krowy],rhs) ;
#       endif
	if (!canDo)
	  continue ;
      }
    }
/*
  We've resolved integrality concerns. If we concluded that we need to
  switch the roles of x and y because of integrality, do that now. If both
  variables are continuous, we may still want to swap for numeric stability.
  Eliminate the variable with the larger coefficient.
*/
    if (integerStatus == 2) {
      CoinSwap(tgtcoly,tgtcolx) ;
      CoinSwap(krowy,krowx) ;
    } else if (integerStatus == 0) {
      if (fabs(colCoeffs[krowy]) < fabs(colCoeffs[krowx])) {
	CoinSwap(tgtcoly,tgtcolx) ;
	CoinSwap(krowy,krowx) ;
      }
    }
/*
  Don't eliminate y just yet if it's entangled in a singleton row (we want to
  capture that explicit bound in a column bound).
*/
    const CoinBigIndex kcsy = colStarts[tgtcoly] ;
    const CoinBigIndex kcey = kcsy+colLengths[tgtcoly] ;
    bool singletonRow = false ;
    for (CoinBigIndex kcol = kcsy ; kcol < kcey ; kcol++) {
      if (rowLengths[rowIndices[kcol]] == 1) {
        singletonRow = true ;
	break ;
      }
    }
    // skip if y prohibited
    if (singletonRow || prob->colProhibited2(tgtcoly)) continue ;

    coeffx = colCoeffs[krowx] ;
    coeffy = colCoeffs[krowy] ;
#   if PRESOLVE_DEBUG > 2
    std::cout
      << "  doubleton row " << tgtrow << ", keep x(" << tgtcolx
      << ") elim x(" << tgtcoly << ")." << std::endl ;
#   endif
    PRESOLVE_DETAIL_PRINT(printf("pre_doubleton %dC %dC %dR E\n",
				 tgtcoly,tgtcolx,tgtrow)) ;
/*
  Capture the existing columns and other information before we start to modify
  the constraint system. Save the shorter column.
*/
    action *s = &actions[nactions] ;
    nactions++ ;
    s->row = tgtrow ;
    s->icolx = tgtcolx ;
    s->clox = clo[tgtcolx] ;
    s->cupx = cup[tgtcolx] ;
    s->costx = cost[tgtcolx] ;
    s->icoly = tgtcoly ;
    s->costy = cost[tgtcoly] ;
    s->rlo = rlo[tgtrow] ;
    s->coeffx = coeffx ;
    s->coeffy = coeffy ;
    s->ncolx = colLengths[tgtcolx] ;
    s->ncoly = colLengths[tgtcoly] ;
    if (s->ncoly < s->ncolx) {
      s->colel	= presolve_dupmajor(colCoeffs,rowIndices,colLengths[tgtcoly],
				    colStarts[tgtcoly],tgtrow) ;
      s->ncolx = 0 ;
    } else {
      s->colel = presolve_dupmajor(colCoeffs,rowIndices,colLengths[tgtcolx],
				   colStarts[tgtcolx],tgtrow) ;
      s->ncoly = 0 ;
    }
/*
  Move finite bound information from y to x, so that y is implied free.
    a x + b y = c
    l1 <= x <= u1
    l2 <= y <= u2
   
    l2 <= (c - a x) / b <= u2
    b/-a > 0 ==> (b l2 - c) / -a <= x <= (b u2 - c) / -a
    b/-a < 0 ==> (b u2 - c) / -a <= x <= (b l2 - c) / -a
*/
    {
      double lo1 = -PRESOLVE_INF ;
      double up1 = PRESOLVE_INF ;
      
      if (-PRESOLVE_INF < clo[tgtcoly]) {
	if (coeffx*coeffy < 0)
	  lo1 = (coeffy*clo[tgtcoly]-rhs)/-coeffx ;
	else 
	  up1 = (coeffy*clo[tgtcoly]-rhs)/-coeffx ;
      }
      
      if (cup[tgtcoly] < PRESOLVE_INF) {
	if (coeffx*coeffy < 0)
	  up1 = (coeffy*cup[tgtcoly]-rhs)/-coeffx ;
	else 
	  lo1 = (coeffy*cup[tgtcoly]-rhs)/-coeffx ;
      }
/*
  Don't forget the objective coefficient.
    costy y = costy ((c - a x) / b) = (costy c)/b + x (costy -a)/b
*/
      cost[tgtcolx] += (cost[tgtcoly]*-coeffx)/coeffy ;
      prob->change_bias((cost[tgtcoly]*rhs)/coeffy) ;
/*
  The transfer of bounds could make x infeasible. Patch it up if the problem
  is minor or if the user was so incautious as to instruct us to ignore it.
  Prefer an integer value if there's one nearby. If there's nothing to be
  done, break out of the main loop.
*/
      {
	double lo2 = CoinMax(clo[tgtcolx],lo1) ;
	double up2 = CoinMin(cup[tgtcolx],up1) ;
	if (lo2 > up2) {
	  if (lo2 <= up2+prob->feasibilityTolerance_ || fixInfeasibility) {
	    double nearest = floor(lo2+0.5) ;
	    if (fabs(nearest-lo2) < 2.0*prob->feasibilityTolerance_) {
	      lo2 = nearest ;
	      up2 = nearest ;
	    } else {
	      lo2 = up2 ;
	    }
	  } else {
	    prob->status_ |= 1 ;
	    prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS,
	    				    prob->messages())
		 << tgtcolx << lo2 << up2 << CoinMessageEol ;
	    break ;
	  }
	}
#       if PRESOLVE_DEBUG > 2
	std::cout
	  << "  x(" << tgtcolx << ") lb " << clo[tgtcolx] << " --> " << lo2
	  << ", ub " << cup[tgtcolx] << " --> " << up2 << std::endl ;
#       endif
	clo[tgtcolx] = lo2 ;
	cup[tgtcolx] = up2 ;
/*
  Do we have a solution to maintain? If so, take a stab at it. If x ends up at
  bound, prefer to set it nonbasic, but if we're short of basic variables
  after eliminating y and the logical for the row, make it basic.

  This code will snap the value of x to bound if it's within the primal
  feasibility tolerance.
*/
	if (rowstat && sol) {
	  int numberBasic = 0 ;
	  double movement = 0 ;
	  if (prob->columnIsBasic(tgtcolx))
	    numberBasic++ ;
	  if (prob->columnIsBasic(tgtcoly))
	    numberBasic++ ;
	  if (prob->rowIsBasic(tgtrow))
	    numberBasic++ ;
	  if (sol[tgtcolx] <= lo2+ztolzb) {
	    movement = lo2-sol[tgtcolx] ;
	    sol[tgtcolx] = lo2 ;
	    prob->setColumnStatus(tgtcolx,
	    			  CoinPrePostsolveMatrix::atLowerBound) ;
	  } else if (sol[tgtcolx] >= up2-ztolzb) {
	    movement = up2-sol[tgtcolx] ;
	    sol[tgtcolx] = up2 ;
	    prob->setColumnStatus(tgtcolx,
	    			  CoinPrePostsolveMatrix::atUpperBound) ;
	  }
	  if (numberBasic > 1)
	    prob->setColumnStatus(tgtcolx,CoinPrePostsolveMatrix::basic) ;
/*
  We need to compensate if x was forced to move. Beyond that, even if x
  didn't move, we've forced y = (c-ax)/b, and that might not have been
  true before. So even if x didn't move, y may have moved. Note that the
  constant term c/b is subtracted out as the constraints are modified,
  so we don't include it when calculating movement for y.
*/
	  if (movement) { 
	    const CoinBigIndex kkcsx = colStarts[tgtcolx] ;
	    const CoinBigIndex kkcex = kkcsx+colLengths[tgtcolx] ;
	    for (CoinBigIndex kcol = kkcsx ; kcol < kkcex ; kcol++) {
	      int row = rowIndices[kcol] ;
	      if (rowLengths[row])
		acts[row] += movement*colCoeffs[kcol] ;
	    }
	  }
	  movement = ((-coeffx*sol[tgtcolx])/coeffy)-sol[tgtcoly] ;
	  if (movement) {
	    const CoinBigIndex kkcsy = colStarts[tgtcoly] ;
	    const CoinBigIndex kkcey = kkcsy+colLengths[tgtcoly] ;
	    for (CoinBigIndex kcol = kkcsy ; kcol < kkcey ; kcol++) {
	      int row = rowIndices[kcol] ;
	      if (rowLengths[row])
		acts[row] += movement*colCoeffs[kcol] ;
	    }
	  }
	}
	if (lo2 == up2)
	  fixed[nfixed++] = tgtcolx ;
      }
    }
/*
  We're done transferring bounds from y to x, and we've patched up the
  solution if one existed to patch. One last thing to do before we eliminate
  column y and the doubleton row: put column x and the entangled rows on
  the lists of columns and rows to look at in the next round of transforms.
*/
    {
      prob->addCol(tgtcolx) ;
      const CoinBigIndex kkcsy = colStarts[tgtcoly] ;
      const CoinBigIndex kkcey = kkcsy+colLengths[tgtcoly] ;
      for (CoinBigIndex kcol = kkcsy ; kcol < kkcey ; kcol++) {
	int row = rowIndices[kcol] ;
	prob->addRow(row) ;
      }
      const CoinBigIndex kkcsx = colStarts[tgtcolx] ;
      const CoinBigIndex kkcex = kkcsx+colLengths[tgtcolx] ;
      for (CoinBigIndex kcol = kkcsx ; kcol < kkcex ; kcol++) {
	int row = rowIndices[kcol] ;
	prob->addRow(row) ;
      }
    }

/*
  Empty tgtrow in the column-major matrix.  Deleting the coefficient for
  (tgtrow,tgtcoly) is a bit costly (given that we're about to drop the whole
  column), but saves the trouble of checking for it in elim_doubleton.
*/
    presolve_delete_from_col(tgtrow,tgtcolx,
    			     colStarts,colLengths,rowIndices,colCoeffs) ;
    presolve_delete_from_col(tgtrow,tgtcoly,
    			     colStarts,colLengths,rowIndices,colCoeffs) ;
/*
  Drop tgtrow in the row-major representation: set the length to 0
  and reclaim the major vector space in bulk storage.
*/
    rowLengths[tgtrow] = 0 ;
    PRESOLVE_REMOVE_LINK(rlink,tgtrow) ;

/*
  Transfer the colx factors to coly. This modifies coefficients in column x
  as it removes coefficients in column y.
*/
    bool no_mem = elim_doubleton("ELIMD",
				 colStarts,rlo,rup,colCoeffs,
				 rowIndices,colIndices,rowLengths,colLengths,
				 clink,n, 
				 rowStarts,rowCoeffs,
				 -coeffx/coeffy,
				 rhs/coeffy,
				 tgtrow,tgtcolx,tgtcoly) ;
    if (no_mem) 
      throwCoinError("out of memory","doubleton_action::presolve") ;

/*
  Eliminate coly entirely from the col rep. We'll want to groom colx to remove
  explicit zeros.
*/
    colLengths[tgtcoly] = 0 ;
    PRESOLVE_REMOVE_LINK(clink, tgtcoly) ;
    cost[tgtcoly] = 0.0 ;

    rlo[tgtrow] = 0.0 ;
    rup[tgtrow] = 0.0 ;

    zeros[nzeros++] = tgtcolx ;

#   if PRESOLVE_CONSISTENCY > 0
    presolve_consistent(prob) ;
    presolve_links_ok(prob) ;
#   endif
  }
/*
  Tidy up the collected actions and clean up explicit zeros and fixed
  variables. Don't bother unless we're feasible (status of 0).
*/
  if (nactions && !prob->status_) {
#   if PRESOLVE_SUMMARY > 0
    printf("NDOUBLETONS:  %d\n", nactions) ;
#   endif
    action *actions1 = new action[nactions] ;
    CoinMemcpyN(actions, nactions, actions1) ;

    next = new doubleton_action(nactions, actions1, next) ;

    if (nzeros)
      next = drop_zero_coefficients_action::presolve(prob, zeros, nzeros, next) ;
    if (nfixed)
      next = remove_fixed_action::presolve(prob, fixed, nfixed, next) ;
  }

  deleteAction(actions,action*) ;

# if COIN_PRESOLVE_TUNING > 0
  if (prob->tuning_) double thisTime = CoinCpuTime() ;
# endif
# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
  presolve_check_sol(prob) ;
# endif
# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
  std::cout
    << "Leaving doubleton_action::presolve, " << droppedRows << " rows, "
    << droppedColumns << " columns dropped" ;
# if COIN_PRESOLVE_TUNING > 0
  std::cout << " in " << thisTime-startTime << "s" ;
# endif
  std::cout << "." << std::endl ;
# endif

  return (next) ;
}