// copyright (C) 2002, International Business Machines
// Corporation and others. All Rights Reserved.
#include <cmath>
#include <cassert>
#include <cfloat>
#include <string>
#include <cstdio>
#include <iostream>
#include "CoinPragma.hpp"
#include "CoinHelperFunctions.hpp"
#include "CoinTime.hpp"
#include "ClpModel.hpp"
#include "ClpEventHandler.hpp"
#include "ClpPackedMatrix.hpp"
#ifndef SLIM_CLP
#include "ClpPlusMinusOneMatrix.hpp"
#endif
#ifndef CLP_NO_VECTOR
#include "CoinPackedVector.hpp"
#endif
#include "CoinIndexedVector.hpp"
#if SLIM_CLP==2
#define SLIM_NOIO
#endif
#ifndef SLIM_NOIO
#include "CoinMpsIO.hpp"
#include "CoinFileIO.hpp"
#include "CoinModel.hpp"
#endif
#include "ClpMessage.hpp"
#include "CoinMessage.hpp"
#include "ClpLinearObjective.hpp"
#ifndef SLIM_CLP
#include "ClpQuadraticObjective.hpp"
#include "CoinBuild.hpp"
#endif
//#############################################################################
ClpModel::ClpModel (bool emptyMessages) :
optimizationDirection_(1),
objectiveValue_(0.0),
smallElement_(1.0e-20),
objectiveScale_(1.0),
rhsScale_(1.0),
numberRows_(0),
numberColumns_(0),
rowActivity_(NULL),
columnActivity_(NULL),
dual_(NULL),
reducedCost_(NULL),
rowLower_(NULL),
rowUpper_(NULL),
objective_(NULL),
rowObjective_(NULL),
columnLower_(NULL),
columnUpper_(NULL),
matrix_(NULL),
rowCopy_(NULL),
ray_(NULL),
rowScale_(NULL),
columnScale_(NULL),
scalingFlag_(3),
status_(NULL),
integerType_(NULL),
userPointer_(NULL),
numberIterations_(0),
solveType_(0),
whatsChanged_(0),
problemStatus_(-1),
secondaryStatus_(0),
lengthNames_(0),
numberThreads_(0),
specialOptions_(0),
#ifndef CLP_NO_STD
defaultHandler_(true),
rowNames_(),
columnNames_()
#else
defaultHandler_(true)
#endif
{
intParam_[ClpMaxNumIteration] = 2147483647;
intParam_[ClpMaxNumIterationHotStart] = 9999999;
intParam_[ClpNameDiscipline] = 0;
dblParam_[ClpDualObjectiveLimit] = COIN_DBL_MAX;
dblParam_[ClpPrimalObjectiveLimit] = COIN_DBL_MAX;
dblParam_[ClpDualTolerance] = 1e-7;
dblParam_[ClpPrimalTolerance] = 1e-7;
dblParam_[ClpObjOffset] = 0.0;
dblParam_[ClpMaxSeconds] = -1.0;
dblParam_[ClpPresolveTolerance] = 1.0e-8;
#ifndef CLP_NO_STD
strParam_[ClpProbName] = "ClpDefaultName";
#endif
handler_ = new CoinMessageHandler();
handler_->setLogLevel(1);
eventHandler_ = new ClpEventHandler();
if (!emptyMessages) {
messages_ = ClpMessage();
coinMessages_ = CoinMessage();
}
CoinSeedRandom(1234567);
}
//-----------------------------------------------------------------------------
ClpModel::~ClpModel ()
{
if (defaultHandler_) {
delete handler_;
handler_ = NULL;
}
gutsOfDelete();
}
void ClpModel::gutsOfDelete()
{
delete [] rowActivity_;
rowActivity_=NULL;
delete [] columnActivity_;
columnActivity_=NULL;
delete [] dual_;
dual_=NULL;
delete [] reducedCost_;
reducedCost_=NULL;
delete [] rowLower_;
delete [] rowUpper_;
delete [] rowObjective_;
rowLower_=NULL;
rowUpper_=NULL;
rowObjective_=NULL;
delete [] columnLower_;
delete [] columnUpper_;
delete objective_;
columnLower_=NULL;
columnUpper_=NULL;
objective_=NULL;
delete matrix_;
matrix_=NULL;
delete rowCopy_;
rowCopy_=NULL;
delete [] ray_;
ray_ = NULL;
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
delete [] integerType_;
integerType_ = NULL;
delete [] status_;
status_=NULL;
delete eventHandler_;
eventHandler_=NULL;
whatsChanged_=0;
specialOptions_ = 0;
}
//#############################################################################
void ClpModel::setPrimalTolerance( double value)
{
if (value>0.0&&value<1.0e10)
dblParam_[ClpPrimalTolerance]=value;
}
void ClpModel::setDualTolerance( double value)
{
if (value>0.0&&value<1.0e10)
dblParam_[ClpDualTolerance]=value;
}
void ClpModel::setOptimizationDirection( double value)
{
optimizationDirection_=value;
}
void
ClpModel::gutsOfLoadModel (int numberRows, int numberColumns,
const double* collb, const double* colub,
const double* obj,
const double* rowlb, const double* rowub,
const double * rowObjective)
{
// save event handler in case already set
ClpEventHandler * handler = eventHandler_->clone();
// Save specialOptions
int saveOptions = specialOptions_;
gutsOfDelete();
specialOptions_ = saveOptions;
eventHandler_ = handler;
numberRows_=numberRows;
numberColumns_=numberColumns;
rowActivity_=new double[numberRows_];
columnActivity_=new double[numberColumns_];
dual_=new double[numberRows_];
reducedCost_=new double[numberColumns_];
CoinZeroN(dual_,numberRows_);
CoinZeroN(reducedCost_,numberColumns_);
int iRow,iColumn;
rowLower_=ClpCopyOfArray(rowlb,numberRows_,-COIN_DBL_MAX);
rowUpper_=ClpCopyOfArray(rowub,numberRows_,COIN_DBL_MAX);
double * objective=ClpCopyOfArray(obj,numberColumns_,0.0);
objective_ = new ClpLinearObjective(objective,numberColumns_);
delete [] objective;
rowObjective_=ClpCopyOfArray(rowObjective,numberRows_);
columnLower_=ClpCopyOfArray(collb,numberColumns_,0.0);
columnUpper_=ClpCopyOfArray(colub,numberColumns_,COIN_DBL_MAX);
// set default solution and clean bounds
for (iRow=0;iRow<numberRows_;iRow++) {
if (rowLower_[iRow]>0.0) {
rowActivity_[iRow]=rowLower_[iRow];
} else if (rowUpper_[iRow]<0.0) {
rowActivity_[iRow]=rowUpper_[iRow];
} else {
rowActivity_[iRow]=0.0;
}
if (rowLower_[iRow]<-1.0e27)
rowLower_[iRow]=-COIN_DBL_MAX;
if (rowUpper_[iRow]>1.0e27)
rowUpper_[iRow]=COIN_DBL_MAX;
}
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
if (columnLower_[iColumn]>0.0) {
columnActivity_[iColumn]=columnLower_[iColumn];
} else if (columnUpper_[iColumn]<0.0) {
columnActivity_[iColumn]=columnUpper_[iColumn];
} else {
columnActivity_[iColumn]=0.0;
}
if (columnLower_[iColumn]<-1.0e27)
columnLower_[iColumn]=-COIN_DBL_MAX;
if (columnUpper_[iColumn]>1.0e27)
columnUpper_[iColumn]=COIN_DBL_MAX;
}
}
// This just loads up a row objective
void ClpModel::setRowObjective(const double * rowObjective)
{
delete [] rowObjective_;
rowObjective_=ClpCopyOfArray(rowObjective,numberRows_);
whatsChanged_=0;
}
void
ClpModel::loadProblem ( const ClpMatrixBase& matrix,
const double* collb, const double* colub,
const double* obj,
const double* rowlb, const double* rowub,
const double * rowObjective)
{
gutsOfLoadModel(matrix.getNumRows(),matrix.getNumCols(),
collb, colub, obj, rowlb, rowub, rowObjective);
if (matrix.isColOrdered()) {
matrix_=matrix.clone();
} else {
// later may want to keep as unknown class
CoinPackedMatrix matrix2;
matrix2.reverseOrderedCopyOf(*matrix.getPackedMatrix());
matrix.releasePackedMatrix();
matrix_=new ClpPackedMatrix(matrix2);
}
matrix_->setDimensions(numberRows_,numberColumns_);
}
void
ClpModel::loadProblem ( const CoinPackedMatrix& matrix,
const double* collb, const double* colub,
const double* obj,
const double* rowlb, const double* rowub,
const double * rowObjective)
{
gutsOfLoadModel(matrix.getNumRows(),matrix.getNumCols(),
collb, colub, obj, rowlb, rowub, rowObjective);
if (matrix.isColOrdered()) {
matrix_=new ClpPackedMatrix(matrix);
} else {
CoinPackedMatrix matrix2;
matrix2.reverseOrderedCopyOf(matrix);
matrix_=new ClpPackedMatrix(matrix2);
}
matrix_->setDimensions(numberRows_,numberColumns_);
}
void
ClpModel::loadProblem (
const int numcols, const int numrows,
const CoinBigIndex* start, const int* index,
const double* value,
const double* collb, const double* colub,
const double* obj,
const double* rowlb, const double* rowub,
const double * rowObjective)
{
gutsOfLoadModel(numrows, numcols,
collb, colub, obj, rowlb, rowub, rowObjective);
int numberElements = start ? start[numcols] : 0;
CoinPackedMatrix matrix(true,numrows,numrows ? numcols : 0,numberElements,
value,index,start,NULL);
matrix_ = new ClpPackedMatrix(matrix);
matrix_->setDimensions(numberRows_,numberColumns_);
}
void
ClpModel::loadProblem (
const int numcols, const int numrows,
const CoinBigIndex* start, const int* index,
const double* value,const int* length,
const double* collb, const double* colub,
const double* obj,
const double* rowlb, const double* rowub,
const double * rowObjective)
{
gutsOfLoadModel(numrows, numcols,
collb, colub, obj, rowlb, rowub, rowObjective);
// Compute number of elements
int numberElements = 0;
int i;
for (i=0;i<numcols;i++)
numberElements += length[i];
CoinPackedMatrix matrix(true,numrows,numcols,numberElements,
value,index,start,length);
matrix_ = new ClpPackedMatrix(matrix);
}
#ifndef SLIM_NOIO
// This loads a model from a coinModel object - returns number of errors
int
ClpModel::loadProblem ( CoinModel & modelObject,bool tryPlusMinusOne)
{
if (modelObject.numberColumns()==0&&modelObject.numberRows()==0)
return 0;
int numberErrors = 0;
// Set arrays for normal use
double * rowLower = modelObject.rowLowerArray();
double * rowUpper = modelObject.rowUpperArray();
double * columnLower = modelObject.columnLowerArray();
double * columnUpper = modelObject.columnUpperArray();
double * objective = modelObject.objectiveArray();
int * integerType = modelObject.integerTypeArray();
double * associated = modelObject.associatedArray();
// If strings then do copies
if (modelObject.stringsExist()) {
numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
objective, integerType,associated);
}
int numberRows = modelObject.numberRows();
int numberColumns = modelObject.numberColumns();
gutsOfLoadModel(numberRows, numberColumns,
columnLower, columnUpper, objective, rowLower, rowUpper, NULL);
CoinBigIndex * startPositive = NULL;
CoinBigIndex * startNegative = NULL;
delete matrix_;
if (tryPlusMinusOne) {
startPositive = new CoinBigIndex[numberColumns+1];
startNegative = new CoinBigIndex[numberColumns];
modelObject.countPlusMinusOne(startPositive,startNegative,associated);
if (startPositive[0]<0) {
// no good
tryPlusMinusOne=false;
delete [] startPositive;
delete [] startNegative;
}
}
#ifndef SLIM_CLP
if (!tryPlusMinusOne) {
#endif
CoinPackedMatrix matrix;
modelObject.createPackedMatrix(matrix,associated);
matrix_ = new ClpPackedMatrix(matrix);
#ifndef SLIM_CLP
} else {
// create +-1 matrix
CoinBigIndex size = startPositive[numberColumns];
int * indices = new int[size];
modelObject.createPlusMinusOne(startPositive,startNegative,indices,
associated);
// Get good object
ClpPlusMinusOneMatrix * matrix = new ClpPlusMinusOneMatrix();
matrix->passInCopy(numberRows,numberColumns,
true,indices,startPositive,startNegative);
matrix_=matrix;
}
#endif
#ifndef CLP_NO_STD
// Do names if wanted
int numberItems;
numberItems = modelObject.rowNames()->numberItems();
if (numberItems) {
const char *const * rowNames=modelObject.rowNames()->names();
copyRowNames(rowNames,0,numberItems);
}
numberItems = modelObject.columnNames()->numberItems();
if (numberItems) {
const char *const * columnNames=modelObject.columnNames()->names();
copyColumnNames(columnNames,0,numberItems);
}
#endif
// Do integers if wanted
assert(integerType);
for (int iColumn=0;iColumn<numberColumns;iColumn++) {
if (integerType[iColumn])
setInteger(iColumn);
}
if (rowLower!=modelObject.rowLowerArray()||
columnLower!=modelObject.columnLowerArray()) {
delete [] rowLower;
delete [] rowUpper;
delete [] columnLower;
delete [] columnUpper;
delete [] objective;
delete [] integerType;
delete [] associated;
if (numberErrors)
handler_->message(CLP_BAD_STRING_VALUES,messages_)
<<numberErrors
<<CoinMessageEol;
}
matrix_->setDimensions(numberRows_,numberColumns_);
return numberErrors;
}
#endif
void
ClpModel::getRowBound(int iRow, double& lower, double& upper) const
{
lower=-COIN_DBL_MAX;
upper=COIN_DBL_MAX;
if (rowUpper_)
upper=rowUpper_[iRow];
if (rowLower_)
lower=rowLower_[iRow];
}
//------------------------------------------------------------------
#ifndef NDEBUG
// For errors to make sure print to screen
// only called in debug mode
static void indexError(int index,
std::string methodName)
{
std::cerr<<"Illegal index "<<index<<" in ClpModel::"<<methodName<<std::endl;
throw CoinError("Illegal index",methodName,"ClpModel");
}
#endif
/* Set an objective function coefficient */
void
ClpModel::setObjectiveCoefficient( int elementIndex, double elementValue )
{
#ifndef NDEBUG
if (elementIndex<0||elementIndex>=numberColumns_) {
indexError(elementIndex,"setObjectiveCoefficient");
}
#endif
objective()[elementIndex] = elementValue;
whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
}
/* Set a single row lower bound<br>
Use -DBL_MAX for -infinity. */
void
ClpModel::setRowLower( int elementIndex, double elementValue ) {
if (elementValue<-1.0e27)
elementValue=-COIN_DBL_MAX;
rowLower_[elementIndex] = elementValue;
whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
}
/* Set a single row upper bound<br>
Use DBL_MAX for infinity. */
void
ClpModel::setRowUpper( int elementIndex, double elementValue ) {
if (elementValue>1.0e27)
elementValue=COIN_DBL_MAX;
rowUpper_[elementIndex] = elementValue;
whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
}
/* Set a single row lower and upper bound */
void
ClpModel::setRowBounds( int elementIndex,
double lower, double upper ) {
if (lower<-1.0e27)
lower=-COIN_DBL_MAX;
if (upper>1.0e27)
upper=COIN_DBL_MAX;
CoinAssert (upper>=lower);
rowLower_[elementIndex] = lower;
rowUpper_[elementIndex] = upper;
whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
}
void ClpModel::setRowSetBounds(const int* indexFirst,
const int* indexLast,
const double* boundList)
{
#ifndef NDEBUG
int n = numberRows_;
#endif
double * lower = rowLower_;
double * upper = rowUpper_;
whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
while (indexFirst != indexLast) {
const int iRow=*indexFirst++;
#ifndef NDEBUG
if (iRow<0||iRow>=n) {
indexError(iRow,"setRowSetBounds");
}
#endif
lower[iRow]= *boundList++;
upper[iRow]= *boundList++;
if (lower[iRow]<-1.0e27)
lower[iRow]=-COIN_DBL_MAX;
if (upper[iRow]>1.0e27)
upper[iRow]=COIN_DBL_MAX;
CoinAssert (upper[iRow]>=lower[iRow]);
}
}
//-----------------------------------------------------------------------------
/* Set a single column lower bound<br>
Use -DBL_MAX for -infinity. */
void
ClpModel::setColumnLower( int elementIndex, double elementValue )
{
#ifndef NDEBUG
int n = numberColumns_;
if (elementIndex<0||elementIndex>=n) {
indexError(elementIndex,"setColumnLower");
}
#endif
if (elementValue<-1.0e27)
elementValue=-COIN_DBL_MAX;
columnLower_[elementIndex] = elementValue;
whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
}
/* Set a single column upper bound<br>
Use DBL_MAX for infinity. */
void
ClpModel::setColumnUpper( int elementIndex, double elementValue )
{
#ifndef NDEBUG
int n = numberColumns_;
if (elementIndex<0||elementIndex>=n) {
indexError(elementIndex,"setColumnUpper");
}
#endif
if (elementValue>1.0e27)
elementValue=COIN_DBL_MAX;
columnUpper_[elementIndex] = elementValue;
whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
}
/* Set a single column lower and upper bound */
void
ClpModel::setColumnBounds( int elementIndex,
double lower, double upper )
{
#ifndef NDEBUG
int n = numberColumns_;
if (elementIndex<0||elementIndex>=n) {
indexError(elementIndex,"setColumnBounds");
}
#endif
if (lower<-1.0e27)
lower=-COIN_DBL_MAX;
if (upper>1.0e27)
upper=COIN_DBL_MAX;
columnLower_[elementIndex] = lower;
columnUpper_[elementIndex] = upper;
CoinAssert (upper>=lower);
whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
}
void ClpModel::setColumnSetBounds(const int* indexFirst,
const int* indexLast,
const double* boundList)
{
double * lower = columnLower_;
double * upper = columnUpper_;
whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
#ifndef NDEBUG
int n = numberColumns_;
#endif
while (indexFirst != indexLast) {
const int iColumn=*indexFirst++;
#ifndef NDEBUG
if (iColumn<0||iColumn>=n) {
indexError(iColumn,"setColumnSetBounds");
}
#endif
lower[iColumn]= *boundList++;
upper[iColumn]= *boundList++;
CoinAssert (upper[iColumn]>=lower[iColumn]);
if (lower[iColumn]<-1.0e27)
lower[iColumn]=-COIN_DBL_MAX;
if (upper[iColumn]>1.0e27)
upper[iColumn]=COIN_DBL_MAX;
}
}
//-----------------------------------------------------------------------------
//#############################################################################
// Copy constructor.
ClpModel::ClpModel(const ClpModel &rhs, int scalingMode) :
optimizationDirection_(rhs.optimizationDirection_),
numberRows_(rhs.numberRows_),
numberColumns_(rhs.numberColumns_)
{
gutsOfCopy(rhs);
if (scalingMode>=0&&matrix_&&
matrix_->allElementsInRange(this,smallElement_,1.0e20)) {
// really do scaling
scalingFlag_=scalingMode;
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
delete rowCopy_; // in case odd
rowCopy_=NULL;
if (scalingMode&&!matrix_->scale(this)) {
// scaling worked - now apply
gutsOfScaling();
// pretend not scaled
scalingFlag_ = -scalingFlag_;
} else {
// not scaled
scalingFlag_=0;
}
}
CoinSeedRandom(1234567);
}
// Assignment operator. This copies the data
ClpModel &
ClpModel::operator=(const ClpModel & rhs)
{
if (this != &rhs) {
if (defaultHandler_) {
delete handler_;
handler_ = NULL;
}
gutsOfDelete();
optimizationDirection_ = rhs.optimizationDirection_;
numberRows_ = rhs.numberRows_;
numberColumns_ = rhs.numberColumns_;
gutsOfCopy(rhs);
}
return *this;
}
// Does most of copying
void
ClpModel::gutsOfCopy(const ClpModel & rhs, bool trueCopy)
{
defaultHandler_ = rhs.defaultHandler_;
if (defaultHandler_)
handler_ = new CoinMessageHandler(*rhs.handler_);
else
handler_ = rhs.handler_;
eventHandler_ = rhs.eventHandler_->clone();
messages_ = rhs.messages_;
coinMessages_ = rhs.coinMessages_;
intParam_[ClpMaxNumIteration] = rhs.intParam_[ClpMaxNumIteration];
intParam_[ClpMaxNumIterationHotStart] =
rhs.intParam_[ClpMaxNumIterationHotStart];
intParam_[ClpNameDiscipline] = rhs.intParam_[ClpNameDiscipline] ;
dblParam_[ClpDualObjectiveLimit] = rhs.dblParam_[ClpDualObjectiveLimit];
dblParam_[ClpPrimalObjectiveLimit] = rhs.dblParam_[ClpPrimalObjectiveLimit];
dblParam_[ClpDualTolerance] = rhs.dblParam_[ClpDualTolerance];
dblParam_[ClpPrimalTolerance] = rhs.dblParam_[ClpPrimalTolerance];
dblParam_[ClpObjOffset] = rhs.dblParam_[ClpObjOffset];
dblParam_[ClpMaxSeconds] = rhs.dblParam_[ClpMaxSeconds];
dblParam_[ClpPresolveTolerance] = rhs.dblParam_[ClpPresolveTolerance];
#ifndef CLP_NO_STD
strParam_[ClpProbName] = rhs.strParam_[ClpProbName];
#endif
optimizationDirection_ = rhs.optimizationDirection_;
objectiveValue_=rhs.objectiveValue_;
smallElement_ = rhs.smallElement_;
objectiveScale_ = rhs.objectiveScale_;
rhsScale_ = rhs.rhsScale_;
numberIterations_ = rhs.numberIterations_;
solveType_ = rhs.solveType_;
whatsChanged_ = rhs.whatsChanged_;
problemStatus_ = rhs.problemStatus_;
secondaryStatus_ = rhs.secondaryStatus_;
numberRows_ = rhs.numberRows_;
numberColumns_ = rhs.numberColumns_;
userPointer_ = rhs.userPointer_;
scalingFlag_ = rhs.scalingFlag_;
specialOptions_ = rhs.specialOptions_;
if (trueCopy) {
#ifndef CLP_NO_STD
lengthNames_ = rhs.lengthNames_;
if (lengthNames_) {
rowNames_ = rhs.rowNames_;
columnNames_ = rhs.columnNames_;
}
#endif
numberThreads_ = rhs.numberThreads_;
integerType_ = CoinCopyOfArray(rhs.integerType_,numberColumns_);
if (rhs.rowActivity_) {
rowActivity_=new double[numberRows_];
columnActivity_=new double[numberColumns_];
dual_=new double[numberRows_];
reducedCost_=new double[numberColumns_];
ClpDisjointCopyN ( rhs.rowActivity_, numberRows_ ,
rowActivity_);
ClpDisjointCopyN ( rhs.columnActivity_, numberColumns_ ,
columnActivity_);
ClpDisjointCopyN ( rhs.dual_, numberRows_ ,
dual_);
ClpDisjointCopyN ( rhs.reducedCost_, numberColumns_ ,
reducedCost_);
} else {
rowActivity_=NULL;
columnActivity_=NULL;
dual_=NULL;
reducedCost_=NULL;
}
rowLower_ = ClpCopyOfArray ( rhs.rowLower_, numberRows_ );
rowUpper_ = ClpCopyOfArray ( rhs.rowUpper_, numberRows_ );
columnLower_ = ClpCopyOfArray ( rhs.columnLower_, numberColumns_ );
int scaleLength = ((specialOptions_&131072)==0) ? 1 : 2;
columnUpper_ = ClpCopyOfArray ( rhs.columnUpper_, numberColumns_ );
rowScale_ = ClpCopyOfArray(rhs.rowScale_,numberRows_*scaleLength);
columnScale_ = ClpCopyOfArray(rhs.columnScale_,numberColumns_*scaleLength);
if (rhs.objective_)
objective_ = rhs.objective_->clone();
else
objective_ = NULL;
rowObjective_ = ClpCopyOfArray ( rhs.rowObjective_, numberRows_ );
status_ = ClpCopyOfArray( rhs.status_,numberColumns_+numberRows_);
ray_ = NULL;
if (problemStatus_==1&&!secondaryStatus_)
ray_ = ClpCopyOfArray (rhs.ray_,numberRows_);
else if (problemStatus_==2)
ray_ = ClpCopyOfArray (rhs.ray_,numberColumns_);
if (rhs.rowCopy_) {
rowCopy_ = rhs.rowCopy_->clone();
} else {
rowCopy_=NULL;
}
matrix_=NULL;
if (rhs.matrix_) {
matrix_ = rhs.matrix_->clone();
}
} else {
rowActivity_ = rhs.rowActivity_;
columnActivity_ = rhs.columnActivity_;
dual_ = rhs.dual_;
reducedCost_ = rhs.reducedCost_;
rowLower_ = rhs.rowLower_;
rowUpper_ = rhs.rowUpper_;
objective_ = rhs.objective_;
rowObjective_ = rhs.rowObjective_;
columnLower_ = rhs.columnLower_;
columnUpper_ = rhs.columnUpper_;
matrix_ = rhs.matrix_;
rowCopy_ = NULL;
ray_ = rhs.ray_;
//rowScale_ = rhs.rowScale_;
//columnScale_ = rhs.columnScale_;
lengthNames_ = 0;
numberThreads_ = rhs.numberThreads_;
#ifndef CLP_NO_STD
rowNames_ = std::vector<std::string> ();
columnNames_ = std::vector<std::string> ();
#endif
integerType_ = NULL;
status_ = rhs.status_;
}
}
/* Borrow model. This is so we dont have to copy large amounts
of data around. It assumes a derived class wants to overwrite
an empty model with a real one - while it does an algorithm */
void
ClpModel::borrowModel(ClpModel & rhs)
{
if (defaultHandler_) {
delete handler_;
handler_ = NULL;
}
gutsOfDelete();
optimizationDirection_ = rhs.optimizationDirection_;
numberRows_ = rhs.numberRows_;
numberColumns_ = rhs.numberColumns_;
delete [] rhs.ray_;
rhs.ray_=NULL;
gutsOfCopy(rhs,false);
}
// Return model - nulls all arrays so can be deleted safely
void
ClpModel::returnModel(ClpModel & otherModel)
{
otherModel.objectiveValue_=objectiveValue_;
otherModel.numberIterations_ = numberIterations_;
otherModel.problemStatus_ = problemStatus_;
otherModel.secondaryStatus_ = secondaryStatus_;
rowActivity_ = NULL;
columnActivity_ = NULL;
dual_ = NULL;
reducedCost_ = NULL;
rowLower_ = NULL;
rowUpper_ = NULL;
objective_ = NULL;
rowObjective_ = NULL;
columnLower_ = NULL;
columnUpper_ = NULL;
matrix_ = NULL;
rowCopy_ = NULL;
delete [] otherModel.ray_;
otherModel.ray_ = ray_;
ray_ = NULL;
//rowScale_=NULL;
//columnScale_=NULL;
// do status
if (otherModel.status_!=status_) {
delete [] otherModel.status_;
otherModel.status_ = status_;
}
status_ = NULL;
if (defaultHandler_) {
delete handler_;
handler_ = NULL;
}
}
//#############################################################################
// Parameter related methods
//#############################################################################
bool
ClpModel::setIntParam(ClpIntParam key, int value)
{
switch (key) {
case ClpMaxNumIteration:
if (value < 0)
return false;
break;
case ClpMaxNumIterationHotStart:
if (value < 0)
return false;
break;
case ClpNameDiscipline:
if (value < 0)
return false;
break;
default:
return false;
}
intParam_[key] = value;
return true;
}
//-----------------------------------------------------------------------------
bool
ClpModel::setDblParam(ClpDblParam key, double value)
{
switch (key) {
case ClpDualObjectiveLimit:
break;
case ClpPrimalObjectiveLimit:
break;
case ClpDualTolerance:
if (value<=0.0||value>1.0e10)
return false;
break;
case ClpPrimalTolerance:
if (value<=0.0||value>1.0e10)
return false;
break;
case ClpObjOffset:
break;
case ClpMaxSeconds:
if(value>=0)
value += CoinCpuTime();
else
value = -1.0;
break;
case ClpPresolveTolerance:
if (value<=0.0||value>1.0e10)
return false;
break;
default:
return false;
}
dblParam_[key] = value;
return true;
}
//-----------------------------------------------------------------------------
#ifndef CLP_NO_STD
bool
ClpModel::setStrParam(ClpStrParam key, const std::string & value)
{
switch (key) {
case ClpProbName:
break;
default:
return false;
}
strParam_[key] = value;
return true;
}
#endif
// Useful routines
// Returns resized array and deletes incoming
double * resizeDouble(double * array , int size, int newSize, double fill,
bool createArray)
{
if ((array||createArray)&&size!=newSize) {
int i;
double * newArray = new double[newSize];
if (array)
CoinMemcpyN(array,CoinMin(newSize,size),newArray);
delete [] array;
array = newArray;
for (i=size;i<newSize;i++)
array[i]=fill;
}
return array;
}
// Returns resized array and updates size
double * deleteDouble(double * array , int size,
int number, const int * which,int & newSize)
{
if (array) {
int i ;
char * deleted = new char[size];
int numberDeleted=0;
CoinZeroN(deleted,size);
for (i=0;i<number;i++) {
int j = which[i];
if (j>=0&&j<size&&!deleted[j]) {
numberDeleted++;
deleted[j]=1;
}
}
newSize = size-numberDeleted;
double * newArray = new double[newSize];
int put=0;
for (i=0;i<size;i++) {
if (!deleted[i]) {
newArray[put++]=array[i];
}
}
delete [] array;
array = newArray;
delete [] deleted;
}
return array;
}
char * deleteChar(char * array , int size,
int number, const int * which,int & newSize,
bool ifDelete)
{
if (array) {
int i ;
char * deleted = new char[size];
int numberDeleted=0;
CoinZeroN(deleted,size);
for (i=0;i<number;i++) {
int j = which[i];
if (j>=0&&j<size&&!deleted[j]) {
numberDeleted++;
deleted[j]=1;
}
}
newSize = size-numberDeleted;
char * newArray = new char[newSize];
int put=0;
for (i=0;i<size;i++) {
if (!deleted[i]) {
newArray[put++]=array[i];
}
}
if (ifDelete)
delete [] array;
array = newArray;
delete [] deleted;
}
return array;
}
// Create empty ClpPackedMatrix
void
ClpModel::createEmptyMatrix()
{
delete matrix_;
whatsChanged_ = 0;
CoinPackedMatrix matrix2;
matrix_=new ClpPackedMatrix(matrix2);
}
/* Really clean up matrix.
a) eliminate all duplicate AND small elements in matrix
b) remove all gaps and set extraGap_ and extraMajor_ to 0.0
c) reallocate arrays and make max lengths equal to lengths
d) orders elements
returns number of elements eliminated or -1 if not ClpMatrix
*/
int
ClpModel::cleanMatrix(double threshold)
{
ClpPackedMatrix * matrix = (dynamic_cast< ClpPackedMatrix*>(matrix_));
if (matrix) {
return matrix->getPackedMatrix()->cleanMatrix(threshold);
} else {
return -1;
}
}
// Resizes
void
ClpModel::resize (int newNumberRows, int newNumberColumns)
{
if (newNumberRows==numberRows_&&
newNumberColumns==numberColumns_)
return; // nothing to do
whatsChanged_ = 0;
rowActivity_ = resizeDouble(rowActivity_,numberRows_,
newNumberRows,0.0,true);
dual_ = resizeDouble(dual_,numberRows_,
newNumberRows,0.0,true);
rowObjective_ = resizeDouble(rowObjective_,numberRows_,
newNumberRows,0.0,false);
rowLower_ = resizeDouble(rowLower_,numberRows_,
newNumberRows,-COIN_DBL_MAX,true);
rowUpper_ = resizeDouble(rowUpper_,numberRows_,
newNumberRows,COIN_DBL_MAX,true);
columnActivity_ = resizeDouble(columnActivity_,numberColumns_,
newNumberColumns,0.0,true);
reducedCost_ = resizeDouble(reducedCost_,numberColumns_,
newNumberColumns,0.0,true);
if (objective_)
objective_->resize(newNumberColumns);
else
objective_ = new ClpLinearObjective(NULL,newNumberColumns);
columnLower_ = resizeDouble(columnLower_,numberColumns_,
newNumberColumns,0.0,true);
columnUpper_ = resizeDouble(columnUpper_,numberColumns_,
newNumberColumns,COIN_DBL_MAX,true);
if (newNumberRows<numberRows_) {
int * which = new int[numberRows_-newNumberRows];
int i;
for (i=newNumberRows;i<numberRows_;i++)
which[i-newNumberRows]=i;
matrix_->deleteRows(numberRows_-newNumberRows,which);
delete [] which;
}
if (numberRows_!=newNumberRows||numberColumns_!=newNumberColumns) {
// set state back to unknown
problemStatus_ = -1;
secondaryStatus_ = 0;
delete [] ray_;
ray_ = NULL;
}
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
if (status_) {
if (newNumberColumns+newNumberRows) {
unsigned char * tempC = new unsigned char [newNumberColumns+newNumberRows];
unsigned char * tempR = tempC + newNumberColumns;
memset(tempC,3,newNumberColumns*sizeof(unsigned char));
memset(tempR,1,newNumberRows*sizeof(unsigned char));
memcpy(tempC,status_,CoinMin(newNumberColumns,numberColumns_)*sizeof(unsigned char));
memcpy(tempR,status_+numberColumns_,CoinMin(newNumberRows,numberRows_)*sizeof(unsigned char));
delete [] status_;
status_ = tempC;
} else {
// empty model - some systems don't like new [0]
delete [] status_;
status_ = NULL;
}
}
#ifndef CLP_NO_STD
if (lengthNames_) {
// redo row and column names
if (numberRows_ < newNumberRows) {
rowNames_.resize(newNumberRows);
lengthNames_ = CoinMax(lengthNames_,8);
char name[9];
for (int iRow = numberRows_;iRow<newNumberRows;iRow++) {
sprintf(name,"R%7.7d",iRow);
rowNames_[iRow]=name;
}
}
if (numberColumns_ < newNumberColumns) {
columnNames_.resize(newNumberColumns);
lengthNames_ = CoinMax(lengthNames_,8);
char name[9];
for (int iColumn = numberColumns_;iColumn<newNumberColumns;iColumn++) {
sprintf(name,"C%7.7d",iColumn);
columnNames_[iColumn]=name;
}
}
}
#endif
numberRows_ = newNumberRows;
if (newNumberColumns<numberColumns_&&matrix_->getNumCols()) {
int * which = new int[numberColumns_-newNumberColumns];
int i;
for (i=newNumberColumns;i<numberColumns_;i++)
which[i-newNumberColumns]=i;
matrix_->deleteCols(numberColumns_-newNumberColumns,which);
delete [] which;
}
if (integerType_) {
char * temp = new char [newNumberColumns];
CoinZeroN(temp,newNumberColumns);
CoinMemcpyN(integerType_,
CoinMin(newNumberColumns,numberColumns_),temp);
delete [] integerType_;
integerType_ = temp;
}
numberColumns_ = newNumberColumns;
}
// Deletes rows
void
ClpModel::deleteRows(int number, const int * which)
{
if (!number)
return; // nothing to do
whatsChanged_ &= ~(1+2+4+8+16+32); // all except columns changed
int newSize=0;
rowActivity_ = deleteDouble(rowActivity_,numberRows_,
number, which, newSize);
dual_ = deleteDouble(dual_,numberRows_,
number, which, newSize);
rowObjective_ = deleteDouble(rowObjective_,numberRows_,
number, which, newSize);
rowLower_ = deleteDouble(rowLower_,numberRows_,
number, which, newSize);
rowUpper_ = deleteDouble(rowUpper_,numberRows_,
number, which, newSize);
if (matrix_->getNumRows())
matrix_->deleteRows(number,which);
//matrix_->removeGaps();
// status
if (status_) {
if (numberColumns_+newSize) {
unsigned char * tempR = (unsigned char *) deleteChar((char *)status_+numberColumns_,
numberRows_,
number, which, newSize,false);
unsigned char * tempC = new unsigned char [numberColumns_+newSize];
memcpy(tempC,status_,numberColumns_*sizeof(unsigned char));
memcpy(tempC+numberColumns_,tempR,newSize*sizeof(unsigned char));
delete [] tempR;
delete [] status_;
status_ = tempC;
} else {
// empty model - some systems don't like new [0]
delete [] status_;
status_ = NULL;
}
}
#ifndef CLP_NO_STD
// Now works if which out of order
if (lengthNames_) {
char * mark = new char [numberRows_];
CoinZeroN(mark,numberRows_);
int i;
for (i=0;i<number;i++)
mark[which[i]]=1;
int k=0;
for ( i = 0; i < numberRows_; ++i) {
if (!mark[i])
rowNames_[k++] = rowNames_[i];
}
rowNames_.erase(rowNames_.begin()+k, rowNames_.end());
delete [] mark;
}
#endif
numberRows_=newSize;
// set state back to unknown
problemStatus_ = -1;
secondaryStatus_ = 0;
delete [] ray_;
ray_ = NULL;
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
}
// Deletes columns
void
ClpModel::deleteColumns(int number, const int * which)
{
if (!number)
return; // nothing to do
whatsChanged_ &= ~(1+2+4+8+64+128+256); // all except rows changed
int newSize=0;
columnActivity_ = deleteDouble(columnActivity_,numberColumns_,
number, which, newSize);
reducedCost_ = deleteDouble(reducedCost_,numberColumns_,
number, which, newSize);
objective_->deleteSome(number, which);
columnLower_ = deleteDouble(columnLower_,numberColumns_,
number, which, newSize);
columnUpper_ = deleteDouble(columnUpper_,numberColumns_,
number, which, newSize);
// possible matrix is not full
if (matrix_->getNumCols()<numberColumns_) {
int * which2 = new int [number];
int n=0;
int nMatrix = matrix_->getNumCols();
for (int i=0;i<number;i++) {
if (which[i]<nMatrix)
which2[n++]=which[i];
}
matrix_->deleteCols(n,which2);
delete [] which2;
} else {
matrix_->deleteCols(number,which);
}
//matrix_->removeGaps();
// status
if (status_) {
if (numberRows_+newSize) {
unsigned char * tempC = (unsigned char *) deleteChar((char *)status_,
numberColumns_,
number, which, newSize,false);
unsigned char * temp = new unsigned char [numberRows_+newSize];
memcpy(temp,tempC,newSize*sizeof(unsigned char));
memcpy(temp+newSize,status_+numberColumns_,
numberRows_*sizeof(unsigned char));
delete [] tempC;
delete [] status_;
status_ = temp;
} else {
// empty model - some systems don't like new [0]
delete [] status_;
status_ = NULL;
}
}
integerType_ = deleteChar(integerType_,numberColumns_,
number, which, newSize,true);
#ifndef CLP_NO_STD
// Now works if which out of order
if (lengthNames_) {
char * mark = new char [numberColumns_];
CoinZeroN(mark,numberColumns_);
int i;
for (i=0;i<number;i++)
mark[which[i]]=1;
int k=0;
for ( i = 0; i < numberColumns_; ++i) {
if (!mark[i])
columnNames_[k++] = columnNames_[i];
}
columnNames_.erase(columnNames_.begin()+k, columnNames_.end());
delete [] mark;
}
#endif
numberColumns_=newSize;
// set state back to unknown
problemStatus_ = -1;
secondaryStatus_ = 0;
delete [] ray_;
ray_ = NULL;
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
}
// Add one row
void
ClpModel::addRow(int numberInRow, const int * columns,
const double * elements, double rowLower, double rowUpper)
{
CoinBigIndex starts[2];
starts[0]=0;
starts[1]=numberInRow;
addRows(1, &rowLower, &rowUpper,starts,columns,elements);
}
// Add rows
void
ClpModel::addRows(int number, const double * rowLower,
const double * rowUpper,
const int * rowStarts, const int * columns,
const double * elements)
{
if (number) {
whatsChanged_ &= ~(1+2+8+16+32); // all except columns changed
int numberRowsNow = numberRows_;
resize(numberRowsNow+number,numberColumns_);
double * lower = rowLower_+numberRowsNow;
double * upper = rowUpper_+numberRowsNow;
int iRow;
if (rowLower) {
for (iRow = 0; iRow < number; iRow++) {
double value = rowLower[iRow];
if (value<-1.0e20)
value = -COIN_DBL_MAX;
lower[iRow]= value;
}
} else {
for (iRow = 0; iRow < number; iRow++) {
lower[iRow]= -COIN_DBL_MAX;
}
}
if (rowUpper) {
for (iRow = 0; iRow < number; iRow++) {
double value = rowUpper[iRow];
if (value>1.0e20)
value = COIN_DBL_MAX;
upper[iRow]= value;
}
} else {
for (iRow = 0; iRow < number; iRow++) {
upper[iRow]= COIN_DBL_MAX;
}
}
// Deal with matrix
delete rowCopy_;
rowCopy_=NULL;
if (!matrix_)
createEmptyMatrix();
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
#ifndef CLP_NO_STD
if (lengthNames_) {
rowNames_.resize(numberRows_);
}
#endif
//if (elements)
matrix_->appendMatrix(number,0,rowStarts,columns,elements);
}
}
// Add rows
void
ClpModel::addRows(int number, const double * rowLower,
const double * rowUpper,
const int * rowStarts,
const int * rowLengths, const int * columns,
const double * elements)
{
if (number) {
CoinBigIndex numberElements=0;
int iRow;
for (iRow=0;iRow<number;iRow++)
numberElements += rowLengths[iRow];
int * newStarts = new int[number+1];
int * newIndex = new int[numberElements];
double * newElements = new double[numberElements];
numberElements=0;
newStarts[0]=0;
for (iRow=0;iRow<number;iRow++) {
int iStart = rowStarts[iRow];
int length = rowLengths[iRow];
CoinMemcpyN(columns+iStart,length,newIndex+numberElements);
CoinMemcpyN(elements+iStart,length,newElements+numberElements);
numberElements += length;
newStarts[iRow+1]=numberElements;
}
addRows(number, rowLower, rowUpper,
newStarts,newIndex,newElements);
delete [] newStarts;
delete [] newIndex;
delete [] newElements;
}
}
#ifndef CLP_NO_VECTOR
void
ClpModel::addRows(int number, const double * rowLower,
const double * rowUpper,
const CoinPackedVectorBase * const * rows)
{
if (!number)
return;
whatsChanged_ &= ~(1+2+8+16+32); // all except columns changed
int numberRowsNow = numberRows_;
resize(numberRowsNow+number,numberColumns_);
double * lower = rowLower_+numberRowsNow;
double * upper = rowUpper_+numberRowsNow;
int iRow;
if (rowLower) {
for (iRow = 0; iRow < number; iRow++) {
double value = rowLower[iRow];
if (value<-1.0e20)
value = -COIN_DBL_MAX;
lower[iRow]= value;
}
} else {
for (iRow = 0; iRow < number; iRow++) {
lower[iRow]= -COIN_DBL_MAX;
}
}
if (rowUpper) {
for (iRow = 0; iRow < number; iRow++) {
double value = rowUpper[iRow];
if (value>1.0e20)
value = COIN_DBL_MAX;
upper[iRow]= value;
}
} else {
for (iRow = 0; iRow < number; iRow++) {
upper[iRow]= COIN_DBL_MAX;
}
}
// Deal with matrix
delete rowCopy_;
rowCopy_=NULL;
if (!matrix_)
createEmptyMatrix();
if (rows)
matrix_->appendRows(number,rows);
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
if (lengthNames_) {
rowNames_.resize(numberRows_);
}
}
#endif
#ifndef SLIM_CLP
// Add rows from a build object
int
ClpModel::addRows(const CoinBuild & buildObject,bool tryPlusMinusOne,bool checkDuplicates)
{
CoinAssertHint (buildObject.type()==0,"Looks as if both addRows and addCols being used"); // check correct
int number = buildObject.numberRows();
int numberErrors=0;
if (number) {
CoinBigIndex size=0;
int iRow;
double * lower = new double [number];
double * upper = new double [number];
if ((!matrix_||!matrix_->getNumElements())&&tryPlusMinusOne) {
// See if can be +-1
for (iRow=0;iRow<number;iRow++) {
const int * columns;
const double * elements;
int numberElements = buildObject.row(iRow,lower[iRow],
upper[iRow],
columns,elements);
for (int i=0;i<numberElements;i++) {
// allow for zero elements
if (elements[i]) {
if (fabs(elements[i])==1.0) {
size++;
} else {
// bad
tryPlusMinusOne=false;
}
}
}
if (!tryPlusMinusOne)
break;
}
} else {
// Will add to whatever sort of matrix exists
tryPlusMinusOne=false;
}
if (!tryPlusMinusOne) {
CoinBigIndex numberElements = buildObject.numberElements();
CoinBigIndex * starts = new CoinBigIndex [number+1];
int * column = new int[numberElements];
double * element = new double[numberElements];
starts[0]=0;
numberElements=0;
for (iRow=0;iRow<number;iRow++) {
const int * columns;
const double * elements;
int numberElementsThis = buildObject.row(iRow,lower[iRow],upper[iRow],
columns,elements);
CoinMemcpyN(columns,numberElementsThis,column+numberElements);
CoinMemcpyN(elements,numberElementsThis,element+numberElements);
numberElements += numberElementsThis;
starts[iRow+1]=numberElements;
}
addRows(number, lower, upper,NULL);
// make sure matrix has enough columns
matrix_->setDimensions(-1,numberColumns_);
numberErrors=matrix_->appendMatrix(number,0,starts,column,element,
checkDuplicates ? numberColumns_ : -1);
delete [] starts;
delete [] column;
delete [] element;
} else {
char * which=NULL; // for duplicates
if (checkDuplicates) {
which = new char[numberColumns_];
CoinZeroN(which,numberColumns_);
}
// build +-1 matrix
// arrays already filled in
addRows(number, lower, upper,NULL);
CoinBigIndex * startPositive = new CoinBigIndex [numberColumns_+1];
CoinBigIndex * startNegative = new CoinBigIndex [numberColumns_];
int * indices = new int [size];
CoinZeroN(startPositive,numberColumns_);
CoinZeroN(startNegative,numberColumns_);
int maxColumn=-1;
// need two passes
for (iRow=0;iRow<number;iRow++) {
const int * columns;
const double * elements;
int numberElements = buildObject.row(iRow,lower[iRow],
upper[iRow],
columns,elements);
for (int i=0;i<numberElements;i++) {
int iColumn=columns[i];
if (checkDuplicates) {
if (iColumn>=numberColumns_) {
if(which[iColumn])
numberErrors++;
else
which[iColumn]=1;
} else {
numberErrors++;
// and may as well switch off
checkDuplicates=false;
}
}
maxColumn = CoinMax(maxColumn,iColumn);
if (elements[i]==1.0) {
startPositive[iColumn]++;
} else if (elements[i]==-1.0) {
startNegative[iColumn]++;
}
}
if (checkDuplicates) {
for (int i=0;i<numberElements;i++) {
int iColumn=columns[i];
which[iColumn]=0;
}
}
}
// check size
int numberColumns = maxColumn+1;
CoinAssertHint (numberColumns<=numberColumns_,
"rows having column indices >= numberColumns_");
size=0;
int iColumn;
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
CoinBigIndex n=startPositive[iColumn];
startPositive[iColumn]=size;
size+= n;
n=startNegative[iColumn];
startNegative[iColumn]=size;
size+= n;
}
startPositive[numberColumns_]=size;
for (iRow=0;iRow<number;iRow++) {
const int * columns;
const double * elements;
int numberElements = buildObject.row(iRow,lower[iRow],
upper[iRow],
columns,elements);
for (int i=0;i<numberElements;i++) {
int iColumn=columns[i];
maxColumn = CoinMax(maxColumn,iColumn);
if (elements[i]==1.0) {
CoinBigIndex position = startPositive[iColumn];
indices[position]=iRow;
startPositive[iColumn]++;
} else if (elements[i]==-1.0) {
CoinBigIndex position = startNegative[iColumn];
indices[position]=iRow;
startNegative[iColumn]++;
}
}
}
// and now redo starts
for (iColumn=numberColumns_-1;iColumn>=0;iColumn--) {
startPositive[iColumn+1]=startNegative[iColumn];
startNegative[iColumn]=startPositive[iColumn];
}
startPositive[0]=0;
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
CoinBigIndex start = startPositive[iColumn];
CoinBigIndex end = startNegative[iColumn];
std::sort(indices+start,indices+end);
start = startNegative[iColumn];
end = startPositive[iColumn+1];
std::sort(indices+start,indices+end);
}
// Get good object
delete matrix_;
ClpPlusMinusOneMatrix * matrix = new ClpPlusMinusOneMatrix();
matrix->passInCopy(numberRows_,numberColumns,
true,indices,startPositive,startNegative);
matrix_=matrix;
delete [] which;
}
delete [] lower;
delete [] upper;
// make sure matrix correct size
matrix_->setDimensions(numberRows_,numberColumns_);
}
return numberErrors;
}
#endif
#ifndef SLIM_NOIO
// Add rows from a model object
int
ClpModel::addRows( CoinModel & modelObject,bool tryPlusMinusOne,bool checkDuplicates)
{
if (modelObject.numberElements()==0)
return 0;
bool goodState=true;
int numberErrors=0;
if (modelObject.columnLowerArray()) {
// some column information exists
int numberColumns2 = modelObject.numberColumns();
const double * columnLower = modelObject.columnLowerArray();
const double * columnUpper = modelObject.columnUpperArray();
const double * objective = modelObject.objectiveArray();
const int * integerType = modelObject.integerTypeArray();
for (int i=0;i<numberColumns2;i++) {
if (columnLower[i]!=0.0)
goodState=false;
if (columnUpper[i]!=COIN_DBL_MAX)
goodState=false;
if (objective[i]!=0.0)
goodState=false;
if (integerType[i]!=0)
goodState=false;
}
}
if (goodState) {
// can do addRows
// Set arrays for normal use
double * rowLower = modelObject.rowLowerArray();
double * rowUpper = modelObject.rowUpperArray();
double * columnLower = modelObject.columnLowerArray();
double * columnUpper = modelObject.columnUpperArray();
double * objective = modelObject.objectiveArray();
int * integerType = modelObject.integerTypeArray();
double * associated = modelObject.associatedArray();
// If strings then do copies
if (modelObject.stringsExist()) {
numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
objective, integerType,associated);
}
int numberRows = numberRows_; // save number of rows
int numberRows2 = modelObject.numberRows();
if (numberRows2&&!numberErrors) {
CoinBigIndex * startPositive = NULL;
CoinBigIndex * startNegative = NULL;
int numberColumns = modelObject.numberColumns();
if ((!matrix_||!matrix_->getNumElements())&&!numberRows&&tryPlusMinusOne) {
startPositive = new CoinBigIndex[numberColumns+1];
startNegative = new CoinBigIndex[numberColumns];
modelObject.countPlusMinusOne(startPositive,startNegative,associated);
if (startPositive[0]<0) {
// no good
tryPlusMinusOne=false;
delete [] startPositive;
delete [] startNegative;
}
} else {
// Will add to whatever sort of matrix exists
tryPlusMinusOne=false;
}
assert (rowLower);
addRows(numberRows2, rowLower, rowUpper,NULL,NULL,NULL);
#ifndef SLIM_CLP
if (!tryPlusMinusOne) {
#endif
CoinPackedMatrix matrix;
modelObject.createPackedMatrix(matrix,associated);
assert (!matrix.getExtraGap());
if (matrix_->getNumRows()) {
// matrix by rows
matrix.reverseOrdering();
assert (!matrix.getExtraGap());
const int * column = matrix.getIndices();
//const int * rowLength = matrix.getVectorLengths();
const CoinBigIndex * rowStart = matrix.getVectorStarts();
const double * element = matrix.getElements();
// make sure matrix has enough columns
matrix_->setDimensions(-1,numberColumns_);
numberErrors+=matrix_->appendMatrix(numberRows2,0,rowStart,column,element,
checkDuplicates ? numberColumns_ : -1);
} else {
delete matrix_;
matrix_ = new ClpPackedMatrix(matrix);
}
#ifndef SLIM_CLP
} else {
// create +-1 matrix
CoinBigIndex size = startPositive[numberColumns];
int * indices = new int[size];
modelObject.createPlusMinusOne(startPositive,startNegative,indices,
associated);
// Get good object
ClpPlusMinusOneMatrix * matrix = new ClpPlusMinusOneMatrix();
matrix->passInCopy(numberRows2,numberColumns,
true,indices,startPositive,startNegative);
delete matrix_;
matrix_=matrix;
}
// Do names if wanted
if (modelObject.rowNames()->numberItems()) {
const char *const * rowNames=modelObject.rowNames()->names();
copyRowNames(rowNames,numberRows,numberRows_);
}
#endif
}
if (rowLower!=modelObject.rowLowerArray()) {
delete [] rowLower;
delete [] rowUpper;
delete [] columnLower;
delete [] columnUpper;
delete [] objective;
delete [] integerType;
delete [] associated;
if (numberErrors)
handler_->message(CLP_BAD_STRING_VALUES,messages_)
<<numberErrors
<<CoinMessageEol;
}
return numberErrors;
} else {
// not suitable for addRows
handler_->message(CLP_COMPLICATED_MODEL,messages_)
<<modelObject.numberRows()
<<modelObject.numberColumns()
<<CoinMessageEol;
return -1;
}
}
#endif
// Add one column
void
ClpModel::addColumn(int numberInColumn,
const int * rows,
const double * elements,
double columnLower,
double columnUpper,
double objective)
{
CoinBigIndex starts[2];
starts[0]=0;
starts[1]=numberInColumn;
addColumns(1, &columnLower, &columnUpper,&objective,starts,rows,elements);
}
// Add columns
void
ClpModel::addColumns(int number, const double * columnLower,
const double * columnUpper,
const double * objIn,
const int * columnStarts, const int * rows,
const double * elements)
{
// Create a list of CoinPackedVectors
if (number) {
whatsChanged_ &= ~(1+2+4+64+128+256); // all except rows changed
int numberColumnsNow = numberColumns_;
resize(numberRows_,numberColumnsNow+number);
double * lower = columnLower_+numberColumnsNow;
double * upper = columnUpper_+numberColumnsNow;
double * obj = objective()+numberColumnsNow;
int iColumn;
if (columnLower) {
for (iColumn = 0; iColumn < number; iColumn++) {
double value = columnLower[iColumn];
if (value<-1.0e20)
value = -COIN_DBL_MAX;
lower[iColumn]= value;
}
} else {
for (iColumn = 0; iColumn < number; iColumn++) {
lower[iColumn]= 0.0;
}
}
if (columnUpper) {
for (iColumn = 0; iColumn < number; iColumn++) {
double value = columnUpper[iColumn];
if (value>1.0e20)
value = COIN_DBL_MAX;
upper[iColumn]= value;
}
} else {
for (iColumn = 0; iColumn < number; iColumn++) {
upper[iColumn]= COIN_DBL_MAX;
}
}
if (objIn) {
for (iColumn = 0; iColumn < number; iColumn++) {
obj[iColumn] = objIn[iColumn];
}
} else {
for (iColumn = 0; iColumn < number; iColumn++) {
obj[iColumn]= 0.0;
}
}
// Deal with matrix
delete rowCopy_;
rowCopy_=NULL;
if (!matrix_)
createEmptyMatrix();
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
#ifndef CLP_NO_STD
if (lengthNames_) {
columnNames_.resize(numberColumns_);
}
#endif
//if (elements)
matrix_->appendMatrix(number,1,columnStarts,rows,elements);
}
}
// Add columns
void
ClpModel::addColumns(int number, const double * columnLower,
const double * columnUpper,
const double * objIn,
const int * columnStarts,
const int * columnLengths, const int * rows,
const double * elements)
{
if (number) {
CoinBigIndex numberElements=0;
int iColumn;
for (iColumn=0;iColumn<number;iColumn++)
numberElements += columnLengths[iColumn];
int * newStarts = new int[number+1];
int * newIndex = new int[numberElements];
double * newElements = new double[numberElements];
numberElements=0;
newStarts[0]=0;
for (iColumn=0;iColumn<number;iColumn++) {
int iStart = columnStarts[iColumn];
int length = columnLengths[iColumn];
CoinMemcpyN(rows+iStart,length,newIndex+numberElements);
CoinMemcpyN(elements+iStart,length,newElements+numberElements);
numberElements += length;
newStarts[iColumn+1]=numberElements;
}
addColumns(number, columnLower, columnUpper,objIn,
newStarts,newIndex,newElements);
delete [] newStarts;
delete [] newIndex;
delete [] newElements;
}
}
#ifndef CLP_NO_VECTOR
void
ClpModel::addColumns(int number, const double * columnLower,
const double * columnUpper,
const double * objIn,
const CoinPackedVectorBase * const * columns)
{
if (!number)
return;
whatsChanged_ &= ~(1+2+4+64+128+256); // all except rows changed
int numberColumnsNow = numberColumns_;
resize(numberRows_,numberColumnsNow+number);
double * lower = columnLower_+numberColumnsNow;
double * upper = columnUpper_+numberColumnsNow;
double * obj = objective()+numberColumnsNow;
int iColumn;
if (columnLower) {
for (iColumn = 0; iColumn < number; iColumn++) {
double value = columnLower[iColumn];
if (value<-1.0e20)
value = -COIN_DBL_MAX;
lower[iColumn]= value;
}
} else {
for (iColumn = 0; iColumn < number; iColumn++) {
lower[iColumn]= 0.0;
}
}
if (columnUpper) {
for (iColumn = 0; iColumn < number; iColumn++) {
double value = columnUpper[iColumn];
if (value>1.0e20)
value = COIN_DBL_MAX;
upper[iColumn]= value;
}
} else {
for (iColumn = 0; iColumn < number; iColumn++) {
upper[iColumn]= COIN_DBL_MAX;
}
}
if (objIn) {
for (iColumn = 0; iColumn < number; iColumn++) {
obj[iColumn] = objIn[iColumn];
}
} else {
for (iColumn = 0; iColumn < number; iColumn++) {
obj[iColumn]= 0.0;
}
}
// Deal with matrix
delete rowCopy_;
rowCopy_=NULL;
if (!matrix_)
createEmptyMatrix();
if (columns)
matrix_->appendCols(number,columns);
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
if (lengthNames_) {
columnNames_.resize(numberColumns_);
}
}
#endif
#ifndef SLIM_CLP
// Add columns from a build object
int
ClpModel::addColumns(const CoinBuild & buildObject,bool tryPlusMinusOne,bool checkDuplicates)
{
CoinAssertHint (buildObject.type()==1,"Looks as if both addRows and addCols being used"); // check correct
int number = buildObject.numberColumns();
int numberErrors=0;
if (number) {
CoinBigIndex size=0;
int maximumLength=0;
double * lower = new double [number];
double * upper = new double [number];
int iColumn;
double * objective = new double [number];
if ((!matrix_||!matrix_->getNumElements())&&tryPlusMinusOne) {
// See if can be +-1
for (iColumn=0;iColumn<number;iColumn++) {
const int * rows;
const double * elements;
int numberElements = buildObject.column(iColumn,lower[iColumn],
upper[iColumn],objective[iColumn],
rows,elements);
maximumLength = CoinMax(maximumLength,numberElements);
for (int i=0;i<numberElements;i++) {
// allow for zero elements
if (elements[i]) {
if (fabs(elements[i])==1.0) {
size++;
} else {
// bad
tryPlusMinusOne=false;
}
}
}
if (!tryPlusMinusOne)
break;
}
} else {
// Will add to whatever sort of matrix exists
tryPlusMinusOne=false;
}
if (!tryPlusMinusOne) {
CoinBigIndex numberElements = buildObject.numberElements();
CoinBigIndex * starts = new CoinBigIndex [number+1];
int * row = new int[numberElements];
double * element = new double[numberElements];
starts[0]=0;
numberElements=0;
for (iColumn=0;iColumn<number;iColumn++) {
const int * rows;
const double * elements;
int numberElementsThis = buildObject.column(iColumn,lower[iColumn],upper[iColumn],
objective[iColumn],rows,elements);
CoinMemcpyN(rows,numberElementsThis,row+numberElements);
CoinMemcpyN(elements,numberElementsThis,element+numberElements);
numberElements += numberElementsThis;
starts[iColumn+1]=numberElements;
}
addColumns(number, lower, upper,objective,NULL);
// make sure matrix has enough rows
matrix_->setDimensions(numberRows_,-1);
numberErrors=matrix_->appendMatrix(number,1,starts,row,element,
checkDuplicates ? numberRows_ : -1);
delete [] starts;
delete [] row;
delete [] element;
} else {
// arrays already filled in
addColumns(number, lower, upper,objective,NULL);
char * which=NULL; // for duplicates
if (checkDuplicates) {
which = new char[numberRows_];
CoinZeroN(which,numberRows_);
}
// build +-1 matrix
CoinBigIndex * startPositive = new CoinBigIndex [number+1];
CoinBigIndex * startNegative = new CoinBigIndex [number];
int * indices = new int [size];
int * neg = new int[maximumLength];
startPositive[0]=0;
size=0;
int maxRow=-1;
for (iColumn=0;iColumn<number;iColumn++) {
const int * rows;
const double * elements;
int numberElements = buildObject.column(iColumn,lower[iColumn],
upper[iColumn],objective[iColumn],
rows,elements);
int nNeg=0;
CoinBigIndex start = size;
for (int i=0;i<numberElements;i++) {
int iRow=rows[i];
if (checkDuplicates) {
if (iRow>=numberRows_) {
if(which[iRow])
numberErrors++;
else
which[iRow]=1;
} else {
numberErrors++;
// and may as well switch off
checkDuplicates=false;
}
}
maxRow = CoinMax(maxRow,iRow);
if (elements[i]==1.0) {
indices[size++]=iRow;
} else if (elements[i]==-1.0) {
neg[nNeg++]=iRow;
}
}
std::sort(indices+start,indices+size);
std::sort(neg,neg+nNeg);
startNegative[iColumn]=size;
CoinMemcpyN(neg,nNeg,indices+size);
size += nNeg;
startPositive[iColumn+1]=size;
}
delete [] neg;
// check size
assert (maxRow+1<=numberRows_);
// Get good object
delete matrix_;
ClpPlusMinusOneMatrix * matrix = new ClpPlusMinusOneMatrix();
matrix->passInCopy(numberRows_,number,true,indices,startPositive,startNegative);
matrix_=matrix;
delete [] which;
}
delete [] objective;
delete [] lower;
delete [] upper;
}
return 0;
}
#endif
#ifndef SLIM_NOIO
// Add columns from a model object
int
ClpModel::addColumns( CoinModel & modelObject,bool tryPlusMinusOne,bool checkDuplicates)
{
if (modelObject.numberElements()==0)
return 0;
bool goodState=true;
if (modelObject.rowLowerArray()) {
// some row information exists
int numberRows2 = modelObject.numberRows();
const double * rowLower = modelObject.rowLowerArray();
const double * rowUpper = modelObject.rowUpperArray();
for (int i=0;i<numberRows2;i++) {
if (rowLower[i]!=-COIN_DBL_MAX)
goodState=false;
if (rowUpper[i]!=COIN_DBL_MAX)
goodState=false;
}
}
if (goodState) {
// can do addColumns
int numberErrors = 0;
// Set arrays for normal use
double * rowLower = modelObject.rowLowerArray();
double * rowUpper = modelObject.rowUpperArray();
double * columnLower = modelObject.columnLowerArray();
double * columnUpper = modelObject.columnUpperArray();
double * objective = modelObject.objectiveArray();
int * integerType = modelObject.integerTypeArray();
double * associated = modelObject.associatedArray();
// If strings then do copies
if (modelObject.stringsExist()) {
numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
objective, integerType,associated);
}
int numberColumns = numberColumns_; // save number of columns
int numberColumns2 = modelObject.numberColumns();
if (numberColumns2&&!numberErrors) {
CoinBigIndex * startPositive = NULL;
CoinBigIndex * startNegative = NULL;
if ((!matrix_||!matrix_->getNumElements())&&!numberColumns&&tryPlusMinusOne) {
startPositive = new CoinBigIndex[numberColumns2+1];
startNegative = new CoinBigIndex[numberColumns2];
modelObject.countPlusMinusOne(startPositive,startNegative,associated);
if (startPositive[0]<0) {
// no good
tryPlusMinusOne=false;
delete [] startPositive;
delete [] startNegative;
}
} else {
// Will add to whatever sort of matrix exists
tryPlusMinusOne=false;
}
assert (columnLower);
addColumns(numberColumns2, columnLower, columnUpper,objective, NULL,NULL,NULL);
#ifndef SLIM_CLP
if (!tryPlusMinusOne) {
#endif
CoinPackedMatrix matrix;
modelObject.createPackedMatrix(matrix,associated);
assert (!matrix.getExtraGap());
if (matrix_->getNumCols()) {
const int * row = matrix.getIndices();
//const int * columnLength = matrix.getVectorLengths();
const CoinBigIndex * columnStart = matrix.getVectorStarts();
const double * element = matrix.getElements();
// make sure matrix has enough rows
matrix_->setDimensions(numberRows_,-1);
numberErrors+=matrix_->appendMatrix(numberColumns2,1,columnStart,row,element,
checkDuplicates ? numberRows_ : -1);
} else {
delete matrix_;
matrix_ = new ClpPackedMatrix(matrix);
}
#ifndef SLIM_CLP
} else {
// create +-1 matrix
CoinBigIndex size = startPositive[numberColumns2];
int * indices = new int[size];
modelObject.createPlusMinusOne(startPositive,startNegative,indices,
associated);
// Get good object
ClpPlusMinusOneMatrix * matrix = new ClpPlusMinusOneMatrix();
matrix->passInCopy(numberRows_,numberColumns2,
true,indices,startPositive,startNegative);
delete matrix_;
matrix_=matrix;
}
#endif
#ifndef CLP_NO_STD
// Do names if wanted
if (modelObject.columnNames()->numberItems()) {
const char *const * columnNames=modelObject.columnNames()->names();
copyColumnNames(columnNames,numberColumns,numberColumns_);
}
#endif
// Do integers if wanted
assert(integerType);
for (int iColumn=0;iColumn<numberColumns2;iColumn++) {
if (integerType[iColumn])
setInteger(iColumn+numberColumns);
}
}
if (columnLower!=modelObject.columnLowerArray()) {
delete [] rowLower;
delete [] rowUpper;
delete [] columnLower;
delete [] columnUpper;
delete [] objective;
delete [] integerType;
delete [] associated;
if (numberErrors)
handler_->message(CLP_BAD_STRING_VALUES,messages_)
<<numberErrors
<<CoinMessageEol;
}
return numberErrors;
} else {
// not suitable for addColumns
handler_->message(CLP_COMPLICATED_MODEL,messages_)
<<modelObject.numberRows()
<<modelObject.numberColumns()
<<CoinMessageEol;
return -1;
}
}
#endif
// chgRowLower
void
ClpModel::chgRowLower(const double * rowLower)
{
int numberRows = numberRows_;
int iRow;
whatsChanged_ = 0; // Use ClpSimplex stuff to keep
if (rowLower) {
for (iRow = 0; iRow < numberRows; iRow++) {
double value = rowLower[iRow];
if (value<-1.0e20)
value = -COIN_DBL_MAX;
rowLower_[iRow]= value;
}
} else {
for (iRow = 0; iRow < numberRows; iRow++) {
rowLower_[iRow]= -COIN_DBL_MAX;
}
}
}
// chgRowUpper
void
ClpModel::chgRowUpper(const double * rowUpper)
{
whatsChanged_ = 0; // Use ClpSimplex stuff to keep
int numberRows = numberRows_;
int iRow;
if (rowUpper) {
for (iRow = 0; iRow < numberRows; iRow++) {
double value = rowUpper[iRow];
if (value>1.0e20)
value = COIN_DBL_MAX;
rowUpper_[iRow]= value;
}
} else {
for (iRow = 0; iRow < numberRows; iRow++) {
rowUpper_[iRow]= COIN_DBL_MAX;;
}
}
}
// chgColumnLower
void
ClpModel::chgColumnLower(const double * columnLower)
{
whatsChanged_ = 0; // Use ClpSimplex stuff to keep
int numberColumns = numberColumns_;
int iColumn;
if (columnLower) {
for (iColumn = 0; iColumn < numberColumns; iColumn++) {
double value = columnLower[iColumn];
if (value<-1.0e20)
value = -COIN_DBL_MAX;
columnLower_[iColumn]= value;
}
} else {
for (iColumn = 0; iColumn < numberColumns; iColumn++) {
columnLower_[iColumn]= 0.0;
}
}
}
// chgColumnUpper
void
ClpModel::chgColumnUpper(const double * columnUpper)
{
whatsChanged_ = 0; // Use ClpSimplex stuff to keep
int numberColumns = numberColumns_;
int iColumn;
if (columnUpper) {
for (iColumn = 0; iColumn < numberColumns; iColumn++) {
double value = columnUpper[iColumn];
if (value>1.0e20)
value = COIN_DBL_MAX;
columnUpper_[iColumn]= value;
}
} else {
for (iColumn = 0; iColumn < numberColumns; iColumn++) {
columnUpper_[iColumn]= COIN_DBL_MAX;;
}
}
}
// chgObjCoefficients
void
ClpModel::chgObjCoefficients(const double * objIn)
{
whatsChanged_ = 0; // Use ClpSimplex stuff to keep
double * obj = objective();
int numberColumns = numberColumns_;
int iColumn;
if (objIn) {
for (iColumn = 0; iColumn < numberColumns; iColumn++) {
obj[iColumn] = objIn[iColumn];
}
} else {
for (iColumn = 0; iColumn < numberColumns; iColumn++) {
obj[iColumn]= 0.0;
}
}
}
// Infeasibility/unbounded ray (NULL returned if none/wrong)
double *
ClpModel::infeasibilityRay() const
{
double * array = NULL;
if (problemStatus_==1&&!secondaryStatus_) {
array = ClpCopyOfArray(ray_,numberRows_);
#if 0
// clean up
double largest=1.0e-30;
double smallest=COIN_DBL_MAX;
int i;
for (i=0;i<numberRows_;i++) {
double value = fabs(array[i]);
smallest = CoinMin(smallest,value);
largest = CoinMax(largest,value);
}
#endif
}
return array;
}
double *
ClpModel::unboundedRay() const
{
double * array = NULL;
if (problemStatus_==2)
array = ClpCopyOfArray(ray_,numberColumns_);
return array;
}
void
ClpModel::setMaximumIterations(int value)
{
if(value>=0)
intParam_[ClpMaxNumIteration]=value;
}
void
ClpModel::setMaximumSeconds(double value)
{
if(value>=0)
dblParam_[ClpMaxSeconds]=value+CoinCpuTime();
else
dblParam_[ClpMaxSeconds]=-1.0;
}
// Returns true if hit maximum iterations (or time)
bool
ClpModel::hitMaximumIterations() const
{
// replaced - compiler error? bool hitMax= (numberIterations_>=maximumIterations());
bool hitMax = (numberIterations_ >= intParam_[ClpMaxNumIteration]);
if (dblParam_[ClpMaxSeconds]>=0.0&&!hitMax) {
hitMax = (CoinCpuTime()>=dblParam_[ClpMaxSeconds]);
}
return hitMax;
}
// On stopped - sets secondary status
void
ClpModel::onStopped()
{
if (problemStatus_==3) {
secondaryStatus_=0;
if (CoinCpuTime()>=dblParam_[ClpMaxSeconds])
secondaryStatus_=9;
}
}
// Pass in Message handler (not deleted at end)
void
ClpModel::passInMessageHandler(CoinMessageHandler * handler)
{
if (defaultHandler_)
delete handler_;
defaultHandler_=false;
handler_=handler;
}
// Pass in Message handler (not deleted at end) and return current
CoinMessageHandler *
ClpModel::pushMessageHandler(CoinMessageHandler * handler,
bool & oldDefault)
{
CoinMessageHandler * returnValue = handler_;
oldDefault = defaultHandler_;
defaultHandler_=false;
handler_=handler;
return returnValue;
}
// back to previous message handler
void
ClpModel::popMessageHandler(CoinMessageHandler * oldHandler,bool oldDefault)
{
if (defaultHandler_)
delete handler_;
defaultHandler_=oldDefault;
handler_=oldHandler;
}
// Set language
void
ClpModel::newLanguage(CoinMessages::Language language)
{
messages_ = ClpMessage(language);
}
#ifndef SLIM_NOIO
// Read an mps file from the given filename
int
ClpModel::readMps(const char *fileName,
bool keepNames,
bool ignoreErrors)
{
if (!strcmp(fileName,"-")||!strcmp(fileName,"stdin")) {
// stdin
} else {
std::string name=fileName;
bool readable = fileCoinReadable(name);
if (!readable) {
handler_->message(CLP_UNABLE_OPEN,messages_)
<<fileName<<CoinMessageEol;
return -1;
}
}
CoinMpsIO m;
m.passInMessageHandler(handler_);
*m.messagesPointer()=coinMessages();
bool savePrefix =m.messageHandler()->prefix();
m.messageHandler()->setPrefix(handler_->prefix());
double time1 = CoinCpuTime(),time2;
int status=0;
try {
status=m.readMps(fileName,"");
}
catch (CoinError e) {
e.print();
status=-1;
}
m.messageHandler()->setPrefix(savePrefix);
if (!status||(ignoreErrors&&(status>0&&status<100000))) {
loadProblem(*m.getMatrixByCol(),
m.getColLower(),m.getColUpper(),
m.getObjCoefficients(),
m.getRowLower(),m.getRowUpper());
if (m.integerColumns()) {
integerType_ = new char[numberColumns_];
CoinMemcpyN(m.integerColumns(),numberColumns_,integerType_);
} else {
integerType_ = NULL;
}
#ifndef SLIM_CLP
// get quadratic part
if (m.reader()->whichSection ( ) == COIN_QUAD_SECTION ) {
int * start=NULL;
int * column = NULL;
double * element = NULL;
status=m.readQuadraticMps(NULL,start,column,element,2);
if (!status||ignoreErrors)
loadQuadraticObjective(numberColumns_,start,column,element);
delete [] start;
delete [] column;
delete [] element;
}
#endif
#ifndef CLP_NO_STD
// set problem name
setStrParam(ClpProbName,m.getProblemName());
// do names
if (keepNames) {
unsigned int maxLength=0;
int iRow;
rowNames_ = std::vector<std::string> ();
columnNames_ = std::vector<std::string> ();
rowNames_.reserve(numberRows_);
for (iRow=0;iRow<numberRows_;iRow++) {
const char * name = m.rowName(iRow);
maxLength = CoinMax(maxLength,(unsigned int) strlen(name));
rowNames_.push_back(name);
}
int iColumn;
columnNames_.reserve(numberColumns_);
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
const char * name = m.columnName(iColumn);
maxLength = CoinMax(maxLength,(unsigned int) strlen(name));
columnNames_.push_back(name);
}
lengthNames_=(int) maxLength;
} else {
lengthNames_=0;
}
#endif
setDblParam(ClpObjOffset,m.objectiveOffset());
time2 = CoinCpuTime();
handler_->message(CLP_IMPORT_RESULT,messages_)
<<fileName
<<time2-time1<<CoinMessageEol;
} else {
// errors
handler_->message(CLP_IMPORT_ERRORS,messages_)
<<status<<fileName<<CoinMessageEol;
}
return status;
}
// Read GMPL files from the given filenames
int
ClpModel::readGMPL(const char *fileName,const char * dataName,
bool keepNames)
{
FILE *fp=fopen(fileName,"r");
if (fp) {
// can open - lets go for it
fclose(fp);
if (dataName) {
fp=fopen(dataName,"r");
if (fp) {
fclose(fp);
} else {
handler_->message(CLP_UNABLE_OPEN,messages_)
<<dataName<<CoinMessageEol;
return -1;
}
}
} else {
handler_->message(CLP_UNABLE_OPEN,messages_)
<<fileName<<CoinMessageEol;
return -1;
}
CoinMpsIO m;
m.passInMessageHandler(handler_);
*m.messagesPointer()=coinMessages();
bool savePrefix =m.messageHandler()->prefix();
m.messageHandler()->setPrefix(handler_->prefix());
double time1 = CoinCpuTime(),time2;
int status=m.readGMPL(fileName,dataName,keepNames);
m.messageHandler()->setPrefix(savePrefix);
if (!status) {
loadProblem(*m.getMatrixByCol(),
m.getColLower(),m.getColUpper(),
m.getObjCoefficients(),
m.getRowLower(),m.getRowUpper());
if (m.integerColumns()) {
integerType_ = new char[numberColumns_];
CoinMemcpyN(m.integerColumns(),numberColumns_,integerType_);
} else {
integerType_ = NULL;
}
#ifndef CLP_NO_STD
// set problem name
setStrParam(ClpProbName,m.getProblemName());
// do names
if (keepNames) {
unsigned int maxLength=0;
int iRow;
rowNames_ = std::vector<std::string> ();
columnNames_ = std::vector<std::string> ();
rowNames_.reserve(numberRows_);
for (iRow=0;iRow<numberRows_;iRow++) {
const char * name = m.rowName(iRow);
maxLength = CoinMax(maxLength,(unsigned int) strlen(name));
rowNames_.push_back(name);
}
int iColumn;
columnNames_.reserve(numberColumns_);
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
const char * name = m.columnName(iColumn);
maxLength = CoinMax(maxLength,(unsigned int) strlen(name));
columnNames_.push_back(name);
}
lengthNames_=(int) maxLength;
} else {
lengthNames_=0;
}
#endif
setDblParam(ClpObjOffset,m.objectiveOffset());
time2 = CoinCpuTime();
handler_->message(CLP_IMPORT_RESULT,messages_)
<<fileName
<<time2-time1<<CoinMessageEol;
} else {
// errors
handler_->message(CLP_IMPORT_ERRORS,messages_)
<<status<<fileName<<CoinMessageEol;
}
return status;
}
#endif
bool ClpModel::isPrimalObjectiveLimitReached() const
{
double limit = 0.0;
getDblParam(ClpPrimalObjectiveLimit, limit);
if (limit > 1e30) {
// was not ever set
return false;
}
const double obj = objectiveValue();
const double maxmin = optimizationDirection();
if (problemStatus_ == 0) // optimal
return maxmin > 0 ? (obj < limit) /*minim*/ : (-obj < limit) /*maxim*/;
else if (problemStatus_==2)
return true;
else
return false;
}
bool ClpModel::isDualObjectiveLimitReached() const
{
double limit = 0.0;
getDblParam(ClpDualObjectiveLimit, limit);
if (limit > 1e30) {
// was not ever set
return false;
}
const double obj = objectiveValue();
const double maxmin = optimizationDirection();
if (problemStatus_ == 0) // optimal
return maxmin > 0 ? (obj > limit) /*minim*/ : (-obj > limit) /*maxim*/;
else if (problemStatus_==1)
return true;
else
return false;
}
void
ClpModel::copyInIntegerInformation(const char * information)
{
delete [] integerType_;
if (information) {
integerType_ = new char[numberColumns_];
CoinMemcpyN(information,numberColumns_,integerType_);
} else {
integerType_ = NULL;
}
}
void
ClpModel::setContinuous(int index)
{
if (integerType_) {
#ifndef NDEBUG
if (index<0||index>=numberColumns_) {
indexError(index,"setContinuous");
}
#endif
integerType_[index]=0;
}
}
//-----------------------------------------------------------------------------
void
ClpModel::setInteger(int index)
{
if (!integerType_) {
integerType_ = new char[numberColumns_];
CoinZeroN ( integerType_, numberColumns_);
}
#ifndef NDEBUG
if (index<0||index>=numberColumns_) {
indexError(index,"setInteger");
}
#endif
integerType_[index]=1;
}
/* Return true if the index-th variable is an integer variable */
bool
ClpModel::isInteger(int index) const
{
if (!integerType_) {
return false;
} else {
#ifndef NDEBUG
if (index<0||index>=numberColumns_) {
indexError(index,"isInteger");
}
#endif
return (integerType_[index]!=0);
}
}
#ifndef CLP_NO_STD
// Drops names - makes lengthnames 0 and names empty
void
ClpModel::dropNames()
{
lengthNames_=0;
rowNames_ = std::vector<std::string> ();
columnNames_ = std::vector<std::string> ();
}
#endif
// Drop integer informations
void
ClpModel::deleteIntegerInformation()
{
delete [] integerType_;
integerType_ = NULL;
}
/* Return copy of status array (char[numberRows+numberColumns]),
use delete [] */
unsigned char *
ClpModel::statusCopy() const
{
return ClpCopyOfArray(status_,numberRows_+numberColumns_);
}
// Copy in status vector
void
ClpModel::copyinStatus(const unsigned char * statusArray)
{
delete [] status_;
if (statusArray) {
status_ = new unsigned char [numberRows_+numberColumns_];
memcpy(status_,statusArray,(numberRows_+numberColumns_)*sizeof(unsigned char));
} else {
status_=NULL;
}
}
#ifndef SLIM_CLP
// Load up quadratic objective
void
ClpModel::loadQuadraticObjective(const int numberColumns, const CoinBigIndex * start,
const int * column, const double * element)
{
whatsChanged_ = 0; // Use ClpSimplex stuff to keep
CoinAssert (numberColumns==numberColumns_);
assert ((dynamic_cast< ClpLinearObjective*>(objective_)));
double offset;
ClpObjective * obj = new ClpQuadraticObjective(objective_->gradient(NULL,NULL,offset,false),
numberColumns,
start,column,element);
delete objective_;
objective_ = obj;
}
void
ClpModel::loadQuadraticObjective ( const CoinPackedMatrix& matrix)
{
whatsChanged_ = 0; // Use ClpSimplex stuff to keep
CoinAssert (matrix.getNumCols()==numberColumns_);
assert ((dynamic_cast< ClpLinearObjective*>(objective_)));
double offset;
ClpQuadraticObjective * obj =
new ClpQuadraticObjective(objective_->gradient(NULL,NULL,offset,false),
numberColumns_,
NULL,NULL,NULL);
delete objective_;
objective_ = obj;
obj->loadQuadraticObjective(matrix);
}
// Get rid of quadratic objective
void
ClpModel::deleteQuadraticObjective()
{
whatsChanged_ = 0; // Use ClpSimplex stuff to keep
ClpQuadraticObjective * obj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
if (obj)
obj->deleteQuadraticObjective();
}
#endif
void
ClpModel::setObjective(ClpObjective * objective)
{
whatsChanged_ = 0; // Use ClpSimplex stuff to keep
delete objective_;
objective_=objective->clone();
}
// Returns resized array and updates size
double * whichDouble(double * array , int number, const int * which)
{
double * newArray=NULL;
if (array&&number) {
int i ;
newArray = new double[number];
for (i=0;i<number;i++)
newArray[i]=array[which[i]];
}
return newArray;
}
char * whichChar(char * array , int number, const int * which)
{
char * newArray=NULL;
if (array&&number) {
int i ;
newArray = new char[number];
for (i=0;i<number;i++)
newArray[i]=array[which[i]];
}
return newArray;
}
unsigned char * whichUnsignedChar(unsigned char * array ,
int number, const int * which)
{
unsigned char * newArray=NULL;
if (array&&number) {
int i ;
newArray = new unsigned char[number];
for (i=0;i<number;i++)
newArray[i]=array[which[i]];
}
return newArray;
}
// Replace Clp Matrix (current is not deleted)
void
ClpModel::replaceMatrix( ClpMatrixBase * matrix,bool deleteCurrent)
{
if (deleteCurrent)
delete matrix_;
matrix_=matrix;
whatsChanged_ = 0; // Too big a change
}
// Subproblem constructor
ClpModel::ClpModel ( const ClpModel * rhs,
int numberRows, const int * whichRow,
int numberColumns, const int * whichColumn,
bool dropNames, bool dropIntegers)
{
defaultHandler_ = rhs->defaultHandler_;
if (defaultHandler_)
handler_ = new CoinMessageHandler(*rhs->handler_);
else
handler_ = rhs->handler_;
eventHandler_ = rhs->eventHandler_->clone();
messages_ = rhs->messages_;
coinMessages_ = rhs->coinMessages_;
intParam_[ClpMaxNumIteration] = rhs->intParam_[ClpMaxNumIteration];
intParam_[ClpMaxNumIterationHotStart] =
rhs->intParam_[ClpMaxNumIterationHotStart];
intParam_[ClpNameDiscipline] = rhs->intParam_[ClpNameDiscipline] ;
dblParam_[ClpDualObjectiveLimit] = rhs->dblParam_[ClpDualObjectiveLimit];
dblParam_[ClpPrimalObjectiveLimit] = rhs->dblParam_[ClpPrimalObjectiveLimit];
dblParam_[ClpDualTolerance] = rhs->dblParam_[ClpDualTolerance];
dblParam_[ClpPrimalTolerance] = rhs->dblParam_[ClpPrimalTolerance];
dblParam_[ClpObjOffset] = rhs->dblParam_[ClpObjOffset];
dblParam_[ClpMaxSeconds] = rhs->dblParam_[ClpMaxSeconds];
dblParam_[ClpPresolveTolerance] = rhs->dblParam_[ClpPresolveTolerance];
#ifndef CLP_NO_STD
strParam_[ClpProbName] = rhs->strParam_[ClpProbName];
#endif
specialOptions_ = rhs->specialOptions_;
optimizationDirection_ = rhs->optimizationDirection_;
objectiveValue_=rhs->objectiveValue_;
smallElement_ = rhs->smallElement_;
objectiveScale_ = rhs->objectiveScale_;
rhsScale_ = rhs->rhsScale_;
numberIterations_ = rhs->numberIterations_;
solveType_ = rhs->solveType_;
whatsChanged_ = 0; // Too big a change
problemStatus_ = rhs->problemStatus_;
secondaryStatus_ = rhs->secondaryStatus_;
// check valid lists
int numberBad=0;
int i;
for (i=0;i<numberRows;i++)
if (whichRow[i]<0||whichRow[i]>=rhs->numberRows_)
numberBad++;
CoinAssertHint(!numberBad,"Bad row list for subproblem constructor");
numberBad=0;
for (i=0;i<numberColumns;i++)
if (whichColumn[i]<0||whichColumn[i]>=rhs->numberColumns_)
numberBad++;
CoinAssertHint(!numberBad,"Bad Column list for subproblem constructor");
numberRows_ = numberRows;
numberColumns_ = numberColumns;
userPointer_ = rhs->userPointer_;
numberThreads_=0;
#ifndef CLP_NO_STD
if (!dropNames) {
unsigned int maxLength=0;
int iRow;
rowNames_ = std::vector<std::string> ();
columnNames_ = std::vector<std::string> ();
rowNames_.reserve(numberRows_);
for (iRow=0;iRow<numberRows_;iRow++) {
rowNames_.push_back(rhs->rowNames_[whichRow[iRow]]);
maxLength = CoinMax(maxLength,(unsigned int) strlen(rowNames_[iRow].c_str()));
}
int iColumn;
columnNames_.reserve(numberColumns_);
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
columnNames_.push_back(rhs->columnNames_[whichColumn[iColumn]]);
maxLength = CoinMax(maxLength,(unsigned int) strlen(columnNames_[iColumn].c_str()));
}
lengthNames_=(int) maxLength;
} else {
lengthNames_ = 0;
rowNames_ = std::vector<std::string> ();
columnNames_ = std::vector<std::string> ();
}
#endif
if (rhs->integerType_&&!dropIntegers) {
integerType_ = whichChar(rhs->integerType_,numberColumns,whichColumn);
} else {
integerType_ = NULL;
}
if (rhs->rowActivity_) {
rowActivity_=whichDouble(rhs->rowActivity_,numberRows,whichRow);
dual_=whichDouble(rhs->dual_,numberRows,whichRow);
columnActivity_=whichDouble(rhs->columnActivity_,numberColumns,
whichColumn);
reducedCost_=whichDouble(rhs->reducedCost_,numberColumns,
whichColumn);
} else {
rowActivity_=NULL;
columnActivity_=NULL;
dual_=NULL;
reducedCost_=NULL;
}
rowLower_=whichDouble(rhs->rowLower_,numberRows,whichRow);
rowUpper_=whichDouble(rhs->rowUpper_,numberRows,whichRow);
columnLower_=whichDouble(rhs->columnLower_,numberColumns,whichColumn);
columnUpper_=whichDouble(rhs->columnUpper_,numberColumns,whichColumn);
if (rhs->objective_)
objective_ = rhs->objective_->subsetClone(numberColumns,whichColumn);
else
objective_ = NULL;
rowObjective_=whichDouble(rhs->rowObjective_,numberRows,whichRow);
// status has to be done in two stages
status_ = new unsigned char[numberColumns_+numberRows_];
unsigned char * rowStatus = whichUnsignedChar(rhs->status_+rhs->numberColumns_,
numberRows_,whichRow);
unsigned char * columnStatus = whichUnsignedChar(rhs->status_,
numberColumns_,whichColumn);
CoinMemcpyN(rowStatus,numberRows_,status_+numberColumns_);
delete [] rowStatus;
CoinMemcpyN(columnStatus,numberColumns_,status_);
delete [] columnStatus;
ray_ = NULL;
if (problemStatus_==1&&!secondaryStatus_)
ray_ = whichDouble (rhs->ray_,numberRows,whichRow);
else if (problemStatus_==2)
ray_ = whichDouble (rhs->ray_,numberColumns,whichColumn);
rowScale_ = NULL;
columnScale_ = NULL;
scalingFlag_ = rhs->scalingFlag_;
rowCopy_=NULL;
matrix_=NULL;
if (rhs->matrix_) {
matrix_ = rhs->matrix_->subsetClone(numberRows,whichRow,
numberColumns,whichColumn);
}
CoinSeedRandom(1234567);
}
#ifndef CLP_NO_STD
// Copies in names
void
ClpModel::copyNames(std::vector<std::string> & rowNames,
std::vector<std::string> & columnNames)
{
unsigned int maxLength=0;
int iRow;
rowNames_ = std::vector<std::string> ();
columnNames_ = std::vector<std::string> ();
rowNames_.reserve(numberRows_);
for (iRow=0;iRow<numberRows_;iRow++) {
rowNames_.push_back(rowNames[iRow]);
maxLength = CoinMax(maxLength,(unsigned int) strlen(rowNames_[iRow].c_str()));
}
int iColumn;
columnNames_.reserve(numberColumns_);
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
columnNames_.push_back(columnNames[iColumn]);
maxLength = CoinMax(maxLength,(unsigned int) strlen(columnNames_[iColumn].c_str()));
}
lengthNames_=(int) maxLength;
}
// Return name or Rnnnnnnn
std::string
ClpModel::getRowName(int iRow) const
{
#ifndef NDEBUG
if (iRow<0||iRow>=numberRows_) {
indexError(iRow,"getRowName");
}
#endif
int size = rowNames_.size();
if (size>iRow) {
return rowNames_[iRow];
} else {
char name[9];
sprintf(name,"R%7.7d",iRow);
std::string rowName(name);
return rowName;
}
}
// Set row name
void
ClpModel::setRowName(int iRow, std::string &name)
{
#ifndef NDEBUG
if (iRow<0||iRow>=numberRows_) {
indexError(iRow,"setRowName");
}
#endif
unsigned int maxLength=lengthNames_;
int size = rowNames_.size();
if (size<=iRow)
rowNames_.resize(iRow+1);
rowNames_[iRow]= name;
maxLength = CoinMax(maxLength,(unsigned int) strlen(name.c_str()));
// May be too big - but we would have to check both rows and columns to be exact
lengthNames_=(int) maxLength;
}
// Return name or Cnnnnnnn
std::string
ClpModel::getColumnName(int iColumn) const
{
#ifndef NDEBUG
if (iColumn<0||iColumn>=numberColumns_) {
indexError(iColumn,"getColumnName");
}
#endif
int size = columnNames_.size();
if (size>iColumn) {
return columnNames_[iColumn];
} else {
char name[9];
sprintf(name,"C%7.7d",iColumn);
std::string columnName(name);
return columnName;
}
}
// Set column name
void
ClpModel::setColumnName(int iColumn, std::string &name)
{
#ifndef NDEBUG
if (iColumn<0||iColumn>=numberColumns_) {
indexError(iColumn,"setColumnName");
}
#endif
unsigned int maxLength=lengthNames_;
int size = columnNames_.size();
if (size<=iColumn)
columnNames_.resize(iColumn+1);
columnNames_[iColumn]= name;
maxLength = CoinMax(maxLength,(unsigned int) strlen(name.c_str()));
// May be too big - but we would have to check both columns and columns to be exact
lengthNames_=(int) maxLength;
}
// Copies in Row names - modifies names first .. last-1
void
ClpModel::copyRowNames(const std::vector<std::string> & rowNames, int first, int last)
{
unsigned int maxLength=lengthNames_;
int size = rowNames_.size();
if (size!=numberRows_)
rowNames_.resize(numberRows_);
int iRow;
for (iRow=first; iRow<last;iRow++) {
rowNames_[iRow]= rowNames[iRow-first];
maxLength = CoinMax(maxLength,(unsigned int) strlen(rowNames_[iRow-first].c_str()));
}
// May be too big - but we would have to check both rows and columns to be exact
lengthNames_=(int) maxLength;
}
// Copies in Column names - modifies names first .. last-1
void
ClpModel::copyColumnNames(const std::vector<std::string> & columnNames, int first, int last)
{
unsigned int maxLength=lengthNames_;
int size = columnNames_.size();
if (size!=numberColumns_)
columnNames_.resize(numberColumns_);
int iColumn;
for (iColumn=first; iColumn<last;iColumn++) {
columnNames_[iColumn]= columnNames[iColumn-first];
maxLength = CoinMax(maxLength,(unsigned int) strlen(columnNames_[iColumn-first].c_str()));
}
// May be too big - but we would have to check both rows and columns to be exact
lengthNames_=(int) maxLength;
}
// Copies in Row names - modifies names first .. last-1
void
ClpModel::copyRowNames(const char * const * rowNames, int first, int last)
{
unsigned int maxLength=lengthNames_;
int size = rowNames_.size();
if (size!=numberRows_)
rowNames_.resize(numberRows_);
int iRow;
for (iRow=first; iRow<last;iRow++) {
if (rowNames[iRow-first]&&strlen(rowNames[iRow-first])) {
rowNames_[iRow]= rowNames[iRow-first];
maxLength = CoinMax(maxLength,(unsigned int) strlen(rowNames[iRow-first]));
} else {
maxLength = CoinMax(maxLength,(unsigned int) 8);
char name[9];
sprintf(name,"R%7.7d",iRow);
rowNames_[iRow]=name;
}
}
// May be too big - but we would have to check both rows and columns to be exact
lengthNames_=(int) maxLength;
}
// Copies in Column names - modifies names first .. last-1
void
ClpModel::copyColumnNames(const char * const * columnNames, int first, int last)
{
unsigned int maxLength=lengthNames_;
int size = columnNames_.size();
if (size!=numberColumns_)
columnNames_.resize(numberColumns_);
int iColumn;
for (iColumn=first; iColumn<last;iColumn++) {
if (columnNames[iColumn-first]&&strlen(columnNames[iColumn-first])) {
columnNames_[iColumn]= columnNames[iColumn-first];
maxLength = CoinMax(maxLength,(unsigned int) strlen(columnNames[iColumn-first]));
} else {
maxLength = CoinMax(maxLength,(unsigned int) 8);
char name[9];
sprintf(name,"C%7.7d",iColumn);
columnNames_[iColumn]=name;
}
}
// May be too big - but we would have to check both rows and columns to be exact
lengthNames_=(int) maxLength;
}
#endif
// Primal objective limit
void
ClpModel::setPrimalObjectiveLimit(double value)
{
dblParam_[ClpPrimalObjectiveLimit]=value;
}
// Dual objective limit
void
ClpModel::setDualObjectiveLimit(double value)
{
dblParam_[ClpDualObjectiveLimit]=value;
}
// Objective offset
void
ClpModel::setObjectiveOffset(double value)
{
dblParam_[ClpObjOffset]=value;
}
// Solve a problem with no elements - return status
int ClpModel::emptyProblem(int * infeasNumber, double * infeasSum,bool printMessage)
{
secondaryStatus_=6; // so user can see something odd
if (printMessage)
handler_->message(CLP_EMPTY_PROBLEM,messages_)
<<numberRows_
<<numberColumns_
<<0
<<CoinMessageEol;
int returnCode=0;
if (numberRows_||numberColumns_) {
if (!status_) {
status_ = new unsigned char[numberRows_+numberColumns_];
CoinZeroN(status_,numberRows_+numberColumns_);
}
}
// status is set directly (as can be used by Interior methods)
// check feasible
int numberPrimalInfeasibilities=0;
double sumPrimalInfeasibilities=0.0;
int numberDualInfeasibilities=0;
double sumDualInfeasibilities=0.0;
if (numberRows_) {
for (int i=0;i<numberRows_;i++) {
dual_[i]=0.0;
if (rowLower_[i]<=rowUpper_[i]) {
if (rowLower_[i]>-1.0e30||rowUpper_[i]<1.0e30) {
if (fabs(rowLower_[i])<fabs(rowUpper_[i]))
rowActivity_[i]=rowLower_[i];
else
rowActivity_[i]=rowUpper_[i];
} else {
rowActivity_[i]=0.0;
}
} else {
rowActivity_[i]=0.0;
numberPrimalInfeasibilities++;
sumPrimalInfeasibilities += rowLower_[i]-rowUpper_[i];
returnCode=1;
}
status_[i+numberColumns_]=1;
}
}
objectiveValue_=0.0;
if (numberColumns_) {
const double * cost = objective();
for (int i=0;i<numberColumns_;i++) {
reducedCost_[i]=cost[i];
double objValue = cost[i]*optimizationDirection_;
if (columnLower_[i]<=columnUpper_[i]) {
if (columnLower_[i]>-1.0e30||columnUpper_[i]<1.0e30) {
if (!objValue) {
if (fabs(columnLower_[i])<fabs(columnUpper_[i])) {
columnActivity_[i]=columnLower_[i];
status_[i]=3;
} else {
columnActivity_[i]=columnUpper_[i];
status_[i]=2;
}
} else if (objValue>0.0) {
if (columnLower_[i]>-1.0e30) {
columnActivity_[i]=columnLower_[i];
status_[i]=3;
} else {
columnActivity_[i]=columnUpper_[i];
status_[i]=2;
numberDualInfeasibilities++;;
sumDualInfeasibilities += fabs(objValue);
returnCode |= 2;
}
objectiveValue_ += columnActivity_[i]*objValue;
} else {
if (columnUpper_[i]<1.0e30) {
columnActivity_[i]=columnUpper_[i];
status_[i]=2;
} else {
columnActivity_[i]=columnLower_[i];
status_[i]=3;
numberDualInfeasibilities++;;
sumDualInfeasibilities += fabs(objValue);
returnCode |= 2;
}
objectiveValue_ += columnActivity_[i]*objValue;
}
} else {
columnActivity_[i]=0.0;
if (objValue) {
numberDualInfeasibilities++;;
sumDualInfeasibilities += fabs(objValue);
returnCode |= 2;
}
status_[i]=0;
}
} else {
if (fabs(columnLower_[i])<fabs(columnUpper_[i])) {
columnActivity_[i]=columnLower_[i];
status_[i]=3;
} else {
columnActivity_[i]=columnUpper_[i];
status_[i]=2;
}
numberPrimalInfeasibilities++;
sumPrimalInfeasibilities += columnLower_[i]-columnUpper_[i];
returnCode |= 1;
}
}
}
objectiveValue_ /= (objectiveScale_*rhsScale_);
if (infeasNumber) {
infeasNumber[0]=numberDualInfeasibilities;
infeasSum[0]=sumDualInfeasibilities;
infeasNumber[1]=numberPrimalInfeasibilities;
infeasSum[1]=sumPrimalInfeasibilities;
}
if (returnCode==3)
returnCode=4;
return returnCode;
}
#ifndef SLIM_NOIO
/* Write the problem in MPS format to the specified file.
Row and column names may be null.
formatType is
<ul>
<li> 0 - normal
<li> 1 - extra accuracy
<li> 2 - IEEE hex (later)
</ul>
Returns non-zero on I/O error
*/
int
ClpModel::writeMps(const char *filename,
int formatType,int numberAcross,
double objSense) const
{
matrix_->setDimensions(numberRows_,numberColumns_);
// Get multiplier for objective function - default 1.0
double * objective = new double[numberColumns_];
CoinMemcpyN(getObjCoefficients(),numberColumns_,objective);
if (objSense*getObjSense()<0.0) {
for (int i = 0; i < numberColumns_; ++i)
objective [i] = - objective[i];
}
// get names
const char * const * const rowNames = rowNamesAsChar();
const char * const * const columnNames = columnNamesAsChar();
CoinMpsIO writer;
writer.passInMessageHandler(handler_);
*writer.messagesPointer()=coinMessages();
writer.setMpsData(*(matrix_->getPackedMatrix()), COIN_DBL_MAX,
getColLower(), getColUpper(),
objective,
(const char*) 0 /*integrality*/,
getRowLower(), getRowUpper(),
columnNames, rowNames);
// Pass in array saying if each variable integer
writer.copyInIntegerInformation(integerInformation());
writer.setObjectiveOffset(objectiveOffset());
delete [] objective;
CoinPackedMatrix * quadratic=NULL;
#ifndef SLIM_CLP
// allow for quadratic objective
#ifndef NO_RTTI
ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
#else
ClpQuadraticObjective * quadraticObj = NULL;
if (objective_->type()==2)
quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
#endif
if (quadraticObj)
quadratic = quadraticObj->quadraticObjective();
#endif
int returnCode = writer.writeMps(filename, 0 /* do not gzip it*/, formatType, numberAcross,
quadratic);
if (rowNames) {
deleteNamesAsChar(rowNames, numberRows_+1);
deleteNamesAsChar(columnNames, numberColumns_);
}
return returnCode;
}
#ifndef CLP_NO_STD
// Create row names as char **
const char * const *
ClpModel::rowNamesAsChar() const
{
char ** rowNames = NULL;
if (lengthNames()) {
rowNames = new char * [numberRows_+1];
int numberNames = rowNames_.size();
numberNames = CoinMin(numberRows_,numberNames);
int iRow;
for (iRow=0;iRow<numberNames;iRow++) {
rowNames[iRow] =
strdup(rowName(iRow).c_str());
#ifdef STRIPBLANKS
char * xx = rowNames[iRow];
int i;
int length = strlen(xx);
int n=0;
for (i=0;i<length;i++) {
if (xx[i]!=' ')
xx[n++]=xx[i];
}
xx[n]='\0';
#endif
}
char name[9];
for ( ;iRow<numberRows_;iRow++) {
sprintf(name,"R%7.7d",iRow);
rowNames[iRow]=strdup(name);
}
rowNames[numberRows_] = strdup("OBJROW");
}
return reinterpret_cast<const char * const *>(rowNames);
}
// Create column names as char **
const char * const *
ClpModel::columnNamesAsChar() const
{
char ** columnNames = NULL;
if (lengthNames()) {
columnNames = new char * [numberColumns_];
int numberNames = columnNames_.size();
numberNames = CoinMin(numberColumns_,numberNames);
int iColumn;
for (iColumn=0;iColumn<numberNames;iColumn++) {
columnNames[iColumn] =
strdup(columnName(iColumn).c_str());
#ifdef STRIPBLANKS
char * xx = columnNames[iColumn];
int i;
int length = strlen(xx);
int n=0;
for (i=0;i<length;i++) {
if (xx[i]!=' ')
xx[n++]=xx[i];
}
xx[n]='\0';
#endif
}
char name[9];
for ( ;iColumn<numberColumns_;iColumn++) {
sprintf(name,"C%7.7d",iColumn);
columnNames[iColumn]=strdup(name);
}
}
return /*reinterpret_cast<const char * const *>*/(columnNames);
}
// Delete char * version of names
void
ClpModel::deleteNamesAsChar(const char * const * names,int number) const
{
for (int i=0;i<number;i++) {
free(const_cast<char *>(names[i]));
}
delete [] const_cast<char **>(names);
}
#endif
#endif
// Pass in Event handler (cloned and deleted at end)
void
ClpModel::passInEventHandler(const ClpEventHandler * eventHandler)
{
delete eventHandler_;
eventHandler_ = eventHandler->clone();
}
// Sets or unsets scaling, 0 -off, 1 on, 2 dynamic(later)
void
ClpModel::scaling(int mode)
{
// If mode changes then we treat as new matrix (need new row copy)
if (mode!=scalingFlag_)
whatsChanged_ &= ~(2+4+8);
if (mode>0&&mode<4) {
scalingFlag_=mode;
} else if (!mode) {
scalingFlag_=0;
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
}
}
void
ClpModel::times(double scalar,
const double * x, double * y) const
{
if (rowScale_)
matrix_->times(scalar,x,y,rowScale_,columnScale_);
else
matrix_->times(scalar,x,y);
}
void
ClpModel::transposeTimes(double scalar,
const double * x, double * y) const
{
if (rowScale_)
matrix_->transposeTimes(scalar,x,y,rowScale_,columnScale_);
else
matrix_->transposeTimes(scalar,x,y);
}
// Does much of scaling
void
ClpModel::gutsOfScaling()
{
int i;
if (rowObjective_) {
for (i=0;i<numberRows_;i++)
rowObjective_[i] /= rowScale_[i];
}
for (i=0;i<numberRows_;i++) {
double multiplier = rowScale_[i];
double inverseMultiplier = 1.0/multiplier;
rowActivity_[i] *= multiplier;
dual_[i] *= inverseMultiplier;
if (rowLower_[i]>-1.0e30)
rowLower_[i] *= multiplier;
else
rowLower_[i] = -COIN_DBL_MAX;
if (rowUpper_[i]<1.0e30)
rowUpper_[i] *= multiplier;
else
rowUpper_[i] = COIN_DBL_MAX;
}
for (i=0;i<numberColumns_;i++) {
double multiplier = 1.0/columnScale_[i];
columnActivity_[i] *= multiplier;
reducedCost_[i] *= columnScale_[i];
if (columnLower_[i]>-1.0e30)
columnLower_[i] *= multiplier;
else
columnLower_[i] = -COIN_DBL_MAX;
if (columnUpper_[i]<1.0e30)
columnUpper_[i] *= multiplier;
else
columnUpper_[i] = COIN_DBL_MAX;
}
//now replace matrix
//and objective
matrix_->reallyScale(rowScale_,columnScale_);
objective_->reallyScale(columnScale_);
}
/* If we constructed a "really" scaled model then this reverses the operation.
Quantities may not be exactly as they were before due to rounding errors */
void
ClpModel::unscale()
{
if (rowScale_) {
int i;
// reverse scaling
for (i=0;i<numberRows_;i++)
rowScale_[i] = 1.0/rowScale_[i];
for (i=0;i<numberColumns_;i++)
columnScale_[i] = 1.0/columnScale_[i];
gutsOfScaling();
}
scalingFlag_=0;
delete [] rowScale_;
rowScale_ = NULL;
delete [] columnScale_;
columnScale_ = NULL;
}
void
ClpModel::setSpecialOptions(unsigned int value)
{
specialOptions_=value;
}
/* This creates a coinModel object
*/
CoinModel *
ClpModel::createCoinModel() const
{
CoinModel * coinModel = new CoinModel();
CoinPackedMatrix matrixByRow;
matrixByRow.reverseOrderedCopyOf(*matrix());
coinModel->setObjectiveOffset(objectiveOffset());
coinModel->setProblemName(problemName().c_str());
// Build by row from scratch
const double * element = matrixByRow.getElements();
const int * column = matrixByRow.getIndices();
const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
const int * rowLength = matrixByRow.getVectorLengths();
int i;
for (i=0;i<numberRows_;i++) {
coinModel->addRow(rowLength[i],column+rowStart[i],
element+rowStart[i],rowLower_[i],rowUpper_[i]);
}
// Now do column part
const double * objective = this->objective();
for (i=0;i<numberColumns_;i++) {
coinModel->setColumnBounds(i,columnLower_[i],columnUpper_[i]);
coinModel->setColumnObjective(i,objective[i]);
}
for ( i=0;i<numberColumns_;i++) {
if (isInteger(i))
coinModel->setColumnIsInteger(i,true);
}
// do names
for (i=0;i<numberRows_;i++) {
char temp[30];
strcpy(temp,rowName(i).c_str());
int length = strlen(temp);
for (int j=0;j<length;j++) {
if (temp[j]=='-')
temp[j]='_';
}
coinModel->setRowName(i,temp);
}
for (i=0;i<numberColumns_;i++) {
char temp[30];
strcpy(temp,columnName(i).c_str());
int length = strlen(temp);
for (int j=0;j<length;j++) {
if (temp[j]=='-')
temp[j]='_';
}
coinModel->setColumnName(i,temp);
}
ClpQuadraticObjective * obj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
if (obj) {
const CoinPackedMatrix * quadObj = obj->quadraticObjective();
// add in quadratic
const double * element = quadObj->getElements();
const int * row = quadObj->getIndices();
const CoinBigIndex * columnStart = quadObj->getVectorStarts();
const int * columnLength = quadObj->getVectorLengths();
for (i=0;i<numberColumns_;i++) {
int nels = columnLength[i];
if (nels) {
CoinBigIndex start = columnStart[i];
double constant = coinModel->getColumnObjective(i);
char temp[100000];
char temp2[30];
sprintf(temp,"%g",constant);
for (CoinBigIndex k=start;k<start+nels;k++) {
int kColumn = row[k];
double value = element[k];
#if 1
// ampl gives twice with assumed 0.5
if (kColumn<i)
continue;
else if (kColumn==i)
value *= 0.5;
#endif
if (value==1.0)
sprintf(temp2,"+%s",coinModel->getColumnName(kColumn));
else if (value==-1.0)
sprintf(temp2,"-%s",coinModel->getColumnName(kColumn));
else if (value>0.0)
sprintf(temp2,"+%g*%s",value,coinModel->getColumnName(kColumn));
else
sprintf(temp2,"%g*%s",value,coinModel->getColumnName(kColumn));
strcat(temp,temp2);
assert (strlen(temp)<100000);
}
coinModel->setObjective(i,temp);
if (logLevel()>2)
printf("el for objective column %s is %s\n",coinModel->getColumnName(i),temp);
}
}
}
return coinModel;
}
/* Find a network subset.
rotate array should be numberRows. On output
-1 not in network
0 in network as is
1 in network with signs swapped
Returns number of network rows (positive if exact network, negative if needs extra row)
From Gulpinar, Gutin, Maros and Mitra
*/
int
ClpModel::findNetwork(char * rotate,double fractionNeeded)
{
int * mapping = new int [numberRows_];
// Get column copy
CoinPackedMatrix * columnCopy = matrix();
// Get a row copy in standard format
CoinPackedMatrix * copy = new CoinPackedMatrix();
copy->reverseOrderedCopyOf(*columnCopy);
// make sure ordered and no gaps
copy->cleanMatrix();
// get matrix data pointers
const int * columnIn = copy->getIndices();
const CoinBigIndex * rowStartIn = copy->getVectorStarts();
const int * rowLength = copy->getVectorLengths();
const double * elementByRowIn = copy->getElements();
int iRow,iColumn;
int numberEligible=0;
int numberIn=0;
int numberElements=0;
for (iRow=0;iRow<numberRows_;iRow++) {
bool possible=true;
mapping[iRow]=-1;
rotate[iRow]=-1;
for (CoinBigIndex j=rowStartIn[iRow];j<rowStartIn[iRow]+rowLength[iRow];j++) {
//int iColumn = column[j];
double value = elementByRowIn[j];
if (fabs(value)!=1.0) {
possible=false;
break;
}
}
if (rowLength[iRow]&&possible) {
mapping[iRow]=numberEligible;
numberEligible++;
numberElements+=rowLength[iRow];
}
}
if (numberEligible<fractionNeeded*numberRows_) {
delete [] mapping;
return 0;
}
// create arrays
int * eligible = new int [numberRows_];
int * column = new int [numberElements];
CoinBigIndex * rowStart = new CoinBigIndex [numberEligible+1];
char * elementByRow = new char [numberElements];
numberEligible=0;
numberElements=0;
rowStart[0]=0;
for (iRow=0;iRow<numberRows_;iRow++) {
if (mapping[iRow]<0)
continue;
assert (numberEligible==mapping[iRow]);
rotate[numberEligible]=0;
for (CoinBigIndex j=rowStartIn[iRow];j<rowStartIn[iRow]+rowLength[iRow];j++) {
column[numberElements] = columnIn[j];
double value = elementByRowIn[j];
if (value==1.0)
elementByRow[numberElements++]=1;
else
elementByRow[numberElements++]=-1;
}
numberEligible++;
rowStart[numberEligible]=numberElements;
}
// get rid of copy to save space
delete copy;
const int * rowIn = columnCopy->getIndices();
const CoinBigIndex * columnStartIn = columnCopy->getVectorStarts();
const int * columnLengthIn = columnCopy->getVectorLengths();
const double * elementByColumnIn = columnCopy->getElements();
int * columnLength = new int [numberColumns_];
// May just be that is a network - worth checking
bool isNetworkAlready=true;
bool trueNetwork=true;
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
double product =1.0;
int n=0;
for (CoinBigIndex j=columnStartIn[iColumn];j<columnStartIn[iColumn]+columnLengthIn[iColumn];j++) {
iRow = mapping[rowIn[j]];
if (iRow>=0) {
n++;
product *= elementByColumnIn[j];
}
}
if (n>=2) {
if (product!=-1.0||n>2)
isNetworkAlready=false;
} else if (n==1) {
trueNetwork=false;
}
columnLength[iColumn]=n;
}
if (!isNetworkAlready) {
// For sorting
double * count = new double [numberRows_];
int * which = new int [numberRows_];
int numberLast=-1;
// Count for columns
char * columnCount = new char[numberColumns_];
memset(columnCount,0,numberColumns_);
char * currentColumnCount = new char[numberColumns_];
// Now do main loop
while (numberIn>numberLast) {
numberLast=numberIn;
int numberLeft = 0;
for (iRow=0;iRow<numberEligible;iRow++) {
if (rotate[iRow]==0) {
which[numberLeft]=iRow;
int merit=0;
bool OK=true;
bool reflectionOK=true;
for (CoinBigIndex j=rowStart[iRow];j<rowStart[iRow+1];j++) {
iColumn = column[j];
int iCount=columnCount[iColumn];
int absCount=CoinAbs(iCount);
if (absCount<2) {
merit = CoinMax(columnLength[iColumn]-absCount-1,merit);
if (elementByRow[j]==iCount)
OK=false;
else if (elementByRow[j]==-iCount)
reflectionOK=false;
} else {
merit =-2;
break;
}
}
if (merit>-2&&(OK||reflectionOK)) {
assert (!OK||!reflectionOK||!numberIn);
//if (!numberLast) merit=1;
count[numberLeft++]=(rowStart[iRow+1]-rowStart[iRow]-1)*((double)merit);
if (OK)
rotate[iRow]=0;
else
rotate[iRow]=1;
} else {
// no good
rotate[iRow]=-1;
}
}
}
CoinSort_2(count,count+numberLeft,which);
// Get G
memset(currentColumnCount,0,numberColumns_);
for (iRow=0;iRow<numberLeft;iRow++) {
int jRow = which[iRow];
bool possible=true;
for (int i=0;i<numberIn;i++) {
for (CoinBigIndex j=rowStart[jRow];j<rowStart[jRow+1];j++) {
if (currentColumnCount[column[j]]) {
possible=false;
break;
}
}
}
if (possible) {
rotate[jRow]+=2;
eligible[numberIn++]=jRow;
char multiplier = (rotate[jRow]==2) ? 1 : -1;
for (CoinBigIndex j=rowStart[jRow];j<rowStart[jRow+1];j++) {
iColumn = column[j];
currentColumnCount[iColumn]++;
int iCount=columnCount[iColumn];
int absCount=CoinAbs(iCount);
if (!absCount) {
columnCount[iColumn]=elementByRow[j]*multiplier;
} else {
columnCount[iColumn]=2;
}
}
}
}
}
for (iRow=0;iRow<numberIn;iRow++) {
int kRow = eligible[iRow];
assert (rotate[kRow]>=2);
}
trueNetwork=true;
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
if (CoinAbs(columnCount[iColumn])==1) {
trueNetwork=false;
break;
}
}
delete [] currentColumnCount;
delete [] columnCount;
delete [] which;
delete [] count;
} else {
numberIn=numberEligible;
for (iRow=0;iRow<numberRows_;iRow++) {
int kRow = mapping[iRow];
if (kRow>=0) {
rotate[kRow]=2;
}
}
}
if (!trueNetwork)
numberIn= - numberIn;
delete [] column;
delete [] rowStart;
delete [] elementByRow;
delete [] columnLength;
// redo rotate
char * rotate2 = CoinCopyOfArray(rotate,numberEligible);
for (iRow=0;iRow<numberRows_;iRow++) {
int kRow = mapping[iRow];
if (kRow>=0) {
int iState=rotate2[kRow];
if (iState>1)
iState -=2;
else
iState = -1;
rotate[iRow]=iState;
} else {
rotate[iRow]=-1;
}
}
delete [] rotate2;
delete [] eligible;
delete [] mapping;
return numberIn;
}
//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################
//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
ClpDataSave::ClpDataSave ()
{
dualBound_ = 0.0;
infeasibilityCost_ = 0.0;
sparseThreshold_ = 0;
pivotTolerance_=0.0;
acceptablePivot_ = 0.0;
objectiveScale_ = 1.0;
perturbation_ = 0;
forceFactorization_=-1;
scalingFlag_=0;
}
//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpDataSave::ClpDataSave (const ClpDataSave & rhs)
{
dualBound_ = rhs.dualBound_;
infeasibilityCost_ = rhs.infeasibilityCost_;
pivotTolerance_ = rhs.pivotTolerance_;
acceptablePivot_ = rhs.acceptablePivot_;
objectiveScale_ = rhs.objectiveScale_;
sparseThreshold_ = rhs.sparseThreshold_;
perturbation_ = rhs.perturbation_;
forceFactorization_=rhs.forceFactorization_;
scalingFlag_=rhs.scalingFlag_;
}
//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
ClpDataSave::~ClpDataSave ()
{
}
//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpDataSave &
ClpDataSave::operator=(const ClpDataSave& rhs)
{
if (this != &rhs) {
dualBound_ = rhs.dualBound_;
infeasibilityCost_ = rhs.infeasibilityCost_;
pivotTolerance_ = rhs.pivotTolerance_;
acceptablePivot_ = rhs.acceptablePivot_;
objectiveScale_ = rhs.objectiveScale_;
sparseThreshold_ = rhs.sparseThreshold_;
perturbation_ = rhs.perturbation_;
forceFactorization_=rhs.forceFactorization_;
scalingFlag_=rhs.scalingFlag_;
}
return *this;
}
// Create C++ lines to get to current state
void
ClpModel::generateCpp( FILE * fp)
{
// Stuff that can't be done easily
if (!lengthNames_) {
// no names
fprintf(fp," clpModel->dropNames();\n");
}
ClpModel defaultModel;
ClpModel * other = &defaultModel;
int iValue1, iValue2;
double dValue1, dValue2;
iValue1 = this->maximumIterations();
iValue2 = other->maximumIterations();
fprintf(fp,"%d int save_maximumIterations = clpModel->maximumIterations();\n",iValue1==iValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->setMaximumIterations(%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
fprintf(fp,"%d clpModel->setMaximumIterations(save_maximumIterations);\n",iValue1==iValue2 ? 7 : 6);
dValue1 = this->primalTolerance();
dValue2 = other->primalTolerance();
fprintf(fp,"%d double save_primalTolerance = clpModel->primalTolerance();\n",dValue1==dValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->setPrimalTolerance(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
fprintf(fp,"%d clpModel->setPrimalTolerance(save_primalTolerance);\n",dValue1==dValue2 ? 7 : 6);
dValue1 = this->dualTolerance();
dValue2 = other->dualTolerance();
fprintf(fp,"%d double save_dualTolerance = clpModel->dualTolerance();\n",dValue1==dValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->setDualTolerance(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
fprintf(fp,"%d clpModel->setDualTolerance(save_dualTolerance);\n",dValue1==dValue2 ? 7 : 6);
iValue1 = this->numberIterations();
iValue2 = other->numberIterations();
fprintf(fp,"%d int save_numberIterations = clpModel->numberIterations();\n",iValue1==iValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->setNumberIterations(%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
fprintf(fp,"%d clpModel->setNumberIterations(save_numberIterations);\n",iValue1==iValue2 ? 7 : 6);
dValue1 = this->maximumSeconds();
dValue2 = other->maximumSeconds();
fprintf(fp,"%d double save_maximumSeconds = clpModel->maximumSeconds();\n",dValue1==dValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->setMaximumSeconds(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
fprintf(fp,"%d clpModel->setMaximumSeconds(save_maximumSeconds);\n",dValue1==dValue2 ? 7 : 6);
dValue1 = this->optimizationDirection();
dValue2 = other->optimizationDirection();
fprintf(fp,"%d double save_optimizationDirection = clpModel->optimizationDirection();\n",dValue1==dValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->setOptimizationDirection(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
fprintf(fp,"%d clpModel->setOptimizationDirection(save_optimizationDirection);\n",dValue1==dValue2 ? 7 : 6);
dValue1 = this->objectiveScale();
dValue2 = other->objectiveScale();
fprintf(fp,"%d double save_objectiveScale = clpModel->objectiveScale();\n",dValue1==dValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->setObjectiveScale(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
fprintf(fp,"%d clpModel->setObjectiveScale(save_objectiveScale);\n",dValue1==dValue2 ? 7 : 6);
dValue1 = this->rhsScale();
dValue2 = other->rhsScale();
fprintf(fp,"%d double save_rhsScale = clpModel->rhsScale();\n",dValue1==dValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->setRhsScale(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
fprintf(fp,"%d clpModel->setRhsScale(save_rhsScale);\n",dValue1==dValue2 ? 7 : 6);
iValue1 = this->scalingFlag();
iValue2 = other->scalingFlag();
fprintf(fp,"%d int save_scalingFlag = clpModel->scalingFlag();\n",iValue1==iValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->scaling(%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
fprintf(fp,"%d clpModel->scaling(save_scalingFlag);\n",iValue1==iValue2 ? 7 : 6);
dValue1 = this->getSmallElementValue();
dValue2 = other->getSmallElementValue();
fprintf(fp,"%d double save_getSmallElementValue = clpModel->getSmallElementValue();\n",dValue1==dValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->setSmallElementValue(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
fprintf(fp,"%d clpModel->setSmallElementValue(save_getSmallElementValue);\n",dValue1==dValue2 ? 7 : 6);
iValue1 = this->logLevel();
iValue2 = other->logLevel();
fprintf(fp,"%d int save_logLevel = clpModel->logLevel();\n",iValue1==iValue2 ? 2 : 1);
fprintf(fp,"%d clpModel->setLogLevel(%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
fprintf(fp,"%d clpModel->setLogLevel(save_logLevel);\n",iValue1==iValue2 ? 7 : 6);
}
syntax highlighted by Code2HTML, v. 0.9.1