Skip to content

Commit e2d44e9

Browse files
committed
Added Highs::getFixedLp(HighsLp& lp)
1 parent b2ceebf commit e2d44e9

File tree

3 files changed

+83
-5
lines changed

3 files changed

+83
-5
lines changed

check/TestMipSolver.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,3 +1035,41 @@ TEST_CASE("issue-2432", "[highs_test_mip_solver]") {
10351035
"found\n");
10361036
solve(highs, kHighsOffString, require_model_status, optimal_objective);
10371037
}
1038+
1039+
TEST_CASE("get-fixed-lp", "[highs_test_mip_solver]") {
1040+
std::string model = "avgas";
1041+
std::string model_file =
1042+
std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
1043+
HighsLp fixed_lp;
1044+
Highs h;
1045+
h.setOptionValue("output_flag", dev_run);
1046+
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
1047+
REQUIRE(h.getFixedLp(fixed_lp) == HighsStatus::kError);
1048+
1049+
model = "flugpl";
1050+
model_file = std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
1051+
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
1052+
REQUIRE(h.getFixedLp(fixed_lp) == HighsStatus::kError);
1053+
1054+
REQUIRE(h.run() == HighsStatus::kOk);
1055+
double mip_optimal_objective = h.getInfo().objective_function_value;
1056+
HighsSolution solution = h.getSolution();
1057+
1058+
REQUIRE(h.getFixedLp(fixed_lp) == HighsStatus::kOk);
1059+
1060+
REQUIRE(h.passModel(fixed_lp) == HighsStatus::kOk);
1061+
REQUIRE(h.run() == HighsStatus::kOk);
1062+
1063+
REQUIRE(h.getInfo().objective_function_value == mip_optimal_objective);
1064+
1065+
// Now run from saved solution without presolve
1066+
h.clearSolver();
1067+
h.setSolution(solution);
1068+
h.setOptionValue("presolve", kHighsOffString);
1069+
REQUIRE(h.run() == HighsStatus::kOk);
1070+
1071+
REQUIRE(h.getInfo().objective_function_value == mip_optimal_objective);
1072+
REQUIRE(h.getInfo().simplex_iteration_count == 0);
1073+
1074+
h.resetGlobalScheduler(true);
1075+
}

highs/Highs.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -459,12 +459,11 @@ class Highs {
459459
}
460460

461461
/**
462-
* @brief Return a const pointer to the original row indices for the
463-
* presolved model
462+
* @brief Return an LP associated with a MIP and its solution, with
463+
* each integer variable fixed to the value it takes in the MIP
464+
* solution. If no solution is available, an error is returned.
464465
*/
465-
const HighsInt* getPresolveOrigRowsIndex() const {
466-
return presolve_.data_.postSolveStack.getOrigRowsIndex();
467-
}
466+
HighsStatus getFixedLp(HighsLp& lp) const;
468467

469468
/**
470469
* @brief Return a const reference to the incumbent LP

highs/lp_data/Highs.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,6 +1893,47 @@ HighsStatus Highs::getStandardFormLp(HighsInt& num_col, HighsInt& num_row,
18931893
return HighsStatus::kOk;
18941894
}
18951895

1896+
HighsStatus Highs::getFixedLp(HighsLp& lp) const {
1897+
if (!this->model_.lp_.isMip()) {
1898+
highsLogUser(options_.log_options, HighsLogType::kError,
1899+
"Incumbent model is not a MIP, so cannot form fixed LP\n");
1900+
return HighsStatus::kError;
1901+
}
1902+
if (!this->solution_.value_valid) {
1903+
highsLogUser(options_.log_options, HighsLogType::kError,
1904+
"Incumbent model does not have a valid solution, so cannot "
1905+
"form fixed LP\n");
1906+
return HighsStatus::kError;
1907+
}
1908+
lp = this->model_.lp_;
1909+
const std::vector<HighsVarType> integrality = this->model_.lp_.integrality_;
1910+
lp.integrality_.clear();
1911+
HighsInt num_non_conts_fractional = 0;
1912+
double max_fractional = 0;
1913+
for (HighsInt iCol = 0; iCol < this->model_.lp_.num_col_; iCol++) {
1914+
if (integrality[iCol] == HighsVarType::kContinuous) continue;
1915+
double value = this->solution_.col_value[iCol];
1916+
if (integrality[iCol] == HighsVarType::kInteger ||
1917+
integrality[iCol] == HighsVarType::kSemiInteger) {
1918+
double fractional = fractionality(value);
1919+
if (fractional > this->options_.mip_feasibility_tolerance) {
1920+
num_non_conts_fractional++;
1921+
max_fractional = std::max(fractional, max_fractional);
1922+
}
1923+
}
1924+
lp.col_lower_[iCol] = value;
1925+
lp.col_upper_[iCol] = value;
1926+
}
1927+
if (num_non_conts_fractional) {
1928+
highsLogUser(
1929+
options_.log_options, HighsLogType::kWarning,
1930+
"Fixed LP has %d variables fixed at max fractional value of %g\n",
1931+
int(num_non_conts_fractional), max_fractional);
1932+
return HighsStatus::kWarning;
1933+
}
1934+
return HighsStatus::kOk;
1935+
}
1936+
18961937
HighsStatus Highs::getDualRay(bool& has_dual_ray, double* dual_ray_value) {
18971938
has_dual_ray = false;
18981939
return getDualRayInterface(has_dual_ray, dual_ray_value);

0 commit comments

Comments
 (0)