/* $Id$ */ // Copyright (C) 2002, International Business Machines // Corporation and others. All Rights Reserved. // This code is licensed under the terms of the Eclipse Public License (EPL). #include "CoinPragma.hpp" #include #include "CoinIndexedVector.hpp" #include "CoinHelperFunctions.hpp" #include "ClpMatrixBase.hpp" #include "ClpSimplex.hpp" //############################################################################# // Constructors / Destructor / Assignment //############################################################################# //------------------------------------------------------------------- // Default Constructor //------------------------------------------------------------------- ClpMatrixBase::ClpMatrixBase() : rhsOffset_(NULL) , startFraction_(0.0) , endFraction_(1.0) , savedBestDj_(0.0) , originalWanted_(0) , currentWanted_(0) , savedBestSequence_(-1) , type_(-1) , lastRefresh_(-1) , refreshFrequency_(0) , minimumObjectsScan_(-1) , minimumGoodReducedCosts_(-1) , trueSequenceIn_(-1) , trueSequenceOut_(-1) , skipDualCheck_(false) { } //------------------------------------------------------------------- // Copy constructor //------------------------------------------------------------------- ClpMatrixBase::ClpMatrixBase(const ClpMatrixBase &rhs) : type_(rhs.type_) , skipDualCheck_(rhs.skipDualCheck_) { startFraction_ = rhs.startFraction_; endFraction_ = rhs.endFraction_; savedBestDj_ = rhs.savedBestDj_; originalWanted_ = rhs.originalWanted_; currentWanted_ = rhs.currentWanted_; savedBestSequence_ = rhs.savedBestSequence_; lastRefresh_ = rhs.lastRefresh_; refreshFrequency_ = rhs.refreshFrequency_; minimumObjectsScan_ = rhs.minimumObjectsScan_; minimumGoodReducedCosts_ = rhs.minimumGoodReducedCosts_; trueSequenceIn_ = rhs.trueSequenceIn_; trueSequenceOut_ = rhs.trueSequenceOut_; skipDualCheck_ = rhs.skipDualCheck_; int numberRows = rhs.getNumRows(); if (rhs.rhsOffset_ && numberRows) { rhsOffset_ = ClpCopyOfArray(rhs.rhsOffset_, numberRows); } else { rhsOffset_ = NULL; } } //------------------------------------------------------------------- // Destructor //------------------------------------------------------------------- ClpMatrixBase::~ClpMatrixBase() { delete[] rhsOffset_; } //---------------------------------------------------------------- // Assignment operator //------------------------------------------------------------------- ClpMatrixBase & ClpMatrixBase::operator=(const ClpMatrixBase &rhs) { if (this != &rhs) { type_ = rhs.type_; delete[] rhsOffset_; int numberRows = rhs.getNumRows(); if (rhs.rhsOffset_ && numberRows) { rhsOffset_ = ClpCopyOfArray(rhs.rhsOffset_, numberRows); } else { rhsOffset_ = NULL; } startFraction_ = rhs.startFraction_; endFraction_ = rhs.endFraction_; savedBestDj_ = rhs.savedBestDj_; originalWanted_ = rhs.originalWanted_; currentWanted_ = rhs.currentWanted_; savedBestSequence_ = rhs.savedBestSequence_; lastRefresh_ = rhs.lastRefresh_; refreshFrequency_ = rhs.refreshFrequency_; minimumObjectsScan_ = rhs.minimumObjectsScan_; minimumGoodReducedCosts_ = rhs.minimumGoodReducedCosts_; trueSequenceIn_ = rhs.trueSequenceIn_; trueSequenceOut_ = rhs.trueSequenceOut_; skipDualCheck_ = rhs.skipDualCheck_; } return *this; } // And for scaling - default aborts for when scaling not supported void ClpMatrixBase::times(double scalar, const double *x, double *y, const double *rowScale, const double * /*columnScale*/) const { if (rowScale) { std::cerr << "Scaling not supported - ClpMatrixBase" << std::endl; abort(); } else { times(scalar, x, y); } } // And for scaling - default aborts for when scaling not supported void ClpMatrixBase::transposeTimes(double scalar, const double *x, double *y, const double *rowScale, const double * /*columnScale*/, double * /*spare*/) const { if (rowScale) { std::cerr << "Scaling not supported - ClpMatrixBase" << std::endl; abort(); } else { transposeTimes(scalar, x, y); } } /* Subset clone (without gaps). Duplicates are allowed and order is as given. Derived classes need not provide this as it may not always make sense */ ClpMatrixBase * ClpMatrixBase::subsetClone( int /*numberRows*/, const int * /*whichRows*/, int /*numberColumns*/, const int * /*whichColumns*/) const { std::cerr << "subsetClone not supported - ClpMatrixBase" << std::endl; abort(); return NULL; } /* Given positive integer weights for each row fills in sum of weights for each column (and slack). Returns weights vector Default returns vector of ones */ CoinBigIndex * ClpMatrixBase::dubiousWeights(const ClpSimplex *model, int * /*inputWeights*/) const { int number = model->numberRows() + model->numberColumns(); CoinBigIndex *weights = new CoinBigIndex[number]; int i; for (i = 0; i < number; i++) weights[i] = 1; return weights; } #ifndef CLP_NO_VECTOR // Append Columns void ClpMatrixBase::appendCols(int /*number*/, const CoinPackedVectorBase *const * /*columns*/) { std::cerr << "appendCols not supported - ClpMatrixBase" << std::endl; abort(); } // Append Rows void ClpMatrixBase::appendRows(int /*number*/, const CoinPackedVectorBase *const * /*rows*/) { std::cerr << "appendRows not supported - ClpMatrixBase" << std::endl; abort(); } #endif /* Returns largest and smallest elements of both signs. Largest refers to largest absolute value. */ void ClpMatrixBase::rangeOfElements(double &smallestNegative, double &largestNegative, double &smallestPositive, double &largestPositive) { smallestNegative = 0.0; largestNegative = 0.0; smallestPositive = 0.0; largestPositive = 0.0; } /* The length of a major-dimension vector. */ int ClpMatrixBase::getVectorLength(int index) const { return getVectorLengths()[index]; } // Says whether it can do partial pricing bool ClpMatrixBase::canDoPartialPricing() const { return false; // default is no } /* Return x *A in z but just for number indices in y. Default cheats with fake CoinIndexedVector and then calls subsetTransposeTimes */ void ClpMatrixBase::listTransposeTimes(const ClpSimplex *model, double *x, int *y, int number, double *z) const { CoinIndexedVector pi; CoinIndexedVector list; CoinIndexedVector output; int *saveIndices = list.getIndices(); list.setNumElements(number); list.setIndexVector(y); double *savePi = pi.denseVector(); pi.setDenseVector(x); double *saveOutput = output.denseVector(); output.setDenseVector(z); output.setPacked(); subsetTransposeTimes(model, &pi, &list, &output); // restore settings list.setIndexVector(saveIndices); pi.setDenseVector(savePi); output.setDenseVector(saveOutput); } // Partial pricing void ClpMatrixBase::partialPricing(ClpSimplex *, double, double, int &, int &) { std::cerr << "partialPricing not supported - ClpMatrixBase" << std::endl; abort(); } /* expands an updated column to allow for extra rows which the main solver does not know about and returns number added. If the arrays are NULL then returns number of extra entries needed. This will normally be a no-op - it is in for GUB! */ int ClpMatrixBase::extendUpdated(ClpSimplex *, CoinIndexedVector *, int) { return 0; } /* utility primal function for dealing with dynamic constraints mode=n see ClpGubMatrix.hpp for definition Remember to update here when settled down */ void ClpMatrixBase::primalExpanded(ClpSimplex *, int) { } /* utility dual function for dealing with dynamic constraints mode=n see ClpGubMatrix.hpp for definition Remember to update here when settled down */ void ClpMatrixBase::dualExpanded(ClpSimplex *, CoinIndexedVector *, double *, int) { } /* general utility function for dealing with dynamic constraints mode=n see ClpGubMatrix.hpp for definition Remember to update here when settled down */ int ClpMatrixBase::generalExpanded(ClpSimplex *model, int mode, int &number) { int returnCode = 0; switch (mode) { // Fill in pivotVariable but not for key variables case 0: { int i; int numberBasic = number; int numberColumns = model->numberColumns(); // Use different array so can build from true pivotVariable_ //int * pivotVariable = model->pivotVariable(); int *pivotVariable = model->rowArray(0)->getIndices(); for (i = 0; i < numberColumns; i++) { if (model->getColumnStatus(i) == ClpSimplex::basic) pivotVariable[numberBasic++] = i; } number = numberBasic; } break; // Do initial extra rows + maximum basic case 2: { number = model->numberRows(); } break; // To see if can dual or primal case 4: { returnCode = 3; } break; default: break; } return returnCode; } // Sets up an effective RHS void ClpMatrixBase::useEffectiveRhs(ClpSimplex *) { std::cerr << "useEffectiveRhs not supported - ClpMatrixBase" << std::endl; abort(); } /* 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_; } /* update information for a pivot (and effective rhs) */ int ClpMatrixBase::updatePivot(ClpSimplex *model, double oldInValue, double) { if (rhsOffset_) { // update effective rhs int sequenceIn = model->sequenceIn(); int sequenceOut = model->sequenceOut(); double *solution = model->solutionRegion(); int numberColumns = model->numberColumns(); if (sequenceIn == sequenceOut) { if (sequenceIn < numberColumns) add(model, rhsOffset_, sequenceIn, oldInValue - solution[sequenceIn]); } else { if (sequenceIn < numberColumns) add(model, rhsOffset_, sequenceIn, oldInValue); if (sequenceOut < numberColumns) add(model, rhsOffset_, sequenceOut, -solution[sequenceOut]); } } return 0; } int ClpMatrixBase::hiddenRows() const { return 0; } /* Creates a variable. This is called after partial pricing and may modify matrix. May update bestSequence. */ void ClpMatrixBase::createVariable(ClpSimplex *, int &) { } // Returns reduced cost of a variable double ClpMatrixBase::reducedCost(ClpSimplex *model, int sequence) const { int numberRows = model->numberRows(); int numberColumns = model->numberColumns(); if (sequence < numberRows + numberColumns) return model->djRegion()[sequence]; else return savedBestDj_; } /* Just for debug if odd type matrix. Returns number and sum of primal infeasibilities. */ int ClpMatrixBase::checkFeasible(ClpSimplex *model, double &sum) const { int numberRows = model->numberRows(); double *rhs = new double[numberRows]; int numberColumns = model->numberColumns(); int iRow; CoinZeroN(rhs, numberRows); times(1.0, model->solutionRegion(), rhs, model->rowScale(), model->columnScale()); int iColumn; int logLevel = model->messageHandler()->logLevel(); int numberInfeasible = 0; const double *rowLower = model->lowerRegion(0); const double *rowUpper = model->upperRegion(0); const double *solution; solution = model->solutionRegion(0); double tolerance = model->primalTolerance() * 1.01; sum = 0.0; for (iRow = 0; iRow < numberRows; iRow++) { double value = rhs[iRow]; double value2 = solution[iRow]; if (logLevel > 3) { if (fabs(value - value2) > 1.0e-8) printf("Row %d stored %g, computed %g\n", iRow, value2, value); } if (value < rowLower[iRow] - tolerance || value > rowUpper[iRow] + tolerance) { numberInfeasible++; sum += CoinMax(rowLower[iRow] - value, value - rowUpper[iRow]); } if (value2 > rowLower[iRow] + tolerance && value2 < rowUpper[iRow] - tolerance && model->getRowStatus(iRow) != ClpSimplex::basic) { assert(model->getRowStatus(iRow) == ClpSimplex::superBasic); } } const double *columnLower = model->lowerRegion(1); const double *columnUpper = model->upperRegion(1); solution = model->solutionRegion(1); for (iColumn = 0; iColumn < numberColumns; iColumn++) { double value = solution[iColumn]; if (value < columnLower[iColumn] - tolerance || value > columnUpper[iColumn] + tolerance) { numberInfeasible++; sum += CoinMax(columnLower[iColumn] - value, value - columnUpper[iColumn]); } if (value > columnLower[iColumn] + tolerance && value < columnUpper[iColumn] - tolerance && model->getColumnStatus(iColumn) != ClpSimplex::basic) { assert(model->getColumnStatus(iColumn) == ClpSimplex::superBasic); } } delete[] rhs; return numberInfeasible; } // These have to match ClpPrimalColumnSteepest version #define reference(i) (((reference[i >> 5] >> (i & 31)) & 1) != 0) // Updates second array for steepest and does devex weights (need not be coded) void ClpMatrixBase::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) { // get subset which have nonzero tableau elements subsetTransposeTimes(model, pi2, dj1, dj2); bool killDjs = (scaleFactor == 0.0); if (!scaleFactor) scaleFactor = 1.0; // columns int number = dj1->getNumElements(); const int *index = dj1->getIndices(); double *updateBy = dj1->denseVector(); double *updateBy2 = dj2->denseVector(); for (int j = 0; j < number; j++) { double thisWeight; double pivot; double pivotSquared; int iSequence = index[j]; double value2 = updateBy[j]; if (killDjs) updateBy[j] = 0.0; double modification = updateBy2[j]; updateBy2[j] = 0.0; ClpSimplex::Status status = model->getStatus(iSequence); if (status != ClpSimplex::basic && status != ClpSimplex::isFixed) { thisWeight = weights[iSequence]; pivot = value2 * scaleFactor; pivotSquared = pivot * pivot; thisWeight += pivotSquared * devex + pivot * modification; if (thisWeight < DEVEX_TRY_NORM) { if (referenceIn < 0.0) { // steepest thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared); } else { // exact thisWeight = referenceIn * pivotSquared; if (reference(iSequence)) thisWeight += 1.0; thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM); } } weights[iSequence] = thisWeight; } } dj2->setNumElements(0); } // Correct sequence in and out to give true value void ClpMatrixBase::correctSequence(const ClpSimplex *, int &, int &) { } // Really scale matrix void ClpMatrixBase::reallyScale(const double *, const double *) { std::cerr << "reallyScale not supported - ClpMatrixBase" << std::endl; abort(); } // Updates two arrays for steepest int ClpMatrixBase::transposeTimes2(const ClpSimplex *, const CoinIndexedVector *, CoinIndexedVector *, const CoinIndexedVector *, CoinIndexedVector *, double *, double *, double, double, // Array for exact devex to say what is in reference framework unsigned int *, double *, double) { std::cerr << "transposeTimes2 not supported - ClpMatrixBase" << std::endl; abort(); return 0; } /* Set the dimensions of the matrix. In effect, append new empty columns/rows to the matrix. A negative number for either dimension means that that dimension doesn't change. Otherwise the new dimensions MUST be at least as large as the current ones otherwise an exception is thrown. */ void ClpMatrixBase::setDimensions(int, int) { // If odd matrix assume user knows what they are doing } /* 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 ClpMatrixBase::appendMatrix(int, int, const CoinBigIndex *, const int *, const double *, int) { std::cerr << "appendMatrix not supported - ClpMatrixBase" << std::endl; abort(); return -1; } /* Modify one element of packed matrix. An element may be added. This works for either ordering If the new element is zero it will be deleted unless keepZero true */ void ClpMatrixBase::modifyCoefficient(int, int, double, bool) { std::cerr << "modifyCoefficient not supported - ClpMatrixBase" << std::endl; abort(); } #if COIN_LONG_WORK // For long double versions (aborts if not supported) void ClpMatrixBase::times(CoinWorkDouble scalar, const CoinWorkDouble *x, CoinWorkDouble *y) const { std::cerr << "long times not supported - ClpMatrixBase" << std::endl; abort(); } void ClpMatrixBase::transposeTimes(CoinWorkDouble scalar, const CoinWorkDouble *x, CoinWorkDouble *y) const { std::cerr << "long transposeTimes not supported - ClpMatrixBase" << std::endl; abort(); } #endif /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2 */