Skip to content

Commit a568d00

Browse files
authored
Merge pull request #2707 from ERGO-Code/fix-2705
Can now pass a presolved MIP from C if it contains implied integers
2 parents fe84e8d + e3fa1ed commit a568d00

File tree

4 files changed

+81
-8
lines changed

4 files changed

+81
-8
lines changed

check/TestMipSolver.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,42 @@ TEST_CASE("get-fixed-lp", "[highs_test_mip_solver]") {
12281228
h.resetGlobalScheduler(true);
12291229
}
12301230

1231+
TEST_CASE("get-presolved-mip", "[highs_test_mip_solver]") {
1232+
HighsLp lp;
1233+
lp.num_col_ = 3;
1234+
lp.num_row_ = 3;
1235+
lp.col_cost_ = {1, 1, 1};
1236+
lp.col_lower_ = {0, -kHighsInf, -kHighsInf};
1237+
lp.col_upper_ = {kHighsInf, kHighsInf, kHighsInf};
1238+
lp.integrality_ = {HighsVarType::kContinuous, HighsVarType::kInteger,
1239+
HighsVarType::kInteger};
1240+
lp.row_lower_ = {2, 6, 8};
1241+
lp.row_upper_ = {2, kHighsInf, kHighsInf};
1242+
lp.a_matrix_.format_ = MatrixFormat::kRowwise;
1243+
lp.a_matrix_.start_ = {0, 3, 6, 9};
1244+
lp.a_matrix_.index_ = {0, 1, 2, 0, 1, 2, 0, 1, 2};
1245+
lp.a_matrix_.value_ = {1, 1, 1, 1, -1, 2, 1, 3, -1};
1246+
Highs h;
1247+
h.setOptionValue("output_flag", dev_run);
1248+
// Code coverage of highsVarTypeToString for all cases
1249+
HighsLogOptions log_options = h.getOptions().log_options;
1250+
for (HighsInt iVarType = -1;
1251+
iVarType < HighsInt(HighsVarType::kImplicitInteger) + 2; iVarType++)
1252+
highsLogUser(log_options, HighsLogType::kInfo, "Variable type %2d is %s\n",
1253+
int(iVarType), highsVarTypeToString(iVarType).c_str());
1254+
h.passModel(lp);
1255+
h.presolve();
1256+
// Presolved MIP has an implied integer, so this tests passing such
1257+
HighsLp presolved_lp = h.getPresolvedModel().lp_;
1258+
h.run();
1259+
const double lp_objective_value = h.getObjectiveValue();
1260+
h.passModel(presolved_lp);
1261+
h.run();
1262+
const double presolved_lp_objective_value = h.getObjectiveValue();
1263+
REQUIRE(presolved_lp_objective_value == lp_objective_value);
1264+
h.resetGlobalScheduler(true);
1265+
}
1266+
12311267
TEST_CASE("get-fixed-lp-semi", "[highs_test_mip_solver]") {
12321268
HighsLp lp;
12331269
lp.num_col_ = 4;
@@ -1245,6 +1281,11 @@ TEST_CASE("get-fixed-lp-semi", "[highs_test_mip_solver]") {
12451281
Highs h;
12461282
h.setOptionValue("output_flag", dev_run);
12471283
h.setOptionValue("presolve", kHighsOffString);
1284+
// Code coverage of highsVarTypeToString for four main types
1285+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
1286+
highsLogUser(h.getOptions().log_options, HighsLogType::kInfo,
1287+
"Column %d is of type %s\n", int(iCol),
1288+
highsVarTypeToString(lp.integrality_[iCol]).c_str());
12481289
h.passModel(lp);
12491290
h.run();
12501291
double mip_optimal_objective = h.getInfo().objective_function_value;
@@ -1256,6 +1297,7 @@ TEST_CASE("get-fixed-lp-semi", "[highs_test_mip_solver]") {
12561297
REQUIRE(h.run() == HighsStatus::kOk);
12571298

12581299
REQUIRE(h.getInfo().objective_function_value == mip_optimal_objective);
1300+
h.resetGlobalScheduler(true);
12591301
}
12601302

12611303
TEST_CASE("row-fixed-lp", "[highs_test_mip_solver]") {

highs/lp_data/Highs.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -464,15 +464,17 @@ HighsStatus Highs::passModel(
464464
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
465465
HighsInt integrality_status = integrality[iCol];
466466
const bool legal_integrality_status =
467-
integrality_status == (HighsInt)HighsVarType::kContinuous ||
468-
integrality_status == (HighsInt)HighsVarType::kInteger ||
469-
integrality_status == (HighsInt)HighsVarType::kSemiContinuous ||
470-
integrality_status == (HighsInt)HighsVarType::kSemiInteger;
467+
integrality_status == HighsInt(HighsVarType::kContinuous) ||
468+
integrality_status == HighsInt(HighsVarType::kInteger) ||
469+
integrality_status == HighsInt(HighsVarType::kSemiContinuous) ||
470+
integrality_status == HighsInt(HighsVarType::kSemiInteger) ||
471+
integrality_status == HighsInt(HighsVarType::kImplicitInteger);
471472
if (!legal_integrality_status) {
472-
highsLogDev(
473-
options_.log_options, HighsLogType::kError,
474-
"Model has illegal integer value of %d for integrality[%d]\n",
475-
(int)integrality_status, iCol);
473+
highsLogUser(options_.log_options, HighsLogType::kError,
474+
"Model has illegal integer value of %d (type %s) for "
475+
"integrality[%d]\n",
476+
int(integrality_status),
477+
highsVarTypeToString(integrality_status).c_str(), iCol);
476478
return HighsStatus::kError;
477479
}
478480
lp.integrality_[iCol] = (HighsVarType)integrality_status;

highs/lp_data/HighsLpUtils.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3658,6 +3658,31 @@ void getSubVectorsTranspose(const HighsIndexCollection& index_collection,
36583658
}
36593659
}
36603660

3661+
std::string highsVarTypeToString(const HighsVarType type) {
3662+
switch (type) {
3663+
case HighsVarType::kContinuous:
3664+
return "continuous";
3665+
case HighsVarType::kInteger:
3666+
return "integer";
3667+
case HighsVarType::kSemiContinuous:
3668+
return "semi continuous";
3669+
case HighsVarType::kSemiInteger:
3670+
return "semi integer";
3671+
case HighsVarType::kImplicitInteger:
3672+
return "implicit integer";
3673+
default:
3674+
return "unknown";
3675+
}
3676+
}
3677+
3678+
std::string highsVarTypeToString(const HighsInt type) {
3679+
if (type < HighsInt(HighsVarType::kContinuous) ||
3680+
type > HighsInt(HighsVarType::kImplicitInteger))
3681+
return "unknown";
3682+
HighsVarType type_ = HighsVarType(uint8_t(type));
3683+
return highsVarTypeToString(type_);
3684+
}
3685+
36613686
void initialiseUserScaleData(const HighsOptions& options,
36623687
HighsUserScaleData& user_scale_data) {
36633688
user_scale_data.initialise(options.user_objective_scale,

highs/lp_data/HighsLpUtils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,10 @@ void getSubVectorsTranspose(const HighsIndexCollection& index_collection,
321321
HighsInt* sub_matrix_index,
322322
double* sub_matrix_value);
323323

324+
std::string highsVarTypeToString(const HighsVarType type);
325+
std::string highsVarTypeToString(const HighsInt type);
326+
324327
void initialiseUserScaleData(const HighsOptions& options,
325328
HighsUserScaleData& user_scale_data);
329+
326330
#endif // LP_DATA_HIGHSLPUTILS_H_

0 commit comments

Comments
 (0)