// 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 " <whichSection ( ) == COIN_QUAD_SECTION ; // do names int iRow; for (iRow=0;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 (iRowwhichSection ( ) == 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;iColumniColumn) { printf("above diag %d %d %g\n",iColumn,jColumn,value); } else if (jColumniColumn) { //printf("above diag %d %d %g\n",iColumn,jColumn,value); } else if (jColumn0) { // 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;imaximumElements_) { 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 (newColumn0) { // 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;imaximumElements_) { 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=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=0); if (whichRow=0); if (whichColumn=0); if (whichColumn=0); if (whichColumn=0); if (whichColumn=0); if (whichRow=0); if (whichColumn=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=0) { iRow = (int) elements_[i].row; assert (iRow>=0&&iRow=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=last); if (now>last) { start_[last+1]=numberElements_; for (int j=last+1;j=last); if (now>last) { start_[last+1]=numberElements_; for (int j=last+1;j=0) { iColumn = (int) elements_[i].column; assert (iColumn>=0&&iColumn=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=last); if (now>last) { start_[last+1]=numberElements_; for (int j=last+1;j=last); if (now>last) { start_[last+1]=numberElements_; for (int j=last+1;j=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=0) { double value = elements_[i].value; if (elements_[i].string) { int position = (int) value; assert (position=0) { double value = elements_[i].value; if (elements_[i].string) { int position = (int) value; assert (position=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=0) { double value = elements_[i].value; if (elements_[i].string) { int position = (int) value; assert (position=0;iColumn--) { startPositive[iColumn+1]=startNegative[iColumn]; startNegative[iColumn]=startPositive[iColumn]; } startPositive[0]=0; for (iColumn=0;iColumn0&&!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;i0) 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;i0) 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=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=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=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=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=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=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=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=0); if (whichRow=0); if (whichRow=0); if (whichColumn=0); if (whichColumn=0); if (whichColumn=0); if (whichColumn=0); if (whichColumnmaximumRows_) { 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=0) { int iColumn = triple.column(); assert (whichRow==triple.row()); if (iColumn=0); int n=0; if (whichColumn=0) { int iRow = triple.row(); assert (whichColumn==triple.column()); if (iRow=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=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=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=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=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;igetElements(); const int * column = quadraticPart->getIndices(); const CoinBigIndex * columnStart = quadraticPart->getVectorStarts(); const int * columnLength = quadraticPart->getVectorLengths(); int numberLook = quadraticPart->getNumCols(); int i; for (i=0;igetElements(); const int * column = row->getIndices(); const CoinBigIndex * columnStart = row->getVectorStarts(); const int * columnLength = row->getVectorLengths(); int numberLook = row->getNumCols(); for (int i=0;igetElements(); 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;i0) { // 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;ireplaceQuadraticRow(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)); }