// Copyright (C) 2003, International Business Machines // Corporation and others. All Rights Reserved. #include #include "CoinPragma.hpp" #include "CoinIndexedVector.hpp" #include "CoinPackedVector.hpp" #include "CoinHelperFunctions.hpp" #include "ClpSimplex.hpp" #include "ClpFactorization.hpp" // at end to get min/max! #include "ClpPlusMinusOneMatrix.hpp" #include "ClpMessage.hpp" //############################################################################# // Constructors / Destructor / Assignment //############################################################################# //------------------------------------------------------------------- // Default Constructor //------------------------------------------------------------------- ClpPlusMinusOneMatrix::ClpPlusMinusOneMatrix () : ClpMatrixBase() { setType(12); matrix_ = NULL; startPositive_ = NULL; startNegative_ = NULL; lengths_=NULL; indices_=NULL; numberRows_=0; numberColumns_=0; columnOrdered_=true; } //------------------------------------------------------------------- // Copy constructor //------------------------------------------------------------------- ClpPlusMinusOneMatrix::ClpPlusMinusOneMatrix (const ClpPlusMinusOneMatrix & rhs) : ClpMatrixBase(rhs) { matrix_ = NULL; startPositive_ = NULL; startNegative_ = NULL; lengths_=NULL; indices_=NULL; numberRows_=rhs.numberRows_; numberColumns_=rhs.numberColumns_; columnOrdered_=rhs.columnOrdered_; if (numberColumns_) { CoinBigIndex numberElements = rhs.startPositive_[numberColumns_]; indices_ = new int [ numberElements]; memcpy(indices_,rhs.indices_,numberElements*sizeof(int)); startPositive_ = new CoinBigIndex [ numberColumns_+1]; memcpy(startPositive_,rhs.startPositive_,(numberColumns_+1)*sizeof(CoinBigIndex)); startNegative_ = new CoinBigIndex [ numberColumns_]; memcpy(startNegative_,rhs.startNegative_,numberColumns_*sizeof(CoinBigIndex)); } int numberRows = getNumRows(); if (rhs.rhsOffset_&&numberRows) { rhsOffset_ = ClpCopyOfArray(rhs.rhsOffset_,numberRows); } else { rhsOffset_=NULL; } } // Constructor from arrays ClpPlusMinusOneMatrix::ClpPlusMinusOneMatrix(int numberRows, int numberColumns, bool columnOrdered, const int * indices, const CoinBigIndex * startPositive, const CoinBigIndex * startNegative) : ClpMatrixBase() { setType(12); matrix_ = NULL; lengths_=NULL; numberRows_=numberRows; numberColumns_=numberColumns; columnOrdered_=columnOrdered; int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_; int numberElements = startPositive[numberMajor]; startPositive_ = ClpCopyOfArray(startPositive,numberMajor+1); startNegative_ = ClpCopyOfArray(startNegative,numberMajor); indices_ = ClpCopyOfArray(indices,numberElements); // Check valid checkValid(false); } ClpPlusMinusOneMatrix::ClpPlusMinusOneMatrix (const CoinPackedMatrix & rhs) : ClpMatrixBase() { setType(12); matrix_ = NULL; startPositive_ = NULL; startNegative_ = NULL; lengths_=NULL; indices_=NULL; int iColumn; assert (rhs.isColOrdered()); // get matrix data pointers const int * row = rhs.getIndices(); const CoinBigIndex * columnStart = rhs.getVectorStarts(); const int * columnLength = rhs.getVectorLengths(); const double * elementByColumn = rhs.getElements(); numberColumns_ = rhs.getNumCols(); numberRows_=-1; indices_ = new int[rhs.getNumElements()]; startPositive_ = new CoinBigIndex [numberColumns_+1]; startNegative_ = new CoinBigIndex [numberColumns_]; int * temp = new int [rhs.getNumRows()]; CoinBigIndex j=0; CoinBigIndex numberGoodP=0; CoinBigIndex numberGoodM=0; CoinBigIndex numberBad=0; for (iColumn=0;iColumn=0 && kRow < numberMinor1) { if (newRow[kRow]<0) { // first time newRow[kRow]=iRow; } else { // duplicate int lastRow = newRow[kRow]; newRow[kRow]=iRow; duplicateRow[iRow] = lastRow; } } else { // bad row numberBad++; } } if (numberBad) throw CoinError("bad minor entries", "subset constructor", "ClpPlusMinusOneMatrix"); // now get size and check columns CoinBigIndex size = 0; int iColumn; numberBad=0; for (iColumn=0;iColumn=0 && kColumn =0) { size++; kRow = duplicateRow[kRow]; } } } else { // bad column numberBad++; printf("%d %d %d %d\n",iColumn,numberMajor,numberMajor1,kColumn); } } if (numberBad) throw CoinError("bad major entries", "subset constructor", "ClpPlusMinusOneMatrix"); // now create arrays startPositive_ = new CoinBigIndex [numberMajor+1]; startNegative_ = new CoinBigIndex [numberMajor]; indices_ = new int[size]; // and fill them size = 0; startPositive_[0]=0; CoinBigIndex * startNegative1 = rhs.startNegative_; for (iColumn=0;iColumn=0) { indices_[size++] = kRow; kRow = duplicateRow[kRow]; } } startNegative_[iColumn] = size; for (;i=0) { indices_[size++] = kRow; kRow = duplicateRow[kRow]; } } startPositive_[iColumn+1] = size; } delete [] newRow; delete [] duplicateRow; } // Check valid checkValid(false); } /* Returns a new matrix in reverse order without gaps */ ClpMatrixBase * ClpPlusMinusOneMatrix::reverseOrderedCopy() const { int numberMinor = (!columnOrdered_) ? numberColumns_ : numberRows_; int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_; // count number in each row/column CoinBigIndex * tempP = new CoinBigIndex [numberMinor]; CoinBigIndex * tempN = new CoinBigIndex [numberMinor]; memset(tempP,0,numberMinor*sizeof(CoinBigIndex)); memset(tempN,0,numberMinor*sizeof(CoinBigIndex)); CoinBigIndex j=0; int i; for (i=0;ipassInCopy(numberMinor, numberMajor, !columnOrdered_, newIndices, newP, newN); return newCopy; } //unscaled versions void ClpPlusMinusOneMatrix::times(double scalar, const double * x, double * y) const { int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_; int i; CoinBigIndex j; assert (columnOrdered_); for (i=0;ix * A + y in z. Squashes small elements and knows about ClpSimplex */ void ClpPlusMinusOneMatrix::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(); bool packed = rowArray->packedMode(); #ifndef NO_RTTI ClpPlusMinusOneMatrix* rowCopy = dynamic_cast< ClpPlusMinusOneMatrix*>(model->rowCopy()); #else ClpPlusMinusOneMatrix* rowCopy = static_cast< ClpPlusMinusOneMatrix*>(model->rowCopy()); #endif 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*10factor*numberRows||!rowCopy) { assert (!y->getNumElements()); // do by column // Need to expand if packed mode int iColumn; CoinBigIndex j=0; assert (columnOrdered_); 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; } } for (i=0;izeroTolerance) { index[numberNonZero++]=iColumn; array[iColumn]=value; } } } columnArray->setNumElements(numberNonZero); } else { // do by row rowCopy->transposeTimesByRow(model, scalar, rowArray, y, columnArray); } } /* Return x * A + y in z. Squashes small elements and knows about ClpSimplex */ void ClpPlusMinusOneMatrix::transposeTimesByRow(const ClpSimplex * model, double scalar, const CoinIndexedVector * rowArray, CoinIndexedVector * y, CoinIndexedVector * columnArray) const { 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(); const int * column = indices_; const CoinBigIndex * startPositive = startPositive_; const CoinBigIndex * startNegative = startNegative_; const int * whichRow = rowArray->getIndices(); bool packed = rowArray->packedMode(); if (numberInRowArray>2) { // do by rows int iRow; double * markVector = y->denseVector(); // probably empty .. but int numberOriginal=0; int i; if (packed) { numberNonZero=0; // and set up mark as char array char * marked = (char *) (index+columnArray->capacity()); double * array2 = y->denseVector(); #ifdef CLP_DEBUG int numberColumns = model->numberColumns(); for (i=0;izeroTolerance) { array[numberNonZero]=value; index[numberNonZero++]=iColumn; } } } } else { numberNonZero=0; // and set up mark as char array char * marked = (char *) markVector; for (i=0;izeroTolerance) { index[numberNonZero++]=iColumn; } else { array[iColumn]=0.0; } } } } else if (numberInRowArray==2) { /* do by rows when two rows (do longer first when not packed and shorter first if packed */ int iRow0 = whichRow[0]; int iRow1 = whichRow[1]; CoinBigIndex j; if (packed) { double pi0 = pi[0]; double pi1 = pi[1]; if (startPositive[iRow0+1]-startPositive[iRow0]> startPositive[iRow1+1]-startPositive[iRow1]) { int temp = iRow0; iRow0 = iRow1; iRow1 = temp; pi0=pi1; pi1=pi[0]; } // and set up mark as char array char * marked = (char *) (index+columnArray->capacity()); int * lookup = y->getIndices(); double value = pi0*scalar; for (j=startPositive[iRow0];jzeroTolerance) { array[numberNonZero] = value; index[numberNonZero++]=iColumn; } } } for (j=startNegative[iRow1];jzeroTolerance) { array[numberNonZero] = -value; index[numberNonZero++]=iColumn; } } } // get rid of tiny values and zero out marked int nDelete=0; for (j=0;jzeroTolerance) { array[numberNonZero]=value; index[numberNonZero++]=iColumn; } } } } else { if (startPositive[iRow0+1]-startPositive[iRow0]< startPositive[iRow1+1]-startPositive[iRow1]) { int temp = iRow0; iRow0 = iRow1; iRow1 = temp; } int numberOriginal; int i; numberNonZero=0; double value; value = pi[iRow0]*scalar; CoinBigIndex j; for (j=startPositive[iRow0];jzeroTolerance) { index[numberNonZero++]=iColumn; } else { array[iColumn]=0.0; } } } } else if (numberInRowArray==1) { // Just one row int iRow=rowArray->getIndices()[0]; numberNonZero=0; double value; iRow = whichRow[0]; CoinBigIndex j; if (packed) { value = pi[0]*scalar; if (fabs(value)>zeroTolerance) { for (j=startPositive[iRow];jzeroTolerance) { for (j=startPositive[iRow];jsetNumElements(numberNonZero); if (packed) columnArray->setPacked(); y->setNumElements(0); } /* Return x *A in z but just for indices in y. */ void ClpPlusMinusOneMatrix::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(); for (jColumn=0;jColumnadd(iRow,1.0); } for (;jadd(iRow,-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 ClpPlusMinusOneMatrix::unpackPacked(ClpSimplex * model, CoinIndexedVector * rowArray, int iColumn) const { int * index = rowArray->getIndices(); double * array = rowArray->denseVector(); int number = 0; CoinBigIndex j=startPositive_[iColumn]; for (;jsetNumElements(number); rowArray->setPackedMode(true); } /* Adds multiple of a column into an CoinIndexedvector You can use quickAdd to add to vector */ void ClpPlusMinusOneMatrix::add(const ClpSimplex * model,CoinIndexedVector * rowArray, int iColumn, double multiplier) const { CoinBigIndex j=startPositive_[iColumn]; for (;jquickAdd(iRow,multiplier); } for (;jquickAdd(iRow,-multiplier); } } /* Adds multiple of a column into an array */ void ClpPlusMinusOneMatrix::add(const ClpSimplex * model,double * array, int iColumn, double multiplier) const { CoinBigIndex j=startPositive_[iColumn]; for (;jgetElements(); } const CoinBigIndex * ClpPlusMinusOneMatrix::getVectorStarts() const { return startPositive_; } /* The lengths of the major-dimension vectors. */ const int * ClpPlusMinusOneMatrix::getVectorLengths() const { if (!lengths_) { int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_; lengths_ = new int [numberMajor]; int i; for (i=0;iindDel. */ void ClpPlusMinusOneMatrix::deleteCols(const int numDel, const int * indDel) { int iColumn; CoinBigIndex newSize=startPositive_[numberColumns_];; int numberBad=0; // Use array to make sure we can have duplicates int * which = new int[numberColumns_]; memset(which,0,numberColumns_*sizeof(int)); int nDuplicate=0; for (iColumn=0;iColumn=numberColumns_) { numberBad++; } else { newSize -= startPositive_[jColumn+1]-startPositive_[jColumn]; if (which[jColumn]) nDuplicate++; else which[jColumn]=1; } } if (numberBad) throw CoinError("Indices out of range", "deleteCols", "ClpPlusMinusOneMatrix"); int newNumber = numberColumns_-numDel+nDuplicate; // Get rid of temporary arrays delete [] lengths_; lengths_=NULL; delete matrix_; matrix_= NULL; CoinBigIndex * newPositive = new CoinBigIndex [newNumber+1]; CoinBigIndex * newNegative = new CoinBigIndex [newNumber]; int * newIndices = new int [newSize]; newNumber=0; newSize=0; for (iColumn=0;iColumnindDel. */ void ClpPlusMinusOneMatrix::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)); int nDuplicate=0; for (iRow=0;iRow=numberRows_) { numberBad++; } else { if (which[jRow]) nDuplicate++; else which[jRow]=1; } } if (numberBad) throw CoinError("Indices out of range", "deleteRows", "ClpPlusMinusOneMatrix"); CoinBigIndex iElement; CoinBigIndex numberElements=startPositive_[numberColumns_]; CoinBigIndex newSize=0; for (iElement=0;iElement=0); if (detail) { if (minIndex>0||maxIndex+1<(columnOrdered_ ? numberRows_ : numberColumns_)) printf("Not full range of indices - %d to %d\n",minIndex,maxIndex); } } /* Given positive integer weights for each row fills in sum of weights for each column (and slack). Returns weights vector */ CoinBigIndex * ClpPlusMinusOneMatrix::dubiousWeights(const ClpSimplex * model,int * inputWeights) const { int numberRows = model->numberRows(); int numberColumns =model->numberColumns(); int number = numberRows+numberColumns; CoinBigIndex * weights = new CoinBigIndex[number]; int i; for (i=0;igetNumElements(); const double * element = columns[iColumn]->getElements(); size += n; int i; for (i=0;igetNumElements(); const int * row = columns[iColumn]->getIndices(); const double * element = columns[iColumn]->getElements(); int i; for (i=0;igetNumElements(); const int * column = rows[iRow]->getIndices(); const double * element = rows[iRow]->getElements(); size += n; int i; for (i=0;igetNumElements(); const int * column = rows[iRow]->getIndices(); const double * element = rows[iRow]->getElements(); int i; for (i=0;istartPositive_[iColumn]) plusOne=true; if (startPositive_[iColumn+1]>startNegative_[iColumn]) minusOne=true; } if (minusOne) { smallestNegative=-1.0; largestNegative=-1.0; } else { smallestNegative=0.0; largestNegative=0.0; } if (plusOne) { smallestPositive=1.0; largestPositive=1.0; } else { smallestPositive=0.0; largestPositive=0.0; } } // Says whether it can do partial pricing bool ClpPlusMinusOneMatrix::canDoPartialPricing() const { return true; } // Partial pricing void ClpPlusMinusOneMatrix::partialPricing(ClpSimplex * model, double startFraction, double endFraction, int & bestSequence, int & numberWanted) { numberWanted=currentWanted_; int start = (int) (startFraction*numberColumns_); int end = CoinMin((int) (endFraction*numberColumns_+1),numberColumns_); CoinBigIndex j; double tolerance=model->currentDualTolerance(); double * reducedCost = model->djRegion(); const double * duals = model->dualRowSolution(); const double * cost = model->costRegion(); double bestDj; if (bestSequence>=0) bestDj = fabs(reducedCost[bestSequence]); else bestDj=tolerance; int sequenceOut = model->sequenceOut(); int saveSequence = bestSequence; int 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=startPositive_[iSequence]; for (;jFREE_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=startPositive_[iSequence]; for (;jtolerance) { 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=startPositive_[iSequence]; for (;jtolerance) { 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=startPositive_[bestSequence]; for (;jgetNumElements(); int numberRows = model->numberRows(); bool packed = pi->packedMode(); // factor should be smaller if doing both with two pi vectors double factor = 0.27; // We may not want to do by row if there may be cache problems // 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 not packed then bias a bit more towards by column if (!packed) factor *= 0.9; return (numberInRowArray>factor*numberRows||!model->rowCopy()); } // These have to match ClpPrimalColumnSteepest version #define reference(i) (((reference[i>>5]>>(i&31))&1)!=0) // Updates two arrays for steepest void ClpPlusMinusOneMatrix::transposeTimes2(const ClpSimplex * model, const CoinIndexedVector * pi1, CoinIndexedVector * dj1, const CoinIndexedVector * pi2, CoinIndexedVector * dj2, CoinIndexedVector * spare, double referenceIn, double devex, // Array for exact devex to say what is in reference framework unsigned int * reference, double * weights, double scaleFactor) { // put row of tableau in dj1 double * pi = pi1->denseVector(); int numberNonZero=0; int * index = dj1->getIndices(); double * array = dj1->denseVector(); int numberInRowArray = pi1->getNumElements(); double zeroTolerance = model->factorization()->zeroTolerance(); bool packed = pi1->packedMode(); // do by column int iColumn; assert (!spare->getNumElements()); double * piWeight = pi2->denseVector(); assert (!pi2->packedMode()); bool killDjs = (scaleFactor==0.0); if (!scaleFactor) scaleFactor=1.0; // Note scale factor was -1.0 if (packed) { // need to expand pi into y assert(spare->capacity()>=model->numberRows()); double * piOld = pi; pi = spare->denseVector(); const int * whichRow = pi1->getIndices(); int i; // modify pi so can collapse to one loop for (i=0;igetStatus(iColumn); if (status==ClpSimplex::basic||status==ClpSimplex::isFixed) continue; double value = 0.0; for (j=startPositive_[iColumn];jzeroTolerance) { // and do other array double modification = 0.0; for (j=startPositive_[iColumn];jgetStatus(iColumn); if (status==ClpSimplex::basic||status==ClpSimplex::isFixed) continue; double value = 0.0; for (j=startPositive_[iColumn];jzeroTolerance) { // and do other array double modification = 0.0; for (j=startPositive_[iColumn];jsetNumElements(numberNonZero); spare->setNumElements(0); if (packed) dj1->setPackedMode(true); } // Updates second array for steepest and does devex weights void ClpPlusMinusOneMatrix::subsetTimes2(const ClpSimplex * model, CoinIndexedVector * dj1, const CoinIndexedVector * pi2, CoinIndexedVector * dj2, double referenceIn, double devex, // Array for exact devex to say what is in reference framework unsigned int * reference, double * weights, double scaleFactor) { int number = dj1->getNumElements(); const int * index = dj1->getIndices(); double * array = dj1->denseVector(); assert( dj1->packedMode()); double * piWeight = pi2->denseVector(); bool killDjs = (scaleFactor==0.0); if (!scaleFactor) scaleFactor=1.0; for (int k=0;k length) { CoinBigIndex * temp; int i; CoinBigIndex end = startPositive_[length]; temp = new CoinBigIndex [number+1]; memcpy(temp,startPositive_,(length+1)*sizeof(CoinBigIndex)); delete [] startPositive_; for (i=length+1;i0) or duplicates If 0 then rows, 1 if columns */ int ClpPlusMinusOneMatrix::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