// Copyright (C) 2005, International Business Machines
// Corporation and others. All Rights Reserved.
#include "CoinUtilsConfig.h"
#include "CoinHelperFunctions.hpp"
#include "CoinModel.hpp"
#include "CoinSort.hpp"
#include "CoinMpsIO.hpp"
#include "CoinFloatEqual.hpp"
//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################
//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
CoinModel::CoinModel ()
: numberRows_(0),
maximumRows_(0),
numberColumns_(0),
maximumColumns_(0),
numberElements_(0),
maximumElements_(0),
numberQuadraticElements_(0),
maximumQuadraticElements_(0),
optimizationDirection_(1.0),
objectiveOffset_(0.0),
rowLower_(NULL),
rowUpper_(NULL),
rowType_(NULL),
objective_(NULL),
columnLower_(NULL),
columnUpper_(NULL),
integerType_(NULL),
columnType_(NULL),
start_(NULL),
elements_(NULL),
quadraticElements_(NULL),
sortIndices_(NULL),
sortElements_(NULL),
sortSize_(0),
sizeAssociated_(0),
associated_(NULL),
numberSOS_(0),
startSOS_(NULL),
memberSOS_(NULL),
typeSOS_(NULL),
prioritySOS_(NULL),
referenceSOS_(NULL),
priority_(NULL),
cut_(NULL),
moreInfo_(NULL),
logLevel_(0),
type_(-1),
links_(0)
{
problemName_ = strdup("");
}
/* Read a problem in MPS or GAMS format from the given filename.
*/
CoinModel::CoinModel(const char *fileName, int allowStrings)
: numberRows_(0),
maximumRows_(0),
numberColumns_(0),
maximumColumns_(0),
numberElements_(0),
maximumElements_(0),
numberQuadraticElements_(0),
maximumQuadraticElements_(0),
optimizationDirection_(1.0),
objectiveOffset_(0.0),
rowLower_(NULL),
rowUpper_(NULL),
rowType_(NULL),
objective_(NULL),
columnLower_(NULL),
columnUpper_(NULL),
integerType_(NULL),
columnType_(NULL),
start_(NULL),
elements_(NULL),
quadraticElements_(NULL),
sortIndices_(NULL),
sortElements_(NULL),
sortSize_(0),
sizeAssociated_(0),
associated_(NULL),
numberSOS_(0),
startSOS_(NULL),
memberSOS_(NULL),
typeSOS_(NULL),
prioritySOS_(NULL),
referenceSOS_(NULL),
priority_(NULL),
cut_(NULL),
moreInfo_(NULL),
logLevel_(0),
type_(-1),
links_(0)
{
problemName_ = strdup("");
int status=0;
if (!strcmp(fileName,"-")||!strcmp(fileName,"stdin")) {
// stdin
} else {
std::string name=fileName;
bool readable = fileCoinReadable(name);
if (!readable) {
std::cerr<<"Unable to open file "
<<fileName<<std::endl;
status = -1;
}
}
CoinMpsIO m;
m.setAllowStringElements(allowStrings);
m.setConvertObjective(true);
if (!status) {
try {
status=m.readMps(fileName,"");
}
catch (CoinError e) {
e.print();
status=-1;
}
}
if (!status) {
// set problem name
free(problemName_);
problemName_=strdup(m.getProblemName());
objectiveOffset_ = m.objectiveOffset();
// build model
int numberRows = m.getNumRows();
int numberColumns = m.getNumCols();
// Build by row from scratch
CoinPackedMatrix matrixByRow = * m.getMatrixByRow();
const double * element = matrixByRow.getElements();
const int * column = matrixByRow.getIndices();
const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
const int * rowLength = matrixByRow.getVectorLengths();
const double * rowLower = m.getRowLower();
const double * rowUpper = m.getRowUpper();
const double * columnLower = m.getColLower();
const double * columnUpper = m.getColUpper();
const double * objective = m.getObjCoefficients();
int i;
for (i=0;i<numberRows;i++) {
addRow(rowLength[i],column+rowStart[i],
element+rowStart[i],rowLower[i],rowUpper[i],m.rowName(i));
}
int numberIntegers = 0;
// Now do column part
for (i=0;i<numberColumns;i++) {
setColumnBounds(i,columnLower[i],columnUpper[i]);
setColumnObjective(i,objective[i]);
if (m.isInteger(i)) {
setColumnIsInteger(i,true);;
numberIntegers++;
}
}
bool quadraticInteger = (numberIntegers!=0)&&m.reader()->whichSection ( ) == COIN_QUAD_SECTION ;
// do names
int iRow;
for (iRow=0;iRow<numberRows_;iRow++) {
const char * name = m.rowName(iRow);
setRowName(iRow,name);
}
bool ifStrings = ( m.numberStringElements() != 0 );
int nChanged=0;
int iColumn;
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
// Replace - + or * if strings
if (!ifStrings&&!quadraticInteger) {
const char * name = m.columnName(iColumn);
setColumnName(iColumn,name);
} else {
assert (strlen(m.columnName(iColumn))<100);
char temp[100];
strcpy(temp,m.columnName(iColumn));
int n=strlen(temp);
bool changed=false;
for (int i=0;i<n;i++) {
if (temp[i]=='-') {
temp[i]='_';
changed=true;
} else
if (temp[i]=='+') {
temp[i]='$';
changed=true;
} else
if (temp[i]=='*') {
temp[i]='&';
changed=true;
}
}
if (changed)
nChanged++;
setColumnName(iColumn,temp);
}
}
if (nChanged)
printf("%d column names changed to eliminate - + or *\n",nChanged);
if (ifStrings) {
// add in
int numberElements = m.numberStringElements();
for (int i=0;i<numberElements;i++) {
const char * line = m.stringElement(i);
int iRow;
int iColumn;
sscanf(line,"%d,%d,",&iRow,&iColumn);
assert (iRow>=0&&iRow<=numberRows_+2);
assert (iColumn>=0&&iColumn<=numberColumns_);
const char * pos = strchr(line,',');
assert (pos);
pos = strchr(pos+1,',');
assert (pos);
pos++;
if (iRow<numberRows_&&iColumn<numberColumns_) {
// element
setElement(iRow,iColumn,pos);
} else {
fprintf(stderr,"code CoinModel strings for rim\n");
abort();
}
}
}
// 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) {
// If strings allowed 13 then just for Hans convert to constraint
int objRow=-1;
if (allowStrings==13) {
int objColumn=numberColumns_;
objRow=numberRows_;
// leave linear part in objective
addColumn(0,NULL,NULL,-COIN_DBL_MAX,COIN_DBL_MAX,1.0,"obj");
double minusOne=-1.0;
addRow(1,&objColumn,&minusOne,-COIN_DBL_MAX,0.0,"objrow");
}
if (!ifStrings&&!numberIntegers) {
// no strings - add to quadratic (not done yet)
for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
for (CoinBigIndex j = start[iColumn];j<start[iColumn+1];j++) {
int jColumn = column[j];
double value = element[j];
// what about diagonal etc
if (jColumn==iColumn) {
printf("diag %d %d %g\n",iColumn,jColumn,value);
setQuadraticElement(iColumn,jColumn,0.5*value);
} else if (jColumn>iColumn) {
printf("above diag %d %d %g\n",iColumn,jColumn,value);
} else if (jColumn<iColumn) {
printf("below diag %d %d %g\n",iColumn,jColumn,value);
setQuadraticElement(iColumn,jColumn,value);
}
}
}
} else {
// add in as strings
for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
char temp[20000];
temp[0]='\0';
int put=0;
int n=0;
bool ifFirst=true;
double value = getColumnObjective(iColumn);
if (value&&objRow<0) {
sprintf(temp,"%g",value);
ifFirst=false;
put = strlen(temp);
}
for (CoinBigIndex j = start[iColumn];j<start[iColumn+1];j++) {
int jColumn = column[j];
double value = element[j];
// what about diagonal etc
if (jColumn==iColumn) {
//printf("diag %d %d %g\n",iColumn,jColumn,value);
value *= 0.5;
} else if (jColumn>iColumn) {
//printf("above diag %d %d %g\n",iColumn,jColumn,value);
} else if (jColumn<iColumn) {
//printf("below diag %d %d %g\n",iColumn,jColumn,value);
value=0.0;
}
if (value) {
n++;
const char * name = columnName(jColumn);
if (value==1.0) {
sprintf(temp+put,"%s%s",ifFirst ? "" : "+",name);
} else {
if (ifFirst||value<0.0)
sprintf(temp+put,"%g*%s",value,name);
else
sprintf(temp+put,"+%g*%s",value,name);
}
put += strlen(temp+put);
assert (put<20000);
ifFirst=false;
}
}
if (n) {
if (objRow<0)
setObjective(iColumn,temp);
else
setElement(objRow,iColumn,temp);
//printf("el for objective column c%7.7d is %s\n",iColumn,temp);
}
}
}
}
delete [] start;
delete [] column;
delete [] element;
}
}
}
//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
CoinModel::CoinModel (const CoinModel & rhs)
: numberRows_(rhs.numberRows_),
maximumRows_(rhs.maximumRows_),
numberColumns_(rhs.numberColumns_),
maximumColumns_(rhs.maximumColumns_),
numberElements_(rhs.numberElements_),
maximumElements_(rhs.maximumElements_),
numberQuadraticElements_(rhs.numberQuadraticElements_),
maximumQuadraticElements_(rhs.maximumQuadraticElements_),
optimizationDirection_(rhs.optimizationDirection_),
objectiveOffset_(rhs.objectiveOffset_),
rowName_(rhs.rowName_),
columnName_(rhs.columnName_),
string_(rhs.string_),
hashElements_(rhs.hashElements_),
rowList_(rhs.rowList_),
columnList_(rhs.columnList_),
hashQuadraticElements_(rhs.hashQuadraticElements_),
sortSize_(rhs.sortSize_),
quadraticRowList_(rhs.quadraticRowList_),
quadraticColumnList_(rhs.quadraticColumnList_),
sizeAssociated_(rhs.sizeAssociated_),
numberSOS_(rhs.numberSOS_),
logLevel_(rhs.logLevel_),
type_(rhs.type_),
links_(rhs.links_)
{
problemName_ = strdup(rhs.problemName_);
rowLower_ = CoinCopyOfArray(rhs.rowLower_,maximumRows_);
rowUpper_ = CoinCopyOfArray(rhs.rowUpper_,maximumRows_);
rowType_ = CoinCopyOfArray(rhs.rowType_,maximumRows_);
objective_ = CoinCopyOfArray(rhs.objective_,maximumColumns_);
columnLower_ = CoinCopyOfArray(rhs.columnLower_,maximumColumns_);
columnUpper_ = CoinCopyOfArray(rhs.columnUpper_,maximumColumns_);
integerType_ = CoinCopyOfArray(rhs.integerType_,maximumColumns_);
columnType_ = CoinCopyOfArray(rhs.columnType_,maximumColumns_);
sortIndices_ = CoinCopyOfArray(rhs.sortIndices_,sortSize_);
sortElements_ = CoinCopyOfArray(rhs.sortElements_,sortSize_);
associated_ = CoinCopyOfArray(rhs.associated_,sizeAssociated_);
priority_ = CoinCopyOfArray(rhs.priority_,maximumColumns_);
cut_ = CoinCopyOfArray(rhs.cut_,maximumRows_);
moreInfo_ = rhs.moreInfo_;
if (numberSOS_) {
startSOS_ = CoinCopyOfArray(rhs.startSOS_,numberSOS_+1);
int numberMembers = startSOS_[numberSOS_];
memberSOS_ = CoinCopyOfArray(rhs.memberSOS_,numberMembers);
typeSOS_ = CoinCopyOfArray(rhs.typeSOS_,numberSOS_);
prioritySOS_ = CoinCopyOfArray(rhs.prioritySOS_,numberSOS_);
referenceSOS_ = CoinCopyOfArray(rhs.referenceSOS_,numberMembers);
} else {
startSOS_ = NULL;
memberSOS_ = NULL;
typeSOS_ = NULL;
prioritySOS_ = NULL;
referenceSOS_ = NULL;
}
if (type_==0) {
start_ = CoinCopyOfArray(rhs.start_,maximumRows_+1);
} else if (type_==1) {
start_ = CoinCopyOfArray(rhs.start_,maximumColumns_+1);
} else {
start_=NULL;
}
elements_ = CoinCopyOfArray(rhs.elements_,maximumElements_);
quadraticElements_ = CoinCopyOfArray(rhs.quadraticElements_,maximumQuadraticElements_);
}
//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
CoinModel::~CoinModel ()
{
delete [] rowLower_;
delete [] rowUpper_;
delete [] rowType_;
delete [] objective_;
delete [] columnLower_;
delete [] columnUpper_;
delete [] integerType_;
delete [] columnType_;
delete [] start_;
delete [] elements_;
delete [] quadraticElements_;
delete [] sortIndices_;
delete [] sortElements_;
delete [] associated_;
delete [] startSOS_;
delete [] memberSOS_;
delete [] typeSOS_;
delete [] prioritySOS_;
delete [] referenceSOS_;
delete [] priority_;
delete [] cut_;
free(problemName_);
}
//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
CoinModel &
CoinModel::operator=(const CoinModel& rhs)
{
if (this != &rhs) {
delete [] rowLower_;
delete [] rowUpper_;
delete [] rowType_;
delete [] objective_;
delete [] columnLower_;
delete [] columnUpper_;
delete [] integerType_;
delete [] columnType_;
delete [] start_;
delete [] elements_;
delete [] quadraticElements_;
delete [] sortIndices_;
delete [] sortElements_;
delete [] associated_;
delete [] startSOS_;
delete [] memberSOS_;
delete [] typeSOS_;
delete [] prioritySOS_;
delete [] referenceSOS_;
delete [] priority_;
delete [] cut_;
free(problemName_);
problemName_ = strdup(rhs.problemName_);
numberRows_ = rhs.numberRows_;
maximumRows_ = rhs.maximumRows_;
numberColumns_ = rhs.numberColumns_;
maximumColumns_ = rhs.maximumColumns_;
numberElements_ = rhs.numberElements_;
maximumElements_ = rhs.maximumElements_;
numberQuadraticElements_ = rhs.numberQuadraticElements_;
maximumQuadraticElements_ = rhs.maximumQuadraticElements_;
optimizationDirection_ = rhs.optimizationDirection_;
objectiveOffset_ = rhs.objectiveOffset_;
sortSize_ = rhs.sortSize_;
rowName_ = rhs.rowName_;
columnName_ = rhs.columnName_;
string_ = rhs.string_;
hashElements_=rhs.hashElements_;
hashQuadraticElements_=rhs.hashQuadraticElements_;
rowList_ = rhs.rowList_;
quadraticColumnList_ = rhs.quadraticColumnList_;
quadraticRowList_ = rhs.quadraticRowList_;
columnList_ = rhs.columnList_;
sizeAssociated_= rhs.sizeAssociated_;
numberSOS_ = rhs.numberSOS_;
type_ = rhs.type_;
logLevel_ = rhs.logLevel_;
links_ = rhs.links_;
rowLower_ = CoinCopyOfArray(rhs.rowLower_,maximumRows_);
rowUpper_ = CoinCopyOfArray(rhs.rowUpper_,maximumRows_);
rowType_ = CoinCopyOfArray(rhs.rowType_,maximumRows_);
objective_ = CoinCopyOfArray(rhs.objective_,maximumColumns_);
columnLower_ = CoinCopyOfArray(rhs.columnLower_,maximumColumns_);
columnUpper_ = CoinCopyOfArray(rhs.columnUpper_,maximumColumns_);
integerType_ = CoinCopyOfArray(rhs.integerType_,maximumColumns_);
columnType_ = CoinCopyOfArray(rhs.columnType_,maximumColumns_);
priority_ = CoinCopyOfArray(rhs.priority_,maximumColumns_);
cut_ = CoinCopyOfArray(rhs.cut_,maximumRows_);
moreInfo_ = rhs.moreInfo_;
if (numberSOS_) {
startSOS_ = CoinCopyOfArray(rhs.startSOS_,numberSOS_+1);
int numberMembers = startSOS_[numberSOS_];
memberSOS_ = CoinCopyOfArray(rhs.memberSOS_,numberMembers);
typeSOS_ = CoinCopyOfArray(rhs.typeSOS_,numberSOS_);
prioritySOS_ = CoinCopyOfArray(rhs.prioritySOS_,numberSOS_);
referenceSOS_ = CoinCopyOfArray(rhs.referenceSOS_,numberMembers);
} else {
startSOS_ = NULL;
memberSOS_ = NULL;
typeSOS_ = NULL;
prioritySOS_ = NULL;
referenceSOS_ = NULL;
}
if (type_==0) {
start_ = CoinCopyOfArray(rhs.start_,maximumRows_+1);
} else if (type_==1) {
start_ = CoinCopyOfArray(rhs.start_,maximumColumns_+1);
} else {
start_=NULL;
}
elements_ = CoinCopyOfArray(rhs.elements_,maximumElements_);
quadraticElements_ = CoinCopyOfArray(rhs.quadraticElements_,maximumQuadraticElements_);
sortIndices_ = CoinCopyOfArray(rhs.sortIndices_,sortSize_);
sortElements_ = CoinCopyOfArray(rhs.sortElements_,sortSize_);
associated_ = CoinCopyOfArray(rhs.associated_,sizeAssociated_);
}
return *this;
}
/* add a row - numberInRow may be zero */
void
CoinModel::addRow(int numberInRow, const int * columns,
const double * elements, double rowLower,
double rowUpper, const char * name)
{
if (type_==-1) {
// initial
type_=0;
resize(100,0,1000);
} else if (type_==1) {
// mixed - do linked lists for rows
createList(1);
}
int newColumn=-1;
if (numberInRow>0) {
// Move and sort
if (numberInRow>sortSize_) {
delete [] sortIndices_;
delete [] sortElements_;
sortSize_ = numberInRow+100;
sortIndices_ = new int [sortSize_];
sortElements_ = new double [sortSize_];
}
bool sorted = true;
int last=-1;
int i;
for (i=0;i<numberInRow;i++) {
int k=columns[i];
if (k<=last)
sorted=false;
last=k;
sortIndices_[i]=k;
sortElements_[i]=elements[i];
}
if (!sorted) {
CoinSort_2(sortIndices_,sortIndices_+numberInRow,sortElements_);
}
// check for duplicates etc
if (sortIndices_[0]<0) {
printf("bad index %d\n",sortIndices_[0]);
// clean up
abort();
}
last=-1;
bool duplicate=false;
for (i=0;i<numberInRow;i++) {
int k=sortIndices_[i];
if (k==last)
duplicate=true;
last=k;
}
if (duplicate) {
printf("duplicates - what do we want\n");
abort();
}
newColumn = CoinMax(newColumn,last);
}
int newRow=0;
int newElement=0;
if (numberElements_+numberInRow>maximumElements_) {
newElement = (3*(numberElements_+numberInRow)/2) + 1000;
if (numberRows_*10>maximumRows_*9)
newRow = (maximumRows_*3)/2+100;
}
if (numberRows_==maximumRows_)
newRow = (maximumRows_*3)/2+100;
if (newRow||newColumn>=maximumColumns_||newElement) {
if (newColumn<maximumColumns_) {
// columns okay
resize(newRow,0,newElement);
} else {
// newColumn will be new numberColumns_
resize(newRow,(3*newColumn)/2+100,newElement);
}
}
// If rows extended - take care of that
fillRows(numberRows_,false,true);
// Do name
if (name) {
rowName_.addHash(numberRows_,name);
} else {
char name[9];
sprintf(name,"r%7.7d",numberRows_);
rowName_.addHash(numberRows_,name);
}
rowLower_[numberRows_]=rowLower;
rowUpper_[numberRows_]=rowUpper;
// If columns extended - take care of that
fillColumns(newColumn,false);
if (type_==0) {
// can do simply
int put = start_[numberRows_];
assert (put==numberElements_);
bool doHash = hashElements_.numberItems()!=0;
for (int i=0;i<numberInRow;i++) {
elements_[put].row=numberRows_;
elements_[put].string=0;
elements_[put].column=sortIndices_[i];
elements_[put].value=sortElements_[i];
if (doHash)
hashElements_.addHash(put,numberRows_,sortIndices_[i],elements_);
put++;
}
start_[numberRows_+1]=put;
numberElements_+=numberInRow;
} else {
if (numberInRow) {
// must update at least one link
assert (links_);
if (links_==1||links_==3) {
int first = rowList_.addEasy(numberRows_,numberInRow,sortIndices_,sortElements_,elements_,
hashElements_);
if (links_==3)
columnList_.addHard(first,elements_,rowList_.firstFree(),rowList_.lastFree(),
rowList_.next());
numberElements_=CoinMax(numberElements_,rowList_.numberElements());
if (links_==3)
assert (columnList_.numberElements()==rowList_.numberElements());
} else if (links_==2) {
columnList_.addHard(numberRows_,numberInRow,sortIndices_,sortElements_,elements_,
hashElements_);
numberElements_=CoinMax(numberElements_,columnList_.numberElements());
}
}
numberElements_=CoinMax(numberElements_,hashElements_.numberItems());
}
numberRows_++;
}
// add a column - numberInColumn may be zero */
void
CoinModel::addColumn(int numberInColumn, const int * rows,
const double * elements,
double columnLower,
double columnUpper, double objectiveValue,
const char * name, bool isInteger)
{
if (type_==-1) {
// initial
type_=1;
resize(0,100,1000);
} else if (type_==0) {
// mixed - do linked lists for columns
createList(2);
}
int newRow=-1;
if (numberInColumn>0) {
// Move and sort
if (numberInColumn>sortSize_) {
delete [] sortIndices_;
delete [] sortElements_;
sortSize_ = numberInColumn+100;
sortIndices_ = new int [sortSize_];
sortElements_ = new double [sortSize_];
}
bool sorted = true;
int last=-1;
int i;
for (i=0;i<numberInColumn;i++) {
int k=rows[i];
if (k<=last)
sorted=false;
last=k;
sortIndices_[i]=k;
sortElements_[i]=elements[i];
}
if (!sorted) {
CoinSort_2(sortIndices_,sortIndices_+numberInColumn,sortElements_);
}
// check for duplicates etc
if (sortIndices_[0]<0) {
printf("bad index %d\n",sortIndices_[0]);
// clean up
abort();
}
last=-1;
bool duplicate=false;
for (i=0;i<numberInColumn;i++) {
int k=sortIndices_[i];
if (k==last)
duplicate=true;
last=k;
}
if (duplicate) {
printf("duplicates - what do we want\n");
abort();
}
newRow = CoinMax(newRow,last);
}
int newColumn=0;
int newElement=0;
if (numberElements_+numberInColumn>maximumElements_) {
newElement = (3*(numberElements_+numberInColumn)/2) + 1000;
if (numberColumns_*10>maximumColumns_*9)
newColumn = (maximumColumns_*3)/2+100;
}
if (numberColumns_==maximumColumns_)
newColumn = (maximumColumns_*3)/2+100;
if (newColumn||newRow>=maximumRows_||newElement) {
if (newRow<maximumRows_) {
// rows okay
resize(0,newColumn,newElement);
} else {
// newRow will be new numberRows_
resize((3*newRow)/2+100,newColumn,newElement);
}
}
// If columns extended - take care of that
fillColumns(numberColumns_,false,true);
// Do name
if (name) {
columnName_.addHash(numberColumns_,name);
} else {
char name[9];
sprintf(name,"c%7.7d",numberColumns_);
columnName_.addHash(numberColumns_,name);
}
columnLower_[numberColumns_]=columnLower;
columnUpper_[numberColumns_]=columnUpper;
objective_[numberColumns_]=objectiveValue;
if (isInteger)
integerType_[numberColumns_]=1;
else
integerType_[numberColumns_]=0;
// If rows extended - take care of that
fillRows(newRow,false);
if (type_==1) {
// can do simply
int put = start_[numberColumns_];
assert (put==numberElements_);
bool doHash = hashElements_.numberItems()!=0;
for (int i=0;i<numberInColumn;i++) {
elements_[put].column=numberColumns_;
elements_[put].string=0;
elements_[put].row=sortIndices_[i];
elements_[put].value=sortElements_[i];
if (doHash)
hashElements_.addHash(put,sortIndices_[i],numberColumns_,elements_);
put++;
}
start_[numberColumns_+1]=put;
numberElements_+=numberInColumn;
} else {
if (numberInColumn) {
// must update at least one link
assert (links_);
if (links_==2||links_==3) {
int first = columnList_.addEasy(numberColumns_,numberInColumn,sortIndices_,sortElements_,elements_,
hashElements_);
if (links_==3)
rowList_.addHard(first,elements_,columnList_.firstFree(),columnList_.lastFree(),
columnList_.next());
numberElements_=CoinMax(numberElements_,columnList_.numberElements());
if (links_==3)
assert (columnList_.numberElements()==rowList_.numberElements());
} else if (links_==1) {
rowList_.addHard(numberColumns_,numberInColumn,sortIndices_,sortElements_,elements_,
hashElements_);
numberElements_=CoinMax(numberElements_,rowList_.numberElements());
}
}
}
numberColumns_++;
}
// Sets value for row i and column j
void
CoinModel::setElement(int i,int j,double value)
{
if (type_==-1) {
// initial
type_=0;
resize(100,100,1000);
createList(2);
} else if (!links_) {
if (type_==0||type_==2) {
createList(1);
} else if(type_==1) {
createList(2);
}
}
if (!hashElements_.maximumItems()) {
hashElements_.resize(maximumElements_,elements_);
}
int position = hashElements_.hash(i,j,elements_);
if (position>=0) {
elements_[position].value=value;
elements_[position].string=0;
} else {
int newColumn=0;
if (j>=maximumColumns_) {
newColumn = j+1;
}
int newRow=0;
if (i>=maximumRows_) {
newRow = i+1;
}
int newElement=0;
if (numberElements_==maximumElements_) {
newElement = (3*numberElements_/2) + 1000;
}
if (newRow||newColumn||newElement) {
if (newColumn)
newColumn = (3*newColumn)/2+100;
if (newRow)
newRow = (3*newRow)/2+100;
resize(newRow,newColumn,newElement);
}
// If columns extended - take care of that
fillColumns(j,false);
// If rows extended - take care of that
fillRows(i,false);
// treat as addRow unless only columnList_ exists
if ((links_&1)!=0) {
int first = rowList_.addEasy(i,1,&j,&value,elements_,hashElements_);
if (links_==3)
columnList_.addHard(first,elements_,rowList_.firstFree(),rowList_.lastFree(),
rowList_.next());
numberElements_=CoinMax(numberElements_,rowList_.numberElements());
if (links_==3)
assert (columnList_.numberElements()==rowList_.numberElements());
} else if (links_==2) {
columnList_.addHard(i,1,&j,&value,elements_,hashElements_);
numberElements_=CoinMax(numberElements_,columnList_.numberElements());
}
numberRows_=CoinMax(numberRows_,i+1);;
numberColumns_=CoinMax(numberColumns_,j+1);;
}
}
// Sets quadratic value for column i and j
void
CoinModel::setQuadraticElement(int i,int j,double value)
{
printf("not written yet\n");
abort();
return;
}
// Sets value for row i and column j as string
void
CoinModel::setElement(int i,int j,const char * value)
{
double dummyValue=1.0;
if (type_==-1) {
// initial
type_=0;
resize(100,100,1000);
createList(2);
} else if (!links_) {
if (type_==0||type_==2) {
createList(1);
} else if(type_==1) {
createList(2);
}
}
if (!hashElements_.maximumItems()) {
// set up number of items
hashElements_.setNumberItems(numberElements_);
hashElements_.resize(maximumElements_,elements_);
}
int position = hashElements_.hash(i,j,elements_);
if (position>=0) {
int iValue = addString(value);
elements_[position].value=iValue;
elements_[position].string=1;
} else {
int newColumn=0;
if (j>=maximumColumns_) {
newColumn = j+1;
}
int newRow=0;
if (i>=maximumRows_) {
newRow = i+1;
}
int newElement=0;
if (numberElements_==maximumElements_) {
newElement = (3*numberElements_/2) + 1000;
}
if (newRow||newColumn||newElement) {
if (newColumn)
newColumn = (3*newColumn)/2+100;
if (newRow)
newRow = (3*newRow)/2+100;
resize(newRow,newColumn,newElement);
}
// If columns extended - take care of that
fillColumns(j,false);
// If rows extended - take care of that
fillRows(i,false);
// treat as addRow unless only columnList_ exists
if ((links_&1)!=0) {
int first = rowList_.addEasy(i,1,&j,&dummyValue,elements_,hashElements_);
if (links_==3)
columnList_.addHard(first,elements_,rowList_.firstFree(),rowList_.lastFree(),
rowList_.next());
numberElements_=CoinMax(numberElements_,rowList_.numberElements());
if (links_==3)
assert (columnList_.numberElements()==rowList_.numberElements());
} else if (links_==2) {
columnList_.addHard(i,1,&j,&dummyValue,elements_,hashElements_);
numberElements_=CoinMax(numberElements_,columnList_.numberElements());
}
numberRows_=CoinMax(numberRows_,i+1);;
numberColumns_=CoinMax(numberColumns_,j+1);;
int position = hashElements_.hash(i,j,elements_);
assert (position>=0);
int iValue = addString(value);
elements_[position].value=iValue;
elements_[position].string=1;
}
}
// Associates a string with a value. Returns string id (or -1 if does not exist)
int
CoinModel::associateElement(const char * stringValue, double value)
{
int position = string_.hash(stringValue);
if (position<0) {
// not there -add
position = addString(stringValue);
assert (position==string_.numberItems()-1);
}
if (sizeAssociated_<=position) {
int newSize = (3*position)/2+100;
double * temp = new double[newSize];
memcpy(temp,associated_,sizeAssociated_*sizeof(double));
CoinFillN(temp+sizeAssociated_,newSize-sizeAssociated_,unsetValue());
delete [] associated_;
associated_ = temp;
sizeAssociated_=newSize;
}
associated_[position]=value;
return position;
}
/* Sets rowLower (if row does not exist then
all rows up to this are defined with default values and no elements)
*/
void
CoinModel::setRowLower(int whichRow,double rowLower)
{
assert (whichRow>=0);
// make sure enough room and fill
fillRows(whichRow,true);
rowLower_[whichRow]=rowLower;
rowType_[whichRow] &= ~1;
}
/* Sets rowUpper (if row does not exist then
all rows up to this are defined with default values and no elements)
*/
void
CoinModel::setRowUpper(int whichRow,double rowUpper)
{
assert (whichRow>=0);
// make sure enough room and fill
fillRows(whichRow,true);
rowUpper_[whichRow]=rowUpper;
rowType_[whichRow] &= ~2;
}
/* Sets rowLower and rowUpper (if row does not exist then
all rows up to this are defined with default values and no elements)
*/
void
CoinModel::setRowBounds(int whichRow,double rowLower,double rowUpper)
{
assert (whichRow>=0);
// make sure enough room and fill
fillRows(whichRow,true);
rowLower_[whichRow]=rowLower;
rowUpper_[whichRow]=rowUpper;
rowType_[whichRow] &= ~3;
}
/* Sets name (if row does not exist then
all rows up to this are defined with default values and no elements)
*/
void
CoinModel::setRowName(int whichRow,const char * rowName)
{
assert (whichRow>=0);
// make sure enough room and fill
fillRows(whichRow,true);
const char * oldName = rowName_.name(whichRow);
if (oldName)
rowName_.deleteHash(whichRow);
if (rowName)
rowName_.addHash(whichRow,rowName);
}
/* Sets columnLower (if column does not exist then
all columns up to this are defined with default values and no elements)
*/
void
CoinModel::setColumnLower(int whichColumn,double columnLower)
{
assert (whichColumn>=0);
// make sure enough room and fill
fillColumns(whichColumn,true);
columnLower_[whichColumn]=columnLower;
columnType_[whichColumn] &= ~1;
}
/* Sets columnUpper (if column does not exist then
all columns up to this are defined with default values and no elements)
*/
void
CoinModel::setColumnUpper(int whichColumn,double columnUpper)
{
assert (whichColumn>=0);
// make sure enough room and fill
fillColumns(whichColumn,true);
columnUpper_[whichColumn]=columnUpper;
columnType_[whichColumn] &= ~2;
}
/* Sets columnLower and columnUpper (if column does not exist then
all columns up to this are defined with default values and no elements)
*/
void
CoinModel::setColumnBounds(int whichColumn,double columnLower,double columnUpper)
{
assert (whichColumn>=0);
// make sure enough room and fill
fillColumns(whichColumn,true);
columnLower_[whichColumn]=columnLower;
columnUpper_[whichColumn]=columnUpper;
columnType_[whichColumn] &= ~3;
}
/* Sets columnObjective (if column does not exist then
all columns up to this are defined with default values and no elements)
*/
void
CoinModel::setColumnObjective(int whichColumn,double columnObjective)
{
assert (whichColumn>=0);
// make sure enough room and fill
fillColumns(whichColumn,true);
objective_[whichColumn]=columnObjective;
columnType_[whichColumn] &= ~4;
}
/* Sets name (if column does not exist then
all columns up to this are defined with default values and no elements)
*/
void
CoinModel::setColumnName(int whichColumn,const char * columnName)
{
assert (whichColumn>=0);
// make sure enough room and fill
fillColumns(whichColumn,true);
const char * oldName = columnName_.name(whichColumn);
if (oldName)
columnName_.deleteHash(whichColumn);
if (columnName)
columnName_.addHash(whichColumn,columnName);
}
/* Sets integer (if column does not exist then
all columns up to this are defined with default values and no elements)
*/
void
CoinModel::setColumnIsInteger(int whichColumn,bool columnIsInteger)
{
assert (whichColumn>=0);
// make sure enough room and fill
fillColumns(whichColumn,true);
integerType_[whichColumn]=(columnIsInteger) ? 1 : 0;
columnType_[whichColumn] &= ~8;
}
// Adds one string, returns index
int
CoinModel::addString(const char * string)
{
int position = string_.hash(string);
if (position<0) {
position = string_.numberItems();
string_.addHash(position,string);
}
return position;
}
/* Sets rowLower (if row does not exist then
all rows up to this are defined with default values and no elements)
*/
void
CoinModel::setRowLower(int whichRow,const char * rowLower)
{
assert (whichRow>=0);
// make sure enough room and fill
fillRows(whichRow,true);
if (rowLower) {
int value = addString(rowLower);
rowLower_[whichRow]=value;
rowType_[whichRow] |= 1;
} else {
rowLower_[whichRow]=-COIN_DBL_MAX;
}
}
/* Sets rowUpper (if row does not exist then
all rows up to this are defined with default values and no elements)
*/
void
CoinModel::setRowUpper(int whichRow,const char * rowUpper)
{
assert (whichRow>=0);
// make sure enough room and fill
fillRows(whichRow,true);
if (rowUpper) {
int value = addString(rowUpper);
rowUpper_[whichRow]=value;
rowType_[whichRow] |= 2;
} else {
rowUpper_[whichRow]=COIN_DBL_MAX;
}
}
/* Sets columnLower (if column does not exist then
all columns up to this are defined with default values and no elements)
*/
void
CoinModel::setColumnLower(int whichColumn,const char * columnLower)
{
assert (whichColumn>=0);
// make sure enough room and fill
fillColumns(whichColumn,true);
if (columnLower) {
int value = addString(columnLower);
columnLower_[whichColumn]=value;
columnType_[whichColumn] |= 1;
} else {
columnLower_[whichColumn]=0.0;
}
}
/* Sets columnUpper (if column does not exist then
all columns up to this are defined with default values and no elements)
*/
void
CoinModel::setColumnUpper(int whichColumn,const char * columnUpper)
{
assert (whichColumn>=0);
// make sure enough room and fill
fillColumns(whichColumn,true);
if (columnUpper) {
int value = addString(columnUpper);
columnUpper_[whichColumn]=value;
columnType_[whichColumn] |= 2;
} else {
columnUpper_[whichColumn]=COIN_DBL_MAX;
}
}
/* Sets columnObjective (if column does not exist then
all columns up to this are defined with default values and no elements)
*/
void
CoinModel::setColumnObjective(int whichColumn,const char * columnObjective)
{
assert (whichColumn>=0);
// make sure enough room and fill
fillColumns(whichColumn,true);
if (columnObjective) {
int value = addString(columnObjective);
objective_[whichColumn]=value;
columnType_[whichColumn] |= 4;
} else {
objective_[whichColumn]=0.0;
}
}
/* Sets integer (if column does not exist then
all columns up to this are defined with default values and no elements)
*/
void
CoinModel::setColumnIsInteger(int whichColumn,const char * columnIsInteger)
{
assert (whichColumn>=0);
// make sure enough room and fill
fillColumns(whichColumn,true);
if (columnIsInteger) {
int value = addString(columnIsInteger);
integerType_[whichColumn]=value;
columnType_[whichColumn] |= 8;
} else {
integerType_[whichColumn]=0;
}
}
//static const char * minusInfinity="-infinity";
//static const char * plusInfinity="+infinity";
//static const char * zero="0.0";
static const char * numeric="Numeric";
/* Gets rowLower (if row does not exist then -COIN_DBL_MAX)
*/
const char *
CoinModel::getRowLowerAsString(int whichRow) const
{
assert (whichRow>=0);
if (whichRow<numberRows_&&rowLower_) {
if ((rowType_[whichRow]&1)!=0) {
int position = (int) rowLower_[whichRow];
return string_.name(position);
} else {
return numeric;
}
} else {
return numeric;
}
}
/* Gets rowUpper (if row does not exist then +COIN_DBL_MAX)
*/
const char *
CoinModel::getRowUpperAsString(int whichRow) const
{
assert (whichRow>=0);
if (whichRow<numberRows_&&rowUpper_) {
if ((rowType_[whichRow]&2)!=0) {
int position = (int) rowUpper_[whichRow];
return string_.name(position);
} else {
return numeric;
}
} else {
return numeric;
}
}
/* Gets columnLower (if column does not exist then 0.0)
*/
const char *
CoinModel::getColumnLowerAsString(int whichColumn) const
{
assert (whichColumn>=0);
if (whichColumn<numberColumns_&&columnLower_) {
if ((columnType_[whichColumn]&1)!=0) {
int position = (int) columnLower_[whichColumn];
return string_.name(position);
} else {
return numeric;
}
} else {
return numeric;
}
}
/* Gets columnUpper (if column does not exist then COIN_DBL_MAX)
*/
const char *
CoinModel::getColumnUpperAsString(int whichColumn) const
{
assert (whichColumn>=0);
if (whichColumn<numberColumns_&&columnUpper_) {
if ((columnType_[whichColumn]&2)!=0) {
int position = (int) columnUpper_[whichColumn];
return string_.name(position);
} else {
return numeric;
}
} else {
return numeric;
}
}
/* Gets columnObjective (if column does not exist then 0.0)
*/
const char *
CoinModel::getColumnObjectiveAsString(int whichColumn) const
{
assert (whichColumn>=0);
if (whichColumn<numberColumns_&&objective_) {
if ((columnType_[whichColumn]&4)!=0) {
int position = (int) objective_[whichColumn];
return string_.name(position);
} else {
return numeric;
}
} else {
return numeric;
}
}
/* Gets if integer (if column does not exist then false)
*/
const char *
CoinModel::getColumnIsIntegerAsString(int whichColumn) const
{
assert (whichColumn>=0);
if (whichColumn<numberColumns_&&integerType_) {
if ((columnType_[whichColumn]&8)!=0) {
int position = integerType_[whichColumn];
return string_.name(position);
} else {
return numeric;
}
} else {
return numeric;
}
}
/* Deletes all entries in row and bounds.*/
void
CoinModel::deleteRow(int whichRow)
{
assert (whichRow>=0);
if (whichRow<numberRows_) {
if (rowLower_) {
rowLower_[whichRow]=-COIN_DBL_MAX;
rowUpper_[whichRow]=COIN_DBL_MAX;
rowType_[whichRow]=0;
rowName_.deleteHash(whichRow);
}
// need lists
if (type_==0) {
assert (start_);
assert (!hashElements_.numberItems());
delete [] start_;
start_=NULL;
}
if ((links_&1)==0) {
createList(1);
}
assert (links_);
// row links guaranteed to exist
rowList_.deleteSame(whichRow,elements_,hashElements_,(links_!=3));
// Just need to set first and last and take out
if (links_==3)
columnList_.updateDeleted(whichRow,elements_,rowList_);
}
}
/* Deletes all entries in column and bounds.*/
void
CoinModel::deleteColumn(int whichColumn)
{
assert (whichColumn>=0);
if (whichColumn<numberColumns_) {
if (columnLower_) {
columnLower_[whichColumn]=0.0;
columnUpper_[whichColumn]=COIN_DBL_MAX;
objective_[whichColumn]=0.0;
integerType_[whichColumn]=0;
columnType_[whichColumn]=0;
columnName_.deleteHash(whichColumn);
}
// need lists
if (type_==0) {
assert (start_);
assert (!hashElements_.numberItems());
delete [] start_;
start_=NULL;
}
if ((links_&2)==0) {
createList(2);
}
assert (links_);
// column links guaranteed to exist
columnList_.deleteSame(whichColumn,elements_,hashElements_,(links_!=3));
// Just need to set first and last and take out
if (links_==3)
rowList_.updateDeleted(whichColumn,elements_,columnList_);
}
}
// Takes element out of matrix
int
CoinModel::deleteElement(int row, int column)
{
int iPos = position(row,column);
if (iPos>=0)
deleteThisElement(row,column,iPos);
return iPos;
}
// Takes element out of matrix when position known
void
CoinModel::deleteThisElement(int row, int column,int position)
{
assert (row<numberRows_&&column<numberColumns_);
assert (row==(int) elements_[position].row&&column==elements_[position].column);
if ((links_&1)==0) {
createList(1);
}
assert (links_);
// row links guaranteed to exist
rowList_.deleteRowOne(position,elements_,hashElements_);
// Just need to set first and last and take out
if (links_==3)
columnList_.updateDeletedOne(position,elements_);
elements_[position].column=-1;
elements_[position].value=0.0;
}
/* Packs down all rows i.e. removes empty rows permanently. Empty rows
have no elements and feasible bounds. returns number of rows deleted. */
int
CoinModel::packRows()
{
int * newRow = new int[numberRows_];
memset(newRow,0,numberRows_*sizeof(int));
int iRow;
int n=0;
for (iRow=0;iRow<numberRows_;iRow++) {
if (rowLower_[iRow]!=-COIN_DBL_MAX)
newRow[iRow]++;
if (rowUpper_[iRow]!=COIN_DBL_MAX)
newRow[iRow]++;
if (rowName_.name(iRow))
newRow[iRow]++;
}
int i;
for ( i=0;i<numberElements_;i++) {
if (elements_[i].column>=0) {
iRow = (int) elements_[i].row;
assert (iRow>=0&&iRow<numberRows_);
newRow[iRow]++;
}
}
bool doRowNames = ( rowName_.numberItems() != 0 );
for (iRow=0;iRow<numberRows_;iRow++) {
if (newRow[iRow]) {
rowLower_[n]=rowLower_[iRow];
rowUpper_[n]=rowUpper_[iRow];
rowType_[n]=rowType_[iRow];
if (doRowNames)
rowName_.setName(n,rowName_.getName(iRow));
newRow[iRow]=n++;
} else {
newRow[iRow]=-1;
}
}
int numberDeleted = numberRows_-n;
if (numberDeleted) {
numberRows_=n;
n=0;
for ( i=0;i<numberElements_;i++) {
if (elements_[i].column>=0) {
elements_[n]=elements_[i];
elements_[n].row = newRow[elements_[i].row];
n++;
}
}
numberElements_=n;
// now redo
if (doRowNames) {
rowName_.setNumberItems(numberRows_);
rowName_.resize(rowName_.maximumItems(),true);
}
if (hashElements_.numberItems()) {
hashElements_.setNumberItems(numberElements_);
hashElements_.resize(hashElements_.maximumItems(),elements_,true);
}
if (start_) {
int last=-1;
if (type_==0) {
for (i=0;i<numberElements_;i++) {
int now = (int) elements_[i].row;
assert (now>=last);
if (now>last) {
start_[last+1]=numberElements_;
for (int j=last+1;j<now;j++)
start_[j+1]=numberElements_;
last=now;
}
}
for (int j=last+1;j<numberRows_;j++)
start_[j+1]=numberElements_;
} else {
assert (type_==1);
for (i=0;i<numberElements_;i++) {
int now = elements_[i].column;
assert (now>=last);
if (now>last) {
start_[last+1]=numberElements_;
for (int j=last+1;j<now;j++)
start_[j+1]=numberElements_;
last=now;
}
}
for (int j=last+1;j<numberColumns_;j++)
start_[j+1]=numberElements_;
}
}
if ((links_&1)!=0) {
rowList_ = CoinModelLinkedList();
links_ &= ~1;
createList(1);
}
if ((links_&2)!=0) {
columnList_ = CoinModelLinkedList();
links_ &= ~2;
createList(2);
}
}
delete [] newRow;
return numberDeleted;
}
/* Packs down all columns i.e. removes empty columns permanently. Empty columns
have no elements and no objective. returns number of columns deleted. */
int
CoinModel::packColumns()
{
int * newColumn = new int[numberColumns_];
memset(newColumn,0,numberColumns_*sizeof(int));
int iColumn;
int n=0;
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
if (columnLower_[iColumn]!=0.0)
newColumn[iColumn]++;
if (columnUpper_[iColumn]!=COIN_DBL_MAX)
newColumn[iColumn]++;
if (objective_[iColumn]!=0.0)
newColumn[iColumn]++;
if (columnName_.name(iColumn))
newColumn[iColumn]++;
}
int i;
for ( i=0;i<numberElements_;i++) {
if (elements_[i].column>=0) {
iColumn = (int) elements_[i].column;
assert (iColumn>=0&&iColumn<numberColumns_);
newColumn[iColumn]++;
}
}
bool doColumnNames = ( columnName_.numberItems() != 0 );
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
if (newColumn[iColumn]) {
columnLower_[n]=columnLower_[iColumn];
columnUpper_[n]=columnUpper_[iColumn];
objective_[n]=objective_[iColumn];
integerType_[n]=integerType_[iColumn];
columnType_[n]=columnType_[iColumn];
if (doColumnNames)
columnName_.setName(n,columnName_.getName(iColumn));
newColumn[iColumn]=n++;
} else {
newColumn[iColumn]=-1;
}
}
int numberDeleted = numberColumns_-n;
if (numberDeleted) {
numberColumns_=n;
n=0;
for ( i=0;i<numberElements_;i++) {
if (elements_[i].column>=0) {
elements_[n]=elements_[i];
elements_[n].column = newColumn[elements_[i].column];
n++;
}
}
numberElements_=n;
// now redo
if (doColumnNames) {
columnName_.setNumberItems(numberColumns_);
columnName_.resize(columnName_.maximumItems(),true);
}
if (hashElements_.numberItems()) {
hashElements_.setNumberItems(numberElements_);
hashElements_.resize(hashElements_.maximumItems(),elements_,true);
}
if (start_) {
int last=-1;
if (type_==0) {
for (i=0;i<numberElements_;i++) {
int now = (int) elements_[i].row;
assert (now>=last);
if (now>last) {
start_[last+1]=numberElements_;
for (int j=last+1;j<now;j++)
start_[j+1]=numberElements_;
last=now;
}
}
for (int j=last+1;j<numberRows_;j++)
start_[j+1]=numberElements_;
} else {
assert (type_==1);
for (i=0;i<numberElements_;i++) {
int now = elements_[i].column;
assert (now>=last);
if (now>last) {
start_[last+1]=numberElements_;
for (int j=last+1;j<now;j++)
start_[j+1]=numberElements_;
last=now;
}
}
for (int j=last+1;j<numberColumns_;j++)
start_[j+1]=numberElements_;
}
}
if ((links_&1)!=0) {
rowList_ = CoinModelLinkedList();
links_ &= ~1;
createList(1);
}
if ((links_&2)!=0) {
columnList_ = CoinModelLinkedList();
links_ &= ~2;
createList(2);
}
}
delete [] newColumn;
return numberDeleted;
}
/* Packs down all rows and columns. i.e. removes empty rows and columns permanently.
Empty rows have no elements and feasible bounds.
Empty columns have no elements and no objective.
returns number of rows+columns deleted. */
int
CoinModel::pack()
{
// For now do slowly (obvious overheads)
return packRows()+packColumns();
}
// Creates a packed matrix - return snumber of errors
int
CoinModel::createPackedMatrix(CoinPackedMatrix & matrix, const double * associated)
{
// Set to say all parts
type_=2;
resize(numberRows_,numberColumns_,numberElements_);
// Do counts for CoinPackedMatrix
int * length = new int[numberColumns_];
CoinZeroN(length,numberColumns_);
int i;
int numberElements=0;
for (i=0;i<numberElements_;i++) {
int column = elements_[i].column;
if (column>=0) {
length[column]++;
numberElements++;
}
}
int numberErrors=0;
CoinBigIndex * start = new int[numberColumns_+1];
int * row = new int[numberElements];
double * element = new double[numberElements];
start[0]=0;
for (i=0;i<numberColumns_;i++) {
start[i+1]=start[i]+length[i];
length[i]=0;
}
numberElements=0;
for (i=0;i<numberElements_;i++) {
int column = elements_[i].column;
if (column>=0) {
double value = elements_[i].value;
if (elements_[i].string) {
int position = (int) value;
assert (position<sizeAssociated_);
value = associated[position];
if (value==unsetValue()) {
numberErrors++;
value=0.0;
}
}
if (value) {
numberElements++;
int put=start[column]+length[column];
row[put]=(int) elements_[i].row;
element[put]=value;
length[column]++;
}
}
}
for (i=0;i<numberColumns_;i++) {
int put = start[i];
CoinSort_2(row+put,row+put+length[i],element+put);
}
matrix=CoinPackedMatrix(true,numberRows_,numberColumns_,numberElements,
element,row,start,length,0.0,0.0);
delete [] start;
delete [] length;
delete [] row;
delete [] element;
return numberErrors;
}
/* Fills in startPositive and startNegative with counts for +-1 matrix.
If not +-1 then startPositive[0]==-1 otherwise counts and
startPositive[numberColumns]== size
- return number of errors
*/
int
CoinModel::countPlusMinusOne(CoinBigIndex * startPositive, CoinBigIndex * startNegative,
const double * associated)
{
memset(startPositive,0,numberColumns_*sizeof(int));
memset(startNegative,0,numberColumns_*sizeof(int));
// Set to say all parts
type_=2;
resize(numberRows_,numberColumns_,numberElements_);
int numberErrors=0;
CoinBigIndex numberElements=0;
for (CoinBigIndex i=0;i<numberElements_;i++) {
int column = elements_[i].column;
if (column>=0) {
double value = elements_[i].value;
if (elements_[i].string) {
int position = (int) value;
assert (position<sizeAssociated_);
value = associated[position];
if (value==unsetValue()) {
numberErrors++;
value=0.0;
startPositive[0]=-1;
break;
}
}
if (value) {
numberElements++;
if (value==1.0) {
startPositive[column]++;
} else if (value==-1.0) {
startNegative[column]++;
} else {
startPositive[0]=-1;
break;
}
}
}
}
if (startPositive[0]>=0)
startPositive[numberColumns_]=numberElements;
return numberErrors;
}
/* Creates +-1 matrix given startPositive and startNegative counts for +-1 matrix.
*/
void
CoinModel::createPlusMinusOne(CoinBigIndex * startPositive, CoinBigIndex * startNegative,
int * indices,
const double * associated)
{
CoinBigIndex 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 (CoinBigIndex i=0;i<numberElements_;i++) {
int column = elements_[i].column;
if (column>=0) {
double value = elements_[i].value;
if (elements_[i].string) {
int position = (int) value;
assert (position<sizeAssociated_);
value = associated[position];
}
int iRow=(int) elements_[i].row;
if (value==1.0) {
CoinBigIndex position = startPositive[column];
indices[position]=iRow;
startPositive[column]++;
} else if (value==-1.0) {
CoinBigIndex position = startNegative[column];
indices[position]=iRow;
startNegative[column]++;
}
}
}
// 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);
}
}
// Fills in all associated - returning number of errors
int CoinModel::computeAssociated(double * associated)
{
CoinYacc info;
info.length=0;
int numberErrors=0;
for (int i=0;i<string_.numberItems();i++) {
if (string_.name(i)&&associated[i]==unsetValue()) {
associated[i] = getDoubleFromString(info,string_.name(i));
if (associated[i]==unsetValue())
numberErrors++;
}
}
return numberErrors;
}
// Creates copies of various arrays - return number of errors
int
CoinModel::createArrays(double * & rowLower, double * & rowUpper,
double * & columnLower, double * & columnUpper,
double * & objective, int * & integerType,
double * & associated)
{
if (sizeAssociated_<string_.numberItems()) {
int newSize = string_.numberItems();
double * temp = new double[newSize];
memcpy(temp,associated_,sizeAssociated_*sizeof(double));
CoinFillN(temp+sizeAssociated_,newSize-sizeAssociated_,unsetValue());
delete [] associated_;
associated_ = temp;
sizeAssociated_=newSize;
}
associated = CoinCopyOfArray(associated_,sizeAssociated_);
int numberErrors = computeAssociated(associated);
// Fill in as much as possible
rowLower = CoinCopyOfArray( rowLower_,numberRows_);
rowUpper = CoinCopyOfArray( rowUpper_,numberRows_);
for (int iRow=0;iRow<numberRows_;iRow++) {
if ((rowType_[iRow]&1)!=0) {
int position = (int) rowLower[iRow];
assert (position<sizeAssociated_);
double value = associated[position];
if (value!=unsetValue()) {
rowLower[iRow]=value;
}
}
if ((rowType_[iRow]&2)!=0) {
int position = (int) rowUpper[iRow];
assert (position<sizeAssociated_);
double value = associated[position];
if (value!=unsetValue()) {
rowUpper[iRow]=value;
}
}
}
columnLower = CoinCopyOfArray( columnLower_,numberColumns_);
columnUpper = CoinCopyOfArray( columnUpper_,numberColumns_);
objective = CoinCopyOfArray( objective_,numberColumns_);
integerType = CoinCopyOfArray( integerType_,numberColumns_);
for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
if ((columnType_[iColumn]&1)!=0) {
int position = (int) columnLower[iColumn];
assert (position<sizeAssociated_);
double value = associated[position];
if (value!=unsetValue()) {
columnLower[iColumn]=value;
}
}
if ((columnType_[iColumn]&2)!=0) {
int position = (int) columnUpper[iColumn];
assert (position<sizeAssociated_);
double value = associated[position];
if (value!=unsetValue()) {
columnUpper[iColumn]=value;
}
}
if ((columnType_[iColumn]&4)!=0) {
int position = (int) objective[iColumn];
assert (position<sizeAssociated_);
double value = associated[position];
if (value!=unsetValue()) {
objective[iColumn]=value;
}
}
if ((columnType_[iColumn]&8)!=0) {
int position = integerType[iColumn];
assert (position<sizeAssociated_);
double value = associated[position];
if (value!=unsetValue()) {
integerType[iColumn]=(int) value;
}
}
}
return numberErrors;
}
/* Write the problem in MPS format to a file with the given filename.
*/
int
CoinModel::writeMps(const char *filename, int compression,
int formatType , int numberAcross , bool keepStrings)
{
int numberErrors = 0;
// Set arrays for normal use
double * rowLower = rowLower_;
double * rowUpper = rowUpper_;
double * columnLower = columnLower_;
double * columnUpper = columnUpper_;
double * objective = objective_;
int * integerType = integerType_;
double * associated = associated_;
// If strings then do copies
if (string_.numberItems()) {
numberErrors = createArrays(rowLower, rowUpper, columnLower, columnUpper,
objective, integerType,associated);
}
CoinPackedMatrix matrix;
createPackedMatrix(matrix,associated);
char* integrality = new char[numberColumns_];
bool hasInteger = false;
for (int i = 0; i < numberColumns_; i++) {
if (integerType[i]) {
integrality[i] = 1;
hasInteger = true;
} else {
integrality[i] = 0;
}
}
CoinMpsIO writer;
writer.setInfinity(COIN_DBL_MAX);
const char *const * rowNames=NULL;
if (rowName_.numberItems())
rowNames=rowName_.names();
const char * const * columnNames=NULL;
if (columnName_.numberItems())
columnNames=columnName_.names();
writer.setMpsData(matrix, COIN_DBL_MAX,
columnLower, columnUpper,
objective, hasInteger ? integrality : 0,
rowLower, rowUpper,
columnNames,rowNames);
delete[] integrality;
if (rowLower!=rowLower_) {
delete [] rowLower;
delete [] rowUpper;
delete [] columnLower;
delete [] columnUpper;
delete [] objective;
delete [] integerType;
delete [] associated;
if (numberErrors&&logLevel_>0&&!keepStrings)
printf("%d string elements had no values associated with them\n",numberErrors);
}
writer.setObjectiveOffset(objectiveOffset_);
writer.setProblemName(problemName_);
if (keepStrings&&string_.numberItems()) {
// load up strings - sorted by column and row
writer.copyStringElements(this);
}
return writer.writeMps(filename, compression, formatType, numberAcross);
}
/* Check two models against each other. Return nonzero if different.
Ignore names if that set.
May modify both models by cleaning up
*/
int
CoinModel::differentModel(CoinModel & other, bool ignoreNames)
{
int numberErrors = 0;
int numberErrors2 = 0;
int returnCode=0;
if (numberRows_!=other.numberRows_||numberColumns_!=other.numberColumns_) {
if (logLevel_>0)
printf("** Mismatch on size, this has %d rows, %d columns - other has %d rows, %d columns\n",
numberRows_,numberColumns_,other.numberRows_,other.numberColumns_);
returnCode=1000;
}
// Set arrays for normal use
double * rowLower = rowLower_;
double * rowUpper = rowUpper_;
double * columnLower = columnLower_;
double * columnUpper = columnUpper_;
double * objective = objective_;
int * integerType = integerType_;
double * associated = associated_;
// If strings then do copies
if (string_.numberItems()) {
numberErrors += createArrays(rowLower, rowUpper, columnLower, columnUpper,
objective, integerType,associated);
}
// Set arrays for normal use
double * rowLower2 = other.rowLower_;
double * rowUpper2 = other.rowUpper_;
double * columnLower2 = other.columnLower_;
double * columnUpper2 = other.columnUpper_;
double * objective2 = other.objective_;
int * integerType2 = other.integerType_;
double * associated2 = other.associated_;
// If strings then do copies
if (other.string_.numberItems()) {
numberErrors2 += other.createArrays(rowLower2, rowUpper2, columnLower2, columnUpper2,
objective2, integerType2,associated2);
}
CoinPackedMatrix matrix;
createPackedMatrix(matrix,associated);
CoinPackedMatrix matrix2;
other.createPackedMatrix(matrix2,associated2);
if (numberErrors||numberErrors2)
if (logLevel_>0)
printf("** Errors when converting strings, %d on this, %d on other\n",
numberErrors,numberErrors2);
CoinRelFltEq tolerance;
if (numberRows_==other.numberRows_) {
bool checkNames = !ignoreNames;
if (!rowName_.numberItems()||
!other.rowName_.numberItems())
checkNames=false;
int numberDifferentL = 0;
int numberDifferentU = 0;
int numberDifferentN = 0;
for (int i=0;i<numberRows_;i++) {
if (!tolerance(rowLower[i],rowLower2[i]))
numberDifferentL++;
if (!tolerance(rowUpper[i],rowUpper2[i]))
numberDifferentU++;
if (checkNames&&rowName_.name(i)&&other.rowName_.name(i)) {
if (strcmp(rowName_.name(i),other.rowName_.name(i)))
numberDifferentN++;
}
}
int n = numberDifferentL+numberDifferentU+numberDifferentN;
returnCode+=n;
if (n&&logLevel_>0)
printf("Row differences , %d lower, %d upper and %d names\n",
numberDifferentL,numberDifferentU,numberDifferentN);
}
if (numberColumns_==other.numberColumns_) {
int numberDifferentL = 0;
int numberDifferentU = 0;
int numberDifferentN = 0;
int numberDifferentO = 0;
int numberDifferentI = 0;
bool checkNames = !ignoreNames;
if (!columnName_.numberItems()||
!other.columnName_.numberItems())
checkNames=false;
for (int i=0;i<numberColumns_;i++) {
if (!tolerance(columnLower[i],columnLower2[i]))
numberDifferentL++;
if (!tolerance(columnUpper[i],columnUpper2[i]))
numberDifferentU++;
if (!tolerance(objective[i],objective2[i]))
numberDifferentO++;
int i1 = (integerType) ? integerType[i] : 0;
int i2 = (integerType2) ? integerType2[i] : 0;
if (i1!=i2)
numberDifferentI++;
if (checkNames&&columnName_.name(i)&&other.columnName_.name(i)) {
if (strcmp(columnName_.name(i),other.columnName_.name(i)))
numberDifferentN++;
}
}
int n = numberDifferentL+numberDifferentU+numberDifferentN;
n+= numberDifferentO+numberDifferentI;
returnCode+=n;
if (n&&logLevel_>0)
printf("Column differences , %d lower, %d upper, %d objective, %d integer and %d names\n",
numberDifferentL,numberDifferentU,numberDifferentO,
numberDifferentI,numberDifferentN);
}
if (numberRows_==other.numberRows_&&
numberColumns_==other.numberColumns_&&
numberElements_==other.numberElements_) {
if (!matrix.isEquivalent(matrix2,tolerance)) {
returnCode+=100;
if (returnCode&&logLevel_>0)
printf("Two matrices are not same\n");
}
}
if (rowLower!=rowLower_) {
delete [] rowLower;
delete [] rowUpper;
delete [] columnLower;
delete [] columnUpper;
delete [] objective;
delete [] integerType;
delete [] associated;
}
if (rowLower2!=other.rowLower_) {
delete [] rowLower2;
delete [] rowUpper2;
delete [] columnLower2;
delete [] columnUpper2;
delete [] objective2;
delete [] integerType2;
delete [] associated2;
}
return returnCode;
}
// Returns value for row i and column j
double
CoinModel::getElement(int i,int j) const
{
if (!hashElements_.numberItems()) {
hashElements_.setNumberItems(numberElements_);
hashElements_.resize(maximumElements_,elements_);
}
int position = hashElements_.hash(i,j,elements_);
if (position>=0) {
return elements_[position].value;
} else {
return 0.0;
}
}
// Returns value for row rowName and column columnName
double
CoinModel::getElement(const char * rowName,const char * columnName) const
{
if (!hashElements_.numberItems()) {
hashElements_.setNumberItems(numberElements_);
hashElements_.resize(maximumElements_,elements_);
}
int i=rowName_.hash(rowName);
int j=columnName_.hash(columnName);
int position;
if (i>=0&&j>=0)
position = hashElements_.hash(i,j,elements_);
else
position=-1;
if (position>=0) {
return elements_[position].value;
} else {
return 0.0;
}
}
// Returns quadratic value for columns i and j
double
CoinModel::getQuadraticElement(int i,int j) const
{
printf("not written yet\n");
abort();
return 0.0;
}
// Returns value for row i and column j as string
const char *
CoinModel::getElementAsString(int i,int j) const
{
if (!hashElements_.numberItems()) {
hashElements_.setNumberItems(numberElements_);
hashElements_.resize(maximumElements_,elements_);
}
int position = hashElements_.hash(i,j,elements_);
if (position>=0) {
if (elements_[position].string) {
int iString = (int) elements_[position].value;
assert (iString>=0&&iString<string_.numberItems());
return string_.name(iString);
} else {
return numeric;
}
} else {
return NULL;
}
}
/* Returns position of element for row i column j.
Only valid until next modification.
-1 if element does not exist */
int
CoinModel::position (int i,int j) const
{
if (!hashElements_.numberItems()) {
hashElements_.setNumberItems(numberElements_);
hashElements_.resize(maximumElements_,elements_,true);
}
return hashElements_.hash(i,j,elements_);
}
/* Returns pointer to element for row i column j.
Only valid until next modification.
NULL if element does not exist */
double *
CoinModel::pointer (int i,int j) const
{
if (!hashElements_.numberItems()) {
hashElements_.setNumberItems(numberElements_);
hashElements_.resize(maximumElements_,elements_);
}
int position = hashElements_.hash(i,j,elements_);
if (position>=0) {
return &(elements_[position].value);
} else {
return NULL;
}
}
/* Returns first element in given row - index is -1 if none.
Index is given by .index and value by .value
*/
CoinModelLink
CoinModel::firstInRow(int whichRow) const
{
CoinModelLink link;
if (whichRow>=0&&whichRow<numberRows_) {
link.setOnRow(true);
if (type_==0) {
assert (start_);
int position = start_[whichRow];
if (position<start_[whichRow+1]) {
link.setRow(whichRow);
link.setPosition(position);
link.setColumn(elements_[position].column);
assert (whichRow==(int) elements_[position].row);
link.setValue(elements_[position].value);
}
} else {
fillList(whichRow,rowList_,1);
int position = rowList_.first(whichRow);
if (position>=0) {
link.setRow(whichRow);
link.setPosition(position);
link.setColumn(elements_[position].column);
assert (whichRow==(int) elements_[position].row);
link.setValue(elements_[position].value);
}
}
}
return link;
}
/* Returns last element in given row - index is -1 if none.
Index is given by .index and value by .value
*/
CoinModelLink
CoinModel::lastInRow(int whichRow) const
{
CoinModelLink link;
if (whichRow>=0&&whichRow<numberRows_) {
link.setOnRow(true);
if (type_==0) {
assert (start_);
int position = start_[whichRow+1]-1;
if (position>=start_[whichRow]) {
link.setRow(whichRow);
link.setPosition(position);
link.setColumn(elements_[position].column);
assert (whichRow==(int) elements_[position].row);
link.setValue(elements_[position].value);
}
} else {
fillList(whichRow,rowList_,1);
int position = rowList_.last(whichRow);
if (position>=0) {
link.setRow(whichRow);
link.setPosition(position);
link.setColumn(elements_[position].column);
assert (whichRow==(int) elements_[position].row);
link.setValue(elements_[position].value);
}
}
}
return link;
}
/* Returns first element in given column - index is -1 if none.
Index is given by .index and value by .value
*/
CoinModelLink
CoinModel::firstInColumn(int whichColumn) const
{
CoinModelLink link;
if (whichColumn>=0&&whichColumn<numberColumns_) {
link.setOnRow(false);
if (type_==1) {
assert (start_);
int position = start_[whichColumn];
if (position<start_[whichColumn+1]) {
link.setColumn(whichColumn);
link.setPosition(position);
link.setRow(elements_[position].row);
assert (whichColumn==(int) elements_[position].column);
link.setValue(elements_[position].value);
}
} else {
fillList(whichColumn,columnList_,2);
if ((links_&2)==0) {
// Create list
assert (!columnList_.numberMajor());
createList(2);
}
int position = columnList_.first(whichColumn);
if (position>=0) {
link.setColumn(whichColumn);
link.setPosition(position);
link.setRow(elements_[position].row);
assert (whichColumn==(int) elements_[position].column);
link.setValue(elements_[position].value);
}
}
}
return link;
}
/* Returns last element in given column - index is -1 if none.
Index is given by .index and value by .value
*/
CoinModelLink
CoinModel::lastInColumn(int whichColumn) const
{
CoinModelLink link;
if (whichColumn>=0&&whichColumn<numberColumns_) {
link.setOnRow(false);
if (type_==1) {
assert (start_);
int position = start_[whichColumn+1]-1;
if (position>=start_[whichColumn]) {
link.setColumn(whichColumn);
link.setPosition(position);
link.setRow(elements_[position].row);
assert (whichColumn==(int) elements_[position].column);
link.setValue(elements_[position].value);
}
} else {
fillList(whichColumn,columnList_,2);
int position = columnList_.last(whichColumn);
if (position>=0) {
link.setColumn(whichColumn);
link.setPosition(position);
link.setRow(elements_[position].row);
assert (whichColumn==(int) elements_[position].column);
link.setValue(elements_[position].value);
}
}
}
return link;
}
/* Returns next element in current row or column - index is -1 if none.
Index is given by .index and value by .value.
User could also tell because input.next would be NULL
*/
CoinModelLink
CoinModel::next(CoinModelLink & current) const
{
CoinModelLink link=current;
int position = current.position();
if (position>=0) {
if (current.onRow()) {
// Doing by row
int whichRow = current.row();
if (type_==0) {
assert (start_);
position++;
if (position<start_[whichRow+1]) {
link.setPosition(position);
link.setColumn(elements_[position].column);
assert (whichRow==(int) elements_[position].row);
link.setValue(elements_[position].value);
} else {
// signal end
link.setPosition(-1);
link.setColumn(-1);
link.setRow(-1);
link.setValue(0.0);
}
} else {
assert ((links_&1)!=0);
position = rowList_.next()[position];
if (position>=0) {
link.setPosition(position);
link.setColumn(elements_[position].column);
assert (whichRow==(int) elements_[position].row);
link.setValue(elements_[position].value);
} else {
// signal end
link.setPosition(-1);
link.setColumn(-1);
link.setRow(-1);
link.setValue(0.0);
}
}
} else {
// Doing by column
int whichColumn = current.column();
if (type_==1) {
assert (start_);
position++;
if (position<start_[whichColumn+1]) {
link.setPosition(position);
link.setRow(elements_[position].row);
assert (whichColumn==(int) elements_[position].column);
link.setValue(elements_[position].value);
} else {
// signal end
link.setPosition(-1);
link.setColumn(-1);
link.setRow(-1);
link.setValue(0.0);
}
} else {
assert ((links_&2)!=0);
position = columnList_.next()[position];
if (position>=0) {
link.setPosition(position);
link.setRow(elements_[position].row);
assert (whichColumn==(int) elements_[position].column);
link.setValue(elements_[position].value);
} else {
// signal end
link.setPosition(-1);
link.setColumn(-1);
link.setRow(-1);
link.setValue(0.0);
}
}
}
}
return link;
}
/* Returns previous element in current row or column - index is -1 if none.
Index is given by .index and value by .value.
User could also tell because input.previous would be NULL
*/
CoinModelLink
CoinModel::previous(CoinModelLink & current) const
{
CoinModelLink link=current;
int position = current.position();
if (position>=0) {
if (current.onRow()) {
// Doing by row
int whichRow = current.row();
if (type_==0) {
assert (start_);
position--;
if (position>=start_[whichRow]) {
link.setPosition(position);
link.setColumn(elements_[position].column);
assert (whichRow==(int) elements_[position].row);
link.setValue(elements_[position].value);
} else {
// signal end
link.setPosition(-1);
link.setColumn(-1);
link.setRow(-1);
link.setValue(0.0);
}
} else {
assert ((links_&1)!=0);
position = rowList_.previous()[position];
if (position>=0) {
link.setPosition(position);
link.setColumn(elements_[position].column);
assert (whichRow==(int) elements_[position].row);
link.setValue(elements_[position].value);
} else {
// signal end
link.setPosition(-1);
link.setColumn(-1);
link.setRow(-1);
link.setValue(0.0);
}
}
} else {
// Doing by column
int whichColumn = current.column();
if (type_==1) {
assert (start_);
position--;
if (position>=start_[whichColumn]) {
link.setPosition(position);
link.setRow(elements_[position].row);
assert (whichColumn==(int) elements_[position].column);
link.setValue(elements_[position].value);
} else {
// signal end
link.setPosition(-1);
link.setColumn(-1);
link.setRow(-1);
link.setValue(0.0);
}
} else {
assert ((links_&2)!=0);
position = columnList_.previous()[position];
if (position>=0) {
link.setPosition(position);
link.setRow(elements_[position].row);
assert (whichColumn==(int) elements_[position].column);
link.setValue(elements_[position].value);
} else {
// signal end
link.setPosition(-1);
link.setColumn(-1);
link.setRow(-1);
link.setValue(0.0);
}
}
}
}
return link;
}
/* Returns first element in given quadratic column - index is -1 if none.
Index is given by .index and value by .value
*/
CoinModelLink
CoinModel::firstInQuadraticColumn(int whichColumn) const
{
printf("not written yet\n");
abort();
CoinModelLink x;
return x;
}
/* Returns last element in given quadratic column - index is -1 if none.
Index is given by .index and value by .value
*/
CoinModelLink
CoinModel::lastInQuadraticColumn(int whichColumn) const
{
printf("not written yet\n");
abort();
CoinModelLink x;
return x;
}
/* Gets rowLower (if row does not exist then -COIN_DBL_MAX)
*/
double
CoinModel::getRowLower(int whichRow) const
{
assert (whichRow>=0);
if (whichRow<numberRows_&&rowLower_)
return rowLower_[whichRow];
else
return -COIN_DBL_MAX;
}
/* Gets rowUpper (if row does not exist then +COIN_DBL_MAX)
*/
double
CoinModel::getRowUpper(int whichRow) const
{
assert (whichRow>=0);
if (whichRow<numberRows_&&rowUpper_)
return rowUpper_[whichRow];
else
return COIN_DBL_MAX;
}
/* Gets name (if row does not exist then "")
*/
const char *
CoinModel::getRowName(int whichRow) const
{
assert (whichRow>=0);
if (whichRow<rowName_.numberItems())
return rowName_.name(whichRow);
else
return NULL;
}
/* Gets columnLower (if column does not exist then 0.0)
*/
double
CoinModel::getColumnLower(int whichColumn) const
{
assert (whichColumn>=0);
if (whichColumn<numberColumns_&&columnLower_)
return columnLower_[whichColumn];
else
return 0.0;
}
/* Gets columnUpper (if column does not exist then COIN_DBL_MAX)
*/
double
CoinModel::getColumnUpper(int whichColumn) const
{
assert (whichColumn>=0);
if (whichColumn<numberColumns_&&columnUpper_)
return columnUpper_[whichColumn];
else
return COIN_DBL_MAX;
}
/* Gets columnObjective (if column does not exist then 0.0)
*/
double
CoinModel::getColumnObjective(int whichColumn) const
{
assert (whichColumn>=0);
if (whichColumn<numberColumns_&&objective_)
return objective_[whichColumn];
else
return 0.0;
}
/* Gets name (if column does not exist then "")
*/
const char *
CoinModel::getColumnName(int whichColumn) const
{
assert (whichColumn>=0);
if (whichColumn<columnName_.numberItems())
return columnName_.name(whichColumn);
else
return NULL;
}
/* Gets if integer (if column does not exist then false)
*/
bool
CoinModel::getColumnIsInteger(int whichColumn) const
{
assert (whichColumn>=0);
if (whichColumn<numberColumns_&&integerType_)
return integerType_[whichColumn]!=0;
else
return false;
}
// Row index from row name (-1 if no names or no match)
int
CoinModel::row(const char * rowName) const
{
return rowName_.hash(rowName);
}
// Column index from column name (-1 if no names or no match)
int
CoinModel::column(const char * columnName) const
{
return columnName_.hash(columnName);
}
// Resize
void
CoinModel::resize(int maximumRows, int maximumColumns, int maximumElements)
{
maximumElements = CoinMax(maximumElements,maximumElements_);
if (type_==0||type_==2) {
// need to redo row stuff
maximumRows = CoinMax(maximumRows,numberRows_);
if (maximumRows>maximumRows_) {
bool needFill = rowLower_==NULL;
double * tempArray;
tempArray = new double[maximumRows];
memcpy(tempArray,rowLower_,numberRows_*sizeof(double));
# ifdef ZEROFAULT
memset(tempArray+numberRows_,0,(maximumRows-numberRows_)*sizeof(double)) ;
# endif
delete [] rowLower_;
rowLower_=tempArray;
tempArray = new double[maximumRows];
memcpy(tempArray,rowUpper_,numberRows_*sizeof(double));
# ifdef ZEROFAULT
memset(tempArray+numberRows_,0,(maximumRows-numberRows_)*sizeof(double)) ;
# endif
delete [] rowUpper_;
rowUpper_=tempArray;
int * tempArray2;
tempArray2 = new int[maximumRows];
memcpy(tempArray2,rowType_,numberRows_*sizeof(int));
# ifdef ZEROFAULT
memset(tempArray2+numberRows_,0,(maximumRows-numberRows_)*sizeof(int)) ;
# endif
delete [] rowType_;
rowType_=tempArray2;
// resize hash
rowName_.resize(maximumRows);
// If we have links we need to resize
if ((links_&1)!=0) {
rowList_.resize(maximumRows,maximumElements);
}
// If we have start then we need to resize that
if (type_==0) {
int * tempArray2;
tempArray2 = new int[maximumRows+1];
# ifdef ZEROFAULT
memset(tempArray2,0,(maximumRows+1)*sizeof(int)) ;
# endif
if (start_) {
memcpy(tempArray2,start_,(numberRows_+1)*sizeof(int));
delete [] start_;
} else {
tempArray2[0]=0;
}
start_=tempArray2;
}
maximumRows_=maximumRows;
// Fill
if (needFill) {
int save=numberRows_-1;
numberRows_=0;
fillRows(save,true);
}
}
}
if (type_==1||type_==2) {
// need to redo column stuff
maximumColumns = CoinMax(maximumColumns,numberColumns_);
if (maximumColumns>maximumColumns_) {
bool needFill = columnLower_==NULL;
double * tempArray;
tempArray = new double[maximumColumns];
memcpy(tempArray,columnLower_,numberColumns_*sizeof(double));
# ifdef ZEROFAULT
memset(tempArray+numberColumns_,0,
(maximumColumns-numberColumns_)*sizeof(double)) ;
# endif
delete [] columnLower_;
columnLower_=tempArray;
tempArray = new double[maximumColumns];
memcpy(tempArray,columnUpper_,numberColumns_*sizeof(double));
# ifdef ZEROFAULT
memset(tempArray+numberColumns_,0,
(maximumColumns-numberColumns_)*sizeof(double)) ;
# endif
delete [] columnUpper_;
columnUpper_=tempArray;
tempArray = new double[maximumColumns];
memcpy(tempArray,objective_,numberColumns_*sizeof(double));
# ifdef ZEROFAULT
memset(tempArray+numberColumns_,0,
(maximumColumns-numberColumns_)*sizeof(double)) ;
# endif
delete [] objective_;
objective_=tempArray;
int * tempArray2;
tempArray2 = new int[maximumColumns];
memcpy(tempArray2,columnType_,numberColumns_*sizeof(int));
# ifdef ZEROFAULT
memset(tempArray2+numberColumns_,0,
(maximumColumns-numberColumns_)*sizeof(int)) ;
# endif
delete [] columnType_;
columnType_=tempArray2;
tempArray2 = new int[maximumColumns];
memcpy(tempArray2,integerType_,numberColumns_*sizeof(int));
# ifdef ZEROFAULT
memset(tempArray2+numberColumns_,0,
(maximumColumns-numberColumns_)*sizeof(int)) ;
# endif
delete [] integerType_;
integerType_=tempArray2;
// resize hash
columnName_.resize(maximumColumns);
// If we have links we need to resize
if ((links_&2)!=0) {
columnList_.resize(maximumColumns,maximumElements);
}
// If we have start then we need to resize that
if (type_==1) {
int * tempArray2;
tempArray2 = new int[maximumColumns+1];
# ifdef ZEROFAULT
memset(tempArray2,0,(maximumColumns+1)*sizeof(int)) ;
# endif
if (start_) {
memcpy(tempArray2,start_,(numberColumns_+1)*sizeof(int));
delete [] start_;
} else {
tempArray2[0]=0;
}
start_=tempArray2;
}
maximumColumns_=maximumColumns;
// Fill
if (needFill) {
int save=numberColumns_-1;
numberColumns_=0;
fillColumns(save,true);
}
}
}
if (maximumElements>maximumElements_) {
CoinModelTriple * tempArray = new CoinModelTriple[maximumElements];
memcpy(tempArray,elements_,numberElements_*sizeof(CoinModelTriple));
# ifdef ZEROFAULT
memset(tempArray+numberElements_,0,
(maximumElements-numberElements_)*sizeof(CoinModelTriple)) ;
# endif
delete [] elements_;
elements_=tempArray;
if (hashElements_.numberItems())
hashElements_.resize(maximumElements,elements_);
maximumElements_=maximumElements;
// If we have links we need to resize
if ((links_&1)!=0) {
rowList_.resize(maximumRows_,maximumElements_);
}
if ((links_&2)!=0) {
columnList_.resize(maximumColumns_,maximumElements_);
}
}
}
void
CoinModel::fillRows(int whichRow, bool forceCreation,bool fromAddRow)
{
if (forceCreation||fromAddRow) {
if (type_==-1) {
// initial
type_=0;
resize(CoinMax(100,whichRow+1),0,1000);
} else if (type_==1) {
type_=2;
}
if (!rowLower_) {
// need to set all
whichRow = numberRows_-1;
numberRows_=0;
resize(CoinMax(100,whichRow+1),0,0);
}
if (whichRow>=maximumRows_) {
resize(CoinMax((3*maximumRows_)/2,whichRow+1),0,0);
}
}
if (whichRow>=numberRows_&&rowLower_) {
// Need to fill
int i;
for ( i=numberRows_;i<=whichRow;i++) {
rowLower_[i]=-COIN_DBL_MAX;
rowUpper_[i]=COIN_DBL_MAX;
rowType_[i]=0;
}
}
if ( !fromAddRow) {
numberRows_=CoinMax(whichRow+1,numberRows_);
// If simple minded then delete start
if (start_) {
delete [] start_;
start_ = NULL;
assert (!links_);
// mixed - do linked lists for rows
createList(1);
}
}
}
void
CoinModel::fillColumns(int whichColumn,bool forceCreation,bool fromAddColumn)
{
if (forceCreation||fromAddColumn) {
if (type_==-1) {
// initial
type_=1;
resize(0,CoinMax(100,whichColumn+1),1000);
} else if (type_==0) {
type_=2;
}
if (!objective_) {
// need to set all
whichColumn = numberColumns_-1;
numberColumns_=0;
resize(0,CoinMax(100,whichColumn+1),0);
}
if (whichColumn>=maximumColumns_) {
resize(0,CoinMax((3*maximumColumns_)/2,whichColumn+1),0);
}
}
if (whichColumn>=numberColumns_&&objective_) {
// Need to fill
int i;
for ( i=numberColumns_;i<=whichColumn;i++) {
columnLower_[i]=0.0;
columnUpper_[i]=COIN_DBL_MAX;
objective_[i]=0.0;
integerType_[i]=0;
columnType_[i]=0;
}
}
if ( !fromAddColumn) {
numberColumns_=CoinMax(whichColumn+1,numberColumns_);
// If simple minded then delete start
if (start_) {
delete [] start_;
start_ = NULL;
assert (!links_);
// mixed - do linked lists for columns
createList(2);
}
}
}
// Fill in default linked list information
void
CoinModel::fillList(int which, CoinModelLinkedList & list, int type) const
{
if ((links_&type)==0) {
// Create list
assert (!list.numberMajor());
if (type==1) {
list.create(maximumRows_,maximumElements_,numberRows_,numberColumns_,0,
numberElements_,elements_);
} else {
list.create(maximumColumns_,maximumElements_,numberColumns_,numberRows_,1,
numberElements_,elements_);
}
if (links_==1 && type== 2) {
columnList_.synchronize(rowList_);
} else if (links_==2 && type==1) {
rowList_.synchronize(columnList_);
}
links_ |= type;
}
int number = list.numberMajor();
if (which>=number) {
// may still need to extend list or fill it in
if (which>=list.maximumMajor()) {
list.resize((which*3)/2+100,list.maximumElements());
}
list.fill(number,which+1);
}
}
/* Gets sorted row - user must provide enough space
(easiest is allocate number of columns).
Returns number of elements
*/
int CoinModel::getRow(int whichRow, int * column, double * element)
{
if (!hashElements_.maximumItems()) {
// set up number of items
hashElements_.setNumberItems(numberElements_);
hashElements_.resize(maximumElements_,elements_);
}
assert (whichRow>=0);
int n=0;
if (whichRow<numberRows_) {
CoinModelLink triple=firstInRow(whichRow);
bool sorted=true;
int last=-1;
while (triple.column()>=0) {
int iColumn = triple.column();
assert (whichRow==triple.row());
if (iColumn<last)
sorted=false;
last=iColumn;
if (column)
column[n]=iColumn;
if (element)
element[n]=triple.value();
n++;
triple=next(triple);
}
if (!sorted) {
CoinSort_2(column,column+n,element);
}
}
return n;
}
/* Gets sorted column - user must provide enough space
(easiest is allocate number of rows).
Returns number of elements
*/
int CoinModel::getColumn(int whichColumn, int * row, double * element)
{
if (!hashElements_.maximumItems()) {
// set up number of items
hashElements_.setNumberItems(numberElements_);
hashElements_.resize(maximumElements_,elements_);
}
assert (whichColumn>=0);
int n=0;
if (whichColumn<numberColumns_) {
CoinModelLink triple=firstInColumn(whichColumn);
bool sorted=true;
int last=-1;
while (triple.column()>=0) {
int iRow = triple.row();
assert (whichColumn==triple.column());
if (iRow<last)
sorted=false;
last=iRow;
if (row)
row[n]=iRow;
if (element)
element[n]=triple.value();
n++;
triple=next(triple);
}
if (!sorted) {
CoinSort_2(row,row+n,element);
}
}
return n;
}
/* Create a linked list and synchronize free
type 1 for row 2 for column
Marked as const as list is mutable */
void
CoinModel::createList(int type) const
{
type_=2;
if (type==1) {
assert ((links_&1)==0);
rowList_.create(maximumRows_,maximumElements_,
numberRows_,numberColumns_,0,
numberElements_,elements_);
if (links_==2) {
// synchronize free list
rowList_.synchronize(columnList_);
}
links_ |= 1;
} else {
assert ((links_&2)==0);
columnList_.create(maximumColumns_,maximumElements_,
numberColumns_,numberRows_,1,
numberElements_,elements_);
if (links_==1) {
// synchronize free list
columnList_.synchronize(rowList_);
}
links_ |= 2;
}
}
void
CoinModel::setLogLevel(int value)
{
if (value>=0&&value<3)
logLevel_=value;
}
void
CoinModel::setProblemName (const char *name)
{
free(problemName_) ;
if (name)
problemName_ = strdup(name) ;
else
problemName_ = strdup("");
}
// Checks that links are consistent
void
CoinModel::validateLinks() const
{
if ((links_&1)) {
// validate row links
rowList_.validateLinks(elements_);
}
if ((links_&2)) {
// validate column links
columnList_.validateLinks(elements_);
}
}
// returns jColumn (-2 if linear term, -1 if unknown) and coefficient
int
CoinModel::decodeBit(char * phrase, char * & nextPhrase, double & coefficient, bool ifFirst) const
{
char * pos = phrase;
// may be leading - (or +)
char * pos2 = pos;
double value=1.0;
if (*pos2=='-'||*pos2=='+')
pos2++;
// next terminator * or + or -
while (*pos2) {
if (*pos2=='*') {
break;
} else if (*pos2=='-'||*pos2=='+') {
if (pos2==pos||*(pos2-1)!='e')
break;
}
pos2++;
}
// if * must be number otherwise must be name
if (*pos2=='*') {
char * pos3 = pos;
while (pos3!=pos2) {
#ifndef NDEBUG
char x = *pos3;
#endif
pos3++;
assert ((x>='0'&&x<='9')||x=='.'||x=='+'||x=='-'||x=='e');
}
char saved = *pos2;
*pos2='\0';
value = atof(pos);
*pos2=saved;
// and down to next
pos2++;
pos=pos2;
while (*pos2) {
if (*pos2=='-'||*pos2=='+')
break;
pos2++;
}
}
char saved = *pos2;
*pos2='\0';
// now name
// might have + or -
if (*pos=='+') {
pos++;
} else if (*pos=='-') {
pos++;
assert (value==1.0);
value = - value;
}
int jColumn = column(pos);
// must be column unless first when may be linear term
if (jColumn<0) {
if (ifFirst) {
char * pos3 = pos;
while (pos3!=pos2) {
#ifndef NDEBUG
char x = *pos3;
#endif
pos3++;
assert ((x>='0'&&x<='9')||x=='.'||x=='+'||x=='-'||x=='e');
}
assert(*pos2=='\0');
// keep possible -
value = value * atof(pos);
jColumn=-2;
} else {
// bad
*pos2=saved;
printf("bad nonlinear term %s\n",phrase);
// maybe return -1
abort();
}
}
*pos2=saved;
pos=pos2;
coefficient=value;
nextPhrase = pos;
return jColumn;
}
/* Gets correct form for a quadratic row - user to delete
If row is not quadratic then returns which other variables are involved
with tiny elements and count of total number of variables which could not
be put in quadratic form
*/
CoinPackedMatrix *
CoinModel::quadraticRow(int rowNumber,double * linearRow,
int & numberBad) const
{
numberBad=0;
CoinZeroN(linearRow,numberColumns_);
int numberElements=0;
assert (rowNumber>=-1&&rowNumber<numberRows_);
if (rowNumber!=-1) {
// not objective
CoinModelLink triple=firstInRow(rowNumber);
while (triple.column()>=0) {
int iColumn = triple.column();
const char * expr = getElementAsString(rowNumber,iColumn);
if (strcmp(expr,"Numeric")) {
// try and see which columns
assert (strlen(expr)<20000);
char temp[20000];
strcpy(temp,expr);
char * pos = temp;
bool ifFirst=true;
while (*pos) {
double value;
int jColumn = decodeBit(pos, pos, value, ifFirst);
// must be column unless first when may be linear term
if (jColumn>=0) {
numberElements++;
} else if (jColumn==-2) {
linearRow[iColumn]=value;
} else if (jColumn==-1) {
// nonlinear term - we will just be marking
numberElements++;
} else {
printf("bad nonlinear term %s\n",temp);
abort();
}
ifFirst=false;
}
} else {
linearRow[iColumn]=getElement(rowNumber,iColumn);
}
triple=next(triple);
}
if (!numberElements) {
return NULL;
} else {
int * column = new int[numberElements];
int * column2 = new int[numberElements];
double * element = new double[numberElements];
numberElements=0;
CoinModelLink triple=firstInRow(rowNumber);
while (triple.column()>=0) {
int iColumn = triple.column();
const char * expr = getElementAsString(rowNumber,iColumn);
if (strcmp(expr,"Numeric")) {
// try and see which columns
assert (strlen(expr)<20000);
char temp[20000];
strcpy(temp,expr);
char * pos = temp;
bool ifFirst=true;
while (*pos) {
double value;
int jColumn = decodeBit(pos, pos, value, ifFirst);
// must be column unless first when may be linear term
if (jColumn>=0) {
column[numberElements]=iColumn;
column2[numberElements]=jColumn;
element[numberElements++]=value;
} else if (jColumn==-1) {
// nonlinear term - we will just be marking
assert (jColumn>=0);
column[numberElements]=iColumn;
column2[numberElements]=jColumn;
element[numberElements++]=1.0e-100;
numberBad++;
} else if (jColumn!=-2) {
printf("bad nonlinear term %s\n",temp);
abort();
}
ifFirst=false;
}
}
triple=next(triple);
}
CoinPackedMatrix * newMatrix = new CoinPackedMatrix(true,column2,column,element,numberElements);
delete [] column;
delete [] column2;
delete [] element;
return newMatrix;
}
} else {
// objective
int iColumn;
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
const char * expr = getColumnObjectiveAsString(iColumn);
if (strcmp(expr,"Numeric")) {
// try and see which columns
assert (strlen(expr)<20000);
char temp[20000];
strcpy(temp,expr);
char * pos = temp;
bool ifFirst=true;
while (*pos) {
double value;
int jColumn = decodeBit(pos, pos, value, ifFirst);
// must be column unless first when may be linear term
if (jColumn>=0) {
numberElements++;
} else if (jColumn==-2) {
linearRow[iColumn]=value;
} else if (jColumn==-1) {
// nonlinear term - we will just be marking
numberElements++;
} else {
printf("bad nonlinear term %s\n",temp);
abort();
}
ifFirst=false;
}
} else {
linearRow[iColumn]=getElement(rowNumber,iColumn);
}
}
if (!numberElements) {
return NULL;
} else {
int * column = new int[numberElements];
int * column2 = new int[numberElements];
double * element = new double[numberElements];
numberElements=0;
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
const char * expr = getColumnObjectiveAsString(iColumn);
if (strcmp(expr,"Numeric")) {
// try and see which columns
assert (strlen(expr)<20000);
char temp[20000];
strcpy(temp,expr);
char * pos = temp;
bool ifFirst=true;
while (*pos) {
double value;
int jColumn = decodeBit(pos, pos, value, ifFirst);
// must be column unless first when may be linear term
if (jColumn>=0) {
column[numberElements]=iColumn;
column2[numberElements]=jColumn;
element[numberElements++]=value;
} else if (jColumn==-1) {
// nonlinear term - we will just be marking
assert (jColumn>=0);
column[numberElements]=iColumn;
column2[numberElements]=jColumn;
element[numberElements++]=1.0e-100;
numberBad++;
} else if (jColumn!=-2) {
printf("bad nonlinear term %s\n",temp);
abort();
}
ifFirst=false;
}
}
}
return new CoinPackedMatrix(true,column2,column,element,numberElements);
}
}
}
// Replaces a quadratic row
void
CoinModel::replaceQuadraticRow(int rowNumber,const double * linearRow, const CoinPackedMatrix * quadraticPart)
{
assert (rowNumber>=-1&&rowNumber<numberRows_);
if (rowNumber>=0) {
CoinModelLink triple=firstInRow(rowNumber);
while (triple.column()>=0) {
int iColumn = triple.column();
deleteElement(rowNumber,iColumn);
// triple stale - so start over
triple=firstInRow(rowNumber);
}
const double * element = quadraticPart->getElements();
const int * column = quadraticPart->getIndices();
const CoinBigIndex * columnStart = quadraticPart->getVectorStarts();
const int * columnLength = quadraticPart->getVectorLengths();
int numberLook = quadraticPart->getNumCols();
int i;
for (i=0;i<numberLook;i++) {
if (!columnLength[i]) {
// just linear part
if (linearRow[i])
setElement(rowNumber,i,linearRow[i]);
} else {
char temp[10000];
int put=0;
char temp2[30];
bool first=true;
if (linearRow[i]) {
sprintf(temp,"%g",linearRow[i]);
first=false;
put = strlen(temp);
}
for (int j=columnStart[i];j<columnStart[i]+columnLength[i];j++) {
int jColumn = column[j];
double value = element[j];
if (value<0.0||first)
sprintf(temp2,"%g*c%7.7d",value,jColumn);
else
sprintf(temp2,"+%g*c%7.7d",value,jColumn);
int nextPut = put + strlen(temp2);
assert (nextPut<10000);
strcpy(temp+put,temp2);
put = nextPut;
}
setElement(rowNumber,i,temp);
}
}
// rest of linear
for (;i<numberColumns_;i++) {
if (linearRow[i])
setElement(rowNumber,i,linearRow[i]);
}
} else {
// objective
int iColumn;
for (iColumn=0;iColumn<numberColumns_;iColumn++) {
setColumnObjective(iColumn,0.0);
}
const double * element = quadraticPart->getElements();
const int * column = quadraticPart->getIndices();
const CoinBigIndex * columnStart = quadraticPart->getVectorStarts();
const int * columnLength = quadraticPart->getVectorLengths();
int numberLook = quadraticPart->getNumCols();
int i;
for (i=0;i<numberLook;i++) {
if (!columnLength[i]) {
// just linear part
if (linearRow[i])
setColumnObjective(i,linearRow[i]);
} else {
char temp[10000];
int put=0;
char temp2[30];
bool first=true;
if (linearRow[i]) {
sprintf(temp,"%g",linearRow[i]);
first=false;
put = strlen(temp);
}
for (int j=columnStart[i];j<columnStart[i]+columnLength[i];j++) {
int jColumn = column[j];
double value = element[j];
if (value<0.0||first)
sprintf(temp2,"%g*c%7.7d",value,jColumn);
else
sprintf(temp2,"+%g*c%7.7d",value,jColumn);
int nextPut = put + strlen(temp2);
assert (nextPut<10000);
strcpy(temp+put,temp2);
put = nextPut;
}
setColumnObjective(i,temp);
}
}
// rest of linear
for (;i<numberColumns_;i++) {
if (linearRow[i])
setColumnObjective(i,linearRow[i]);
}
}
}
/* If possible return a model where if all variables marked nonzero are fixed
the problem will be linear. At present may only work if quadratic.
Returns NULL if not possible
*/
CoinModel *
CoinModel::reorder(const char * mark) const
{
// redo array so 2 high priority nonlinear, 1 nonlinear, 0 linear
char * highPriority = new char [numberColumns_];
double * linear = new double[numberColumns_];
CoinModel * newModel = new CoinModel(*this);
int iRow;
for (iRow=-1;iRow<numberRows_;iRow++) {
int numberBad;
CoinPackedMatrix * row = quadraticRow(iRow,linear,numberBad);
assert (!numberBad); // fix later
if (row) {
// see if valid
//const double * element = row->getElements();
const int * column = row->getIndices();
const CoinBigIndex * columnStart = row->getVectorStarts();
const int * columnLength = row->getVectorLengths();
int numberLook = row->getNumCols();
for (int i=0;i<numberLook;i++) {
if (mark[i])
highPriority[i]=2;
else
highPriority[i]=1;
for (int j=columnStart[i];j<columnStart[i]+columnLength[i];j++) {
int iColumn = column[j];
if (mark[iColumn])
highPriority[iColumn]=2;
else
highPriority[iColumn]=1;
}
}
delete row;
}
}
for (iRow=-1;iRow<numberRows_;iRow++) {
int numberBad;
CoinPackedMatrix * row = quadraticRow(iRow,linear,numberBad);
if (row) {
// see if valid
const double * element = row->getElements();
const int * columnLow = row->getIndices();
const CoinBigIndex * columnHigh = row->getVectorStarts();
const int * columnLength = row->getVectorLengths();
int numberLook = row->getNumCols();
int canSwap=0;
for (int i=0;i<numberLook;i++) {
// this one needs to be available
int iPriority = highPriority[i];
for (int j=columnHigh[i];j<columnHigh[i]+columnLength[i];j++) {
int iColumn = columnLow[j];
if (highPriority[iColumn]<=1) {
assert (highPriority[iColumn]==1);
if (iPriority==1) {
canSwap=-1; // no good
break;
} else {
canSwap=1;
}
}
}
}
if (canSwap) {
if (canSwap>0) {
// rewrite row
/* get triples
then swap ones needed
then create packedmatrix
then replace row
*/
int numberElements=columnHigh[numberLook];
int * columnHigh2 = new int [numberElements];
int * columnLow2 = new int [numberElements];
double * element2 = new double [numberElements];
for (int i=0;i<numberLook;i++) {
// this one needs to be available
int iPriority = highPriority[i];
if (iPriority==2) {
for (int j=columnHigh[i];j<columnHigh[i]+columnLength[i];j++) {
columnHigh2[j]=i;
columnLow2[j]=columnLow[j];
element2[j]=element[j];
}
} else {
for (int j=columnHigh[i];j<columnHigh[i]+columnLength[i];j++) {
columnLow2[j]=i;
columnHigh2[j]=columnLow[j];
element2[j]=element[j];
}
}
}
delete row;
row = new CoinPackedMatrix(true,columnHigh2,columnLow2,element2,numberElements);
delete [] columnHigh2;
delete [] columnLow2;
delete [] element2;
// Now replace row
newModel->replaceQuadraticRow(iRow,linear,row);
delete row;
} else {
delete row;
delete newModel;
newModel=NULL;
printf("Unable to use priority - row %d\n",iRow);
break;
}
}
}
}
delete [] highPriority;
delete [] linear;
return newModel;
}
// Sets cut marker array
void
CoinModel::setCutMarker(int size,const int * marker)
{
delete [] cut_;
cut_ = new int [maximumRows_];
CoinZeroN(cut_,maximumRows_);
memcpy(cut_,marker,size*sizeof(int));
}
// Sets priority array
void
CoinModel::setPriorities(int size,const int * priorities)
{
delete [] priority_;
priority_ = new int [maximumColumns_];
CoinZeroN(priority_,maximumColumns_);
memcpy(priority_,priorities,size*sizeof(int));
}
syntax highlighted by Code2HTML, v. 0.9.1