/* $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 "CoinHelperFunctions.hpp" #include "CoinIndexedVector.hpp" #include "ClpFactorization.hpp" #include "ClpSimplex.hpp" #include "ClpQuadraticObjective.hpp" //############################################################################# // Constructors / Destructor / Assignment //############################################################################# //------------------------------------------------------------------- // Default Constructor //------------------------------------------------------------------- ClpQuadraticObjective::ClpQuadraticObjective() : ClpObjective() { type_ = 2; objective_ = NULL; quadraticObjective_ = NULL; gradient_ = NULL; numberColumns_ = 0; numberExtendedColumns_ = 0; activated_ = 0; fullMatrix_ = false; } //------------------------------------------------------------------- // 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; } //------------------------------------------------------------------- // Copy constructor //------------------------------------------------------------------- ClpQuadraticObjective::ClpQuadraticObjective(const ClpQuadraticObjective &rhs, int type) : ClpObjective(rhs) { numberColumns_ = rhs.numberColumns_; numberExtendedColumns_ = rhs.numberExtendedColumns_; fullMatrix_ = rhs.fullMatrix_; 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_) { // see what type of matrix wanted if (type == 0) { // just copy quadraticObjective_ = new CoinPackedMatrix(*rhs.quadraticObjective_); } else if (type == 1) { // expand to full symmetric fullMatrix_ = true; const int *columnQuadratic1 = rhs.quadraticObjective_->getIndices(); const CoinBigIndex *columnQuadraticStart1 = rhs.quadraticObjective_->getVectorStarts(); const int *columnQuadraticLength1 = rhs.quadraticObjective_->getVectorLengths(); const double *quadraticElement1 = rhs.quadraticObjective_->getElements(); CoinBigIndex *columnQuadraticStart2 = new CoinBigIndex[numberExtendedColumns_ + 1]; int *columnQuadraticLength2 = new int[numberExtendedColumns_]; int iColumn; int numberColumns = rhs.quadraticObjective_->getNumCols(); int numberBelow = 0; int numberAbove = 0; int numberDiagonal = 0; CoinZeroN(columnQuadraticLength2, numberExtendedColumns_); for (iColumn = 0; iColumn < numberColumns; iColumn++) { for (CoinBigIndex j = columnQuadraticStart1[iColumn]; j < columnQuadraticStart1[iColumn] + columnQuadraticLength1[iColumn]; j++) { int jColumn = columnQuadratic1[j]; if (jColumn > iColumn) { numberBelow++; columnQuadraticLength2[jColumn]++; columnQuadraticLength2[iColumn]++; } else if (jColumn == iColumn) { numberDiagonal++; columnQuadraticLength2[iColumn]++; } else { numberAbove++; } } } if (numberAbove > 0) { if (numberAbove == numberBelow) { // already done quadraticObjective_ = new CoinPackedMatrix(*rhs.quadraticObjective_); delete[] columnQuadraticStart2; delete[] columnQuadraticLength2; } else { printf("number above = %d, number below = %d, error\n", numberAbove, numberBelow); abort(); } } else { int numberElements = numberDiagonal + 2 * numberBelow; int *columnQuadratic2 = new int[numberElements]; double *quadraticElement2 = new double[numberElements]; columnQuadraticStart2[0] = 0; numberElements = 0; for (iColumn = 0; iColumn < numberColumns; iColumn++) { int n = columnQuadraticLength2[iColumn]; columnQuadraticLength2[iColumn] = 0; numberElements += n; columnQuadraticStart2[iColumn + 1] = numberElements; } for (iColumn = 0; iColumn < numberColumns; iColumn++) { for (CoinBigIndex j = columnQuadraticStart1[iColumn]; j < columnQuadraticStart1[iColumn] + columnQuadraticLength1[iColumn]; j++) { int jColumn = columnQuadratic1[j]; if (jColumn > iColumn) { // put in two places CoinBigIndex put = columnQuadraticLength2[jColumn] + columnQuadraticStart2[jColumn]; columnQuadraticLength2[jColumn]++; quadraticElement2[put] = quadraticElement1[j]; columnQuadratic2[put] = iColumn; put = columnQuadraticLength2[iColumn] + columnQuadraticStart2[iColumn]; columnQuadraticLength2[iColumn]++; quadraticElement2[put] = quadraticElement1[j]; columnQuadratic2[put] = jColumn; } else if (jColumn == iColumn) { CoinBigIndex put = columnQuadraticLength2[iColumn] + columnQuadraticStart2[iColumn]; columnQuadraticLength2[iColumn]++; quadraticElement2[put] = quadraticElement1[j]; columnQuadratic2[put] = iColumn; } else { abort(); } } } // Now create quadraticObjective_ = new CoinPackedMatrix(true, rhs.numberExtendedColumns_, rhs.numberExtendedColumns_, numberElements, quadraticElement2, columnQuadratic2, columnQuadraticStart2, columnQuadraticLength2, 0.0, 0.0); delete[] columnQuadraticStart2; delete[] columnQuadraticLength2; delete[] columnQuadratic2; delete[] quadraticElement2; } } else { fullMatrix_ = false; abort(); // code when needed } } else { quadraticObjective_ = NULL; } } /* 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; } } //------------------------------------------------------------------- // Destructor //------------------------------------------------------------------- ClpQuadraticObjective::~ClpQuadraticObjective() { delete[] objective_; delete[] gradient_; delete quadraticObjective_; } //---------------------------------------------------------------- // 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; } // Returns gradient double * ClpQuadraticObjective::gradient(const ClpSimplex *model, const double *solution, double &offset, bool refresh, int includeLinear) { offset = 0.0; bool scaling = false; if (model && (model->rowScale() || model->objectiveScale() != 1.0 || model->optimizationDirection() != 1.0)) scaling = true; const double *cost = NULL; if (model) cost = model->costRegion(); if (!cost) { // not in solve cost = objective_; scaling = false; } if (!scaling) { if (!quadraticObjective_ || !solution || !activated_) { return objective_; } else { if (refresh || !gradient_) { if (!gradient_) gradient_ = new double[numberExtendedColumns_]; const int *columnQuadratic = quadraticObjective_->getIndices(); const CoinBigIndex *columnQuadraticStart = quadraticObjective_->getVectorStarts(); const int *columnQuadraticLength = quadraticObjective_->getVectorLengths(); const double *quadraticElement = quadraticObjective_->getElements(); offset = 0.0; // use current linear cost region if (includeLinear == 1) CoinMemcpyN(cost, numberExtendedColumns_, gradient_); else if (includeLinear == 2) CoinMemcpyN(objective_, numberExtendedColumns_, gradient_); else memset(gradient_, 0, numberExtendedColumns_ * sizeof(double)); if (activated_) { if (!fullMatrix_) { int iColumn; for (iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double elementValue = quadraticElement[j]; if (iColumn != jColumn) { offset += valueI * valueJ * elementValue; //if (fabs(valueI*valueJ*elementValue)>1.0e-12) //printf("%d %d %g %g %g -> %g\n", // iColumn,jColumn,valueI,valueJ,elementValue, // valueI*valueJ*elementValue); double gradientI = valueJ * elementValue; double gradientJ = valueI * elementValue; gradient_[iColumn] += gradientI; gradient_[jColumn] += gradientJ; } else { offset += 0.5 * valueI * valueI * elementValue; //if (fabs(valueI*valueI*elementValue)>1.0e-12) //printf("XX %d %g %g -> %g\n", // iColumn,valueI,elementValue, // 0.5*valueI*valueI*elementValue); double gradientI = valueI * elementValue; gradient_[iColumn] += gradientI; } } } } else { // full matrix int iColumn; offset *= 2.0; for (iColumn = 0; iColumn < numberColumns_; iColumn++) { CoinBigIndex j; double value = 0.0; double current = gradient_[iColumn]; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn] * quadraticElement[j]; value += valueJ; } offset += value * solution[iColumn]; gradient_[iColumn] = current + value; } offset *= 0.5; } } } if (model) offset *= model->optimizationDirection() * model->objectiveScale(); return gradient_; } } else { // do scaling assert(solution); // for now only if half assert(!fullMatrix_); if (refresh || !gradient_) { if (!gradient_) gradient_ = new double[numberExtendedColumns_]; double direction = model->optimizationDirection() * model->objectiveScale(); // direction is actually scale out not scale in //if (direction) //direction = 1.0/direction; const int *columnQuadratic = quadraticObjective_->getIndices(); const CoinBigIndex *columnQuadraticStart = quadraticObjective_->getVectorStarts(); const int *columnQuadraticLength = quadraticObjective_->getVectorLengths(); const double *quadraticElement = quadraticObjective_->getElements(); int iColumn; const double *columnScale = model->columnScale(); // use current linear cost region (already scaled) if (includeLinear == 1) { CoinMemcpyN(model->costRegion(), numberExtendedColumns_, gradient_); } else if (includeLinear == 2) { memset(gradient_ + numberColumns_, 0, (numberExtendedColumns_ - numberColumns_) * sizeof(double)); if (!columnScale) { for (iColumn = 0; iColumn < numberColumns_; iColumn++) { gradient_[iColumn] = objective_[iColumn] * direction; } } else { for (iColumn = 0; iColumn < numberColumns_; iColumn++) { gradient_[iColumn] = objective_[iColumn] * direction * columnScale[iColumn]; } } } else { memset(gradient_, 0, numberExtendedColumns_ * sizeof(double)); } if (!columnScale) { if (activated_) { for (iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double elementValue = quadraticElement[j]; elementValue *= direction; if (iColumn != jColumn) { offset += valueI * valueJ * elementValue; double gradientI = valueJ * elementValue; double gradientJ = valueI * elementValue; gradient_[iColumn] += gradientI; gradient_[jColumn] += gradientJ; } else { offset += 0.5 * valueI * valueI * elementValue; double gradientI = valueI * elementValue; gradient_[iColumn] += gradientI; } } } } } else { // scaling if (activated_) { for (iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; double scaleI = columnScale[iColumn] * direction; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double elementValue = quadraticElement[j]; double scaleJ = columnScale[jColumn]; elementValue *= scaleI * scaleJ; if (iColumn != jColumn) { offset += valueI * valueJ * elementValue; double gradientI = valueJ * elementValue; double gradientJ = valueI * elementValue; gradient_[iColumn] += gradientI; gradient_[jColumn] += gradientJ; } else { offset += 0.5 * valueI * valueI * elementValue; double gradientI = valueI * elementValue; gradient_[iColumn] += gradientI; } } } } } } if (model) offset *= model->optimizationDirection(); return gradient_; } } //------------------------------------------------------------------- // Clone //------------------------------------------------------------------- ClpObjective *ClpQuadraticObjective::clone() const { return new ClpQuadraticObjective(*this); } /* Subset clone. Duplicates are allowed and order is as given. */ ClpObjective * ClpQuadraticObjective::subsetClone(int numberColumns, const int *whichColumns) const { return new ClpQuadraticObjective(*this, numberColumns, whichColumns); } // 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; } } // Delete columns in objective void ClpQuadraticObjective::deleteSome(int numberToDelete, const int *which) { int newNumberColumns = numberColumns_ - numberToDelete; int newExtended = numberExtendedColumns_ - numberToDelete; if (objective_) { int i; char *deleted = new char[numberColumns_]; int numberDeleted = 0; memset(deleted, 0, numberColumns_ * sizeof(char)); for (i = 0; i < numberToDelete; i++) { int j = which[i]; if (j >= 0 && j < numberColumns_ && !deleted[j]) { numberDeleted++; deleted[j] = 1; } } newNumberColumns = numberColumns_ - numberDeleted; newExtended = numberExtendedColumns_ - numberDeleted; double *newArray = new double[newExtended]; int put = 0; for (i = 0; i < numberColumns_; i++) { if (!deleted[i]) { newArray[put++] = objective_[i]; } } delete[] objective_; objective_ = newArray; delete[] deleted; CoinMemcpyN(objective_ + numberColumns_, (numberExtendedColumns_ - numberColumns_), objective_ + newNumberColumns); } if (gradient_) { int i; char *deleted = new char[numberColumns_]; int numberDeleted = 0; memset(deleted, 0, numberColumns_ * sizeof(char)); for (i = 0; i < numberToDelete; i++) { int j = which[i]; if (j >= 0 && j < numberColumns_ && !deleted[j]) { numberDeleted++; deleted[j] = 1; } } newNumberColumns = numberColumns_ - numberDeleted; newExtended = numberExtendedColumns_ - numberDeleted; double *newArray = new double[newExtended]; int put = 0; for (i = 0; i < numberColumns_; i++) { if (!deleted[i]) { newArray[put++] = gradient_[i]; } } delete[] gradient_; gradient_ = newArray; delete[] deleted; CoinMemcpyN(gradient_ + numberColumns_, (numberExtendedColumns_ - numberColumns_), gradient_ + newNumberColumns); } numberColumns_ = newNumberColumns; numberExtendedColumns_ = newExtended; if (quadraticObjective_) { quadraticObjective_->deleteCols(numberToDelete, which); quadraticObjective_->deleteRows(numberToDelete, which); } } // 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_; } } void ClpQuadraticObjective::loadQuadraticObjective(const CoinPackedMatrix &matrix) { delete quadraticObjective_; quadraticObjective_ = new CoinPackedMatrix(matrix); } // Get rid of quadratic objective void ClpQuadraticObjective::deleteQuadraticObjective() { delete quadraticObjective_; quadraticObjective_ = NULL; } /* Returns reduced gradient.Returns an offset (to be added to current one). */ double ClpQuadraticObjective::reducedGradient(ClpSimplex *model, double *region, bool useFeasibleCosts) { int numberRows = model->numberRows(); int numberColumns = model->numberColumns(); //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 *costNow = gradient(model, model->solutionRegion(), offset_, true, useFeasibleCosts ? 2 : 1); double *cost = model->costRegion(); const int *pivotVariable = model->pivotVariable(); for (iRow = 0; iRow < numberRows; iRow++) { int iPivot = pivotVariable[iRow]; double value; if (iPivot < numberColumns) value = costNow[iPivot]; else if (!useFeasibleCosts) value = cost[iPivot]; else value = 0.0; if (value) { array[iRow] = value; index[number++] = iRow; } } arrayVector.setNumElements(number); // Btran basic costs model->factorization()->updateColumnTranspose(workSpace, &arrayVector); double *work = workSpace->denseVector(); ClpFillN(work, numberRows, 0.0); // now look at dual solution double *rowReducedCost = region + numberColumns; double *dual = rowReducedCost; const double *rowCost = cost + numberColumns; for (iRow = 0; iRow < numberRows; iRow++) { dual[iRow] = array[iRow]; } double *dj = region; ClpDisjointCopyN(costNow, 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 offset_; } /* Returns step length which gives minimum of objective for solution + theta * change vector up to maximum theta. arrays are numberColumns+numberRows */ double ClpQuadraticObjective::stepLength(ClpSimplex *model, const double *solution, const double *change, double maximumTheta, double ¤tObj, double &predictedObj, double &thetaObj) { const double *cost = model->costRegion(); bool inSolve = true; if (!cost) { // not in solve cost = objective_; inSolve = false; } double delta = 0.0; double linearCost = 0.0; int numberRows = model->numberRows(); int numberColumns = model->numberColumns(); int numberTotal = numberColumns; if (inSolve) numberTotal += numberRows; currentObj = 0.0; thetaObj = 0.0; for (int iColumn = 0; iColumn < numberTotal; iColumn++) { delta += cost[iColumn] * change[iColumn]; linearCost += cost[iColumn] * solution[iColumn]; } if (!activated_ || !quadraticObjective_) { currentObj = linearCost; thetaObj = currentObj + delta * maximumTheta; if (delta < 0.0) { return maximumTheta; } else { COIN_DETAIL_PRINT(printf("odd linear direction %g\n", delta)); return 0.0; } } assert(model); bool scaling = false; if ((model->rowScale() || model->objectiveScale() != 1.0 || model->optimizationDirection() != 1.0) && inSolve) scaling = true; const int *columnQuadratic = quadraticObjective_->getIndices(); const CoinBigIndex *columnQuadraticStart = quadraticObjective_->getVectorStarts(); const int *columnQuadraticLength = quadraticObjective_->getVectorLengths(); const double *quadraticElement = quadraticObjective_->getElements(); double a = 0.0; double b = delta; double c = 0.0; if (!scaling) { if (!fullMatrix_) { int iColumn; for (iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; double changeI = change[iColumn]; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double changeJ = change[jColumn]; double elementValue = quadraticElement[j]; if (iColumn != jColumn) { a += changeI * changeJ * elementValue; b += (changeI * valueJ + changeJ * valueI) * elementValue; c += valueI * valueJ * elementValue; } else { a += 0.5 * changeI * changeI * elementValue; b += changeI * valueI * elementValue; c += 0.5 * valueI * valueI * elementValue; } } } } else { // full matrix stored int iColumn; for (iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; double changeI = change[iColumn]; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double changeJ = change[jColumn]; double elementValue = quadraticElement[j]; valueJ *= elementValue; a += changeI * changeJ * elementValue; b += changeI * valueJ; c += valueI * valueJ; } } a *= 0.5; c *= 0.5; } } else { // scaling // for now only if half assert(!fullMatrix_); const double *columnScale = model->columnScale(); double direction = model->optimizationDirection() * model->objectiveScale(); // direction is actually scale out not scale in if (direction) direction = 1.0 / direction; if (!columnScale) { for (int iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; double changeI = change[iColumn]; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double changeJ = change[jColumn]; double elementValue = quadraticElement[j]; elementValue *= direction; if (iColumn != jColumn) { a += changeI * changeJ * elementValue; b += (changeI * valueJ + changeJ * valueI) * elementValue; c += valueI * valueJ * elementValue; } else { a += 0.5 * changeI * changeI * elementValue; b += changeI * valueI * elementValue; c += 0.5 * valueI * valueI * elementValue; } } } } else { // scaling for (int iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; double changeI = change[iColumn]; double scaleI = columnScale[iColumn] * direction; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double changeJ = change[jColumn]; double elementValue = quadraticElement[j]; elementValue *= scaleI * columnScale[jColumn]; if (iColumn != jColumn) { a += changeI * changeJ * elementValue; b += (changeI * valueJ + changeJ * valueI) * elementValue; c += valueI * valueJ * elementValue; } else { a += 0.5 * changeI * changeI * elementValue; b += changeI * valueI * elementValue; c += 0.5 * valueI * valueI * elementValue; } } } } } double theta; //printf("Current cost %g\n",c+linearCost); currentObj = c + linearCost; thetaObj = currentObj + a * maximumTheta * maximumTheta + b * maximumTheta; // minimize a*x*x + b*x + c if (a <= 0.0) { theta = maximumTheta; } else { theta = -0.5 * b / a; } predictedObj = currentObj + a * theta * theta + b * theta; if (b > 0.0) { if (model->messageHandler()->logLevel() & 32) printf("a %g b %g c %g => %g\n", a, b, c, theta); b = 0.0; } return CoinMin(theta, maximumTheta); } // Return objective value (without any ClpModel offset) (model may be NULL) double ClpQuadraticObjective::objectiveValue(const ClpSimplex *model, const double *solution) const { bool scaling = false; if (model && (model->rowScale() || model->objectiveScale() != 1.0)) scaling = true; const double *cost = NULL; if (model) cost = model->costRegion(); if (!cost) { // not in solve cost = objective_; scaling = false; } double linearCost = 0.0; int numberColumns = model->numberColumns(); int numberTotal = numberColumns; double currentObj = 0.0; for (int iColumn = 0; iColumn < numberTotal; iColumn++) { linearCost += cost[iColumn] * solution[iColumn]; } if (!activated_ || !quadraticObjective_) { currentObj = linearCost; return currentObj; } assert(model); const int *columnQuadratic = quadraticObjective_->getIndices(); const CoinBigIndex *columnQuadraticStart = quadraticObjective_->getVectorStarts(); const int *columnQuadraticLength = quadraticObjective_->getVectorLengths(); const double *quadraticElement = quadraticObjective_->getElements(); double c = 0.0; if (!scaling) { if (!fullMatrix_) { int iColumn; for (iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double elementValue = quadraticElement[j]; if (iColumn != jColumn) { c += valueI * valueJ * elementValue; } else { c += 0.5 * valueI * valueI * elementValue; } } } } else { // full matrix stored int iColumn; for (iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double elementValue = quadraticElement[j]; valueJ *= elementValue; c += valueI * valueJ; } } c *= 0.5; } } else { // scaling // for now only if half assert(!fullMatrix_); const double *columnScale = model->columnScale(); double direction = model->objectiveScale(); // direction is actually scale out not scale in if (direction) direction = 1.0 / direction; if (!columnScale) { for (int iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double elementValue = quadraticElement[j]; elementValue *= direction; if (iColumn != jColumn) { c += valueI * valueJ * elementValue; } else { c += 0.5 * valueI * valueI * elementValue; } } } } else { // scaling for (int iColumn = 0; iColumn < numberColumns_; iColumn++) { double valueI = solution[iColumn]; double scaleI = columnScale[iColumn] * direction; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = solution[jColumn]; double elementValue = quadraticElement[j]; elementValue *= scaleI * columnScale[jColumn]; if (iColumn != jColumn) { c += valueI * valueJ * elementValue; } else { c += 0.5 * valueI * valueI * elementValue; } } } } } currentObj = c + linearCost; return currentObj; } // Scale objective void ClpQuadraticObjective::reallyScale(const double *columnScale) { const int *columnQuadratic = quadraticObjective_->getIndices(); const CoinBigIndex *columnQuadraticStart = quadraticObjective_->getVectorStarts(); const int *columnQuadraticLength = quadraticObjective_->getVectorLengths(); double *quadraticElement = quadraticObjective_->getMutableElements(); for (int iColumn = 0; iColumn < numberColumns_; iColumn++) { double scaleI = columnScale[iColumn]; objective_[iColumn] *= scaleI; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; quadraticElement[j] *= scaleI * columnScale[jColumn]; } } } /* Given a zeroed array sets nonlinear columns to 1. Returns number of nonlinear columns */ int ClpQuadraticObjective::markNonlinear(char *which) { int iColumn; const int *columnQuadratic = quadraticObjective_->getIndices(); const CoinBigIndex *columnQuadraticStart = quadraticObjective_->getVectorStarts(); const int *columnQuadraticLength = quadraticObjective_->getVectorLengths(); for (iColumn = 0; iColumn < numberColumns_; iColumn++) { CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; which[jColumn] = 1; which[iColumn] = 1; } } int numberNonLinearColumns = 0; for (iColumn = 0; iColumn < numberColumns_; iColumn++) { if (which[iColumn]) numberNonLinearColumns++; } return numberNonLinearColumns; } /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2 */