/* $Id$ */ // Copyright (C) 2003, 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 "CoinIndexedVector.hpp" #include "ClpFactorization.hpp" #include "ClpSimplex.hpp" #include "ClpLinearObjective.hpp" #include "CoinHelperFunctions.hpp" //############################################################################# // Constructors / Destructor / Assignment //############################################################################# //------------------------------------------------------------------- // Default Constructor //------------------------------------------------------------------- ClpLinearObjective::ClpLinearObjective() : ClpObjective() { type_ = 1; objective_ = NULL; numberColumns_ = 0; } //------------------------------------------------------------------- // Useful Constructor //------------------------------------------------------------------- ClpLinearObjective::ClpLinearObjective(const double *objective, int numberColumns) : ClpObjective() { type_ = 1; numberColumns_ = numberColumns; objective_ = CoinCopyOfArray(objective, numberColumns_, 0.0); } //------------------------------------------------------------------- // Copy constructor //------------------------------------------------------------------- ClpLinearObjective::ClpLinearObjective(const ClpLinearObjective &rhs) : ClpObjective(rhs) { numberColumns_ = rhs.numberColumns_; objective_ = CoinCopyOfArray(rhs.objective_, numberColumns_); } /* Subset constructor. Duplicates are allowed and order is as given. */ ClpLinearObjective::ClpLinearObjective(const ClpLinearObjective &rhs, int numberColumns, const int *whichColumn) : ClpObjective(rhs) { objective_ = NULL; numberColumns_ = 0; 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", "ClpLinearObjective"); numberColumns_ = numberColumns; objective_ = new double[numberColumns_]; for (i = 0; i < numberColumns_; i++) objective_[i] = rhs.objective_[whichColumn[i]]; } } //------------------------------------------------------------------- // Destructor //------------------------------------------------------------------- ClpLinearObjective::~ClpLinearObjective() { delete[] objective_; } //---------------------------------------------------------------- // Assignment operator //------------------------------------------------------------------- ClpLinearObjective & ClpLinearObjective::operator=(const ClpLinearObjective &rhs) { if (this != &rhs) { ClpObjective::operator=(rhs); numberColumns_ = rhs.numberColumns_; delete[] objective_; objective_ = CoinCopyOfArray(rhs.objective_, numberColumns_); } return *this; } // Returns gradient double * ClpLinearObjective::gradient(const ClpSimplex * /*model*/, const double * /*solution*/, double &offset, bool /*refresh*/, int /*includeLinear*/) { // not sure what to do about scaling //assert (!model); //assert (includeLinear==2); //otherwise need to return all zeros offset = 0.0; return objective_; } /* Returns reduced gradient.Returns an offset (to be added to current one). */ double ClpLinearObjective::reducedGradient(ClpSimplex *model, double *region, bool /*useFeasibleCosts*/) { int numberRows = model->numberRows(); //work space CoinIndexedVector *workSpace = model->rowArray(0); CoinIndexedVector arrayVector; arrayVector.reserve(numberRows + 1); int iRow; #ifdef CLP_DEBUG workSpace->checkClear(); #endif double *array = arrayVector.denseVector(); int *index = arrayVector.getIndices(); int number = 0; const double *cost = model->costRegion(); //assert (!useFeasibleCosts); const int *pivotVariable = model->pivotVariable(); for (iRow = 0; iRow < numberRows; iRow++) { int iPivot = pivotVariable[iRow]; double value = cost[iPivot]; if (value) { array[iRow] = value; index[number++] = iRow; } } arrayVector.setNumElements(number); int numberColumns = model->numberColumns(); // Btran basic costs double *work = workSpace->denseVector(); model->factorization()->updateColumnTranspose(workSpace, &arrayVector); ClpFillN(work, numberRows, 0.0); // now look at dual solution double *rowReducedCost = region + numberColumns; double *dual = rowReducedCost; double *rowCost = model->costRegion(0); for (iRow = 0; iRow < numberRows; iRow++) { dual[iRow] = array[iRow]; } double *dj = region; ClpDisjointCopyN(model->costRegion(1), numberColumns, dj); model->transposeTimes(-1.0, dual, dj); for (iRow = 0; iRow < numberRows; iRow++) { // slack double value = dual[iRow]; value += rowCost[iRow]; rowReducedCost[iRow] = value; } return 0.0; } /* Returns step length which gives minimum of objective for solution + theta * change vector up to maximum theta. arrays are numberColumns+numberRows */ double ClpLinearObjective::stepLength(ClpSimplex *model, const double *solution, const double *change, double maximumTheta, double ¤tObj, double &predictedObj, double &thetaObj) { const double *cost = model->costRegion(); double delta = 0.0; int numberRows = model->numberRows(); int numberColumns = model->numberColumns(); currentObj = 0.0; thetaObj = 0.0; for (int iColumn = 0; iColumn < numberColumns + numberRows; iColumn++) { delta += cost[iColumn] * change[iColumn]; currentObj += cost[iColumn] * solution[iColumn]; } thetaObj = currentObj + delta * maximumTheta; predictedObj = currentObj + delta * maximumTheta; if (delta < 0.0) { return maximumTheta; } else { printf("odd linear direction %g\n", delta); return 0.0; } } // Return objective value (without any ClpModel offset) (model may be NULL) double ClpLinearObjective::objectiveValue(const ClpSimplex *model, const double *solution) const { const double *cost = objective_; if (model && model->costRegion()) cost = model->costRegion(); double currentObj = 0.0; for (int iColumn = 0; iColumn < numberColumns_; iColumn++) { currentObj += cost[iColumn] * solution[iColumn]; } return currentObj; } //------------------------------------------------------------------- // Clone //------------------------------------------------------------------- ClpObjective *ClpLinearObjective::clone() const { return new ClpLinearObjective(*this); } /* Subset clone. Duplicates are allowed and order is as given. */ ClpObjective * ClpLinearObjective::subsetClone(int numberColumns, const int *whichColumns) const { return new ClpLinearObjective(*this, numberColumns, whichColumns); } // 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; } } // Delete columns in objective void ClpLinearObjective::deleteSome(int numberToDelete, const int *which) { if (objective_) { int i; char *deleted = new char[numberColumns_]; int numberDeleted = 0; CoinZeroN(deleted, numberColumns_); for (i = 0; i < numberToDelete; i++) { int j = which[i]; if (j >= 0 && j < numberColumns_ && !deleted[j]) { numberDeleted++; deleted[j] = 1; } } int newNumberColumns = numberColumns_ - numberDeleted; double *newArray = new double[newNumberColumns]; int put = 0; for (i = 0; i < numberColumns_; i++) { if (!deleted[i]) { newArray[put++] = objective_[i]; } } delete[] objective_; objective_ = newArray; delete[] deleted; numberColumns_ = newNumberColumns; } } // Scale objective void ClpLinearObjective::reallyScale(const double *columnScale) { for (int iColumn = 0; iColumn < numberColumns_; iColumn++) { objective_[iColumn] *= columnScale[iColumn]; } } /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2 */