#include <CoinMpsIO.hpp>
Public Member Functions | |
Methods to retrieve problem information | |
These methods return information about the problem held by the CoinMpsIO object.
Querying an object that has no data associated with it result in zeros for the number of rows and columns, and NULL pointers from the methods that return vectors. Const pointers returned from any data-query method are always valid | |
int | getNumCols () const |
Get number of columns. | |
int | getNumRows () const |
Get number of rows. | |
int | getNumElements () const |
Get number of nonzero elements. | |
const double * | getColLower () const |
Get pointer to array[getNumCols()] of column lower bounds. | |
const double * | getColUpper () const |
Get pointer to array[getNumCols()] of column upper bounds. | |
const char * | getRowSense () const |
const double * | getRightHandSide () const |
const double * | getRowRange () const |
const double * | getRowLower () const |
Get pointer to array[getNumRows()] of row lower bounds. | |
const double * | getRowUpper () const |
Get pointer to array[getNumRows()] of row upper bounds. | |
const double * | getObjCoefficients () const |
Get pointer to array[getNumCols()] of objective function coefficients. | |
const CoinPackedMatrix * | getMatrixByRow () const |
Get pointer to row-wise copy of the coefficient matrix. | |
const CoinPackedMatrix * | getMatrixByCol () const |
Get pointer to column-wise copy of the coefficient matrix. | |
bool | isContinuous (int colNumber) const |
Return true if column is a continuous variable. | |
bool | isInteger (int columnNumber) const |
const char * | integerColumns () const |
const char * | rowName (int index) const |
const char * | columnName (int index) const |
int | rowIndex (const char *name) const |
int | columnIndex (const char *name) const |
double | objectiveOffset () const |
const char * | getProblemName () const |
Return the problem name. | |
const char * | getObjectiveName () const |
Return the objective name. | |
const char * | getRhsName () const |
Return the RHS vector name. | |
const char * | getRangeName () const |
Return the range vector name. | |
const char * | getBoundName () const |
Return the bound vector name. | |
Methods to set problem information | |
void | setMpsData (const CoinPackedMatrix &m, const double infinity, const double *collb, const double *colub, const double *obj, const char *integrality, const double *rowlb, const double *rowub, char const *const *const colnames, char const *const *const rownames) |
Set the problem data. | |
void | setMpsData (const CoinPackedMatrix &m, const double infinity, const double *collb, const double *colub, const double *obj, const char *integrality, const double *rowlb, const double *rowub, const std::vector< std::string > &colnames, const std::vector< std::string > &rownames) |
void | setMpsData (const CoinPackedMatrix &m, const double infinity, const double *collb, const double *colub, const double *obj, const char *integrality, const char *rowsen, const double *rowrhs, const double *rowrng, char const *const *const colnames, char const *const *const rownames) |
void | setMpsData (const CoinPackedMatrix &m, const double infinity, const double *collb, const double *colub, const double *obj, const char *integrality, const char *rowsen, const double *rowrhs, const double *rowrng, const std::vector< std::string > &colnames, const std::vector< std::string > &rownames) |
void | copyInIntegerInformation (const char *integerInformation) |
Parameter set/get methods | |
Methods to set and retrieve MPS IO parameters. | |
void | setInfinity (double value) |
Set infinity. | |
double | getInfinity () const |
Get infinity. | |
void | setDefaultBound (int value) |
Set default upper bound for integer variables. | |
int | getDefaultBound () const |
Get default upper bound for integer variables. | |
Methods for problem input and output | |
Methods to read and write MPS format problem files. The read and write methods return the number of errors that occurred during the IO operation, or -1 if no file is opened.
| |
void | setFileName (const char *name) |
Set the current file name for the CoinMpsIO object. | |
const char * | getFileName () const |
Get the current file name for the CoinMpsIO object. | |
const bool | fileReadable () const |
Test if a file with the currrent file name exists and is readable. | |
int | readMps (const char *filename, const char *extension="mps") |
int | readMps () |
int | writeMps (const char *filename, int compression=0, int formatType=0, int numberAcross=2) const |
int | readQuadraticMps (const char *filename, int *&columnStart, int *&column, double *&elements, int checkSymmetry) |
int | readConicMps (const char *filename, int *&columnStart, int *&column, int &numberCones) |
Constructors and destructors | |
CoinMpsIO () | |
Default Constructor. | |
CoinMpsIO (const CoinMpsIO &) | |
Copy constructor. | |
CoinMpsIO & | operator= (const CoinMpsIO &rhs) |
Assignment operator. | |
~CoinMpsIO () | |
Destructor. | |
Message handling | |
void | passInMessageHandler (CoinMessageHandler *handler) |
void | newLanguage (CoinMessages::Language language) |
Set the language for messages. | |
void | setLanguage (CoinMessages::Language language) |
Set the language for messages. | |
CoinMessageHandler * | messageHandler () const |
Return the message handler. | |
CoinMessages | messages () |
Return the messages. | |
Methods to release storage | |
These methods allow the client to reduce the storage used by the CoinMpsIO object be selectively releasing unneeded problem information. | |
void | releaseRedundantInformation () |
void | releaseRowInformation () |
Release all row information (lower, upper). | |
void | releaseColumnInformation () |
Release all column information (lower, upper, objective). | |
void | releaseIntegerInformation () |
Release integer information. | |
void | releaseRowNames () |
Release row names. | |
void | releaseColumnNames () |
Release column names. | |
void | releaseMatrixInformation () |
Release matrix information. | |
Protected Member Functions | |
Miscellaneous helper functions | |
void | setMpsDataWithoutRowAndColNames (const CoinPackedMatrix &m, const double infinity, const double *collb, const double *colub, const double *obj, const char *integrality, const double *rowlb, const double *rowub) |
Utility method used several times to implement public methods. | |
void | setMpsDataColAndRowNames (const std::vector< std::string > &colnames, const std::vector< std::string > &rownames) |
void | setMpsDataColAndRowNames (char const *const *const colnames, char const *const *const rownames) |
void | gutsOfDestructor () |
Does the heavy lifting for destruct and assignment. | |
void | gutsOfCopy (const CoinMpsIO &) |
Does the heavy lifting for copy and assignment. | |
void | freeAll () |
Clears problem data from the CoinMpsIO object. | |
void | convertBoundToSense (const double lower, const double upper, char &sense, double &right, double &range) const |
void | convertSenseToBound (const char sense, const double right, const double range, double &lower, double &upper) const |
int | dealWithFileName (const char *filename, const char *extension, FILE *&fp, gzFile &gzfp) |
Hash table methods | |
void | startHash (char **names, const int number, int section) |
Creates hash list for names (section = 0 for rows, 1 columns). | |
void | startHash (int section) const |
This one does it when names are already in. | |
void | stopHash (int section) |
Deletes hash storage. | |
int | findHash (const char *name, int section) const |
Finds match using hash, -1 not found. | |
Protected Attributes | |
Cached problem information | |
char * | problemName_ |
Problem name. | |
char * | objectiveName_ |
Objective row name. | |
char * | rhsName_ |
Right-hand side vector name. | |
char * | rangeName_ |
Range vector name. | |
char * | boundName_ |
Bounds vector name. | |
int | numberRows_ |
Number of rows. | |
int | numberColumns_ |
Number of columns. | |
CoinBigIndex | numberElements_ |
Number of coefficients. | |
char * | rowsense_ |
Pointer to dense vector of row sense indicators. | |
double * | rhs_ |
Pointer to dense vector of row right-hand side values. | |
double * | rowrange_ |
CoinPackedMatrix * | matrixByRow_ |
Pointer to row-wise copy of problem matrix coefficients. | |
CoinPackedMatrix * | matrixByColumn_ |
Pointer to column-wise copy of problem matrix coefficients. | |
double * | rowlower_ |
Pointer to dense vector of row lower bounds. | |
double * | rowupper_ |
Pointer to dense vector of row upper bounds. | |
double * | collower_ |
Pointer to dense vector of column lower bounds. | |
double * | colupper_ |
Pointer to dense vector of column upper bounds. | |
double * | objective_ |
Pointer to dense vector of objective coefficients. | |
double | objectiveOffset_ |
Constant offset for objective value (i.e., RHS value for OBJ row). | |
char * | integerType_ |
char ** | names_ [2] |
Hash tables | |
char * | fileName_ |
Current file name. | |
int | numberHash_ [2] |
Number of entries in a hash table section. | |
CoinHashLink * | hash_ [2] |
Hash tables (two sections, 0 - row names, 1 - column names). | |
CoinMpsIO object parameters | |
int | defaultBound_ |
Upper bound when no bounds for integers. | |
double | infinity_ |
Value to use for infinity. | |
CoinMessageHandler * | handler_ |
Message handler. | |
bool | defaultHandler_ |
CoinMessages | messages_ |
Messages. | |
CoinMpsCardReader * | cardReader_ |
Card reader. | |
Friends | |
void | CoinMpsIOUnitTest (const std::string &mpsDir) |
This class can be used to read in mps files without a solver. After reading the file, the CoinMpsIO object contains all relevant data, which may be more than a particular OsiSolverInterface allows for. Items may be deleted to allow for flexibility of data storage.
The implementation makes the CoinMpsIO object look very like a dummy solver, as the same conventions are used.
Definition at line 163 of file CoinMpsIO.hpp.
|
Returns the index for the specified column name Returns -1 if the name is not found. Definition at line 2942 of file CoinMpsIO.cpp. References findHash(), hash_, and startHash().
02943 { 02944 if (!hash_[1]) { 02945 if (numberColumns_) { 02946 startHash(1); 02947 } else { 02948 return -1; 02949 } 02950 } 02951 return findHash ( name , 1 ); 02952 } |
|
Returns the column name for the specified index. Returns 0 if the index is out of range. Definition at line 2922 of file CoinMpsIO.cpp. Referenced by readMps().
02923 { 02924 if (index>=0&&index<numberColumns_) { 02925 return names_[1][index]; 02926 } else { 02927 return NULL; 02928 } 02929 } |
|
A quick inlined function to convert from lb/ub style constraint definition to sense/rhs/range style Definition at line 2538 of file CoinMpsIO.cpp. References infinity_. Referenced by getRightHandSide(), getRowRange(), and getRowSense().
02541 { 02542 range = 0.0; 02543 if (lower > -infinity_) { 02544 if (upper < infinity_) { 02545 right = upper; 02546 if (upper==lower) { 02547 sense = 'E'; 02548 } else { 02549 sense = 'R'; 02550 range = upper - lower; 02551 } 02552 } else { 02553 sense = 'G'; 02554 right = lower; 02555 } 02556 } else { 02557 if (upper < infinity_) { 02558 sense = 'L'; 02559 right = upper; 02560 } else { 02561 sense = 'N'; 02562 right = 0.0; 02563 } 02564 } 02565 } |
|
A quick inlined function to convert from sense/rhs/range stryle constraint definition to lb/ub style Definition at line 2571 of file CoinMpsIO.cpp. References infinity_.
02574 { 02575 switch (sense) { 02576 case 'E': 02577 lower = upper = right; 02578 break; 02579 case 'L': 02580 lower = -infinity_; 02581 upper = right; 02582 break; 02583 case 'G': 02584 lower = right; 02585 upper = infinity_; 02586 break; 02587 case 'R': 02588 lower = right - range; 02589 upper = right; 02590 break; 02591 case 'N': 02592 lower = -infinity_; 02593 upper = infinity_; 02594 break; 02595 } 02596 } |
|
Pass in an array[getNumCols()] specifying if a variable is integer. At present, simply coded as zero (continuous) and non-zero (integer) May be extended at a later date. Definition at line 2902 of file CoinMpsIO.cpp. References integerType_.
02903 { 02904 if (integerType) { 02905 if (!integerType_) 02906 integerType_ = new char [numberColumns_]; 02907 memcpy(integerType_,integerType,numberColumns_); 02908 } else { 02909 delete [] integerType_; 02910 integerType_=NULL; 02911 } 02912 } |
|
Deal with a filename As the name says. Returns +1 if the file name is new, 0 if it's the same as before (i.e., matches fileName_), and -1 if there's an error and the file can't be opened. Handles automatic append of .gz suffix when compiled with libz.
Definition at line 930 of file CoinMpsIO.cpp. References fileName_, handler_, CoinMessageHandler::message(), and messages_. Referenced by readConicMps(), readMps(), and readQuadraticMps().
00932 { 00933 fp=NULL; 00934 int goodFile=0; 00935 gzfp=NULL; 00936 if (!fileName_||(filename!=NULL&&strcmp(filename,fileName_))) { 00937 if (filename==NULL) { 00938 handler_->message(COIN_MPS_FILE,messages_)<<"NULL" 00939 <<CoinMessageEol; 00940 return -1; 00941 } 00942 goodFile=-1; 00943 // looks new name 00944 char newName[400]; 00945 if (strcmp(filename,"stdin")&&strcmp(filename,"-")) { 00946 if (extension&&strlen(extension)) { 00947 // There was an extension - but see if user gave .xxx 00948 int i = strlen(filename)-1; 00949 strcpy(newName,filename); 00950 bool foundDot=false; 00951 for (;i>=0;i--) { 00952 char character = filename[i]; 00953 if (character=='/'||character=='\\') { 00954 break; 00955 } else if (character=='.') { 00956 foundDot=true; 00957 break; 00958 } 00959 } 00960 if (!foundDot) { 00961 strcat(newName,"."); 00962 strcat(newName,extension); 00963 } 00964 } else { 00965 // no extension 00966 strcpy(newName,filename); 00967 } 00968 } else { 00969 strcpy(newName,"stdin"); 00970 } 00971 // See if new name 00972 if (fileName_&&!strcmp(newName,fileName_)) { 00973 // old name 00974 return 0; 00975 } else { 00976 // new file 00977 free(fileName_); 00978 fileName_=strdup(newName); 00979 if (strcmp(fileName_,"stdin")) { 00980 #ifdef COIN_USE_ZLIB 00981 int length=strlen(fileName_); 00982 if (!strcmp(fileName_+length-3,".gz")) { 00983 gzfp = gzopen(fileName_,"rb"); 00984 fp = NULL; 00985 goodFile = (gzfp!=NULL); 00986 } else { 00987 #endif 00988 fp = fopen ( fileName_, "r" ); 00989 if (fp!=NULL) 00990 goodFile=1; 00991 #ifdef COIN_USE_ZLIB 00992 if (goodFile<0) { 00993 std::string fname(fileName_); 00994 fname += ".gz"; 00995 gzfp = gzopen(fname.c_str(),"rb"); 00996 printf("%s\n", fname.c_str()); 00997 if (gzfp!=NULL) 00998 goodFile=1; 00999 } 01000 } 01001 #endif 01002 } else { 01003 fp = stdin; 01004 goodFile = 1; 01005 } 01006 } 01007 } else { 01008 // same as before 01009 // reset section ? 01010 goodFile=0; 01011 } 01012 if (goodFile<0) 01013 handler_->message(COIN_MPS_FILE,messages_)<<fileName_ 01014 <<CoinMessageEol; 01015 return goodFile; 01016 } |
|
Get pointer to array[getNumRows()] of constraint right-hand sides. Given constraints with upper (rowupper) and/or lower (rowlower) bounds, the constraint right-hand side (rhs) is set as
Definition at line 2620 of file CoinMpsIO.cpp. References convertBoundToSense(), numberRows_, rhs_, rowlower_, and rowupper_.
02621 { 02622 if ( rhs_==NULL ) { 02623 02624 int nr=numberRows_; 02625 rhs_ = (double *) malloc(nr*sizeof(double)); 02626 02627 02628 char dum1; 02629 double dum2; 02630 int i; 02631 for ( i=0; i<nr; i++ ) { 02632 convertBoundToSense(rowlower_[i],rowupper_[i],dum1,rhs_[i],dum2); 02633 } 02634 } 02635 return rhs_; 02636 } |
|
Get pointer to array[getNumRows()] of row ranges. Given constraints with upper (rowupper) and/or lower (rowlower) bounds, the constraint range (rowrange) is set as
Definition at line 2642 of file CoinMpsIO.cpp. References convertBoundToSense(), numberRows_, rowlower_, rowrange_, and rowupper_.
02643 { 02644 if ( rowrange_==NULL ) { 02645 02646 int nr=numberRows_; 02647 rowrange_ = (double *) malloc(nr*sizeof(double)); 02648 std::fill(rowrange_,rowrange_+nr,0.0); 02649 02650 char dum1; 02651 double dum2; 02652 int i; 02653 for ( i=0; i<nr; i++ ) { 02654 convertBoundToSense(rowlower_[i],rowupper_[i],dum1,dum2,rowrange_[i]); 02655 } 02656 } 02657 return rowrange_; 02658 } |
|
Get pointer to array[getNumRows()] of constraint senses.
Definition at line 2600 of file CoinMpsIO.cpp. References convertBoundToSense(), numberRows_, rowlower_, rowsense_, and rowupper_. Referenced by writeMps().
02601 { 02602 if ( rowsense_==NULL ) { 02603 02604 int nr=numberRows_; 02605 rowsense_ = (char *) malloc(nr*sizeof(char)); 02606 02607 02608 double dum1,dum2; 02609 int i; 02610 for ( i=0; i<nr; i++ ) { 02611 convertBoundToSense(rowlower_[i],rowupper_[i],rowsense_[i],dum1,dum2); 02612 } 02613 } 02614 return rowsense_; 02615 } |
|
Returns array[getNumCols()] specifying if a variable is integer. At present, simply coded as zero (continuous) and non-zero (integer) May be extended at a later date. Definition at line 2896 of file CoinMpsIO.cpp. References integerType_.
02897 { 02898 return integerType_; 02899 } |
|
Return true if a column is an integer variable Note: This function returns true if the the column is a binary or general integer variable. Definition at line 2887 of file CoinMpsIO.cpp. References integerType_. Referenced by writeMps().
02888 { 02889 const char * intType = integerType_; 02890 if ( intType==NULL ) return false; 02891 assert (columnNumber>=0 && columnNumber < numberColumns_); 02892 if ( intType[columnNumber]!=0 ) return true; 02893 return false; 02894 } |
|
Returns the (constant) objective offset This is the RHS entry for the objective row Definition at line 1018 of file CoinMpsIO.cpp. References objectiveOffset_.
01019 { 01020 return objectiveOffset_; 01021 } |
|
Pass in Message handler Supply a custom message handler. It will not be destroyed when the CoinMpsIO object is destroyed. Definition at line 3258 of file CoinMpsIO.cpp. References defaultHandler_, and handler_.
03259 { 03260 if (defaultHandler_) 03261 delete handler_; 03262 defaultHandler_=false; 03263 handler_=handler; 03264 } |
|
Read in a list of cones from the given filename. If filename is NULL (or the same as the currently open file) then reading continues from the current file. If not, the file is closed and the specified file is opened. Code should be added to general MPS reader to read this if CSECTION No checking is done that in unique cone Arrays should be deleted by delete [] Returns number of errors, -1 bad file, -2 no conic section, -3 empty section columnStart is numberCones+1 long, other number of columns in matrix Definition at line 3503 of file CoinMpsIO.cpp. References CoinMpsCardReader::card(), CoinMpsCardReader::cardNumber(), cardReader_, CoinMpsCardReader::columnName(), dealWithFileName(), fileName_, findHash(), handler_, CoinMessageHandler::message(), messages_, CoinMpsCardReader::mpsType(), CoinMpsCardReader::nextField(), CoinMpsCardReader::readToNextSection(), startHash(), stopHash(), and CoinMpsCardReader::whichSection().
03505 { 03506 // Deal with filename - +1 if new, 0 if same as before, -1 if error 03507 FILE *fp=NULL; 03508 gzFile gzfp=NULL; 03509 int returnCode = dealWithFileName(filename,"",fp,gzfp); 03510 if (returnCode<0) { 03511 return -1; 03512 } else if (returnCode>0) { 03513 delete cardReader_; 03514 cardReader_ = new CoinMpsCardReader ( fp , gzfp, this); 03515 } 03516 03517 cardReader_->readToNextSection(); 03518 03519 // Skip NAME 03520 if ( cardReader_->whichSection ( ) == COIN_NAME_SECTION ) 03521 cardReader_->readToNextSection(); 03522 numberCones=0; 03523 03524 // Get arrays 03525 columnStart = new int [numberColumns_+1]; 03526 column = new int [numberColumns_]; 03527 int numberErrors = 0; 03528 columnStart[0]=0; 03529 int numberElements=0; 03530 startHash(1); 03531 03532 //if (cardReader_->whichSection()==COIN_CONIC_SECTION) 03533 //cardReader_->cleanCard(); // skip doing last 03534 while ( cardReader_->nextField ( ) == COIN_CONIC_SECTION ) { 03535 // should check QUAD 03536 // Have to check by hand 03537 if (!strncmp(cardReader_->card(),"CSECTION",8)) { 03538 if (numberElements==columnStart[numberCones]) { 03539 printf("Cone must have at least one column\n"); 03540 abort(); 03541 } 03542 columnStart[++numberCones]=numberElements; 03543 continue; 03544 } 03545 COINColumnIndex iColumn1; 03546 switch ( cardReader_->mpsType ( ) ) { 03547 case COIN_BLANK_COLUMN: 03548 // get index 03549 iColumn1 = findHash ( cardReader_->columnName ( ) , 1 ); 03550 03551 if ( iColumn1 >= 0 ) { 03552 column[numberElements++]=iColumn1; 03553 } else { 03554 numberErrors++; 03555 if ( numberErrors < 100 ) { 03556 handler_->message(COIN_MPS_NOMATCHCOL,messages_) 03557 <<cardReader_->columnName()<<cardReader_->cardNumber()<<cardReader_->card() 03558 <<CoinMessageEol; 03559 } else if (numberErrors > 100000) { 03560 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 03561 return numberErrors; 03562 } 03563 } 03564 break; 03565 default: 03566 numberErrors++; 03567 if ( numberErrors < 100 ) { 03568 handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber() 03569 <<cardReader_->card() 03570 <<CoinMessageEol; 03571 } else if (numberErrors > 100000) { 03572 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 03573 return numberErrors; 03574 } 03575 } 03576 } 03577 if ( cardReader_->whichSection ( ) == COIN_ENDATA_SECTION ) { 03578 // Error if no cones 03579 if (!numberElements) { 03580 handler_->message(COIN_MPS_EOF,messages_)<<fileName_ 03581 <<CoinMessageEol; 03582 delete [] columnStart; 03583 delete [] column; 03584 columnStart = NULL; 03585 column = NULL; 03586 return -3; 03587 } else { 03588 columnStart[++numberCones]=numberElements; 03589 } 03590 } else { 03591 handler_->message(COIN_MPS_BADFILE1,messages_)<<cardReader_->card() 03592 <<cardReader_->cardNumber() 03593 <<fileName_ 03594 <<CoinMessageEol; 03595 delete [] columnStart; 03596 delete [] column; 03597 columnStart = NULL; 03598 column = NULL; 03599 numberCones=0; 03600 return -2; 03601 } 03602 03603 stopHash(1); 03604 return numberErrors; 03605 } |
|
Read a problem in MPS format from a previously opened file More precisely, read a problem using a CoinMpsCardReader object already associated with this CoinMpsIO object.
Definition at line 1056 of file CoinMpsIO.cpp. References boundName_, CoinMpsCardReader::card(), CoinMpsCardReader::cardNumber(), cardReader_, collower_, columnName(), CoinMpsCardReader::columnName(), colupper_, defaultBound_, fileName_, CoinMpsCardReader::filePointer(), findHash(), handler_, infinity_, integerType_, matrixByColumn_, CoinMessageHandler::message(), messages_, CoinMpsCardReader::mpsType(), CoinMpsCardReader::nextField(), numberColumns_, numberElements_, numberRows_, objective_, objectiveName_, objectiveOffset_, problemName_, rangeName_, CoinMpsCardReader::readToNextSection(), rhsName_, rowlower_, CoinMpsCardReader::rowName(), rowName(), rowupper_, startHash(), stopHash(), CoinMpsCardReader::value(), and CoinMpsCardReader::whichSection(). Referenced by readMps().
01057 { 01058 bool ifmps; 01059 01060 cardReader_->readToNextSection(); 01061 01062 if ( cardReader_->whichSection ( ) == COIN_NAME_SECTION ) { 01063 ifmps = true; 01064 // save name of section 01065 free(problemName_); 01066 problemName_=strdup(cardReader_->columnName()); 01067 } else if ( cardReader_->whichSection ( ) == COIN_UNKNOWN_SECTION ) { 01068 handler_->message(COIN_MPS_BADFILE1,messages_)<<cardReader_->card() 01069 <<1 01070 <<fileName_ 01071 <<CoinMessageEol; 01072 #ifdef COIN_USE_ZLIB 01073 if (!cardReader_->filePointer()) 01074 handler_->message(COIN_MPS_BADFILE2,messages_)<<CoinMessageEol; 01075 01076 #endif 01077 return -2; 01078 } else if ( cardReader_->whichSection ( ) != COIN_EOF_SECTION ) { 01079 // save name of section 01080 free(problemName_); 01081 problemName_=strdup(cardReader_->card()); 01082 ifmps = false; 01083 } else { 01084 handler_->message(COIN_MPS_EOF,messages_)<<fileName_ 01085 <<CoinMessageEol; 01086 return -3; 01087 } 01088 CoinBigIndex *start; 01089 COINRowIndex *row; 01090 double *element; 01091 objectiveOffset_ = 0.0; 01092 01093 int numberErrors = 0; 01094 int i; 01095 01096 if ( ifmps ) { 01097 // mps file - always read in free format 01098 bool gotNrow = false; 01099 01100 //get ROWS 01101 cardReader_->nextField ( ) ; 01102 // Fudge for what ever code has OBJSENSE 01103 if (!strncmp(cardReader_->card(),"OBJSENSE",8)) { 01104 cardReader_->nextField(); 01105 int i; 01106 const char * thisCard = cardReader_->card(); 01107 int direction = 0; 01108 for (i=0;i<20;i++) { 01109 if (thisCard[i]!=' ') { 01110 if (!strncmp(thisCard+i,"MAX",3)) 01111 direction=-1; 01112 else if (!strncmp(thisCard+i,"MIN",3)) 01113 direction=1; 01114 break; 01115 } 01116 } 01117 if (!direction) 01118 printf("No MAX/MIN found after OBJSENSE\n"); 01119 else 01120 printf("%s found after OBJSENSE - Coin ignores\n", 01121 (direction>0 ? "MIN" : "MAX")); 01122 cardReader_->nextField(); 01123 } 01124 if ( cardReader_->whichSection ( ) != COIN_ROW_SECTION ) { 01125 handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber() 01126 <<cardReader_->card() 01127 <<CoinMessageEol; 01128 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01129 return numberErrors; 01130 } 01131 //use malloc etc as I don't know how to do realloc in C++ 01132 numberRows_ = 0; 01133 numberColumns_ = 0; 01134 numberElements_ = 0; 01135 COINRowIndex maxRows = 1000; 01136 COINMpsType *rowType = 01137 01138 ( COINMpsType * ) malloc ( maxRows * sizeof ( COINMpsType ) ); 01139 char **rowName = ( char ** ) malloc ( maxRows * sizeof ( char * ) ); 01140 01141 // for discarded free rows 01142 COINRowIndex maxFreeRows = 100; 01143 COINRowIndex numberOtherFreeRows = 0; 01144 char **freeRowName = 01145 01146 ( char ** ) malloc ( maxFreeRows * sizeof ( char * ) ); 01147 while ( cardReader_->nextField ( ) == COIN_ROW_SECTION ) { 01148 switch ( cardReader_->mpsType ( ) ) { 01149 case COIN_N_ROW: 01150 if ( !gotNrow ) { 01151 gotNrow = true; 01152 // save name of section 01153 free(objectiveName_); 01154 objectiveName_=strdup(cardReader_->columnName()); 01155 } else { 01156 // add to discard list 01157 if ( numberOtherFreeRows == maxFreeRows ) { 01158 maxFreeRows = ( 3 * maxFreeRows ) / 2 + 100; 01159 freeRowName = 01160 ( char ** ) realloc ( freeRowName, 01161 01162 maxFreeRows * sizeof ( char * ) ); 01163 } 01164 freeRowName[numberOtherFreeRows] = 01165 strdup ( cardReader_->columnName ( ) ); 01166 numberOtherFreeRows++; 01167 } 01168 break; 01169 case COIN_E_ROW: 01170 case COIN_L_ROW: 01171 case COIN_G_ROW: 01172 if ( numberRows_ == maxRows ) { 01173 maxRows = ( 3 * maxRows ) / 2 + 1000; 01174 rowType = 01175 ( COINMpsType * ) realloc ( rowType, 01176 maxRows * sizeof ( COINMpsType ) ); 01177 rowName = 01178 01179 ( char ** ) realloc ( rowName, maxRows * sizeof ( char * ) ); 01180 } 01181 rowType[numberRows_] = cardReader_->mpsType ( ); 01182 rowName[numberRows_] = strdup ( cardReader_->columnName ( ) ); 01183 numberRows_++; 01184 break; 01185 default: 01186 numberErrors++; 01187 if ( numberErrors < 100 ) { 01188 handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber() 01189 <<cardReader_->card() 01190 <<CoinMessageEol; 01191 } else if (numberErrors > 100000) { 01192 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01193 return numberErrors; 01194 } 01195 } 01196 } 01197 if ( cardReader_->whichSection ( ) != COIN_COLUMN_SECTION ) { 01198 handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber() 01199 <<cardReader_->card() 01200 <<CoinMessageEol; 01201 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01202 return numberErrors; 01203 } 01204 assert ( gotNrow ); 01205 rowType = 01206 ( COINMpsType * ) realloc ( rowType, 01207 numberRows_ * sizeof ( COINMpsType ) ); 01208 // put objective and other free rows at end 01209 rowName = 01210 ( char ** ) realloc ( rowName, 01211 ( numberRows_ + 1 + 01212 01213 numberOtherFreeRows ) * sizeof ( char * ) ); 01214 rowName[numberRows_] = strdup(objectiveName_); 01215 memcpy ( rowName + numberRows_ + 1, freeRowName, 01216 numberOtherFreeRows * sizeof ( char * ) ); 01217 // now we can get rid of this array 01218 free(freeRowName); 01219 01220 startHash ( rowName, numberRows_ + 1 + numberOtherFreeRows , 0 ); 01221 COINColumnIndex maxColumns = 1000 + numberRows_ / 5; 01222 CoinBigIndex maxElements = 5000 + numberRows_ / 2; 01223 COINMpsType *columnType = ( COINMpsType * ) 01224 malloc ( maxColumns * sizeof ( COINMpsType ) ); 01225 char **columnName = ( char ** ) malloc ( maxColumns * sizeof ( char * ) ); 01226 01227 objective_ = ( double * ) malloc ( maxColumns * sizeof ( double ) ); 01228 start = ( CoinBigIndex * ) 01229 malloc ( ( maxColumns + 1 ) * sizeof ( CoinBigIndex ) ); 01230 row = ( COINRowIndex * ) 01231 malloc ( maxElements * sizeof ( COINRowIndex ) ); 01232 element = 01233 ( double * ) malloc ( maxElements * sizeof ( double ) ); 01234 // for duplicates 01235 CoinBigIndex *rowUsed = new CoinBigIndex[numberRows_]; 01236 01237 for (i=0;i<numberRows_;i++) { 01238 rowUsed[i]=-1; 01239 } 01240 bool objUsed = false; 01241 01242 numberElements_ = 0; 01243 char lastColumn[200]; 01244 01245 memset ( lastColumn, '\0', 200 ); 01246 COINColumnIndex column = -1; 01247 bool inIntegerSet = false; 01248 COINColumnIndex numberIntegers = 0; 01249 const double tinyElement = 1.0e-14; 01250 01251 while ( cardReader_->nextField ( ) == COIN_COLUMN_SECTION ) { 01252 switch ( cardReader_->mpsType ( ) ) { 01253 case COIN_BLANK_COLUMN: 01254 if ( strcmp ( lastColumn, cardReader_->columnName ( ) ) ) { 01255 // new column 01256 01257 // reset old column and take out tiny 01258 if ( numberColumns_ ) { 01259 objUsed = false; 01260 CoinBigIndex i; 01261 CoinBigIndex k = start[column]; 01262 01263 for ( i = k; i < numberElements_; i++ ) { 01264 COINRowIndex irow = row[i]; 01265 #if 0 01266 if ( fabs ( element[i] ) > tinyElement ) { 01267 element[k++] = element[i]; 01268 } 01269 #endif 01270 rowUsed[irow] = -1; 01271 } 01272 //numberElements_ = k; 01273 } 01274 column = numberColumns_; 01275 if ( numberColumns_ == maxColumns ) { 01276 maxColumns = ( 3 * maxColumns ) / 2 + 1000; 01277 columnType = ( COINMpsType * ) 01278 realloc ( columnType, maxColumns * sizeof ( COINMpsType ) ); 01279 columnName = ( char ** ) 01280 realloc ( columnName, maxColumns * sizeof ( char * ) ); 01281 01282 objective_ = ( double * ) 01283 realloc ( objective_, maxColumns * sizeof ( double ) ); 01284 start = ( CoinBigIndex * ) 01285 realloc ( start, 01286 ( maxColumns + 1 ) * sizeof ( CoinBigIndex ) ); 01287 } 01288 if ( !inIntegerSet ) { 01289 columnType[column] = COIN_UNSET_BOUND; 01290 } else { 01291 columnType[column] = COIN_INTORG; 01292 numberIntegers++; 01293 } 01294 columnName[column] = strdup ( cardReader_->columnName ( ) ); 01295 strcpy ( lastColumn, cardReader_->columnName ( ) ); 01296 objective_[column] = 0.0; 01297 start[column] = numberElements_; 01298 numberColumns_++; 01299 } 01300 if ( fabs ( cardReader_->value ( ) ) > tinyElement ) { 01301 if ( numberElements_ == maxElements ) { 01302 maxElements = ( 3 * maxElements ) / 2 + 1000; 01303 row = ( COINRowIndex * ) 01304 realloc ( row, maxElements * sizeof ( COINRowIndex ) ); 01305 element = ( double * ) 01306 realloc ( element, maxElements * sizeof ( double ) ); 01307 } 01308 // get row number 01309 COINRowIndex irow = findHash ( cardReader_->rowName ( ) , 0 ); 01310 01311 if ( irow >= 0 ) { 01312 double value = cardReader_->value ( ); 01313 01314 // check for duplicates 01315 if ( irow == numberRows_ ) { 01316 // objective 01317 if ( objUsed ) { 01318 numberErrors++; 01319 if ( numberErrors < 100 ) { 01320 handler_->message(COIN_MPS_DUPOBJ,messages_) 01321 <<cardReader_->cardNumber()<<cardReader_->card() 01322 <<CoinMessageEol; 01323 } else if (numberErrors > 100000) { 01324 handler_->message(COIN_MPS_RETURNING,messages_) 01325 <<CoinMessageEol; 01326 return numberErrors; 01327 } 01328 } else { 01329 objUsed = true; 01330 } 01331 value += objective_[column]; 01332 if ( fabs ( value ) <= tinyElement ) 01333 value = 0.0; 01334 objective_[column] = value; 01335 } else if ( irow < numberRows_ ) { 01336 // other free rows will just be discarded so won't get here 01337 if ( rowUsed[irow] >= 0 ) { 01338 element[rowUsed[irow]] += value; 01339 numberErrors++; 01340 if ( numberErrors < 100 ) { 01341 handler_->message(COIN_MPS_DUPROW,messages_) 01342 <<cardReader_->rowName()<<cardReader_->cardNumber() 01343 <<cardReader_->card() 01344 <<CoinMessageEol; 01345 } else if (numberErrors > 100000) { 01346 handler_->message(COIN_MPS_RETURNING,messages_) 01347 <<CoinMessageEol; 01348 return numberErrors; 01349 } 01350 } else { 01351 row[numberElements_] = irow; 01352 element[numberElements_] = value; 01353 rowUsed[irow] = numberElements_; 01354 numberElements_++; 01355 } 01356 } 01357 } else { 01358 numberErrors++; 01359 if ( numberErrors < 100 ) { 01360 handler_->message(COIN_MPS_NOMATCHROW,messages_) 01361 <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card() 01362 <<CoinMessageEol; 01363 } else if (numberErrors > 100000) { 01364 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01365 return numberErrors; 01366 } 01367 } 01368 } 01369 break; 01370 case COIN_INTORG: 01371 inIntegerSet = true; 01372 break; 01373 case COIN_INTEND: 01374 inIntegerSet = false; 01375 break; 01376 case COIN_S1_COLUMN: 01377 case COIN_S2_COLUMN: 01378 case COIN_S3_COLUMN: 01379 case COIN_SOSEND: 01380 std::cout << "** code sos etc later" << std::endl; 01381 abort ( ); 01382 break; 01383 default: 01384 numberErrors++; 01385 if ( numberErrors < 100 ) { 01386 handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber() 01387 <<cardReader_->card() 01388 <<CoinMessageEol; 01389 } else if (numberErrors > 100000) { 01390 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01391 return numberErrors; 01392 } 01393 } 01394 } 01395 start[numberColumns_] = numberElements_; 01396 delete[]rowUsed; 01397 if ( cardReader_->whichSection ( ) != COIN_RHS_SECTION ) { 01398 handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber() 01399 <<cardReader_->card() 01400 <<CoinMessageEol; 01401 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01402 return numberErrors; 01403 } 01404 columnType = 01405 ( COINMpsType * ) realloc ( columnType, 01406 numberColumns_ * sizeof ( COINMpsType ) ); 01407 columnName = 01408 01409 ( char ** ) realloc ( columnName, numberColumns_ * sizeof ( char * ) ); 01410 objective_ = ( double * ) 01411 realloc ( objective_, numberColumns_ * sizeof ( double ) ); 01412 start = ( CoinBigIndex * ) 01413 realloc ( start, ( numberColumns_ + 1 ) * sizeof ( CoinBigIndex ) ); 01414 row = ( COINRowIndex * ) 01415 realloc ( row, numberElements_ * sizeof ( COINRowIndex ) ); 01416 element = ( double * ) 01417 realloc ( element, numberElements_ * sizeof ( double ) ); 01418 01419 rowlower_ = ( double * ) malloc ( numberRows_ * sizeof ( double ) ); 01420 rowupper_ = ( double * ) malloc ( numberRows_ * sizeof ( double ) ); 01421 for (i=0;i<numberRows_;i++) { 01422 rowlower_[i]=-infinity_; 01423 rowupper_[i]=infinity_; 01424 } 01425 objUsed = false; 01426 memset ( lastColumn, '\0', 200 ); 01427 bool gotRhs = false; 01428 01429 // need coding for blank rhs 01430 while ( cardReader_->nextField ( ) == COIN_RHS_SECTION ) { 01431 COINRowIndex irow; 01432 01433 switch ( cardReader_->mpsType ( ) ) { 01434 case COIN_BLANK_COLUMN: 01435 if ( strcmp ( lastColumn, cardReader_->columnName ( ) ) ) { 01436 01437 // skip rest if got a rhs 01438 if ( gotRhs ) { 01439 while ( cardReader_->nextField ( ) == COIN_RHS_SECTION ) { 01440 } 01441 break; 01442 } else { 01443 gotRhs = true; 01444 strcpy ( lastColumn, cardReader_->columnName ( ) ); 01445 // save name of section 01446 free(rhsName_); 01447 rhsName_=strdup(cardReader_->columnName()); 01448 } 01449 } 01450 // get row number 01451 irow = findHash ( cardReader_->rowName ( ) , 0 ); 01452 if ( irow >= 0 ) { 01453 double value = cardReader_->value ( ); 01454 01455 // check for duplicates 01456 if ( irow == numberRows_ ) { 01457 // objective 01458 if ( objUsed ) { 01459 numberErrors++; 01460 if ( numberErrors < 100 ) { 01461 handler_->message(COIN_MPS_DUPOBJ,messages_) 01462 <<cardReader_->cardNumber()<<cardReader_->card() 01463 <<CoinMessageEol; 01464 } else if (numberErrors > 100000) { 01465 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01466 return numberErrors; 01467 } 01468 } else { 01469 objUsed = true; 01470 } 01471 objectiveOffset_ += value; 01472 } else if ( irow < numberRows_ ) { 01473 if ( rowlower_[irow] != -infinity_ ) { 01474 numberErrors++; 01475 if ( numberErrors < 100 ) { 01476 handler_->message(COIN_MPS_DUPROW,messages_) 01477 <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card() 01478 <<CoinMessageEol; 01479 } else if (numberErrors > 100000) { 01480 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01481 return numberErrors; 01482 } 01483 } else { 01484 rowlower_[irow] = value; 01485 } 01486 } 01487 } else { 01488 numberErrors++; 01489 if ( numberErrors < 100 ) { 01490 handler_->message(COIN_MPS_NOMATCHROW,messages_) 01491 <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card() 01492 <<CoinMessageEol; 01493 } else if (numberErrors > 100000) { 01494 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01495 return numberErrors; 01496 } 01497 } 01498 break; 01499 default: 01500 numberErrors++; 01501 if ( numberErrors < 100 ) { 01502 handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber() 01503 <<cardReader_->card() 01504 <<CoinMessageEol; 01505 } else if (numberErrors > 100000) { 01506 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01507 return numberErrors; 01508 } 01509 } 01510 } 01511 if ( cardReader_->whichSection ( ) == COIN_RANGES_SECTION ) { 01512 memset ( lastColumn, '\0', 200 ); 01513 bool gotRange = false; 01514 COINRowIndex irow; 01515 01516 // need coding for blank range 01517 while ( cardReader_->nextField ( ) == COIN_RANGES_SECTION ) { 01518 switch ( cardReader_->mpsType ( ) ) { 01519 case COIN_BLANK_COLUMN: 01520 if ( strcmp ( lastColumn, cardReader_->columnName ( ) ) ) { 01521 01522 // skip rest if got a range 01523 if ( gotRange ) { 01524 while ( cardReader_->nextField ( ) == COIN_RANGES_SECTION ) { 01525 } 01526 break; 01527 } else { 01528 gotRange = true; 01529 strcpy ( lastColumn, cardReader_->columnName ( ) ); 01530 // save name of section 01531 free(rangeName_); 01532 rangeName_=strdup(cardReader_->columnName()); 01533 } 01534 } 01535 // get row number 01536 irow = findHash ( cardReader_->rowName ( ) , 0 ); 01537 if ( irow >= 0 ) { 01538 double value = cardReader_->value ( ); 01539 01540 // check for duplicates 01541 if ( irow == numberRows_ ) { 01542 // objective 01543 numberErrors++; 01544 if ( numberErrors < 100 ) { 01545 handler_->message(COIN_MPS_DUPOBJ,messages_) 01546 <<cardReader_->cardNumber()<<cardReader_->card() 01547 <<CoinMessageEol; 01548 } else if (numberErrors > 100000) { 01549 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01550 return numberErrors; 01551 } 01552 } else { 01553 if ( rowupper_[irow] != infinity_ ) { 01554 numberErrors++; 01555 if ( numberErrors < 100 ) { 01556 handler_->message(COIN_MPS_DUPROW,messages_) 01557 <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card() 01558 <<CoinMessageEol; 01559 } else if (numberErrors > 100000) { 01560 handler_->message(COIN_MPS_RETURNING,messages_) 01561 <<CoinMessageEol; 01562 return numberErrors; 01563 } 01564 } else { 01565 rowupper_[irow] = value; 01566 } 01567 } 01568 } else { 01569 numberErrors++; 01570 if ( numberErrors < 100 ) { 01571 handler_->message(COIN_MPS_NOMATCHROW,messages_) 01572 <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card() 01573 <<CoinMessageEol; 01574 } else if (numberErrors > 100000) { 01575 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01576 return numberErrors; 01577 } 01578 } 01579 break; 01580 default: 01581 numberErrors++; 01582 if ( numberErrors < 100 ) { 01583 handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber() 01584 <<cardReader_->card() 01585 <<CoinMessageEol; 01586 } else if (numberErrors > 100000) { 01587 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01588 return numberErrors; 01589 } 01590 } 01591 } 01592 } 01593 stopHash ( 0 ); 01594 // massage ranges 01595 { 01596 COINRowIndex irow; 01597 01598 for ( irow = 0; irow < numberRows_; irow++ ) { 01599 double lo = rowlower_[irow]; 01600 double up = rowupper_[irow]; 01601 double up2 = rowupper_[irow]; //range 01602 01603 switch ( rowType[irow] ) { 01604 case COIN_E_ROW: 01605 if ( lo == -infinity_ ) 01606 lo = 0.0; 01607 if ( up == infinity_ ) { 01608 up = lo; 01609 } else if ( up > 0.0 ) { 01610 up += lo; 01611 } else { 01612 up = lo; 01613 lo += up2; 01614 } 01615 break; 01616 case COIN_L_ROW: 01617 if ( lo == -infinity_ ) { 01618 up = 0.0; 01619 } else { 01620 up = lo; 01621 lo = -infinity_; 01622 } 01623 if ( up2 != infinity_ ) { 01624 lo = up - fabs ( up2 ); 01625 } 01626 break; 01627 case COIN_G_ROW: 01628 if ( lo == -infinity_ ) { 01629 lo = 0.0; 01630 up = infinity_; 01631 } else { 01632 up = infinity_; 01633 } 01634 if ( up2 != infinity_ ) { 01635 up = lo + fabs ( up2 ); 01636 } 01637 break; 01638 default: 01639 abort(); 01640 } 01641 rowlower_[irow] = lo; 01642 rowupper_[irow] = up; 01643 } 01644 } 01645 free ( rowType ); 01646 // default bounds 01647 collower_ = ( double * ) malloc ( numberColumns_ * sizeof ( double ) ); 01648 colupper_ = ( double * ) malloc ( numberColumns_ * sizeof ( double ) ); 01649 for (i=0;i<numberColumns_;i++) { 01650 collower_[i]=0.0; 01651 colupper_[i]=infinity_; 01652 } 01653 // set up integer region just in case 01654 integerType_ = (char *) malloc (numberColumns_*sizeof(char)); 01655 01656 for ( column = 0; column < numberColumns_; column++ ) { 01657 if ( columnType[column] == COIN_INTORG ) { 01658 columnType[column] = COIN_UNSET_BOUND; 01659 integerType_[column] = 1; 01660 } else { 01661 integerType_[column] = 0; 01662 } 01663 } 01664 // start hash even if no bound section - to make sure names survive 01665 startHash ( columnName, numberColumns_ , 1 ); 01666 if ( cardReader_->whichSection ( ) == COIN_BOUNDS_SECTION ) { 01667 memset ( lastColumn, '\0', 200 ); 01668 bool gotBound = false; 01669 01670 while ( cardReader_->nextField ( ) == COIN_BOUNDS_SECTION ) { 01671 if ( strcmp ( lastColumn, cardReader_->columnName ( ) ) ) { 01672 01673 // skip rest if got a bound 01674 if ( gotBound ) { 01675 while ( cardReader_->nextField ( ) == COIN_BOUNDS_SECTION ) { 01676 } 01677 break; 01678 } else { 01679 gotBound = true;; 01680 strcpy ( lastColumn, cardReader_->columnName ( ) ); 01681 // save name of section 01682 free(boundName_); 01683 boundName_=strdup(cardReader_->columnName()); 01684 } 01685 } 01686 // get column number 01687 COINColumnIndex icolumn = findHash ( cardReader_->rowName ( ) , 1 ); 01688 01689 if ( icolumn >= 0 ) { 01690 double value = cardReader_->value ( ); 01691 bool ifError = false; 01692 01693 switch ( cardReader_->mpsType ( ) ) { 01694 case COIN_UP_BOUND: 01695 if ( value == -1.0e100 ) 01696 ifError = true; 01697 if ( columnType[icolumn] == COIN_UNSET_BOUND ) { 01698 if ( value < 0.0 ) { 01699 collower_[icolumn] = -infinity_; 01700 } 01701 } else if ( columnType[icolumn] == COIN_LO_BOUND ) { 01702 if ( value < collower_[icolumn] ) { 01703 ifError = true; 01704 } else if ( value < collower_[icolumn] + tinyElement ) { 01705 value = collower_[icolumn]; 01706 } 01707 } else if ( columnType[icolumn] == COIN_MI_BOUND ) { 01708 } else { 01709 ifError = true; 01710 } 01711 colupper_[icolumn] = value; 01712 columnType[icolumn] = COIN_UP_BOUND; 01713 break; 01714 case COIN_LO_BOUND: 01715 if ( value == -1.0e100 ) 01716 ifError = true; 01717 if ( columnType[icolumn] == COIN_UNSET_BOUND ) { 01718 } else if ( columnType[icolumn] == COIN_UP_BOUND || 01719 columnType[icolumn] == COIN_UI_BOUND ) { 01720 if ( value > colupper_[icolumn] ) { 01721 ifError = true; 01722 } else if ( value > colupper_[icolumn] - tinyElement ) { 01723 value = colupper_[icolumn]; 01724 } 01725 } else { 01726 ifError = true; 01727 } 01728 collower_[icolumn] = value; 01729 columnType[icolumn] = COIN_LO_BOUND; 01730 break; 01731 case COIN_FX_BOUND: 01732 if ( value == -1.0e100 ) 01733 ifError = true; 01734 if ( columnType[icolumn] == COIN_UNSET_BOUND ) { 01735 } else if ( columnType[icolumn] == COIN_UI_BOUND || 01736 columnType[icolumn] == COIN_BV_BOUND) { 01737 // Allow so people can easily put FX's at end 01738 double value2 = floor(value); 01739 if (fabs(value2-value)>1.0e-12|| 01740 value2<collower_[icolumn]|| 01741 value2>colupper_[icolumn]) { 01742 ifError=true; 01743 } else { 01744 // take off integer list 01745 assert(integerType_[icolumn] ); 01746 numberIntegers--; 01747 integerType_[icolumn] = 0; 01748 } 01749 } else { 01750 ifError = true; 01751 } 01752 collower_[icolumn] = value; 01753 colupper_[icolumn] = value; 01754 columnType[icolumn] = COIN_FX_BOUND; 01755 break; 01756 case COIN_FR_BOUND: 01757 if ( columnType[icolumn] == COIN_UNSET_BOUND ) { 01758 } else { 01759 ifError = true; 01760 } 01761 collower_[icolumn] = -infinity_; 01762 colupper_[icolumn] = infinity_; 01763 columnType[icolumn] = COIN_FR_BOUND; 01764 break; 01765 case COIN_MI_BOUND: 01766 if ( columnType[icolumn] == COIN_UNSET_BOUND ) { 01767 colupper_[icolumn] = COIN_DBL_MAX; 01768 } else if ( columnType[icolumn] == COIN_UP_BOUND ) { 01769 } else { 01770 ifError = true; 01771 } 01772 collower_[icolumn] = -infinity_; 01773 columnType[icolumn] = COIN_MI_BOUND; 01774 break; 01775 case COIN_PL_BOUND: 01776 if ( columnType[icolumn] == COIN_UNSET_BOUND ) { 01777 } else { 01778 ifError = true; 01779 } 01780 columnType[icolumn] = COIN_PL_BOUND; 01781 break; 01782 case COIN_UI_BOUND: 01783 #if 0 01784 if ( value == -1.0e100 ) 01785 ifError = true; 01786 if ( columnType[icolumn] == COIN_UNSET_BOUND ) { 01787 } else if ( columnType[icolumn] == COIN_LO_BOUND ) { 01788 if ( value < collower_[icolumn] ) { 01789 ifError = true; 01790 } else if ( value < collower_[icolumn] + tinyElement ) { 01791 value = collower_[icolumn]; 01792 } 01793 } else { 01794 ifError = true; 01795 } 01796 #else 01797 if ( value == -1.0e100 ) { 01798 value = infinity_; 01799 if (columnType[icolumn] != COIN_UNSET_BOUND && 01800 columnType[icolumn] != COIN_LO_BOUND) { 01801 ifError = true; 01802 } 01803 } else { 01804 if ( columnType[icolumn] == COIN_UNSET_BOUND ) { 01805 } else if ( columnType[icolumn] == COIN_LO_BOUND ) { 01806 if ( value < collower_[icolumn] ) { 01807 ifError = true; 01808 } else if ( value < collower_[icolumn] + tinyElement ) { 01809 value = collower_[icolumn]; 01810 } 01811 } else { 01812 ifError = true; 01813 } 01814 } 01815 #endif 01816 colupper_[icolumn] = value; 01817 columnType[icolumn] = COIN_UI_BOUND; 01818 if ( !integerType_[icolumn] ) { 01819 numberIntegers++; 01820 integerType_[icolumn] = 1; 01821 } 01822 break; 01823 case COIN_BV_BOUND: 01824 if ( columnType[icolumn] == COIN_UNSET_BOUND ) { 01825 } else { 01826 ifError = true; 01827 } 01828 collower_[icolumn] = 0.0; 01829 colupper_[icolumn] = 1.0; 01830 columnType[icolumn] = COIN_BV_BOUND; 01831 if ( !integerType_[icolumn] ) { 01832 numberIntegers++; 01833 integerType_[icolumn] = 1; 01834 } 01835 break; 01836 default: 01837 ifError = true; 01838 break; 01839 } 01840 if ( ifError ) { 01841 numberErrors++; 01842 if ( numberErrors < 100 ) { 01843 handler_->message(COIN_MPS_BADIMAGE,messages_) 01844 <<cardReader_->cardNumber() 01845 <<cardReader_->card() 01846 <<CoinMessageEol; 01847 } else if (numberErrors > 100000) { 01848 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01849 return numberErrors; 01850 } 01851 } 01852 } else { 01853 numberErrors++; 01854 if ( numberErrors < 100 ) { 01855 handler_->message(COIN_MPS_NOMATCHCOL,messages_) 01856 <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card() 01857 <<CoinMessageEol; 01858 } else if (numberErrors > 100000) { 01859 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01860 return numberErrors; 01861 } 01862 } 01863 } 01864 } 01865 stopHash ( 1 ); 01866 // clean up integers 01867 if ( !numberIntegers ) { 01868 free(integerType_); 01869 integerType_ = NULL; 01870 } else { 01871 COINColumnIndex icolumn; 01872 01873 for ( icolumn = 0; icolumn < numberColumns_; icolumn++ ) { 01874 if ( integerType_[icolumn] ) { 01875 assert ( collower_[icolumn] >= -MAX_INTEGER ); 01876 // if 0 infinity make 0-1 ??? 01877 if ( columnType[icolumn] == COIN_UNSET_BOUND ) 01878 colupper_[icolumn] = defaultBound_; 01879 if ( colupper_[icolumn] > MAX_INTEGER ) 01880 colupper_[icolumn] = MAX_INTEGER; 01881 } 01882 } 01883 } 01884 free ( columnType ); 01885 if ( cardReader_->whichSection ( ) != COIN_ENDATA_SECTION ) { 01886 handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber() 01887 <<cardReader_->card() 01888 <<CoinMessageEol; 01889 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 01890 return numberErrors; 01891 } 01892 } else { 01893 // This is very simple format - what should we use? 01894 COINColumnIndex i; 01895 FILE * fp = cardReader_->filePointer(); 01896 fscanf ( fp, "%d %d %d\n", &numberRows_, &numberColumns_, &i); 01897 numberElements_ = i; // done this way in case numberElements_ long 01898 01899 rowlower_ = ( double * ) malloc ( numberRows_ * sizeof ( double ) ); 01900 rowupper_ = ( double * ) malloc ( numberRows_ * sizeof ( double ) ); 01901 for ( i = 0; i < numberRows_; i++ ) { 01902 int j; 01903 01904 fscanf ( fp, "%d %lg %lg\n", &j, &rowlower_[i], &rowupper_[i] ); 01905 assert ( i == j ); 01906 } 01907 collower_ = ( double * ) malloc ( numberColumns_ * sizeof ( double ) ); 01908 colupper_ = ( double * ) malloc ( numberColumns_ * sizeof ( double ) ); 01909 objective_= ( double * ) malloc ( numberColumns_ * sizeof ( double ) ); 01910 start = ( CoinBigIndex *) malloc ((numberColumns_ + 1) * 01911 sizeof (CoinBigIndex) ); 01912 row = ( COINRowIndex * ) malloc (numberElements_ * sizeof (COINRowIndex)); 01913 element = ( double * ) malloc (numberElements_ * sizeof (double) ); 01914 01915 start[0] = 0; 01916 numberElements_ = 0; 01917 for ( i = 0; i < numberColumns_; i++ ) { 01918 int j; 01919 int n; 01920 01921 fscanf ( fp, "%d %d %lg %lg %lg\n", &j, &n, &collower_[i], &colupper_[i], 01922 &objective_[i] ); 01923 assert ( i == j ); 01924 for ( j = 0; j < n; j++ ) { 01925 fscanf ( fp, " %d %lg\n", &row[numberElements_], 01926 &element[numberElements_] ); 01927 numberElements_++; 01928 } 01929 start[i + 1] = numberElements_; 01930 } 01931 } 01932 // construct packed matrix 01933 matrixByColumn_ = 01934 new CoinPackedMatrix(true, 01935 numberRows_,numberColumns_,numberElements_, 01936 element,row,start,NULL); 01937 free ( row ); 01938 free ( start ); 01939 free ( element ); 01940 01941 handler_->message(COIN_MPS_STATS,messages_)<<problemName_ 01942 <<numberRows_ 01943 <<numberColumns_ 01944 <<numberElements_ 01945 <<CoinMessageEol; 01946 return numberErrors; 01947 } |
|
Read a problem in MPS format from the given filename. Use "stdin" or "-" to read from stdin. Definition at line 1042 of file CoinMpsIO.cpp. References cardReader_, dealWithFileName(), and readMps().
01043 { 01044 // Deal with filename - +1 if new, 0 if same as before, -1 if error 01045 FILE *fp=NULL; 01046 gzFile gzfp=NULL; 01047 int returnCode = dealWithFileName(filename,extension,fp,gzfp); 01048 if (returnCode<0) { 01049 return -1; 01050 } else if (returnCode>0) { 01051 delete cardReader_; 01052 cardReader_ = new CoinMpsCardReader ( fp , gzfp, this); 01053 } 01054 return readMps(); 01055 } |
|
Read in a quadratic objective from the given filename. If filename is NULL (or the same as the currently open file) then reading continues from the current file. If not, the file is closed and the specified file is opened. Code should be added to general MPS reader to read this if QSECTION Data is assumed to be Q and objective is c + 1/2 xT Q x No assumption is made for symmetry, positive definite, etc. No check is made for duplicates or non-triangular if checkSymmetry==0. If 1 checks lower triangular (so off diagonal should be 2*Q) if 2 makes lower triangular and assumes full Q (but adds off diagonals) Arrays should be deleted by delete [] Returns number of errors:
Definition at line 3282 of file CoinMpsIO.cpp. References CoinMpsCardReader::card(), CoinMpsCardReader::cardNumber(), cardReader_, CoinMpsCardReader::columnName(), dealWithFileName(), fileName_, findHash(), handler_, CoinMessageHandler::message(), messages_, CoinMpsCardReader::mpsType(), CoinMpsCardReader::nextField(), problemName_, CoinMpsCardReader::readToNextSection(), CoinMpsCardReader::rowName(), startHash(), stopHash(), CoinMpsCardReader::value(), and CoinMpsCardReader::whichSection().
03285 { 03286 // Deal with filename - +1 if new, 0 if same as before, -1 if error 03287 FILE *fp=NULL; 03288 gzFile gzfp=NULL; 03289 int returnCode = dealWithFileName(filename,"",fp,gzfp); 03290 if (returnCode<0) { 03291 return -1; 03292 } else if (returnCode>0) { 03293 delete cardReader_; 03294 cardReader_ = new CoinMpsCardReader ( fp , gzfp, this); 03295 } 03296 03297 cardReader_->readToNextSection(); 03298 03299 // Skip NAME 03300 if ( cardReader_->whichSection ( ) == COIN_NAME_SECTION ) 03301 cardReader_->readToNextSection(); 03302 if ( cardReader_->whichSection ( ) == COIN_QUADRATIC_SECTION ) { 03303 // save name of section 03304 free(problemName_); 03305 problemName_=strdup(cardReader_->columnName()); 03306 } else if ( cardReader_->whichSection ( ) == COIN_EOF_SECTION ) { 03307 handler_->message(COIN_MPS_EOF,messages_)<<fileName_ 03308 <<CoinMessageEol; 03309 return -3; 03310 } else { 03311 handler_->message(COIN_MPS_BADFILE1,messages_)<<cardReader_->card() 03312 <<cardReader_->cardNumber() 03313 <<fileName_ 03314 <<CoinMessageEol; 03315 return -2; 03316 } 03317 03318 int numberErrors = 0; 03319 03320 // Guess at size of data 03321 int maximumNonZeros = 5 *numberColumns_; 03322 // Use malloc so can use realloc 03323 int * column = (int *) malloc(maximumNonZeros*sizeof(int)); 03324 int * column2Temp = (int *) malloc(maximumNonZeros*sizeof(int)); 03325 double * elementTemp = (double *) malloc(maximumNonZeros*sizeof(double)); 03326 03327 startHash(1); 03328 int numberElements=0; 03329 03330 const double tinyElement = 1.0e-14; 03331 03332 while ( cardReader_->nextField ( ) == COIN_QUADRATIC_SECTION ) { 03333 switch ( cardReader_->mpsType ( ) ) { 03334 case COIN_BLANK_COLUMN: 03335 if ( fabs ( cardReader_->value ( ) ) > tinyElement ) { 03336 if ( numberElements == maximumNonZeros ) { 03337 maximumNonZeros = ( 3 * maximumNonZeros ) / 2 + 1000; 03338 column = ( COINColumnIndex * ) 03339 realloc ( column, maximumNonZeros * sizeof ( COINColumnIndex ) ); 03340 column2Temp = ( COINColumnIndex * ) 03341 realloc ( column2Temp, maximumNonZeros * sizeof ( COINColumnIndex ) ); 03342 elementTemp = ( double * ) 03343 realloc ( elementTemp, maximumNonZeros * sizeof ( double ) ); 03344 } 03345 // get indices 03346 COINColumnIndex iColumn1 = findHash ( cardReader_->columnName ( ) , 1 ); 03347 COINColumnIndex iColumn2 = findHash ( cardReader_->rowName ( ) , 1 ); 03348 03349 if ( iColumn1 >= 0 ) { 03350 if (iColumn2 >=0) { 03351 double value = cardReader_->value ( ); 03352 column[numberElements]=iColumn1; 03353 column2Temp[numberElements]=iColumn2; 03354 elementTemp[numberElements++]=value; 03355 } else { 03356 numberErrors++; 03357 if ( numberErrors < 100 ) { 03358 handler_->message(COIN_MPS_NOMATCHROW,messages_) 03359 <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card() 03360 <<CoinMessageEol; 03361 } else if (numberErrors > 100000) { 03362 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 03363 return numberErrors; 03364 } 03365 } 03366 } else { 03367 numberErrors++; 03368 if ( numberErrors < 100 ) { 03369 handler_->message(COIN_MPS_NOMATCHCOL,messages_) 03370 <<cardReader_->columnName()<<cardReader_->cardNumber()<<cardReader_->card() 03371 <<CoinMessageEol; 03372 } else if (numberErrors > 100000) { 03373 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 03374 return numberErrors; 03375 } 03376 } 03377 } 03378 break; 03379 default: 03380 numberErrors++; 03381 if ( numberErrors < 100 ) { 03382 handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber() 03383 <<cardReader_->card() 03384 <<CoinMessageEol; 03385 } else if (numberErrors > 100000) { 03386 handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol; 03387 return numberErrors; 03388 } 03389 } 03390 } 03391 stopHash(1); 03392 // Do arrays as new [] and make column ordered 03393 columnStart = new int [numberColumns_+1]; 03394 // for counts 03395 int * count = new int[numberColumns_]; 03396 memset(count,0,numberColumns_*sizeof(int)); 03397 CoinBigIndex i; 03398 // See about lower triangular 03399 if (checkSymmetry&&numberErrors) 03400 checkSymmetry=2; // force corrections 03401 if (checkSymmetry) { 03402 if (checkSymmetry==1) { 03403 // just check lower triangular 03404 for ( i = 0; i < numberElements; i++ ) { 03405 int iColumn = column[i]; 03406 int iColumn2 = column2Temp[i]; 03407 if (iColumn2<iColumn) { 03408 numberErrors=-4; 03409 column[i]=iColumn2; 03410 column2Temp[i]=iColumn; 03411 } 03412 } 03413 } else { 03414 // make lower triangular 03415 for ( i = 0; i < numberElements; i++ ) { 03416 int iColumn = column[i]; 03417 int iColumn2 = column2Temp[i]; 03418 if (iColumn2<iColumn) { 03419 column[i]=iColumn2; 03420 column2Temp[i]=iColumn; 03421 } 03422 } 03423 } 03424 } 03425 for ( i = 0; i < numberElements; i++ ) { 03426 int iColumn = column[i]; 03427 count[iColumn]++; 03428 } 03429 // Do starts 03430 int number = 0; 03431 columnStart[0]=0; 03432 for (i=0;i<numberColumns_;i++) { 03433 number += count[i]; 03434 count[i]= columnStart[i]; 03435 columnStart[i+1]=number; 03436 } 03437 column2 = new int[numberElements]; 03438 elements = new double[numberElements]; 03439 03440 // Get column ordering 03441 for ( i = 0; i < numberElements; i++ ) { 03442 int iColumn = column[i]; 03443 int iColumn2 = column2Temp[i]; 03444 int put = count[iColumn]; 03445 elements[put]=elementTemp[i]; 03446 column2[put++]=iColumn2; 03447 count[iColumn]=put; 03448 } 03449 free(column); 03450 free(column2Temp); 03451 free(elementTemp); 03452 03453 // Now in column order - deal with duplicates 03454 for (i=0;i<numberColumns_;i++) 03455 count[i] = -1; 03456 03457 int start = 0; 03458 number=0; 03459 for (i=0;i<numberColumns_;i++) { 03460 int j; 03461 for (j=start;j<columnStart[i+1];j++) { 03462 int iColumn2 = column2[j]; 03463 if (count[iColumn2]<0) { 03464 count[iColumn2]=j; 03465 } else { 03466 // duplicate 03467 int iOther = count[iColumn2]; 03468 double value = elements[iOther]+elements[j]; 03469 elements[iOther]=value; 03470 elements[j]=0.0; 03471 } 03472 } 03473 for (j=start;j<columnStart[i+1];j++) { 03474 int iColumn2 = column2[j]; 03475 count[iColumn2]=-1; 03476 double value = elements[j]; 03477 if (value) { 03478 column2[number]=iColumn2; 03479 elements[number++]=value; 03480 } 03481 } 03482 start = columnStart[i+1]; 03483 columnStart[i+1]=number; 03484 } 03485 03486 delete [] count; 03487 return numberErrors; 03488 } |
|
Release all information which can be re-calculated. E.g., row sense, copies of rows, hash tables for names. Definition at line 3241 of file CoinMpsIO.cpp. References hash_, matrixByRow_, rhs_, rowrange_, and rowsense_. Referenced by freeAll(), releaseColumnNames(), releaseMatrixInformation(), and releaseRowNames().
03242 { 03243 free( rowsense_); 03244 free( rhs_); 03245 free( rowrange_); 03246 rowsense_=NULL; 03247 rhs_=NULL; 03248 rowrange_=NULL; 03249 free (hash_[0]); 03250 free (hash_[1]); 03251 hash_[0]=0; 03252 hash_[1]=0; 03253 delete matrixByRow_; 03254 matrixByRow_=NULL; 03255 } |
|
Returns the index for the specified row name Returns -1 if the name is not found. Returns numberRows for the objective row and > numberRows for dropped free rows. Definition at line 2931 of file CoinMpsIO.cpp. References findHash(), hash_, and startHash().
02932 { 02933 if (!hash_[0]) { 02934 if (numberRows_) { 02935 startHash(0); 02936 } else { 02937 return -1; 02938 } 02939 } 02940 return findHash ( name , 0 ); 02941 } |
|
Returns the row name for the specified index. Returns 0 if the index is out of range. Definition at line 2914 of file CoinMpsIO.cpp. Referenced by readMps().
02915 { 02916 if (index>=0&&index<numberRows_) { 02917 return names_[0][index]; 02918 } else { 02919 return NULL; 02920 } 02921 } |
|
Write the problem in MPS format to a file with the given filename.
Definition at line 2104 of file CoinMpsIO.cpp. References getColLower(), getColUpper(), getMatrixByCol(), getObjCoefficients(), getRowLower(), getRowSense(), getRowUpper(), infinity_, isInteger(), names_, numberColumns_, numberRows_, and problemName_.
02106 { 02107 std::string line = filename; 02108 FILE * fp = NULL; 02109 gzFile gzfp = NULL; 02110 switch (compression) { 02111 case 1: 02112 #ifdef COIN_USE_ZLIB 02113 { 02114 if (strcmp(line.c_str() +(line.size()-3), ".gz") != 0) { 02115 line += ".gz"; 02116 } 02117 gzfp = gzopen(line.c_str(), "wb"); 02118 if (gzfp) { 02119 break; 02120 } 02121 } 02122 #endif 02123 fp = fopen(filename,"w"); 02124 if (!fp) 02125 return -1; 02126 break; 02127 02128 case 2: /* bzip2: to be implemented */ 02129 case 0: 02130 fp = fopen(filename,"w"); 02131 if (!fp) 02132 return -1; 02133 break; 02134 } 02135 02136 const char * const * const rowNames = names_[0]; 02137 const char * const * const columnNames = names_[1]; 02138 int i; 02139 unsigned int length = 8; 02140 bool freeFormat = (formatType!=0); 02141 for (i = 0 ; i < numberRows_; ++i) { 02142 if (strlen(rowNames[i]) > length) { 02143 length = strlen(rowNames[i]); 02144 break; 02145 } 02146 } 02147 if (length <= 8) { 02148 for (i = 0 ; i < numberColumns_; ++i) { 02149 if (strlen(columnNames[i]) > length) { 02150 length = strlen(columnNames[i]); 02151 break; 02152 } 02153 } 02154 } 02155 if (length > 8 && !freeFormat) { 02156 freeFormat = true; 02157 formatType = 4; 02158 } 02159 02160 // NAME card 02161 02162 line = "NAME "; 02163 if (strcmp(problemName_,"")==0) { 02164 line.append("BLANK "); 02165 } else { 02166 if (strlen(problemName_) >= 8) { 02167 line.append(problemName_, 8); 02168 } else { 02169 line.append(problemName_); 02170 line.append(8-strlen(problemName_), ' '); 02171 } 02172 } 02173 if (freeFormat) 02174 line.append(" FREE"); 02175 // finish off name and do ROWS card and objective 02176 line.append("\nROWS\n N OBJROW\n"); 02177 writeString(fp, gzfp, line.c_str()); 02178 02179 // Rows section 02180 // Sense array 02181 // But massage if looks odd 02182 char * sense = new char [numberRows_]; 02183 memcpy( sense , getRowSense(), numberRows_); 02184 const double * rowLower = getRowLower(); 02185 const double * rowUpper = getRowUpper(); 02186 02187 for (i=0;i<numberRows_;i++) { 02188 line = " "; 02189 if (sense[i]!='R') { 02190 line.append(1,sense[i]); 02191 } else { 02192 if (rowLower[i]>-1.0e30) { 02193 if(rowUpper[i]<1.0e30) { 02194 line.append("L"); 02195 } else { 02196 sense[i]='G'; 02197 line.append(1,sense[i]); 02198 } 02199 } else { 02200 sense[i]='L'; 02201 line.append(1,sense[i]); 02202 } 02203 } 02204 line.append(" "); 02205 line.append(rowNames[i]); 02206 line.append("\n"); 02207 writeString(fp, gzfp, line.c_str()); 02208 } 02209 02210 // COLUMNS card 02211 writeString(fp, gzfp, "COLUMNS\n"); 02212 02213 bool ifBounds=false; 02214 double largeValue = infinity_; 02215 02216 const double * columnLower = getColLower(); 02217 const double * columnUpper = getColUpper(); 02218 const double * objective = getObjCoefficients(); 02219 const CoinPackedMatrix * matrix = getMatrixByCol(); 02220 const double * elements = matrix->getElements(); 02221 const int * rows = matrix->getIndices(); 02222 const CoinBigIndex * starts = matrix->getVectorStarts(); 02223 const int * lengths = matrix->getVectorLengths(); 02224 02225 char outputValue[2][20]; 02226 char outputRow[2][100]; 02227 02228 // Through columns (only put out if elements or objective value) 02229 for (i=0;i<numberColumns_;i++) { 02230 if (objective[i]||lengths[i]) { 02231 // see if bound will be needed 02232 if (columnLower[i]||columnUpper[i]<largeValue||isInteger(i)) 02233 ifBounds=true; 02234 int numberFields=0; 02235 if (objective[i]) { 02236 convertDouble(formatType,objective[i],outputValue[0], 02237 "OBJROW",outputRow[0]); 02238 numberFields=1; 02239 } 02240 if (numberFields==numberAcross) { 02241 // put out card 02242 outputCard(formatType, numberFields, 02243 fp, gzfp, " ", 02244 columnNames[i], 02245 outputValue, 02246 outputRow); 02247 numberFields=0; 02248 } 02249 int j; 02250 for (j=0;j<lengths[i];j++) { 02251 convertDouble(formatType,elements[starts[i]+j], 02252 outputValue[numberFields], 02253 rowNames[rows[starts[i]+j]], 02254 outputRow[numberFields]); 02255 numberFields++; 02256 if (numberFields==numberAcross) { 02257 // put out card 02258 outputCard(formatType, numberFields, 02259 fp, gzfp, " ", 02260 columnNames[i], 02261 outputValue, 02262 outputRow); 02263 numberFields=0; 02264 } 02265 } 02266 if (numberFields) { 02267 // put out card 02268 outputCard(formatType, numberFields, 02269 fp, gzfp, " ", 02270 columnNames[i], 02271 outputValue, 02272 outputRow); 02273 } 02274 } 02275 } 02276 02277 bool ifRange=false; 02278 // RHS 02279 writeString(fp, gzfp, "RHS\n"); 02280 02281 int numberFields = 0; 02282 for (i=0;i<numberRows_;i++) { 02283 double value; 02284 switch (sense[i]) { 02285 case 'E': 02286 value=rowLower[i]; 02287 break; 02288 case 'R': 02289 value=rowUpper[i]; 02290 ifRange=true; 02291 break; 02292 case 'L': 02293 value=rowUpper[i]; 02294 break; 02295 case 'G': 02296 value=rowLower[i]; 02297 break; 02298 default: 02299 value=0.0; 02300 break; 02301 } 02302 if (value != 0.0) { 02303 convertDouble(formatType,value, 02304 outputValue[numberFields], 02305 rowNames[i], 02306 outputRow[numberFields]); 02307 numberFields++; 02308 if (numberFields==numberAcross) { 02309 // put out card 02310 outputCard(formatType, numberFields, 02311 fp, gzfp, " ", 02312 "RHS", 02313 outputValue, 02314 outputRow); 02315 numberFields=0; 02316 } 02317 } 02318 } 02319 if (numberFields) { 02320 // put out card 02321 outputCard(formatType, numberFields, 02322 fp, gzfp, " ", 02323 "RHS", 02324 outputValue, 02325 outputRow); 02326 } 02327 02328 if (ifRange) { 02329 // RANGES 02330 writeString(fp, gzfp, "RANGES\n"); 02331 02332 numberFields = 0; 02333 for (i=0;i<numberRows_;i++) { 02334 if (sense[i]=='R') { 02335 double value =rowUpper[i]-rowLower[i]; 02336 if (value<1.0e30) { 02337 convertDouble(formatType,value, 02338 outputValue[numberFields], 02339 rowNames[i], 02340 outputRow[numberFields]); 02341 numberFields++; 02342 if (numberFields==numberAcross) { 02343 // put out card 02344 outputCard(formatType, numberFields, 02345 fp, gzfp, " ", 02346 "RANGE", 02347 outputValue, 02348 outputRow); 02349 numberFields=0; 02350 } 02351 } 02352 } 02353 } 02354 if (numberFields) { 02355 // put out card 02356 outputCard(formatType, numberFields, 02357 fp, gzfp, " ", 02358 "RANGE", 02359 outputValue, 02360 outputRow); 02361 } 02362 } 02363 delete [] sense; 02364 if (ifBounds) { 02365 // BOUNDS 02366 writeString(fp, gzfp, "BOUNDS\n"); 02367 02368 for (i=0;i<numberColumns_;i++) { 02369 if (objective[i]||lengths[i]) { 02370 // see if bound will be needed 02371 if (columnLower[i]||columnUpper[i]<largeValue||isInteger(i)) { 02372 double lowerValue = columnLower[i]; 02373 double upperValue = columnUpper[i]; 02374 if (isInteger(i)) { 02375 // Old argument - what are correct ranges for integer variables 02376 lowerValue = max(lowerValue,(double) -INT_MAX); 02377 upperValue = min(upperValue,(double) INT_MAX); 02378 } 02379 int numberFields=1; 02380 std::string header[2]; 02381 double value[2]; 02382 if (lowerValue<=-largeValue) { 02383 // FR or MI 02384 if (upperValue>=largeValue) { 02385 header[0]=" FR "; 02386 value[0] = largeValue; 02387 } else { 02388 header[0]=" MI "; 02389 value[0] = largeValue; 02390 header[1]=" UP "; 02391 value[1] = upperValue; 02392 numberFields=2; 02393 } 02394 } else if (fabs(upperValue-lowerValue)<1.0e-8) { 02395 header[0]=" FX "; 02396 value[0] = lowerValue; 02397 } else { 02398 // do LO if needed 02399 if (lowerValue) { 02400 // LO 02401 header[0]=" LO "; 02402 value[0] = lowerValue; 02403 if (isInteger(i)) { 02404 // Integer variable so UI 02405 header[1]=" UI "; 02406 value[1] = upperValue; 02407 numberFields=2; 02408 } else if (upperValue<largeValue) { 02409 // UP 02410 header[1]=" UP "; 02411 value[1] = upperValue; 02412 numberFields=2; 02413 } 02414 } else { 02415 if (isInteger(i)) { 02416 // Integer variable so BV or UI 02417 if (fabs(upperValue-1.0)<1.0e-8) { 02418 // BV 02419 header[0]=" BV "; 02420 value[0] = largeValue; 02421 } else { 02422 // UI 02423 header[0]=" UI "; 02424 value[0] = upperValue; 02425 } 02426 } else { 02427 // UP 02428 header[0]=" UP "; 02429 value[0] = upperValue; 02430 } 02431 } 02432 } 02433 // put out fields 02434 int j; 02435 for (j=0;j<numberFields;j++) { 02436 convertDouble(formatType,value[j], 02437 outputValue[0], 02438 columnNames[i], 02439 outputRow[0]); 02440 // put out card 02441 outputCard(formatType, 1, 02442 fp, gzfp, header[j], 02443 "BOUND", 02444 outputValue, 02445 outputRow); 02446 } 02447 } 02448 } 02449 } 02450 } 02451 02452 // and finish 02453 02454 writeString(fp, gzfp, "ENDATA\n"); 02455 02456 if (fp) { 02457 fclose(fp); 02458 } 02459 #ifdef COIN_USE_ZLIB 02460 if (gzfp) { 02461 gzclose(gzfp); 02462 } 02463 #endif 02464 02465 return 0; 02466 } |
|
A function that tests the methods in the CoinMpsIO class. The only reason for it not to be a member method is that this way it doesn't have to be compiled into the library. And that's a gain, because the library should be compiled with optimization on, but this method should be compiled with debugging. Also, if this method is compiled with optimization, the compilation takes 10-15 minutes and the machine pages (has 256M core memory!)... Definition at line 21 of file CoinMpsIOTest.cpp.
00022 { 00023 00024 // Test default constructor 00025 { 00026 CoinMpsIO m; 00027 assert( m.rowsense_==NULL ); 00028 assert( m.rhs_==NULL ); 00029 assert( m.rowrange_==NULL ); 00030 assert( m.matrixByRow_==NULL ); 00031 assert( m.matrixByColumn_==NULL ); 00032 assert( m.integerType_==NULL); 00033 assert( !strcmp( m.getFileName() , "stdin")); 00034 assert( !strcmp( m.getProblemName() , "")); 00035 assert( !strcmp( m.objectiveName_ , "")); 00036 assert( !strcmp( m.rhsName_ , "")); 00037 assert( !strcmp( m.rangeName_ , "")); 00038 assert( !strcmp( m.boundName_ , "")); 00039 } 00040 00041 00042 { 00043 CoinRelFltEq eq; 00044 CoinMpsIO m; 00045 std::string fn = mpsDir+"exmip1"; 00046 int numErr = m.readMps(fn.c_str(),"mps"); 00047 assert( numErr== 0 ); 00048 00049 assert( !strcmp( m.problemName_ , "EXAMPLE")); 00050 assert( !strcmp( m.objectiveName_ , "OBJ")); 00051 assert( !strcmp( m.rhsName_ , "RHS1")); 00052 assert( !strcmp( m.rangeName_ , "RNG1")); 00053 assert( !strcmp( m.boundName_ , "BND1")); 00054 00055 // Test language and re-use 00056 m.newLanguage(CoinMessages::it); 00057 m.messageHandler()->setPrefix(false); 00058 00059 // This call should return an error indicating that the 00060 // end-of-file was reached. 00061 // This is because the file remains open to possibly read 00062 // a quad. section. 00063 numErr = m.readMps(fn.c_str(),"mps"); 00064 assert( numErr < 0 ); 00065 00066 // Test copy constructor and assignment operator 00067 { 00068 CoinMpsIO lhs; 00069 { 00070 CoinMpsIO im(m); 00071 00072 CoinMpsIO imC1(im); 00073 assert( imC1.getNumCols() == im.getNumCols() ); 00074 assert( imC1.getNumRows() == im.getNumRows() ); 00075 00076 CoinMpsIO imC2(im); 00077 assert( imC2.getNumCols() == im.getNumCols() ); 00078 assert( imC2.getNumRows() == im.getNumRows() ); 00079 00080 lhs=imC2; 00081 } 00082 // Test that lhs has correct values even though rhs has gone out of scope 00083 00084 assert( lhs.getNumCols() == m.getNumCols() ); 00085 assert( lhs.getNumRows() == m.getNumRows() ); 00086 } 00087 00088 00089 { 00090 CoinMpsIO dumSi(m); 00091 int nc = dumSi.getNumCols(); 00092 int nr = dumSi.getNumRows(); 00093 const double * cl = dumSi.getColLower(); 00094 const double * cu = dumSi.getColUpper(); 00095 const double * rl = dumSi.getRowLower(); 00096 const double * ru = dumSi.getRowUpper(); 00097 assert( nc == 8 ); 00098 assert( nr == 5 ); 00099 assert( eq(cl[0],2.5) ); 00100 assert( eq(cl[1],0.0) ); 00101 assert( eq(cu[1],4.1) ); 00102 assert( eq(cu[2],1.0) ); 00103 assert( eq(rl[0],2.5) ); 00104 assert( eq(rl[4],3.0) ); 00105 assert( eq(ru[1],2.1) ); 00106 assert( eq(ru[4],15.0) ); 00107 00108 assert( !eq(cl[3],1.2345) ); 00109 00110 assert( !eq(cu[4],10.2345) ); 00111 00112 assert( eq( dumSi.getObjCoefficients()[0], 1.0) ); 00113 assert( eq( dumSi.getObjCoefficients()[1], 0.0) ); 00114 assert( eq( dumSi.getObjCoefficients()[2], 0.0) ); 00115 assert( eq( dumSi.getObjCoefficients()[3], 0.0) ); 00116 assert( eq( dumSi.getObjCoefficients()[4], 2.0) ); 00117 assert( eq( dumSi.getObjCoefficients()[5], 0.0) ); 00118 assert( eq( dumSi.getObjCoefficients()[6], 0.0) ); 00119 assert( eq( dumSi.getObjCoefficients()[7], -1.0) ); 00120 00121 dumSi.writeMps("CoinMpsIoTest.mps");//,0,0,1); 00122 } 00123 00124 // Read just written file 00125 { 00126 CoinMpsIO dumSi; 00127 dumSi.readMps("CoinMpsIoTest"); 00128 int nc = dumSi.getNumCols(); 00129 int nr = dumSi.getNumRows(); 00130 const double * cl = dumSi.getColLower(); 00131 const double * cu = dumSi.getColUpper(); 00132 const double * rl = dumSi.getRowLower(); 00133 const double * ru = dumSi.getRowUpper(); 00134 assert( nc == 8 ); 00135 assert( nr == 5 ); 00136 assert( eq(cl[0],2.5) ); 00137 assert( eq(cl[1],0.0) ); 00138 assert( eq(cu[1],4.1) ); 00139 assert( eq(cu[2],1.0) ); 00140 assert( eq(rl[0],2.5) ); 00141 assert( eq(rl[4],3.0) ); 00142 assert( eq(ru[1],2.1) ); 00143 assert( eq(ru[4],15.0) ); 00144 00145 assert( !eq(cl[3],1.2345) ); 00146 00147 assert( !eq(cu[4],10.2345) ); 00148 00149 assert( eq( dumSi.getObjCoefficients()[0], 1.0) ); 00150 assert( eq( dumSi.getObjCoefficients()[1], 0.0) ); 00151 assert( eq( dumSi.getObjCoefficients()[2], 0.0) ); 00152 assert( eq( dumSi.getObjCoefficients()[3], 0.0) ); 00153 assert( eq( dumSi.getObjCoefficients()[4], 2.0) ); 00154 assert( eq( dumSi.getObjCoefficients()[5], 0.0) ); 00155 assert( eq( dumSi.getObjCoefficients()[6], 0.0) ); 00156 assert( eq( dumSi.getObjCoefficients()[7], -1.0) ); 00157 } 00158 00159 // Test matrixByRow method 00160 { 00161 const CoinMpsIO si(m); 00162 const CoinPackedMatrix * smP = si.getMatrixByRow(); 00163 // LL: const CoinDumPackedMatrix * osmP = dynamic_cast<const CoinDumPackedMatrix*>(smP); 00164 // LL: assert( osmP!=NULL ); 00165 00166 CoinRelFltEq eq; 00167 const double * ev = smP->getElements(); 00168 assert( eq(ev[0], 3.0) ); 00169 assert( eq(ev[1], 1.0) ); 00170 assert( eq(ev[2], -2.0) ); 00171 assert( eq(ev[3], -1.0) ); 00172 assert( eq(ev[4], -1.0) ); 00173 assert( eq(ev[5], 2.0) ); 00174 assert( eq(ev[6], 1.1) ); 00175 assert( eq(ev[7], 1.0) ); 00176 assert( eq(ev[8], 1.0) ); 00177 assert( eq(ev[9], 2.8) ); 00178 assert( eq(ev[10], -1.2) ); 00179 assert( eq(ev[11], 5.6) ); 00180 assert( eq(ev[12], 1.0) ); 00181 assert( eq(ev[13], 1.9) ); 00182 00183 const CoinBigIndex * mi = smP->getVectorStarts(); 00184 assert( mi[0]==0 ); 00185 assert( mi[1]==5 ); 00186 assert( mi[2]==7 ); 00187 assert( mi[3]==9 ); 00188 assert( mi[4]==11 ); 00189 assert( mi[5]==14 ); 00190 00191 const int * ei = smP->getIndices(); 00192 assert( ei[0] == 0 ); 00193 assert( ei[1] == 1 ); 00194 assert( ei[2] == 3 ); 00195 assert( ei[3] == 4 ); 00196 assert( ei[4] == 7 ); 00197 assert( ei[5] == 1 ); 00198 assert( ei[6] == 2 ); 00199 assert( ei[7] == 2 ); 00200 assert( ei[8] == 5 ); 00201 assert( ei[9] == 3 ); 00202 assert( ei[10] == 6 ); 00203 assert( ei[11] == 0 ); 00204 assert( ei[12] == 4 ); 00205 assert( ei[13] == 7 ); 00206 00207 assert( smP->getMajorDim() == 5 ); 00208 assert( smP->getNumElements() == 14 ); 00209 00210 } 00211 // Test matrixByCol method 00212 { 00213 00214 const CoinMpsIO si(m); 00215 const CoinPackedMatrix * smP = si.getMatrixByCol(); 00216 // LL: const CoinDumPackedMatrix * osmP = dynamic_cast<const CoinDumPackedMatrix*>(smP); 00217 // LL: assert( osmP!=NULL ); 00218 00219 CoinRelFltEq eq; 00220 const double * ev = smP->getElements(); 00221 assert( eq(ev[0], 3.0) ); 00222 assert( eq(ev[1], 5.6) ); 00223 assert( eq(ev[2], 1.0) ); 00224 assert( eq(ev[3], 2.0) ); 00225 assert( eq(ev[4], 1.1) ); 00226 assert( eq(ev[5], 1.0) ); 00227 assert( eq(ev[6], -2.0) ); 00228 assert( eq(ev[7], 2.8) ); 00229 assert( eq(ev[8], -1.0) ); 00230 assert( eq(ev[9], 1.0) ); 00231 assert( eq(ev[10], 1.0) ); 00232 assert( eq(ev[11], -1.2) ); 00233 assert( eq(ev[12], -1.0) ); 00234 assert( eq(ev[13], 1.9) ); 00235 00236 const CoinBigIndex * mi = smP->getVectorStarts(); 00237 assert( mi[0]==0 ); 00238 assert( mi[1]==2 ); 00239 assert( mi[2]==4 ); 00240 assert( mi[3]==6 ); 00241 assert( mi[4]==8 ); 00242 assert( mi[5]==10 ); 00243 assert( mi[6]==11 ); 00244 assert( mi[7]==12 ); 00245 assert( mi[8]==14 ); 00246 00247 const int * ei = smP->getIndices(); 00248 assert( ei[0] == 0 ); 00249 assert( ei[1] == 4 ); 00250 assert( ei[2] == 0 ); 00251 assert( ei[3] == 1 ); 00252 assert( ei[4] == 1 ); 00253 assert( ei[5] == 2 ); 00254 assert( ei[6] == 0 ); 00255 assert( ei[7] == 3 ); 00256 assert( ei[8] == 0 ); 00257 assert( ei[9] == 4 ); 00258 assert( ei[10] == 2 ); 00259 assert( ei[11] == 3 ); 00260 assert( ei[12] == 0 ); 00261 assert( ei[13] == 4 ); 00262 00263 assert( smP->getMajorDim() == 8 ); 00264 assert( smP->getNumElements() == 14 ); 00265 00266 assert( smP->getSizeVectorStarts()==9 ); 00267 assert( smP->getMinorDim() == 5 ); 00268 00269 } 00270 //-------------- 00271 // Test rowsense, rhs, rowrange, matrixByRow 00272 { 00273 CoinMpsIO lhs; 00274 { 00275 assert( m.rowrange_==NULL ); 00276 assert( m.rowsense_==NULL ); 00277 assert( m.rhs_==NULL ); 00278 assert( m.matrixByRow_==NULL ); 00279 00280 CoinMpsIO siC1(m); 00281 assert( siC1.rowrange_==NULL ); 00282 assert( siC1.rowsense_==NULL ); 00283 assert( siC1.rhs_==NULL ); 00284 assert( siC1.matrixByRow_==NULL ); 00285 00286 const char * siC1rs = siC1.getRowSense(); 00287 assert( siC1rs[0]=='G' ); 00288 assert( siC1rs[1]=='L' ); 00289 assert( siC1rs[2]=='E' ); 00290 assert( siC1rs[3]=='R' ); 00291 assert( siC1rs[4]=='R' ); 00292 00293 const double * siC1rhs = siC1.getRightHandSide(); 00294 assert( eq(siC1rhs[0],2.5) ); 00295 assert( eq(siC1rhs[1],2.1) ); 00296 assert( eq(siC1rhs[2],4.0) ); 00297 assert( eq(siC1rhs[3],5.0) ); 00298 assert( eq(siC1rhs[4],15.) ); 00299 00300 const double * siC1rr = siC1.getRowRange(); 00301 assert( eq(siC1rr[0],0.0) ); 00302 assert( eq(siC1rr[1],0.0) ); 00303 assert( eq(siC1rr[2],0.0) ); 00304 assert( eq(siC1rr[3],5.0-1.8) ); 00305 assert( eq(siC1rr[4],15.0-3.0) ); 00306 00307 const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow(); 00308 assert( siC1mbr != NULL ); 00309 00310 const double * ev = siC1mbr->getElements(); 00311 assert( eq(ev[0], 3.0) ); 00312 assert( eq(ev[1], 1.0) ); 00313 assert( eq(ev[2], -2.0) ); 00314 assert( eq(ev[3], -1.0) ); 00315 assert( eq(ev[4], -1.0) ); 00316 assert( eq(ev[5], 2.0) ); 00317 assert( eq(ev[6], 1.1) ); 00318 assert( eq(ev[7], 1.0) ); 00319 assert( eq(ev[8], 1.0) ); 00320 assert( eq(ev[9], 2.8) ); 00321 assert( eq(ev[10], -1.2) ); 00322 assert( eq(ev[11], 5.6) ); 00323 assert( eq(ev[12], 1.0) ); 00324 assert( eq(ev[13], 1.9) ); 00325 00326 const CoinBigIndex * mi = siC1mbr->getVectorStarts(); 00327 assert( mi[0]==0 ); 00328 assert( mi[1]==5 ); 00329 assert( mi[2]==7 ); 00330 assert( mi[3]==9 ); 00331 assert( mi[4]==11 ); 00332 assert( mi[5]==14 ); 00333 00334 const int * ei = siC1mbr->getIndices(); 00335 assert( ei[0] == 0 ); 00336 assert( ei[1] == 1 ); 00337 assert( ei[2] == 3 ); 00338 assert( ei[3] == 4 ); 00339 assert( ei[4] == 7 ); 00340 assert( ei[5] == 1 ); 00341 assert( ei[6] == 2 ); 00342 assert( ei[7] == 2 ); 00343 assert( ei[8] == 5 ); 00344 assert( ei[9] == 3 ); 00345 assert( ei[10] == 6 ); 00346 assert( ei[11] == 0 ); 00347 assert( ei[12] == 4 ); 00348 assert( ei[13] == 7 ); 00349 00350 assert( siC1mbr->getMajorDim() == 5 ); 00351 assert( siC1mbr->getNumElements() == 14 ); 00352 00353 00354 assert( siC1rs == siC1.getRowSense() ); 00355 assert( siC1rhs == siC1.getRightHandSide() ); 00356 assert( siC1rr == siC1.getRowRange() ); 00357 } 00358 } 00359 } 00360 00361 } |
|
Flag to say if the message handler is the default handler. If true, the handler will be destroyed when the CoinMpsIO object is destroyed; if false, it will not be destroyed. Definition at line 746 of file CoinMpsIO.hpp. Referenced by CoinMpsIO(), gutsOfCopy(), gutsOfDestructor(), operator=(), and passInMessageHandler(). |
|
Pointer to dense vector specifying if a variable is continuous (0) or integer (1). Definition at line 711 of file CoinMpsIO.hpp. Referenced by copyInIntegerInformation(), freeAll(), gutsOfCopy(), integerColumns(), isContinuous(), isInteger(), readMps(), releaseIntegerInformation(), and setMpsDataWithoutRowAndColNames(). |
|
Row and column names Linked to hash table sections (0 - row names, 1 column names) Definition at line 716 of file CoinMpsIO.hpp. Referenced by findHash(), gutsOfCopy(), startHash(), and writeMps(). |
|
Pointer to dense vector of slack variable upper bounds for range constraints (undefined for non-range rows) Definition at line 681 of file CoinMpsIO.hpp. Referenced by getRowRange(), and releaseRedundantInformation(). |