// Copyright (C) 2003, International Business Machines // Corporation and others. All Rights Reserved. #include #include "CoinPragma.hpp" #include "CoinIndexedVector.hpp" #include "CoinHelperFunctions.hpp" #include "CoinPackedVector.hpp" #include "ClpSimplex.hpp" #include "ClpFactorization.hpp" // at end to get min/max! #include "ClpNetworkMatrix.hpp" #include "ClpPlusMinusOneMatrix.hpp" #include "ClpMessage.hpp" #include #include //############################################################################# // Constructors / Destructor / Assignment //############################################################################# //------------------------------------------------------------------- // Default Constructor //------------------------------------------------------------------- ClpNetworkMatrix::ClpNetworkMatrix () : ClpMatrixBase() { setType(11); matrix_ = NULL; lengths_=NULL; indices_=NULL; numberRows_=0; numberColumns_=0; trueNetwork_=false; } /* Constructor from two arrays */ ClpNetworkMatrix::ClpNetworkMatrix(int numberColumns, const int * head, const int * tail) : ClpMatrixBase() { setType(11); matrix_ = NULL; lengths_=NULL; indices_=new int[2*numberColumns];; numberRows_=-1; numberColumns_=numberColumns; trueNetwork_=true; int iColumn; CoinBigIndex j=0; for (iColumn=0;iColumn0; } } //------------------------------------------------------------------- // Destructor //------------------------------------------------------------------- ClpNetworkMatrix::~ClpNetworkMatrix () { delete matrix_; delete [] lengths_; delete [] indices_; } //---------------------------------------------------------------- // Assignment operator //------------------------------------------------------------------- ClpNetworkMatrix & ClpNetworkMatrix::operator=(const ClpNetworkMatrix& rhs) { if (this != &rhs) { ClpMatrixBase::operator=(rhs); delete matrix_; delete [] lengths_; delete [] indices_; matrix_ = NULL; lengths_=NULL; indices_=NULL; numberRows_=rhs.numberRows_; numberColumns_=rhs.numberColumns_; trueNetwork_=rhs.trueNetwork_; if (numberColumns_) { indices_ = new int [ 2*numberColumns_]; memcpy(indices_,rhs.indices_,2*numberColumns_*sizeof(int)); } } return *this; } //------------------------------------------------------------------- // Clone //------------------------------------------------------------------- ClpMatrixBase * ClpNetworkMatrix::clone() const { return new ClpNetworkMatrix(*this); } /* Returns a new matrix in reverse order without gaps */ ClpMatrixBase * ClpNetworkMatrix::reverseOrderedCopy() const { // count number in each row CoinBigIndex * tempP = new CoinBigIndex [numberRows_]; CoinBigIndex * tempN = new CoinBigIndex [numberRows_]; memset(tempP,0,numberRows_*sizeof(CoinBigIndex)); memset(tempN,0,numberRows_*sizeof(CoinBigIndex)); CoinBigIndex j=0; int i; for (i=0;ipassInCopy(numberRows_, numberColumns_, false, newIndices, newP, newN); return newCopy; } //unscaled versions void ClpNetworkMatrix::times(double scalar, const double * x, double * y) const { int iColumn; CoinBigIndex j=0; if (trueNetwork_) { for (iColumn=0;iColumn=0) y[iRowM] -= value; if (iRowP>=0) y[iRowP] += value; } } } } void ClpNetworkMatrix::transposeTimes(double scalar, const double * x, double * y) const { int iColumn; CoinBigIndex j=0; if (trueNetwork_) { for (iColumn=0;iColumn=0) value -= scalar*x[iRowM]; if (iRowP>=0) value += scalar*x[iRowP]; y[iColumn] = value; } } } void ClpNetworkMatrix::times(double scalar, const double * x, double * y, const double * rowScale, const double * columnScale) const { // we know it is not scaled times(scalar, x, y); } void ClpNetworkMatrix::transposeTimes( double scalar, const double * x, double * y, const double * rowScale, const double * columnScale, double * spare) const { // we know it is not scaled transposeTimes(scalar, x, y); } /* Return x * A + y in z. Squashes small elements and knows about ClpSimplex */ void ClpNetworkMatrix::transposeTimes(const ClpSimplex * model, double scalar, const CoinIndexedVector * rowArray, CoinIndexedVector * y, CoinIndexedVector * columnArray) const { // we know it is not scaled columnArray->clear(); double * pi = rowArray->denseVector(); int numberNonZero=0; int * index = columnArray->getIndices(); double * array = columnArray->denseVector(); int numberInRowArray = rowArray->getNumElements(); // maybe I need one in OsiSimplex double zeroTolerance = model->factorization()->zeroTolerance(); int numberRows = model->numberRows(); #ifndef NO_RTTI ClpPlusMinusOneMatrix* rowCopy = dynamic_cast< ClpPlusMinusOneMatrix*>(model->rowCopy()); #else ClpPlusMinusOneMatrix* rowCopy = static_cast< ClpPlusMinusOneMatrix*>(model->rowCopy()); #endif bool packed = rowArray->packedMode(); double factor = 0.3; // We may not want to do by row if there may be cache problems int numberColumns = model->numberColumns(); // It would be nice to find L2 cache size - for moment 512K // Be slightly optimistic if (numberColumns*sizeof(double)>1000000) { if (numberRows*10numberIterations()%50==0) //printf("%d nonzero\n",numberInRowArray); } if (numberInRowArray>factor*numberRows||!rowCopy) { // do by column int iColumn; assert (!y->getNumElements()); CoinBigIndex j=0; if (packed) { // need to expand pi into y assert(y->capacity()>=numberRows); double * piOld = pi; pi = y->denseVector(); const int * whichRow = rowArray->getIndices(); int i; // modify pi so can collapse to one loop for (i=0;izeroTolerance) { array[numberNonZero]=value; index[numberNonZero++]=iColumn; } } } else { // skip negative rows for (iColumn=0;iColumn=0) value -= pi[iRowM]; if (iRowP>=0) value += pi[iRowP]; if (fabs(value)>zeroTolerance) { array[numberNonZero]=value; index[numberNonZero++]=iColumn; } } } for (i=0;izeroTolerance) { index[numberNonZero++]=iColumn; array[iColumn]=value; } } } else { // skip negative rows for (iColumn=0;iColumn=0) value -= scalar*pi[iRowM]; if (iRowP>=0) value += scalar*pi[iRowP]; if (fabs(value)>zeroTolerance) { index[numberNonZero++]=iColumn; array[iColumn]=value; } } } } columnArray->setNumElements(numberNonZero); } else { // do by row rowCopy->transposeTimesByRow(model, scalar, rowArray, y, columnArray); } } /* Return x *A in z but just for indices in y. */ void ClpNetworkMatrix::subsetTransposeTimes(const ClpSimplex * model, const CoinIndexedVector * rowArray, const CoinIndexedVector * y, CoinIndexedVector * columnArray) const { columnArray->clear(); double * pi = rowArray->denseVector(); double * array = columnArray->denseVector(); int jColumn; int numberToDo = y->getNumElements(); const int * which = y->getIndices(); assert (!rowArray->packedMode()); columnArray->setPacked(); if (trueNetwork_) { for (jColumn=0;jColumn=0) value -= pi[iRowM]; if (iRowP>=0) value += pi[iRowP]; array[jColumn]=value; } } } /// returns number of elements in column part of basis, CoinBigIndex ClpNetworkMatrix::countBasis(ClpSimplex * model, const int * whichColumn, int numberBasic, int & numberColumnBasic) { int i; CoinBigIndex numberElements=0; if (trueNetwork_) { numberElements = 2*numberColumnBasic; } else { for (i=0;i=0) numberElements ++; if (iRowP>=0) numberElements ++; } } return numberElements; } void ClpNetworkMatrix::fillBasis(ClpSimplex * model, const int * whichColumn, int & numberColumnBasic, int * indexRowU, int * start, int * rowCount, int * columnCount, double * elementU) { int i; CoinBigIndex numberElements=start[0]; if (trueNetwork_) { for (i=0;i=0) { indexRowU[numberElements]=iRowM; rowCount[iRowM]++; elementU[numberElements++]=-1.0; } if (iRowP>=0) { indexRowU[numberElements]=iRowP; rowCount[iRowP]++; elementU[numberElements++]=1.0; } start[i+1]=numberElements; columnCount[i]=numberElements-start[i]; } } } /* Unpacks a column into an CoinIndexedvector */ void ClpNetworkMatrix::unpack(const ClpSimplex * model,CoinIndexedVector * rowArray, int iColumn) const { CoinBigIndex j=iColumn<<1; int iRowM = indices_[j]; int iRowP = indices_[j+1]; if (iRowM>=0) rowArray->add(iRowM,-1.0); if (iRowP>=0) rowArray->add(iRowP,1.0); } /* Unpacks a column into an CoinIndexedvector ** in packed foramt Note that model is NOT const. Bounds and objective could be modified if doing column generation (just for this variable) */ void ClpNetworkMatrix::unpackPacked(ClpSimplex * model, CoinIndexedVector * rowArray, int iColumn) const { int * index = rowArray->getIndices(); double * array = rowArray->denseVector(); int number = 0; CoinBigIndex j=iColumn<<1; int iRowM = indices_[j]; int iRowP = indices_[j+1]; if (iRowM>=0) { array[number]=-1.0; index[number++]=iRowM; } if (iRowP>=0) { array[number]=1.0; index[number++]=iRowP; } rowArray->setNumElements(number); rowArray->setPackedMode(true); } /* Adds multiple of a column into an CoinIndexedvector You can use quickAdd to add to vector */ void ClpNetworkMatrix::add(const ClpSimplex * model,CoinIndexedVector * rowArray, int iColumn, double multiplier) const { CoinBigIndex j=iColumn<<1; int iRowM = indices_[j]; int iRowP = indices_[j+1]; if (iRowM>=0) rowArray->quickAdd(iRowM,-multiplier); if (iRowP>=0) rowArray->quickAdd(iRowP,multiplier); } /* Adds multiple of a column into an array */ void ClpNetworkMatrix::add(const ClpSimplex * model,double * array, int iColumn, double multiplier) const { CoinBigIndex j=iColumn<<1; int iRowM = indices_[j]; int iRowP = indices_[j+1]; if (iRowM>=0) array[iRowM] -= multiplier; if (iRowP>=0) array[iRowP] += multiplier; } // Return a complete CoinPackedMatrix CoinPackedMatrix * ClpNetworkMatrix::getPackedMatrix() const { if (!matrix_) { assert (trueNetwork_); // fix later int numberElements = 2*numberColumns_; double * elements = new double [numberElements]; CoinBigIndex i; for (i=0;i<2*numberColumns_;i+=2) { elements[i]=-1.0; elements[i+1]=1.0; } CoinBigIndex * starts = new CoinBigIndex [numberColumns_+1]; for (i=0;iassignMatrix(true,numberRows_,numberColumns_, getNumElements(), elements,indices, starts,lengths_); assert(!elements); assert(!starts); assert (!indices); assert (!lengths_); } return matrix_; } /* A vector containing the elements in the packed matrix. Note that there might be gaps in this list, entries that do not belong to any major-dimension vector. To get the actual elements one should look at this vector together with vectorStarts and vectorLengths. */ const double * ClpNetworkMatrix::getElements() const { if (!matrix_) getPackedMatrix(); return matrix_->getElements(); } const CoinBigIndex * ClpNetworkMatrix::getVectorStarts() const { if (!matrix_) getPackedMatrix(); return matrix_->getVectorStarts(); } /* The lengths of the major-dimension vectors. */ const int * ClpNetworkMatrix::getVectorLengths() const { assert (trueNetwork_); // fix later if (!lengths_) { lengths_ = new int [numberColumns_]; int i; for (i=0;iindDel. */ void ClpNetworkMatrix::deleteCols(const int numDel, const int * indDel) { assert (trueNetwork_); int iColumn; int numberBad=0; // Use array to make sure we can have duplicates char * which = new char[numberColumns_]; memset(which,0,numberColumns_); int nDuplicate=0; for (iColumn=0;iColumn=numberColumns_) { numberBad++; } else { if (which[jColumn]) nDuplicate++; else which[jColumn]=1; } } if (numberBad) throw CoinError("Indices out of range", "deleteCols", "ClpNetworkMatrix"); int newNumber = numberColumns_-numDel+nDuplicate; // Get rid of temporary arrays delete [] lengths_; lengths_=NULL; delete matrix_; matrix_= NULL; int newSize=2*newNumber; int * newIndices = new int [newSize]; newSize=0; for (iColumn=0;iColumnindDel. */ void ClpNetworkMatrix::deleteRows(const int numDel, const int * indDel) { int iRow; int numberBad=0; // Use array to make sure we can have duplicates int * which = new int [numberRows_]; memset(which,0,numberRows_*sizeof(int)); for (iRow=0;iRow=numberRows_) { numberBad++; } else { which[jRow]=1; } } if (numberBad) throw CoinError("Indices out of range", "deleteRows", "ClpNetworkMatrix"); // Only valid of all columns have 0 entries int iColumn; for (iColumn=0;iColumnnumberRows(); int numberColumns =model->numberColumns(); int number = numberRows+numberColumns; CoinBigIndex * weights = new CoinBigIndex[number]; int i; for (i=0;i=0) { count += inputWeights[iRowM]; } if (iRowP>=0) { count += inputWeights[iRowP]; } weights[i]=count; } for (i=0;icurrentDualTolerance(); double * reducedCost = model->djRegion(); const double * duals = model->dualRowSolution(); const double * cost = model->costRegion(); double bestDj; if (bestSequence>=0) bestDj = fabs(reducedCost[bestSequence]); else bestDj=tolerance; int sequenceOut = model->sequenceOut(); int saveSequence = bestSequence; if (!trueNetwork_) { // Not true network int iSequence; for (iSequence=start;iSequencegetStatus(iSequence); switch(status) { case ClpSimplex::basic: case ClpSimplex::isFixed: break; case ClpSimplex::isFree: case ClpSimplex::superBasic: value=cost[iSequence]; j = iSequence<<1; // skip negative rows iRowM = indices_[j]; iRowP = indices_[j+1]; if (iRowM>=0) value += duals[iRowM]; if (iRowP>=0) value -= duals[iRowP]; value = fabs(value); if (value>FREE_ACCEPT*tolerance) { numberWanted--; // we are going to bias towards free (but only if reasonable) value *= FREE_BIAS; if (value>bestDj) { // check flagged variable and correct dj if (!model->flagged(iSequence)) { bestDj=value; bestSequence = iSequence; } else { // just to make sure we don't exit before got something numberWanted++; } } } break; case ClpSimplex::atUpperBound: value=cost[iSequence]; j = iSequence<<1; // skip negative rows iRowM = indices_[j]; iRowP = indices_[j+1]; if (iRowM>=0) value += duals[iRowM]; if (iRowP>=0) value -= duals[iRowP]; if (value>tolerance) { numberWanted--; if (value>bestDj) { // check flagged variable and correct dj if (!model->flagged(iSequence)) { bestDj=value; bestSequence = iSequence; } else { // just to make sure we don't exit before got something numberWanted++; } } } break; case ClpSimplex::atLowerBound: value=cost[iSequence]; j = iSequence<<1; // skip negative rows iRowM = indices_[j]; iRowP = indices_[j+1]; if (iRowM>=0) value += duals[iRowM]; if (iRowP>=0) value -= duals[iRowP]; value = -value; if (value>tolerance) { numberWanted--; if (value>bestDj) { // check flagged variable and correct dj if (!model->flagged(iSequence)) { bestDj=value; bestSequence = iSequence; } else { // just to make sure we don't exit before got something numberWanted++; } } } break; } } if (!numberWanted) break; } if (bestSequence!=saveSequence) { // recompute dj double value=cost[bestSequence]; j = bestSequence<<1; // skip negative rows int iRowM = indices_[j]; int iRowP = indices_[j+1]; if (iRowM>=0) value += duals[iRowM]; if (iRowP>=0) value -= duals[iRowP]; reducedCost[bestSequence] = value; savedBestSequence_ = bestSequence; savedBestDj_ = reducedCost[savedBestSequence_]; } } else { // true network int iSequence; for (iSequence=start;iSequencegetStatus(iSequence); switch(status) { case ClpSimplex::basic: case ClpSimplex::isFixed: break; case ClpSimplex::isFree: case ClpSimplex::superBasic: value=cost[iSequence]; j = iSequence<<1; iRowM = indices_[j]; iRowP = indices_[j+1]; value += duals[iRowM]; value -= duals[iRowP]; value = fabs(value); if (value>FREE_ACCEPT*tolerance) { numberWanted--; // we are going to bias towards free (but only if reasonable) value *= FREE_BIAS; if (value>bestDj) { // check flagged variable and correct dj if (!model->flagged(iSequence)) { bestDj=value; bestSequence = iSequence; } else { // just to make sure we don't exit before got something numberWanted++; } } } break; case ClpSimplex::atUpperBound: value=cost[iSequence]; j = iSequence<<1; iRowM = indices_[j]; iRowP = indices_[j+1]; value += duals[iRowM]; value -= duals[iRowP]; if (value>tolerance) { numberWanted--; if (value>bestDj) { // check flagged variable and correct dj if (!model->flagged(iSequence)) { bestDj=value; bestSequence = iSequence; } else { // just to make sure we don't exit before got something numberWanted++; } } } break; case ClpSimplex::atLowerBound: value=cost[iSequence]; j = iSequence<<1; iRowM = indices_[j]; iRowP = indices_[j+1]; value += duals[iRowM]; value -= duals[iRowP]; value = -value; if (value>tolerance) { numberWanted--; if (value>bestDj) { // check flagged variable and correct dj if (!model->flagged(iSequence)) { bestDj=value; bestSequence = iSequence; } else { // just to make sure we don't exit before got something numberWanted++; } } } break; } } if (!numberWanted) break; } if (bestSequence!=saveSequence) { // recompute dj double value=cost[bestSequence]; j = bestSequence<<1; int iRowM = indices_[j]; int iRowP = indices_[j+1]; value += duals[iRowM]; value -= duals[iRowP]; reducedCost[bestSequence] = value; savedBestSequence_ = bestSequence; savedBestDj_ = reducedCost[savedBestSequence_]; } } currentWanted_=numberWanted; } // Allow any parts of a created CoinMatrix to be deleted void ClpNetworkMatrix::releasePackedMatrix() const { delete matrix_; delete [] lengths_; matrix_=NULL; lengths_=NULL; } // Append Columns void ClpNetworkMatrix::appendCols(int number, const CoinPackedVectorBase * const * columns) { int iColumn; int numberBad=0; for (iColumn=0;iColumngetNumElements(); const double * element = columns[iColumn]->getElements(); if (n!=2) numberBad++; if (fabs(element[0])!=1.0||fabs(element[1])!=1.0) numberBad++; else if (element[0]*element[1]!=-1.0) numberBad++; } if (numberBad) throw CoinError("Not network", "appendCols", "ClpNetworkMatrix"); // Get rid of temporary arrays delete [] lengths_; lengths_=NULL; delete matrix_; matrix_= NULL; CoinBigIndex size = 2*number; int * temp2 = new int [numberColumns_*2+size]; memcpy(temp2,indices_,numberColumns_*2*sizeof(int)); delete [] indices_; indices_= temp2; // now add size=2*numberColumns_; for (iColumn=0;iColumngetIndices(); const double * element = columns[iColumn]->getElements(); if (element[0]==-1.0) { indices_[size++]=row[0]; indices_[size++]=row[1]; } else { indices_[size++]=row[1]; indices_[size++]=row[0]; } } numberColumns_ += number; } // Append Rows void ClpNetworkMatrix::appendRows(int number, const CoinPackedVectorBase * const * rows) { // must be zero arrays int numberBad=0; int iRow; for (iRow=0;iRowgetNumElements(); } if (numberBad) throw CoinError("Not NULL rows", "appendRows", "ClpNetworkMatrix"); numberRows_ += number; } #ifndef SLIM_CLP /* Append a set of rows/columns to the end of the matrix. Returns number of errors i.e. if any of the new rows/columns contain an index that's larger than the number of columns-1/rows-1 (if numberOther>0) or duplicates If 0 then rows, 1 if columns */ int ClpNetworkMatrix::appendMatrix(int number, int type, const CoinBigIndex * starts, const int * index, const double * element, int numberOther) { int numberErrors=0; // make into CoinPackedVector CoinPackedVectorBase ** vectors= new CoinPackedVectorBase * [number]; int iVector; for (iVector=0;iVector=0&&jRow