#include "HCheckConfig.h"
#include "Highs.h"
#include "SpecialLps.h"
#include "catch.hpp"
const bool dev_run = false;
bool doubleEqual(const double v0, const double v1) {
return std::fabs(v0 - v1) < 1e-8;
}
void presolveSolvePostsolve(const std::string& model_file,
const bool solve_relaxation = false);
TEST_CASE("presolve-solve-postsolve-lp", "[highs_test_presolve]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/25fv47.mps";
presolveSolvePostsolve(model_file);
}
TEST_CASE("postsolve-no-basis", "[highs_test_presolve]") {
Highs highs;
highs.setOptionValue("output_flag", dev_run);
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/afiro.mps";
highs.readModel(model_file);
highs.run();
const double objective_function_value =
highs.getInfo().objective_function_value;
highs.clearSolver();
highs.presolve();
HighsLp presolved_lp = highs.getPresolvedLp();
Highs highs1;
highs1.setOptionValue("output_flag", dev_run);
if (dev_run)
printf("presolved_lp.integrality_.size() = %d\n",
int(presolved_lp.integrality_.size()));
presolved_lp.integrality_.clear();
highs1.setOptionValue("presolve", kHighsOffString);
highs1.passModel(presolved_lp);
highs1.run();
HighsSolution solution = highs1.getSolution();
HighsStatus status;
for (HighsInt k = 0; k < 2; k++) {
if (dev_run)
printf(
"Calling highs.postsolve(solution) with solution.col_value.size() = "
"%d solution.col_dual.size() = %d\n",
int(solution.col_value.size()), int(solution.col_dual.size()));
status = highs.postsolve(solution);
if (k == 0) {
REQUIRE(status == HighsStatus::kOk);
REQUIRE(highs.getModelStatus() == HighsModelStatus::kOptimal);
} else {
REQUIRE(status == HighsStatus::kWarning);
REQUIRE(highs.getModelStatus() == HighsModelStatus::kUnknown);
}
REQUIRE(std::fabs(highs.getInfo().objective_function_value -
objective_function_value) <=
1e-8 * std::max(1.0, std::fabs(objective_function_value)));
HighsSolution postsolve_solution = highs.getSolution();
const HighsInt* original_col_indices = highs.getPresolveOrigColsIndex();
if (dev_run)
printf(
"Presolved model Original model\n"
"Col Primal Col Primal\n");
for (HighsInt iCol = 0; iCol < presolved_lp.num_col_; iCol++) {
HighsInt original_iCol = original_col_indices[iCol];
if (dev_run)
printf("%3d %11.5g %3d %11.5g\n", int(iCol), solution.col_value[iCol],
int(original_iCol), postsolve_solution.col_value[original_iCol]);
REQUIRE(doubleEqual(solution.col_value[iCol],
postsolve_solution.col_value[original_iCol]));
}
solution.dual_valid = false;
solution.col_dual.clear();
solution.row_dual.clear();
}
highs.resetGlobalScheduler(true);
}
TEST_CASE("presolve-solve-postsolve-mip", "[highs_test_presolve]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/flugpl.mps";
presolveSolvePostsolve(model_file);
}
TEST_CASE("presolve-solve-postsolve-relaxation", "[highs_test_presolve]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/flugpl.mps";
presolveSolvePostsolve(model_file, true);
}
TEST_CASE("presolve", "[highs_test_presolve]") {
Highs highs;
highs.setOptionValue("output_flag", dev_run);
const HighsModel& presolved_model = highs.getPresolvedModel();
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kNotReduced);
std::string model_file;
model_file = std::string(HIGHS_DIR) + "/check/instances/adlittle.mps";
highs.readModel(model_file);
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kReduced);
REQUIRE(!presolved_model.isEmpty());
model_file = std::string(HIGHS_DIR) + "/check/instances/gas11.mps";
highs.readModel(model_file);
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(highs.getModelPresolveStatus() ==
HighsPresolveStatus::kUnboundedOrInfeasible);
REQUIRE(presolved_model.isEmpty());
HighsLp lp;
HighsModelStatus require_model_status;
double optimal_objective;
SpecialLps special_lps;
special_lps.scipLpi3Lp(lp, require_model_status);
highs.passModel(lp);
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kInfeasible);
REQUIRE(highs.getModelStatus() == require_model_status);
REQUIRE(presolved_model.isEmpty());
special_lps.distillationLp(lp, require_model_status, optimal_objective);
lp.setMatrixDimensions();
highs.passModel(lp);
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(lp.equalButForNames(presolved_model.lp_));
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kNotReduced);
REQUIRE(highs.getModelStatus() == HighsModelStatus::kNotset);
REQUIRE(!presolved_model.isEmpty());
special_lps.primalDualInfeasible1Lp(lp, require_model_status);
highs.passModel(lp);
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kInfeasible);
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
REQUIRE(presolved_model.isEmpty());
}
TEST_CASE("empty-row", "[highs_test_presolve]") {
Highs highs;
highs.setOptionValue("output_flag", dev_run);
HighsLp lp;
lp.num_col_ = 3;
lp.num_row_ = 1;
lp.col_cost_ = {-7.0, -6.0, -5.0};
lp.col_lower_ = {-73.0, -83.0, -94.0};
lp.col_upper_ = {62.0, 96.0, 62.0};
lp.row_lower_ = {-19.0};
lp.row_upper_ = {11.0};
lp.a_matrix_.format_ = MatrixFormat::kRowwise;
lp.a_matrix_.start_ = {0, 0};
highs.passModel(lp);
highs.run();
const HighsSolution& solution = highs.getSolution();
const HighsBasis& basis = highs.getBasis();
REQUIRE(HighsInt(solution.row_value.size()) == lp.num_row_);
REQUIRE(HighsInt(basis.row_status.size()) == lp.num_row_);
highs.resetGlobalScheduler(true);
}
void presolveSolvePostsolve(const std::string& model_file,
const bool solve_relaxation) {
Highs highs0;
Highs highs1;
highs0.setOptionValue("output_flag", dev_run);
highs1.setOptionValue("output_flag", dev_run);
HighsStatus return_status;
highs0.readModel(model_file);
highs0.setOptionValue("solve_relaxation", solve_relaxation);
return_status = highs0.presolve();
REQUIRE(return_status == HighsStatus::kOk);
HighsPresolveStatus model_presolve_status = highs0.getModelPresolveStatus();
if (model_presolve_status == HighsPresolveStatus::kTimeout) {
if (dev_run)
printf("Presolve timeout: return status = %d\n", (int)return_status);
}
HighsLp lp = highs0.getPresolvedLp();
highs1.passModel(lp);
highs1.setOptionValue("solve_relaxation", solve_relaxation);
highs1.setOptionValue("presolve", kHighsOffString);
highs1.run();
HighsSolution solution = highs1.getSolution();
const double objective_value = highs1.getInfo().objective_function_value;
if (lp.isMip() && !solve_relaxation) {
return_status = highs0.postsolve(solution);
REQUIRE(return_status == HighsStatus::kWarning);
HighsModelStatus model_status = highs0.getModelStatus();
REQUIRE(model_status == HighsModelStatus::kUnknown);
const double dl_objective_value =
std::fabs(highs0.getInfo().objective_function_value - objective_value);
REQUIRE(dl_objective_value < 1e-9);
REQUIRE(highs0.getInfo().primal_solution_status == kSolutionStatusFeasible);
double mip_feasibility_tolerance;
highs0.getOptionValue("mip_feasibility_tolerance",
mip_feasibility_tolerance);
REQUIRE(highs0.getInfo().max_integrality_violation <=
mip_feasibility_tolerance);
} else {
HighsBasis basis = highs1.getBasis();
REQUIRE(basis.valid);
return_status = highs0.postsolve(solution, basis);
REQUIRE(return_status == HighsStatus::kOk);
HighsModelStatus model_status = highs0.getModelStatus();
REQUIRE(model_status == HighsModelStatus::kOptimal);
REQUIRE(highs0.getInfo().simplex_iteration_count <= 0);
}
highs1.resetGlobalScheduler(true);
}
HighsStatus zeroCostColSing() {
HighsLp lp;
lp.num_col_ = 2;
lp.num_row_ = 1;
lp.a_matrix_.start_.push_back(0);
lp.a_matrix_.start_.push_back(1);
lp.a_matrix_.start_.push_back(2);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.value_.push_back(0.5);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.value_.push_back(0.5);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.row_lower_.push_back(0.1);
lp.row_upper_.push_back(0.9);
lp.col_cost_.push_back(0);
lp.col_cost_.push_back(1);
Highs highs;
highs.setOptionValue("output_flag", dev_run);
HighsStatus status = highs.passModel(lp);
assert(status == HighsStatus::kOk);
status = highs.run();
highs.resetGlobalScheduler(true);
return status;
}
HighsStatus colSingDoubletonEquality() {
HighsLp lp;
lp.num_col_ = 4;
lp.num_row_ = 2;
lp.a_matrix_.format_ = MatrixFormat::kColwise;
lp.a_matrix_.start_.push_back(0);
lp.a_matrix_.start_.push_back(2);
lp.a_matrix_.start_.push_back(3);
lp.a_matrix_.start_.push_back(4);
lp.a_matrix_.start_.push_back(5);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.index_.push_back(1);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.index_.push_back(1);
lp.a_matrix_.index_.push_back(1);
lp.a_matrix_.value_.push_back(0.5);
lp.a_matrix_.value_.push_back(0.5);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.value_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.col_upper_.push_back(1);
lp.row_lower_.push_back(1);
lp.row_upper_.push_back(1);
lp.row_lower_.push_back(0);
lp.row_upper_.push_back(1);
lp.col_cost_.push_back(1);
lp.col_cost_.push_back(2);
lp.col_cost_.push_back(1);
lp.col_cost_.push_back(1);
Highs highs;
highs.setOptionValue("output_flag", dev_run);
HighsStatus status = highs.passModel(lp);
assert(status == HighsStatus::kOk);
status = highs.run();
highs.resetGlobalScheduler(true);
return status;
}
HighsStatus colSingDoubletonInequality() {
HighsLp lp;
lp.num_col_ = 4;
lp.num_row_ = 2;
lp.a_matrix_.format_ = MatrixFormat::kColwise;
lp.a_matrix_.start_.push_back(0);
lp.a_matrix_.start_.push_back(2);
lp.a_matrix_.start_.push_back(3);
lp.a_matrix_.start_.push_back(4);
lp.a_matrix_.start_.push_back(5);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.index_.push_back(1);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.index_.push_back(1);
lp.a_matrix_.index_.push_back(1);
lp.a_matrix_.value_.push_back(0.5);
lp.a_matrix_.value_.push_back(0.5);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.value_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.col_upper_.push_back(1);
lp.row_lower_.push_back(0);
lp.row_upper_.push_back(1);
lp.row_lower_.push_back(0);
lp.row_upper_.push_back(1);
lp.col_cost_.push_back(1);
lp.col_cost_.push_back(2);
lp.col_cost_.push_back(1);
lp.col_cost_.push_back(1);
Highs highs;
highs.setOptionValue("output_flag", dev_run);
HighsStatus status = highs.passModel(lp);
assert(status == HighsStatus::kOk);
status = highs.run();
highs.resetGlobalScheduler(true);
return status;
}
HighsStatus twoColSingDoubletonEquality() {
HighsLp lp;
lp.num_col_ = 2;
lp.num_row_ = 1;
lp.a_matrix_.start_.push_back(0);
lp.a_matrix_.start_.push_back(1);
lp.a_matrix_.start_.push_back(2);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.value_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.row_lower_.push_back(1);
lp.row_upper_.push_back(1);
lp.col_cost_.push_back(1);
lp.col_cost_.push_back(2);
Highs highs;
highs.setOptionValue("output_flag", dev_run);
HighsStatus status = highs.passModel(lp);
assert(status == HighsStatus::kOk);
status = highs.run();
highs.resetGlobalScheduler(true);
return status;
}
HighsStatus twoColSingDoubletonInequality() {
HighsLp lp;
lp.num_col_ = 2;
lp.num_row_ = 1;
lp.a_matrix_.start_.push_back(0);
lp.a_matrix_.start_.push_back(1);
lp.a_matrix_.start_.push_back(2);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.value_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.col_lower_.push_back(0);
lp.col_upper_.push_back(1);
lp.row_lower_.push_back(0);
lp.row_upper_.push_back(1);
lp.col_cost_.push_back(1);
lp.col_cost_.push_back(2);
Highs highs;
highs.setOptionValue("output_flag", dev_run);
HighsStatus status = highs.passModel(lp);
assert(status == HighsStatus::kOk);
highs.run();
status = highs.run();
highs.resetGlobalScheduler(true);
return status;
}
TEST_CASE("zero-cost", "[presolve-col-sing]") {
if (dev_run) std::cout << "Presolve 1." << std::endl;
HighsStatus status = zeroCostColSing();
std::string str = highsStatusToString(status);
CHECK(str == "OK");
}
TEST_CASE("col-sing-doubleton-eq", "[presolve-col-sing]") {
if (dev_run) std::cout << "Presolve 2." << std::endl;
HighsStatus status = colSingDoubletonEquality();
std::string str = highsStatusToString(status);
CHECK(str == "OK");
}
TEST_CASE("col-sing-doubleton-ineq", "[presolve-col-sing]") {
if (dev_run) std::cout << "Presolve 3." << std::endl;
HighsStatus status = colSingDoubletonInequality();
std::string str = highsStatusToString(status);
CHECK(str == "OK");
}
TEST_CASE("two-col-sing-doubleton-eq", "[presolve-col-sing]") {
if (dev_run) std::cout << "Presolve 4." << std::endl;
HighsStatus status = twoColSingDoubletonEquality();
std::string str = highsStatusToString(status);
CHECK(str == "OK");
}
TEST_CASE("two-col-sing-doubleton-ineq", "[presolve-col-sing]") {
if (dev_run) std::cout << "Presolve 5." << std::endl;
HighsStatus status = twoColSingDoubletonInequality();
std::string str = highsStatusToString(status);
REQUIRE(str == "OK");
}
HighsStatus issue425() {
HighsLp lp;
lp.num_col_ = 4;
lp.num_row_ = 4;
lp.a_matrix_.start_.push_back(0);
lp.a_matrix_.start_.push_back(3);
lp.a_matrix_.start_.push_back(5);
lp.a_matrix_.start_.push_back(6);
lp.a_matrix_.start_.push_back(7);
lp.a_matrix_.index_.push_back(0);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.index_.push_back(2);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.index_.push_back(3);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.index_.push_back(1);
lp.a_matrix_.value_.push_back(2);
lp.a_matrix_.index_.push_back(3);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.index_.push_back(3);
lp.a_matrix_.value_.push_back(1);
lp.a_matrix_.index_.push_back(3);
lp.a_matrix_.value_.push_back(1);
lp.col_lower_.assign(lp.num_col_, 0);
lp.col_upper_.assign(lp.num_col_, kHighsInf);
std::vector<double> b{1, 2, 2, 4};
lp.row_lower_ = b;
lp.row_upper_ = b;
lp.col_cost_.push_back(1);
lp.col_cost_.push_back(1);
lp.col_cost_.push_back(1);
lp.col_cost_.push_back(2);
Highs highs;
highs.setOptionValue("output_flag", dev_run);
HighsStatus status = highs.passModel(lp);
assert(status == HighsStatus::kOk);
status = highs.run();
highs.resetGlobalScheduler(true);
return status;
}
TEST_CASE("presolve-issue-425", "[highs_test_presolve]") {
if (dev_run) {
std::cout << std::endl;
std::cout << "Presolve issue 425." << std::endl;
}
HighsStatus status = issue425();
REQUIRE(status == HighsStatus::kOk);
}
TEST_CASE("postsolve-reduced-to-empty", "[highs_test_presolve]") {
Highs highs;
highs.setOptionValue("output_flag", dev_run);
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/egout.mps";
highs.readModel(model_file);
std::vector<HighsInt> vars(highs.getNumCol(), 1);
std::vector<HighsVarType> integral(highs.getNumCol(),
HighsVarType::kContinuous);
highs.changeColsIntegrality(vars.data(), integral.data());
HighsStatus presolveStatus = highs.presolve();
REQUIRE(presolveStatus == HighsStatus::kOk);
REQUIRE(highs.getModelPresolveStatus() ==
HighsPresolveStatus::kReducedToEmpty);
HighsSolution hsol = HighsSolution();
hsol.value_valid = true;
hsol.dual_valid = true;
HighsStatus postsolveStatus = highs.postsolve(hsol);
REQUIRE(postsolveStatus == HighsStatus::kOk);
REQUIRE(highs.getModelStatus() == HighsModelStatus::kOptimal);
REQUIRE(highs.getInfo().num_primal_infeasibilities == 0);
REQUIRE(highs.getInfo().num_dual_infeasibilities == 0);
}
TEST_CASE("write-presolved-model", "[highs_test_presolve]") {
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
const std::string presolved_model_file = test_name + ".mps";
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/afiro.mps";
Highs highs;
highs.setOptionValue("output_flag", dev_run);
REQUIRE(highs.readModel(model_file) == HighsStatus::kOk);
highs.presolve();
highs.writePresolvedModel(presolved_model_file);
Highs highs1;
highs1.setOptionValue("output_flag", dev_run);
highs1.readModel(presolved_model_file);
highs1.run();
HighsSolution solution = highs1.getSolution();
HighsBasis basis = highs1.getBasis();
highs.postsolve(solution, basis);
REQUIRE(highs.getInfo().simplex_iteration_count == -1);
std::remove(presolved_model_file.c_str());
highs1.resetGlobalScheduler(true);
}
TEST_CASE("presolve-slacks", "[highs_test_presolve]") {
HighsLp lp;
lp.num_col_ = 2;
lp.num_row_ = 1;
lp.col_cost_ = {1, 0};
lp.col_lower_ = {0, 0};
lp.col_upper_ = {kHighsInf, kHighsInf};
lp.row_lower_ = {1};
lp.row_upper_ = {1};
lp.a_matrix_.start_ = {0, 1, 2};
lp.a_matrix_.index_ = {0, 0};
lp.a_matrix_.value_ = {1, 1};
Highs h;
h.setOptionValue("output_flag", dev_run);
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
REQUIRE(h.presolve() == HighsStatus::kOk);
REQUIRE(h.getPresolvedLp().num_col_ == 0);
REQUIRE(h.getPresolvedLp().num_row_ == 0);
lp.num_col_ = 4;
lp.num_row_ = 2;
lp.col_cost_ = {-10, -25, 0, 0};
lp.col_lower_ = {0, 0, 0, 0};
lp.col_upper_ = {kHighsInf, kHighsInf, kHighsInf, kHighsInf};
lp.row_lower_ = {80, 120};
lp.row_upper_ = {80, 120};
lp.a_matrix_.start_ = {0, 2, 4, 5, 6};
lp.a_matrix_.index_ = {0, 1, 0, 1, 0, 1};
lp.a_matrix_.value_ = {1, 1, 2, 4, 1, 1};
REQUIRE(h.setOptionValue("presolve_remove_slacks", true) == HighsStatus::kOk);
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
REQUIRE(h.run() == HighsStatus::kOk);
REQUIRE(h.presolve() == HighsStatus::kOk);
REQUIRE(h.getPresolvedLp().num_col_ == 2);
REQUIRE(h.getPresolvedLp().num_row_ == 2);
h.resetGlobalScheduler(true);
}
TEST_CASE("presolve-issue-2095", "[highs_test_presolve]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/issue-2095.mps";
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.readModel(model_file);
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kReduced);
}
TEST_CASE("presolve-only-at-root", "[highs_test_presolve]") {
std::string model_file = std::string(HIGHS_DIR) + "/check/instances/rgn.mps";
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.setOptionValue("mip_root_presolve_only", true);
highs.readModel(model_file);
REQUIRE(highs.run() == HighsStatus::kOk);
highs.resetGlobalScheduler(true);
}
TEST_CASE("lifting-for-probing", "[highs_test_presolve]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/gesa2.mps";
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.setOptionValue("mip_lifting_for_probing", 1);
highs.readModel(model_file);
REQUIRE(highs.presolve() == HighsStatus::kOk);
}
TEST_CASE("presolve-issue-2388", "[highs_test_presolve]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/issue-2388.lp";
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.readModel(model_file);
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(highs.getModelPresolveStatus() ==
HighsPresolveStatus::kReducedToEmpty);
}
TEST_CASE("presolve-issue-2402", "[highs_test_presolve]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/issue-2402.mps";
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.readModel(model_file);
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kInfeasible);
}
TEST_CASE("presolve-issue-2446", "[highs_test_presolve]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/issue-2446.mps";
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.readModel(model_file);
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kReduced);
}
TEST_CASE("presolve-solve-postsolve-no-col-dual", "[highs_test_presolve]") {
Highs highs;
highs.setOptionValue("output_flag", dev_run);
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/afiro.mps";
highs.readModel(model_file);
highs.presolve();
HighsLp presolved_lp = highs.getPresolvedLp();
Highs highs1;
highs1.setOptionValue("output_flag", dev_run);
highs1.setOptionValue("presolve", kHighsOffString);
highs1.passModel(presolved_lp);
highs1.run();
HighsSolution solution = highs1.getSolution();
REQUIRE(highs.postsolve(solution) == HighsStatus::kOk);
solution.col_dual.clear();
REQUIRE(highs.postsolve(solution) == HighsStatus::kError);
highs.resetGlobalScheduler(true);
}
TEST_CASE("presolve-egout-ac", "[highs_test_presolve]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/egout-ac.mps";
Highs h;
h.setOptionValue("output_flag", dev_run);
REQUIRE(h.setOptionValue("presolve_rule_logging", true) == HighsStatus::kOk);
if (dev_run)
REQUIRE(h.setOptionValue("log_dev_level", 1) == HighsStatus::kOk);
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
REQUIRE(h.presolve() == HighsStatus::kOk);
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
const HighsLp& presolved_lp = h.getPresolvedLp();
REQUIRE(presolved_lp.num_col_ == 0);
REQUIRE(presolved_lp.num_row_ == 0);
HighsSolution solution;
HighsBasis basis;
basis.useful = true;
solution.value_valid = true;
solution.dual_valid = true;
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
REQUIRE(h.setOptionValue("solver", kIpmString) == HighsStatus::kOk);
REQUIRE(h.run() == HighsStatus::kOk);
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
REQUIRE(h.presolve() == HighsStatus::kOk);
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
bool lp_presolve_requires_basis_postsolve = false;
REQUIRE(h.setOptionValue("lp_presolve_requires_basis_postsolve",
lp_presolve_requires_basis_postsolve) ==
HighsStatus::kOk);
REQUIRE(h.presolve() == HighsStatus::kOk);
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call > 0);
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
REQUIRE(h.getOptions().lp_presolve_requires_basis_postsolve ==
lp_presolve_requires_basis_postsolve);
REQUIRE(h.setOptionValue("run_crossover", kHighsOffString) ==
HighsStatus::kOk);
lp_presolve_requires_basis_postsolve = true;
REQUIRE(h.setOptionValue("lp_presolve_requires_basis_postsolve",
lp_presolve_requires_basis_postsolve) ==
HighsStatus::kOk);
REQUIRE(h.clearSolver() == HighsStatus::kOk);
REQUIRE(h.run() == HighsStatus::kOk);
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call > 0);
REQUIRE(h.getOptions().lp_presolve_requires_basis_postsolve ==
lp_presolve_requires_basis_postsolve);
h.resetGlobalScheduler(true);
}
TEST_CASE("dual-bound-tightening", "[highs_test_presolve]") {
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/gesa2.mps";
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.readModel(model_file);
HighsLp lp = highs.getLp();
std::transform(lp.a_matrix_.value_.begin(), lp.a_matrix_.value_.end(),
lp.a_matrix_.value_.begin(), [](double v) { return -v; });
std::transform(lp.col_cost_.begin(), lp.col_cost_.end(), lp.col_cost_.begin(),
[](double v) { return -v; });
std::transform(lp.col_upper_.begin(), lp.col_upper_.end(),
lp.col_upper_.begin(), [](double v) { return -v; });
std::transform(lp.col_lower_.begin(), lp.col_lower_.end(),
lp.col_lower_.begin(), [](double v) { return -v; });
std::swap(lp.col_lower_, lp.col_upper_);
highs.passModel(lp);
REQUIRE(highs.presolve() == HighsStatus::kOk);
}