Skip to content

Commit

Permalink
Merge pull request #2199 from ERGO-Code/mps-read-modes
Browse files Browse the repository at this point in the history
MPS read mods
  • Loading branch information
jajhall authored Mar 1, 2025
2 parents 2417238 + 9acbd2a commit ef5be32
Show file tree
Hide file tree
Showing 12 changed files with 430 additions and 131 deletions.
29 changes: 22 additions & 7 deletions check/TestFilereader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,20 +146,17 @@ TEST_CASE("filereader-edge-cases", "[highs_filereader]") {
void freeFixedModelTest(const std::string model_name) {
std::string filename;
filename = std::string(HIGHS_DIR) + "/check/instances/" + model_name + ".mps";
HighsStatus status;

Highs highs;
highs.setOptionValue("output_flag", dev_run);
status = highs.readModel(filename);
REQUIRE(status == HighsStatus::kOk);
REQUIRE(highs.readModel(filename) == HighsStatus::kOk);

HighsModel model_free = highs.getModel();

status = highs.setOptionValue("mps_parser_type_free", false);
REQUIRE(status == HighsStatus::kOk);
REQUIRE(highs.setOptionValue("mps_parser_type_free", false) ==
HighsStatus::kOk);

status = highs.readModel(filename);
REQUIRE(status == HighsStatus::kOk);
REQUIRE(highs.readModel(filename) == HighsStatus::kWarning);

HighsModel model_fixed = highs.getModel();

Expand Down Expand Up @@ -439,3 +436,21 @@ TEST_CASE("write-MI-bound-model", "[highs_filereader]") {
REQUIRE(required_objective_value == h.getInfo().objective_function_value);
std::remove(write_model_file.c_str());
}

TEST_CASE("mps-warnings", "[highs_filereader]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/warnings.mps";
Highs h;
h.setOptionValue("output_flag", dev_run);
HighsStatus return_status = h.readModel(model_file);
REQUIRE(return_status == HighsStatus::kWarning);
}

TEST_CASE("mps-silly-names", "[highs_filereader]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/silly-names.mps";
Highs h;
h.setOptionValue("output_flag", dev_run);
HighsStatus return_status = h.readModel(model_file);
REQUIRE(return_status == HighsStatus::kOk);
}
1 change: 1 addition & 0 deletions check/TestMipSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,7 @@ TEST_CASE("issue-2122", "[highs_test_mip_solver]") {
TEST_CASE("issue-2171", "[highs_test_mip_solver]") {
std::string filename = std::string(HIGHS_DIR) + "/check/instances/2171.mps";
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.setOptionValue("mip_rel_gap", 0);
highs.setOptionValue("mip_abs_gap", 0);
highs.readModel(filename);
Expand Down
14 changes: 14 additions & 0 deletions check/instances/silly-names.mps
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
NAME SILLY-NAMES
OBJSENSE MIN
ROWS
G R0
N COST
COLUMNS
C0 R0 -1.0 COST -1.0
OBJSENSE R0 -1.0 COST -1.0
RANGES R0 -1.0 COST -1.0
RHS R0 -1.0 COST -1.0
C1 R0 -1.0 COST -1.0
RHS
DEMANDS R0 -1.0
ENDATA
68 changes: 68 additions & 0 deletions check/instances/warnings.mps
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
NAME WARNINGS
ROWS
G R0
G R1
G R2
G R3
G R4
G R5
N COST
COLUMNS
C0 R0 -1.0 COST -1.0
C0 R11 1.0 R12 1.0
C0 R13 1.0 R14 1.0
C0 R15 1.0 COST 1.0
C0 COST 2.0 COST 3.0
C0 COST 4.0 COST 5.0
C0 R0 1.0 R0 2.0
C0 R0 3.0 R0 4.0
C0 R0 5.0 R0 6.0
MARK0000 'MARKER' 'INTORG'
C1 R0 -1.0 COST -1.0
C2 R0 -1.0 COST -1.0
C3 R0 -1.0 COST -1.0
C4 R0 -1.0 COST -1.0
C5 R0 -1.0 COST -1.0
MARK0001 'MARKER' 'INTEND'
C6 R0 -1.0 COST -1.0
C7 R0 -1.0 COST -1.0
C8 R0 -1.0 COST -1.0
RHS
DEMANDS R0 -1.0 R11 -1.0
DEMANDS R12 -1.0 R13 -1.0
DEMANDS R14 -1.0 R15 -1.0
DEMANDS R0 1.0 R0 2.0
DEMANDS R0 3.0 R0 4.0
DEMANDS R0 5.0
BOUNDS
UP SERVINGS C0 -1.0
UP SERVINGS C0 1.0
UP SERVINGS C0 2.0
UP SERVINGS C0 3.0
UP SERVINGS C0 4.0
UP SERVINGS C0 5.0
UP SERVINGS C10 1.0
LI SERVINGS C1 1.1
UI SERVINGS C2 2.1
SI SERVINGS C3 3.1
LI SERVINGS C4 4.1
UI SERVINGS C5 5.1
LO SERVINGS C4 1.0
LO SERVINGS C6 1.0
LO SERVINGS C7 1.0
LO SERVINGS C8 1.0
UP SERVINGS C4 -1.0
UP SERVINGS C6 -1.0
UP SERVINGS C7 -1.0
UP SERVINGS C8 -1.0
RANGES
RNG R0 0.1 R0 1.0
RNG R0 2.0 R0 3.0
RNG R0 4.0 R0 5.0
RNG R11 0.1 R12 1.0
RNG R13 2.0 R14 3.0
RNG R15 4.0 COST 5.0
RNG COST 6.0 COST 7.0
RNG COST 8.0 COST 9.0

ENDATA
1 change: 1 addition & 0 deletions src/io/Filereader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ void interpretFilereaderRetcode(const HighsLogOptions& log_options,
const FilereaderRetcode code) {
switch (code) {
case FilereaderRetcode::kOk:
case FilereaderRetcode::kWarning:
break;
case FilereaderRetcode::kFileNotFound:
highsLogUser(log_options, HighsLogType::kError, "File %s not found\n",
Expand Down
7 changes: 4 additions & 3 deletions src/io/Filereader.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@

enum class FilereaderRetcode {
kOk = 0,
kFileNotFound = 1,
kParserError = 2,
kNotImplemented = 3,
kWarning = 1,
kFileNotFound = 2,
kParserError = 3,
kNotImplemented = 4,
kTimeout
};

Expand Down
13 changes: 10 additions & 3 deletions src/io/FilereaderMps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,16 @@ FilereaderRetcode FilereaderMps::readModelFromFile(const HighsOptions& options,
if (options.mps_parser_type_free) {
HMpsFF parser{};
if (options.time_limit < kHighsInf && options.time_limit > 0)
parser.time_limit = options.time_limit;
parser.time_limit_ = options.time_limit;

FreeFormatParserReturnCode result =
parser.loadProblem(options.log_options, filename, model);
switch (result) {
case FreeFormatParserReturnCode::kSuccess:
lp.ensureColwise();
assert(model.lp_.objective_name_ != "");
return FilereaderRetcode::kOk;
return parser.warning_issued_ ? FilereaderRetcode::kWarning
: FilereaderRetcode::kOk;
case FreeFormatParserReturnCode::kParserError:
return FilereaderRetcode::kParserError;
case FreeFormatParserReturnCode::kFileNotFound:
Expand All @@ -55,19 +56,25 @@ FilereaderRetcode FilereaderMps::readModelFromFile(const HighsOptions& options,
}

// else use fixed format parser
//
// If the fixed format parser has had to be used, then a warning was
// issued, otherwise no warning has yet been issued
bool warning_issued = options.mps_parser_type_free;
FilereaderRetcode return_code =
readMps(options.log_options, filename, -1, -1, lp.num_row_, lp.num_col_,
lp.sense_, lp.offset_, lp.a_matrix_.start_, lp.a_matrix_.index_,
lp.a_matrix_.value_, lp.col_cost_, lp.col_lower_, lp.col_upper_,
lp.row_lower_, lp.row_upper_, lp.integrality_, lp.objective_name_,
lp.col_names_, lp.row_names_, hessian.dim_, hessian.start_,
hessian.index_, hessian.value_, lp.cost_row_location_,
options.keep_n_rows);
warning_issued, options.keep_n_rows);
if (return_code == FilereaderRetcode::kOk) lp.ensureColwise();
// Comment on existence of names with spaces
hasNamesWithSpaces(options.log_options, lp.num_col_, lp.col_names_);
hasNamesWithSpaces(options.log_options, lp.num_row_, lp.row_names_);
assert(model.lp_.objective_name_ != "");
if (return_code == FilereaderRetcode::kOk && warning_issued)
return_code = FilereaderRetcode::kWarning;
return return_code;
}

Expand Down
22 changes: 17 additions & 5 deletions src/io/HMPSIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ FilereaderRetcode readMps(
vector<HighsVarType>& integerColumn, std::string& objective_name,
vector<std::string>& col_names, vector<std::string>& row_names,
HighsInt& Qdim, vector<HighsInt>& Qstart, vector<HighsInt>& Qindex,
vector<double>& Qvalue, HighsInt& cost_row_location,
vector<double>& Qvalue, HighsInt& cost_row_location, bool& warning_issued,
const HighsInt keep_n_rows) {
// Keep track of any warnings that are issued so that
// Highs::readModel can return HighsStatus::kWarning
warning_issued = false;
// MPS file buffer
numRow = 0;
numCol = 0;
Expand Down Expand Up @@ -205,12 +208,14 @@ FilereaderRetcode readMps(
}
Astart.push_back(Aindex.size());

if (num_alien_entries)
if (num_alien_entries) {
warning_issued = true;
highsLogUser(log_options, HighsLogType::kWarning,
"COLUMNS section entries contain %8" HIGHSINT_FORMAT
" with row not in ROWS "
" section: ignored\n",
num_alien_entries);
}
highsLogDev(log_options, HighsLogType::kInfo, "readMPS: Read COLUMNS OK\n");

// Load RHS
Expand Down Expand Up @@ -254,12 +259,14 @@ FilereaderRetcode readMps(
}
save_flag1 = flag[1];
}
if (num_alien_entries)
if (num_alien_entries) {
warning_issued = true;
highsLogUser(log_options, HighsLogType::kWarning,
"RHS section entries contain %8" HIGHSINT_FORMAT
" with row not in ROWS "
" section: ignored\n",
num_alien_entries);
}
highsLogDev(log_options, HighsLogType::kInfo, "readMPS: Read RHS OK\n");

// Load RANGES
Expand Down Expand Up @@ -326,12 +333,14 @@ FilereaderRetcode readMps(
break;
}
}
if (num_alien_entries)
if (num_alien_entries) {
warning_issued = true;
highsLogUser(log_options, HighsLogType::kWarning,
"RANGES section entries contain %8" HIGHSINT_FORMAT
" with row not in ROWS "
" section: ignored\n",
num_alien_entries);
}
highsLogDev(log_options, HighsLogType::kInfo, "readMPS: Read RANGES OK\n");

// Load BOUNDS
Expand Down Expand Up @@ -383,6 +392,7 @@ FilereaderRetcode readMps(
}
// Load Hessian
if (flag[0] == 'Q') {
warning_issued = true;
highsLogUser(
log_options, HighsLogType::kWarning,
"Quadratic section: under development. Assumes QUADOBJ section\n");
Expand Down Expand Up @@ -443,12 +453,14 @@ FilereaderRetcode readMps(
if (colUpper[iCol] >= kHighsInf) colUpper[iCol] = 1;
}
}
if (num_alien_entries)
if (num_alien_entries) {
warning_issued = true;
highsLogUser(log_options, HighsLogType::kWarning,
"BOUNDS section entries contain %8" HIGHSINT_FORMAT
" with col not in "
"COLUMNS section: ignored\n",
num_alien_entries);
}
highsLogDev(log_options, HighsLogType::kInfo, "readMPS: Read BOUNDS OK\n");
highsLogDev(log_options, HighsLogType::kInfo, "readMPS: Read ENDATA OK\n");
highsLogDev(log_options, HighsLogType::kInfo,
Expand Down
2 changes: 1 addition & 1 deletion src/io/HMPSIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ FilereaderRetcode readMps(
vector<HighsVarType>& integerColumn, std::string& objective_name,
vector<std::string>& col_names, vector<std::string>& row_names,
HighsInt& Qdim, vector<HighsInt>& Qstart, vector<HighsInt>& Qindex,
vector<double>& Qvalue, HighsInt& cost_row_location,
vector<double>& Qvalue, HighsInt& cost_row_location, bool& warning_issued,
const HighsInt keep_n_rows = 0);

HighsStatus writeMps(
Expand Down
Loading

0 comments on commit ef5be32

Please sign in to comment.