From 17c4c8ac05e41b2ef6436f7d33f5f65ca00ad93c Mon Sep 17 00:00:00 2001 From: Julian Hall Date: Fri, 29 Nov 2024 13:03:40 +0000 Subject: [PATCH] Introduced simplex_stats_ and presolved_lp_simplex_stats_ into Highs.h --- check/TestLpSolvers.cpp | 36 +++++++++++++++++++++++++++++------- src/Highs.h | 13 ++++++++++--- src/lp_data/Highs.cpp | 7 +++++++ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/check/TestLpSolvers.cpp b/check/TestLpSolvers.cpp index 49da8322b0..6b7d5d1c8c 100644 --- a/check/TestLpSolvers.cpp +++ b/check/TestLpSolvers.cpp @@ -648,23 +648,45 @@ TEST_CASE("simplex-stats", "[highs_lp_solver]") { Highs h; const HighsSimplexStats& simplex_stats = h.getSimplexStats(); + const HighsSimplexStats& presolved_lp_simplex_stats = + h.getPresolvedLpSimplexStats(); h.setOptionValue("output_flag", dev_run); + // std::string model = "dcp2"; + std::string model = "adlittle"; std::string model_file = - std::string(HIGHS_DIR) + "/check/instances/adlittle.mps"; + std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps"; REQUIRE(h.readModel(model_file) == HighsStatus::kOk); REQUIRE(h.run() == HighsStatus::kOk); REQUIRE(simplex_stats.valid); - REQUIRE(simplex_stats.iteration_count == 0); - REQUIRE(simplex_stats.num_invert == 1); + REQUIRE(simplex_stats.iteration_count >= 0); + REQUIRE(simplex_stats.num_invert > 0); REQUIRE(simplex_stats.last_invert_num_el > 0); REQUIRE(simplex_stats.last_factored_basis_num_el > 0); - REQUIRE(simplex_stats.col_aq_density == 0); - REQUIRE(simplex_stats.row_ep_density == 0); - REQUIRE(simplex_stats.row_ap_density == 0); - REQUIRE(simplex_stats.row_DSE_density == 0); + if (simplex_stats.iteration_count > 0) { + REQUIRE(simplex_stats.col_aq_density > 0); + REQUIRE(simplex_stats.row_ep_density > 0); + REQUIRE(simplex_stats.row_ap_density > 0); + REQUIRE(simplex_stats.row_DSE_density > 0); + } else { + REQUIRE(simplex_stats.col_aq_density == 0); + REQUIRE(simplex_stats.row_ep_density == 0); + REQUIRE(simplex_stats.row_ap_density == 0); + REQUIRE(simplex_stats.row_DSE_density == 0); + } if (dev_run) h.reportSimplexStats(stdout); + REQUIRE(presolved_lp_simplex_stats.valid); + REQUIRE(presolved_lp_simplex_stats.iteration_count > 0); + REQUIRE(presolved_lp_simplex_stats.num_invert > 0); + REQUIRE(presolved_lp_simplex_stats.last_invert_num_el > 0); + REQUIRE(presolved_lp_simplex_stats.last_factored_basis_num_el > 0); + REQUIRE(presolved_lp_simplex_stats.col_aq_density > 0); + REQUIRE(presolved_lp_simplex_stats.row_ep_density > 0); + REQUIRE(presolved_lp_simplex_stats.row_ap_density > 0); + REQUIRE(presolved_lp_simplex_stats.row_DSE_density > 0); + if (dev_run) h.reportPresolvedLpSimplexStats(stdout); + h.clearSolver(); h.setOptionValue("presolve", kHighsOffString); REQUIRE(h.run() == HighsStatus::kOk); diff --git a/src/Highs.h b/src/Highs.h index 70d800a5de..b2553f21c1 100644 --- a/src/Highs.h +++ b/src/Highs.h @@ -1216,11 +1216,16 @@ class Highs { // Start of advanced methods for HiGHS MIP solver - const HighsSimplexStats& getSimplexStats() const { - return ekk_instance_.getSimplexStats(); + const HighsSimplexStats& getPresolvedLpSimplexStats() const { + return presolved_lp_simplex_stats_; } + void reportPresolvedLpSimplexStats(FILE* file) const { + presolved_lp_simplex_stats_.report(file, "Presolved LP"); + } + + const HighsSimplexStats& getSimplexStats() const { return simplex_stats_; } void reportSimplexStats(FILE* file) const { - ekk_instance_.reportSimplexStats(file); + simplex_stats_.report(file, "Original LP"); } /** @@ -1438,6 +1443,8 @@ class Highs { HighsSparseMatrix standard_form_matrix_; HEkk ekk_instance_; + HighsSimplexStats simplex_stats_; + HighsSimplexStats presolved_lp_simplex_stats_; HighsPresolveLog presolve_log_; diff --git a/src/lp_data/Highs.cpp b/src/lp_data/Highs.cpp index 6352a68a09..f9119a9ba7 100644 --- a/src/lp_data/Highs.cpp +++ b/src/lp_data/Highs.cpp @@ -1275,6 +1275,7 @@ HighsStatus Highs::solve() { solveLp(incumbent_lp, "Solving LP without presolve, or with basis, or unconstrained", this_solve_original_lp_time); + simplex_stats_ = this->ekk_instance_.getSimplexStats(); return_status = interpretCallStatus(options_.log_options, call_status, return_status, "callSolveLp"); if (return_status == HighsStatus::kError) @@ -1318,6 +1319,7 @@ HighsStatus Highs::solve() { ekk_instance_.lp_name_ = "Original LP"; solveLp(incumbent_lp, "Not presolved: solving the LP", this_solve_original_lp_time); + simplex_stats_ = this->ekk_instance_.getSimplexStats(); return_status = interpretCallStatus(options_.log_options, call_status, return_status, "callSolveLp"); if (return_status == HighsStatus::kError) @@ -1330,6 +1332,7 @@ HighsStatus Highs::solve() { reportPresolveReductions(log_options, incumbent_lp, false); solveLp(incumbent_lp, "Problem not reduced by presolve: solving the LP", this_solve_original_lp_time); + simplex_stats_ = this->ekk_instance_.getSimplexStats(); return_status = interpretCallStatus(options_.log_options, call_status, return_status, "callSolveLp"); if (return_status == HighsStatus::kError) @@ -1378,6 +1381,7 @@ HighsStatus Highs::solve() { options_.objective_bound = kHighsInf; solveLp(reduced_lp, "Solving the presolved LP", this_solve_presolved_lp_time); + presolved_lp_simplex_stats_ = this->ekk_instance_.getSimplexStats(); if (ekk_instance_.status_.initialised_for_solve) { // Record the pivot threshold resulting from solving the presolved LP // with simplex @@ -1442,6 +1446,7 @@ HighsStatus Highs::solve() { "Solving the original LP with primal simplex " "to determine infeasible or unbounded", this_solve_original_lp_time); + simplex_stats_ = this->ekk_instance_.getSimplexStats(); // Recover the options options_ = save_options; if (return_status == HighsStatus::kError) @@ -1579,6 +1584,7 @@ HighsStatus Highs::solve() { solveLp(incumbent_lp, "Solving the original LP from the solution after postsolve", this_solve_original_lp_time); + simplex_stats_ = this->ekk_instance_.getSimplexStats(); // Determine the iteration count postsolve_iteration_count += info_.simplex_iteration_count; return_status = @@ -4191,6 +4197,7 @@ HighsStatus Highs::callRunPostsolve(const HighsSolution& solution, "Solving the original LP from the solution after postsolve"); // Determine the timing record timer_.stop(timer_.solve_clock); + simplex_stats_ = this->ekk_instance_.getSimplexStats(); return_status = interpretCallStatus(options_.log_options, call_status, return_status, "callSolveLp"); // Recover the options