// Copyright (C) 2003, International Business Machines // Corporation and others. All Rights Reserved. #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_= max(numberColumns_,numberExtendedColumns); else numberExtendedColumns_= numberColumns_; if (objective) { objective_ = new double [numberExtendedColumns_]; memcpy(objective_,objective,numberColumns_*sizeof(double)); 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_]; memcpy(objective_,rhs.objective_,numberExtendedColumns_*sizeof(double)); } else { objective_=NULL; } if (rhs.gradient_) { gradient_ = new double [numberExtendedColumns_]; memcpy(gradient_,rhs.gradient_,numberExtendedColumns_*sizeof(double)); } 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;iColumniColumn) { 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;iColumniColumn) { // 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=rhs.numberColumns_) numberBad++; if (numberBad) throw CoinError("bad column list", "subset constructor", "ClpQuadraticObjective"); numberColumns_ = numberColumns; objective_ = new double[numberExtendedColumns_]; for (i=0;irowScale()|| 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) memcpy(gradient_,cost,numberExtendedColumns_*sizeof(double)); else if (includeLinear==2) memcpy(gradient_,objective_,numberExtendedColumns_*sizeof(double)); else memset(gradient_,0,numberExtendedColumns_*sizeof(double)); if (activated_) { if (!fullMatrix_) { int iColumn; for (iColumn=0;iColumn1.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;iColumnoptimizationDirection()*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) { memcpy(gradient_,model->costRegion(),numberExtendedColumns_*sizeof(double)); } else if (includeLinear==2) { memset(gradient_+numberColumns_,0,(numberExtendedColumns_-numberColumns_)*sizeof(double)); if (!columnScale) { for (iColumn=0;iColumnoptimizationDirection(); 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_) memcpy(newArray,objective_, CoinMin(newExtended,numberExtendedColumns_)*sizeof(double)); delete [] objective_; objective_ = newArray; for (i=numberColumns_;ideleteRows(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=0&&j=0&&jdeleteCols(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]; memcpy(newArray,objective_,numberColumns_*sizeof(double)); delete [] objective_; objective_ = newArray; memset(objective_+numberColumns_,0,(numberExtended-numberColumns_)*sizeof(double)); } if (gradient_) { // make correct size double * newArray = new double[numberExtended]; memcpy(newArray,gradient_,numberColumns_*sizeof(double)); 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;iRowfactorization()->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;iRowtransposeTimes(-1.0,dual,dj); for (iRow=0;iRowcostRegion(); 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;iColumnrowScale()|| 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;iColumncolumnScale(); 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;iColumn0.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;iColumngetIndices(); 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;iColumncolumnScale(); double direction = model->objectiveScale(); // direction is actually scale out not scale in if (direction) direction = 1.0/direction; if (!columnScale) { for (int iColumn=0;iColumngetIndices(); const CoinBigIndex * columnQuadraticStart = quadraticObjective_->getVectorStarts(); const int * columnQuadraticLength = quadraticObjective_->getVectorLengths(); double * quadraticElement = quadraticObjective_->getMutableElements(); for (int iColumn=0;iColumngetIndices(); const CoinBigIndex * columnQuadraticStart = quadraticObjective_->getVectorStarts(); const int * columnQuadraticLength = quadraticObjective_->getVectorLengths(); for (iColumn=0;iColumn