Skip to content

Commit

Permalink
Gurobi reads MPS keywords in mixed case, so convert to upper case in …
Browse files Browse the repository at this point in the history
…HiGHS for comparisons
  • Loading branch information
jajhall committed Feb 7, 2025
1 parent cd68efd commit e515dca
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 25 deletions.
58 changes: 33 additions & 25 deletions src/io/HMpsFF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,57 +399,63 @@ HMpsFF::Parsekey HMpsFF::checkFirstWord(std::string& strline, size_t& start,

word = strline.substr(start, end - start);

// Create an upper-case version of WORD, so that keywords are
// read as if they were in lower or mixed case
std::string upper_word = word;
toupper(upper_word);

// store rest of strline for keywords that have arguments
if (word == "QCMATRIX" || word == "QSECTION" || word == "CSECTION")
if (upper_word == "QCMATRIX" || upper_word == "QSECTION" ||
upper_word == "CSECTION")
section_args = strline.substr(end, strline.length());

if (word == "NAME")
if (upper_word == "NAME")
return HMpsFF::Parsekey::kName;
else if (word == "OBJSENSE")
else if (upper_word == "OBJSENSE")
return HMpsFF::Parsekey::kObjsense;
else if (word == "MAX")
else if (upper_word == "MAX")
return HMpsFF::Parsekey::kMax;
else if (word == "MIN")
else if (upper_word == "MIN")
return HMpsFF::Parsekey::kMin;
else if (word == "ROWS")
else if (upper_word == "ROWS")
return HMpsFF::Parsekey::kRows;
else if (word == "COLUMNS")
else if (upper_word == "COLUMNS")
return HMpsFF::Parsekey::kCols;
else if (word == "RHS")
else if (upper_word == "RHS")
return HMpsFF::Parsekey::kRhs;
else if (word == "BOUNDS")
else if (upper_word == "BOUNDS")
return HMpsFF::Parsekey::kBounds;
else if (word == "RANGES")
else if (upper_word == "RANGES")
return HMpsFF::Parsekey::kRanges;
else if (word == "QSECTION")
else if (upper_word == "QSECTION")
return HMpsFF::Parsekey::kQsection;
else if (word == "QMATRIX")
else if (upper_word == "QMATRIX")
return HMpsFF::Parsekey::kQmatrix;
else if (word == "QUADOBJ")
else if (upper_word == "QUADOBJ")
return HMpsFF::Parsekey::kQuadobj;
else if (word == "QCMATRIX")
else if (upper_word == "QCMATRIX")
return HMpsFF::Parsekey::kQcmatrix;
else if (word == "CSECTION")
else if (upper_word == "CSECTION")
return HMpsFF::Parsekey::kCsection;
else if (word == "DELAYEDROWS")
else if (upper_word == "DELAYEDROWS")
return HMpsFF::Parsekey::kDelayedrows;
else if (word == "MODELCUTS")
else if (upper_word == "MODELCUTS")
return HMpsFF::Parsekey::kModelcuts;
else if (word == "INDICATORS")
else if (upper_word == "INDICATORS")
return HMpsFF::Parsekey::kIndicators;
else if (word == "SETS")
else if (upper_word == "SETS")
return HMpsFF::Parsekey::kSets;
else if (word == "SOS")
else if (upper_word == "SOS")
return HMpsFF::Parsekey::kSos;
else if (word == "GENCONS")
else if (upper_word == "GENCONS")
return HMpsFF::Parsekey::kGencons;
else if (word == "PWLOBJ")
else if (upper_word == "PWLOBJ")
return HMpsFF::Parsekey::kPwlobj;
else if (word == "PWLNAM")
else if (upper_word == "PWLNAM")
return HMpsFF::Parsekey::kPwlnam;
else if (word == "PWLCON")
else if (upper_word == "PWLCON")
return HMpsFF::Parsekey::kPwlcon;
else if (word == "ENDATA")
else if (upper_word == "ENDATA")
return HMpsFF::Parsekey::kEnd;
else
return HMpsFF::Parsekey::kNone;
Expand Down Expand Up @@ -496,6 +502,8 @@ HMpsFF::Parsekey HMpsFF::parseDefault(const HighsLogOptions& log_options,
// Look for Gurobi-style definition of MAX/MIN on OBJSENSE line
if (e < strline.length()) {
std::string sense = first_word(strline, e);
// Convert to upper case
toupper(sense);

Check warning on line 506 in src/io/HMpsFF.cpp

View check run for this annotation

Codecov / codecov/patch

src/io/HMpsFF.cpp#L506

Added line #L506 was not covered by tests
if (sense.compare("MAX") == 0) {
// Found MAX sense on OBJSENSE line
obj_sense = ObjSense::kMaximize;
Expand Down
5 changes: 5 additions & 0 deletions src/util/stringutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ void tolower(std::string& str) {
[](unsigned char c) { return std::tolower(c); });
}

void toupper(std::string& str) {
std::transform(str.begin(), str.end(), str.begin(),
[](unsigned char c) { return std::toupper(c); });
}

std::string& ltrim(std::string& str, const std::string& chars) {
str.erase(0, str.find_first_not_of(chars));
return str;
Expand Down
1 change: 1 addition & 0 deletions src/util/stringutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ void strTrim(char* str);
// std::string& str_tolower(std::string s);

void tolower(std::string& str);
void toupper(std::string& str);

const std::string default_non_chars = "\t\n\v\f\r ";
std::string& ltrim(std::string& str,
Expand Down

0 comments on commit e515dca

Please sign in to comment.