Skip to content

Commit cfd986d

Browse files
authored
Merge branch 'latest' into no-col-dual
2 parents 77e3b43 + 5d45136 commit cfd986d

File tree

10 files changed

+633
-57
lines changed

10 files changed

+633
-57
lines changed

check/TestPresolve.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,3 +760,81 @@ TEST_CASE("presolve-solve-postsolve-no-col-dual", "[highs_test_presolve]") {
760760

761761
highs.resetGlobalScheduler(true);
762762
}
763+
764+
TEST_CASE("presolve-egout-ac", "[highs_test_presolve]") {
765+
// Tests the case where, for this model when run_crossover is off,
766+
// sparsify is used to reduce the LP to empty. However, when
767+
// starting from an empty LP, basis postsolve is always used
768+
std::string model_file =
769+
std::string(HIGHS_DIR) + "/check/instances/egout-ac.mps";
770+
Highs h;
771+
h.setOptionValue("output_flag", dev_run);
772+
REQUIRE(h.setOptionValue("presolve_rule_logging", true) == HighsStatus::kOk);
773+
if (dev_run)
774+
REQUIRE(h.setOptionValue("log_dev_level", 1) == HighsStatus::kOk);
775+
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
776+
// Firstly check that pure presolve reduces the LP to empty
777+
REQUIRE(h.presolve() == HighsStatus::kOk);
778+
// Ensure that sparsify isn't called
779+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
780+
781+
const HighsLp& presolved_lp = h.getPresolvedLp();
782+
REQUIRE(presolved_lp.num_col_ == 0);
783+
REQUIRE(presolved_lp.num_row_ == 0);
784+
785+
HighsSolution solution;
786+
HighsBasis basis;
787+
basis.useful = true;
788+
solution.value_valid = true;
789+
solution.dual_valid = true;
790+
// Check that postsolve with the empty solution and basis runs OK -
791+
// ie doesn't trigger assert due to sparsify having been used
792+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
793+
794+
// Check that using IPM with crossover runs OK without using
795+
// sparsify
796+
REQUIRE(h.setOptionValue("solver", kIpmString) == HighsStatus::kOk);
797+
REQUIRE(h.run() == HighsStatus::kOk);
798+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
799+
800+
// Check that pure presolve reduces the LP to empty without using
801+
// sparsify
802+
REQUIRE(h.presolve() == HighsStatus::kOk);
803+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
804+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
805+
806+
// Check that pure presolve reduces the LP to empty using sparsify
807+
// when lp_presolve_requires_basis_postsolve is false
808+
bool lp_presolve_requires_basis_postsolve = false;
809+
REQUIRE(h.setOptionValue("lp_presolve_requires_basis_postsolve",
810+
lp_presolve_requires_basis_postsolve) ==
811+
HighsStatus::kOk);
812+
REQUIRE(h.presolve() == HighsStatus::kOk);
813+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call > 0);
814+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
815+
REQUIRE(h.getOptions().lp_presolve_requires_basis_postsolve ==
816+
lp_presolve_requires_basis_postsolve);
817+
818+
// Now, with crossover off
819+
REQUIRE(h.setOptionValue("run_crossover", kHighsOffString) ==
820+
HighsStatus::kOk);
821+
822+
// Now reset lp_presolve_requires_basis_postsolve default to true,
823+
// to test whether it's set false due to running IPM without
824+
// crossover
825+
lp_presolve_requires_basis_postsolve = true;
826+
REQUIRE(h.setOptionValue("lp_presolve_requires_basis_postsolve",
827+
lp_presolve_requires_basis_postsolve) ==
828+
HighsStatus::kOk);
829+
830+
REQUIRE(h.clearSolver() == HighsStatus::kOk);
831+
REQUIRE(h.run() == HighsStatus::kOk);
832+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call > 0);
833+
// Ensure that lp_presolve_requires_basis_postsolve has been reset
834+
// to true, after being set false before presolve when using IPM
835+
// without crossover
836+
REQUIRE(h.getOptions().lp_presolve_requires_basis_postsolve ==
837+
lp_presolve_requires_basis_postsolve);
838+
839+
h.resetGlobalScheduler(true);
840+
}

0 commit comments

Comments
 (0)