From b32cfd0892d48b55ff58afbd799e28b052aff118 Mon Sep 17 00:00:00 2001 From: JAJHall Date: Fri, 8 Nov 2024 18:21:37 +0000 Subject: [PATCH] Tidied and formatted --- check/TestPresolve.cpp | 8 ++-- src/lp_data/Highs.cpp | 72 +++++++++++++++------------- src/lp_data/HighsOptions.h | 8 ++-- src/presolve/HPresolve.cpp | 29 ++++++----- src/presolve/HPresolve.h | 2 +- src/presolve/HighsPostsolveStack.cpp | 34 ++++++++----- src/presolve/HighsPostsolveStack.h | 29 ++++------- src/qpsolver/dantzigpricing.hpp | 2 +- src/qpsolver/devexpricing.hpp | 2 +- 9 files changed, 98 insertions(+), 88 deletions(-) diff --git a/check/TestPresolve.cpp b/check/TestPresolve.cpp index 40d1ea900c..7d2e5d9604 100644 --- a/check/TestPresolve.cpp +++ b/check/TestPresolve.cpp @@ -616,7 +616,7 @@ TEST_CASE("presolve-slacks", "[highs_test_presolve]") { lp.a_matrix_.index_ = {0, 0}; lp.a_matrix_.value_ = {1, 1}; Highs h; - // h.setOptionValue("output_flag", dev_run); + h.setOptionValue("output_flag", dev_run); REQUIRE(h.passModel(lp) == HighsStatus::kOk); REQUIRE(h.presolve() == HighsStatus::kOk); REQUIRE(h.getPresolvedLp().num_col_ == 0); @@ -632,10 +632,10 @@ TEST_CASE("presolve-slacks", "[highs_test_presolve]") { 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); + REQUIRE(h.getPresolvedLp().num_col_ == 2); + REQUIRE(h.getPresolvedLp().num_row_ == 2); } diff --git a/src/lp_data/Highs.cpp b/src/lp_data/Highs.cpp index 05d89e3ca4..894b703aac 100644 --- a/src/lp_data/Highs.cpp +++ b/src/lp_data/Highs.cpp @@ -1251,40 +1251,46 @@ HighsStatus Highs::run() { // Run solver. bool have_optimal_solution = false; // ToDo Put solution of presolved problem in a separate method - + // if (!this->options_.presolve_remove_slacks) { - HighsLp& reduced_lp = presolve_.getReducedProblem(); - HighsInt num_double_slack = 0; - HighsInt num_slack = 0; - HighsInt num_zero_cost_slack = 0; - HighsInt num_unit_coeff_slack = 0; - double min_slack_coeff = kHighsInf; - double max_slack_coeff = -kHighsInf; - std::vector found_slack; - found_slack.assign(reduced_lp.num_row_, false); - for (HighsInt iCol = 0; iCol < reduced_lp.num_col_; iCol++) { - HighsInt nnz = reduced_lp.a_matrix_.start_[iCol+1] - reduced_lp.a_matrix_.start_[iCol]; - if (nnz != 1) continue; - HighsInt iRow = reduced_lp.a_matrix_.index_[reduced_lp.a_matrix_.start_[iCol]]; - if (found_slack[iRow]) { - num_double_slack++; - continue; - } - if (reduced_lp.row_lower_[iRow] != reduced_lp.row_upper_[iRow]) continue; - num_slack++; - printf("Column %d is slack\n", int(iCol)); - double coeff = std::fabs(reduced_lp.a_matrix_.value_[reduced_lp.a_matrix_.start_[iCol]]); - if (coeff == 1.0) num_unit_coeff_slack++; - min_slack_coeff = std::min(coeff,min_slack_coeff); - max_slack_coeff = std::max(coeff,max_slack_coeff); - found_slack[iRow] = true; - if (reduced_lp.col_cost_[iCol] == 0) num_zero_cost_slack++; + HighsLp& reduced_lp = presolve_.getReducedProblem(); + HighsInt num_double_slack = 0; + HighsInt num_slack = 0; + HighsInt num_zero_cost_slack = 0; + HighsInt num_unit_coeff_slack = 0; + double min_slack_coeff = kHighsInf; + double max_slack_coeff = -kHighsInf; + std::vector found_slack; + found_slack.assign(reduced_lp.num_row_, false); + for (HighsInt iCol = 0; iCol < reduced_lp.num_col_; iCol++) { + HighsInt nnz = reduced_lp.a_matrix_.start_[iCol + 1] - + reduced_lp.a_matrix_.start_[iCol]; + if (nnz != 1) continue; + HighsInt iRow = + reduced_lp.a_matrix_.index_[reduced_lp.a_matrix_.start_[iCol]]; + if (found_slack[iRow]) { + num_double_slack++; + continue; } - printf("grepSlack,model,col,slack,unit coeff,zero_cost,double,min coeff, max_coeff\n"); - printf("grepSlack,%s,%d, %d, %d, %d, %d, %g, %g\n", this->model_.lp_.model_name_.c_str(), - int(reduced_lp.num_col_), int(num_slack), int(num_unit_coeff_slack), int(num_zero_cost_slack), int(num_double_slack), - min_slack_coeff, max_slack_coeff); - // } + if (reduced_lp.row_lower_[iRow] != reduced_lp.row_upper_[iRow]) continue; + num_slack++; + printf("Column %d is slack\n", int(iCol)); + double coeff = std::fabs( + reduced_lp.a_matrix_.value_[reduced_lp.a_matrix_.start_[iCol]]); + if (coeff == 1.0) num_unit_coeff_slack++; + min_slack_coeff = std::min(coeff, min_slack_coeff); + max_slack_coeff = std::max(coeff, max_slack_coeff); + found_slack[iRow] = true; + if (reduced_lp.col_cost_[iCol] == 0) num_zero_cost_slack++; + } + printf( + "grepSlack,model,col,slack,unit coeff,zero_cost,double,min coeff, " + "max_coeff\n"); + printf("grepSlack,%s,%d, %d, %d, %d, %d, %g, %g\n", + this->model_.lp_.model_name_.c_str(), int(reduced_lp.num_col_), + int(num_slack), int(num_unit_coeff_slack), int(num_zero_cost_slack), + int(num_double_slack), min_slack_coeff, max_slack_coeff); + // } switch (model_presolve_status_) { case HighsPresolveStatus::kNotPresolved: { @@ -1310,7 +1316,7 @@ HighsStatus Highs::run() { break; } case HighsPresolveStatus::kReduced: { - HighsLp& reduced_lp = presolve_.getReducedProblem(); + HighsLp& reduced_lp = presolve_.getReducedProblem(); reduced_lp.setMatrixDimensions(); if (kAllowDeveloperAssert) { // Validate the reduced LP diff --git a/src/lp_data/HighsOptions.h b/src/lp_data/HighsOptions.h index 8103f4db7b..64d565014e 100644 --- a/src/lp_data/HighsOptions.h +++ b/src/lp_data/HighsOptions.h @@ -508,7 +508,7 @@ struct HighsOptionsStruct { presolve_substitution_maxfillin(0), presolve_rule_off(0), presolve_rule_logging(false), - presolve_remove_slacks(false), + presolve_remove_slacks(false), simplex_initial_condition_check(false), no_unnecessary_rebuild_refactor(false), simplex_initial_condition_tolerance(0.0), @@ -1326,9 +1326,9 @@ class HighsOptions : public HighsOptionsStruct { advanced, &presolve_rule_logging, false); records.push_back(record_bool); - record_bool = new OptionRecordBool( - "presolve_remove_slacks", "Remove slacks after presolve", - advanced, &presolve_remove_slacks, true);//false); + record_bool = new OptionRecordBool("presolve_remove_slacks", + "Remove slacks after presolve", advanced, + &presolve_remove_slacks, false); records.push_back(record_bool); record_int = new OptionRecordInt( diff --git a/src/presolve/HPresolve.cpp b/src/presolve/HPresolve.cpp index e1e721347c..de5a26204e 100644 --- a/src/presolve/HPresolve.cpp +++ b/src/presolve/HPresolve.cpp @@ -4380,7 +4380,8 @@ HPresolve::Result HPresolve::presolve(HighsPostsolveStack& postsolve_stack) { return Result::kOk; } -HPresolve::Result HPresolve::removeSlacks(HighsPostsolveStack& postsolve_stack) { +HPresolve::Result HPresolve::removeSlacks( + HighsPostsolveStack& postsolve_stack) { // singletonColumns data structure appears not to be retained // throughout presolve // @@ -4399,7 +4400,10 @@ HPresolve::Result HPresolve::removeSlacks(HighsPostsolveStack& postsolve_stack) double cost = model->col_cost_[iCol]; double rhs = model->row_lower_[iRow]; double coeff = Avalue[coliter]; - printf("Col %d is continuous and is singleton in equality row %d with cost %g, bounds [%g, %g], coeff %g and RHS = %g\n", int(iCol), int(iRow), cost, lower, upper, coeff, rhs); + printf( + "Col %d is continuous and is singleton in equality row %d with cost " + "%g, bounds [%g, %g], coeff %g and RHS = %g\n", + int(iCol), int(iRow), cost, lower, upper, coeff, rhs); if (unit_coeff_only && std::fabs(coeff) != 1.0) continue; assert(coeff); // Slack is s = (rhs - a^Tx)/coeff @@ -4409,26 +4413,27 @@ HPresolve::Result HPresolve::removeSlacks(HighsPostsolveStack& postsolve_stack) // For coeff > 0 [rhs - coeff * upper, rhs - coeff * lower] // // For coeff < 0 [rhs - coeff * lower, rhs - coeff * upper] - model->row_lower_[iRow] = coeff > 0 ? rhs - coeff * upper : rhs - coeff * lower; - model->row_upper_[iRow] = coeff > 0 ? rhs - coeff * lower : rhs - coeff * upper; + model->row_lower_[iRow] = + coeff > 0 ? rhs - coeff * upper : rhs - coeff * lower; + model->row_upper_[iRow] = + coeff > 0 ? rhs - coeff * lower : rhs - coeff * upper; if (cost) { // Cost is (cost * rhs / coeff) + (col_cost - (cost/coeff) row_values)^Tx double multiplier = cost / coeff; for (const HighsSliceNonzero& nonzero : getRowVector(iRow)) { - HighsInt local_iCol = nonzero.index(); - double local_value = nonzero.value(); - model->col_cost_[local_iCol] -= multiplier * local_value; + HighsInt local_iCol = nonzero.index(); + double local_value = nonzero.value(); + model->col_cost_[local_iCol] -= multiplier * local_value; } model->offset_ += multiplier * rhs; } - // - postsolve_stack.slackColSubstitution(iRow, iCol, rhs, cost, lower, upper, //coeff, - getRowVector(iRow), - getColumnVector(iCol)); + // + postsolve_stack.slackColSubstitution(iRow, iCol, rhs, cost, + getRowVector(iRow)); + markColDeleted(iCol); unlink(coliter); - } return Result::kOk; } diff --git a/src/presolve/HPresolve.h b/src/presolve/HPresolve.h index 28ac2bbe47..3699d23399 100644 --- a/src/presolve/HPresolve.h +++ b/src/presolve/HPresolve.h @@ -270,7 +270,7 @@ class HPresolve { Result presolve(HighsPostsolveStack& postsolve_stack); Result removeSlacks(HighsPostsolveStack& postsolve_stack); - + Result checkLimits(HighsPostsolveStack& postsolve_stack); void storeCurrentProblemSize(); diff --git a/src/presolve/HighsPostsolveStack.cpp b/src/presolve/HighsPostsolveStack.cpp index 9a976187f9..43485006ea 100644 --- a/src/presolve/HighsPostsolveStack.cpp +++ b/src/presolve/HighsPostsolveStack.cpp @@ -1353,9 +1353,7 @@ void HighsPostsolveStack::DuplicateColumn::transformToPresolvedSpace( void HighsPostsolveStack::SlackColSubstitution::undo( const HighsOptions& options, const std::vector& rowValues, - const std::vector& colValues, HighsSolution& solution, - HighsBasis& basis) { - + HighsSolution& solution, HighsBasis& basis) { // Taken from HighsPostsolveStack::FreeColSubstitution::undo( // // a (removed) cut may have been used in this reduction. @@ -1378,33 +1376,47 @@ void HighsPostsolveStack::SlackColSubstitution::undo( assert(colCoef != 0); // Row values aren't fully postsolved, so why do this? - if (isModelRow) solution.row_value[row] = + if (isModelRow) + solution.row_value[row] = double(rowValue + colCoef * solution.col_value[col]); - printf("HighsPostsolveStack::SlackColSubstitution::undo rowValue = %g\n", double(rowValue)); + solution.col_value[col] = double((rhs - rowValue) / colCoef); + printf( + "\nHighsPostsolveStack::SlackColSubstitution::undo rowValue = %g; " + "colValue = %g\n", + double(rowValue), solution.col_value[col]); // if no dual values requested, return here if (!solution.dual_valid) return; // compute the row dual value such that reduced cost of basic column is 0 + double save_row_dual = solution.row_dual[row]; if (isModelRow) { solution.row_dual[row] = 0; - HighsCDouble dualval = colCost; - for (const auto& colVal : colValues) { - if (static_cast(colVal.index) < solution.row_dual.size()) - dualval -= colVal.value * solution.row_dual[colVal.index]; - } + HighsCDouble dualval = HighsCDouble(colCost); + dualval = -colCoef * solution.row_dual[row]; solution.row_dual[row] = double(dualval / colCoef); } solution.col_dual[col] = 0; + printf( + "HighsPostsolveStack::SlackColSubstitution::undo OgRowDual = %g; rowDual " + "= %g; colDual = %g\n", + save_row_dual, solution.row_dual[row], solution.col_dual[col]); // set basis status if necessary if (!basis.valid) return; basis.col_status[col] = HighsBasisStatus::kBasic; + HighsBasisStatus save_row_basis_status = basis.row_status[row]; if (isModelRow) - basis.row_status[row] = computeRowStatus(solution.row_dual[row], RowType::kEq); + basis.row_status[row] = + computeRowStatus(solution.row_dual[row], RowType::kEq); + printf( + "HighsPostsolveStack::SlackColSubstitution::undo OgRowStatus = %d; " + "RowStatus = %d; ColStatus = %d\n", + int(save_row_basis_status), int(basis.row_status[row]), + int(basis.col_status[col])); } } // namespace presolve diff --git a/src/presolve/HighsPostsolveStack.h b/src/presolve/HighsPostsolveStack.h index 954ffd2732..418462103c 100644 --- a/src/presolve/HighsPostsolveStack.h +++ b/src/presolve/HighsPostsolveStack.h @@ -222,15 +222,11 @@ class HighsPostsolveStack { struct SlackColSubstitution { double rhs; double colCost; - double colLower; - double colUpper; - // double colCoeff; HighsInt row; HighsInt col; void undo(const HighsOptions& options, - const std::vector& rowValues, - const std::vector& colValues, HighsSolution& solution, + const std::vector& rowValues, HighsSolution& solution, HighsBasis& basis); }; @@ -339,24 +335,17 @@ class HighsPostsolveStack { reductionAdded(ReductionType::kFreeColSubstitution); } - template + template void slackColSubstitution(HighsInt row, HighsInt col, double rhs, - double colCost, double colLower, double colUpper, //double colCoeff, - const HighsMatrixSlice& rowVec, - const HighsMatrixSlice& colVec) { + double colCost, + const HighsMatrixSlice& rowVec) { rowValues.clear(); for (const HighsSliceNonzero& rowVal : rowVec) rowValues.emplace_back(origColIndex[rowVal.index()], rowVal.value()); - colValues.clear(); - for (const HighsSliceNonzero& colVal : colVec) - colValues.emplace_back(origRowIndex[colVal.index()], colVal.value()); - - reductionValues.push(SlackColSubstitution{rhs, colCost, colLower, colUpper, //colCoeff, - origRowIndex[row], - origColIndex[col]}); + reductionValues.push(SlackColSubstitution{rhs, colCost, origRowIndex[row], + origColIndex[col]}); reductionValues.push(rowValues); - reductionValues.push(colValues); reductionAdded(ReductionType::kSlackColSubstitution); } @@ -749,10 +738,9 @@ class HighsPostsolveStack { } case ReductionType::kSlackColSubstitution: { SlackColSubstitution reduction; - reductionValues.pop(colValues); reductionValues.pop(rowValues); reductionValues.pop(reduction); - reduction.undo(options, rowValues, colValues, solution, basis); + reduction.undo(options, rowValues, solution, basis); break; } default: @@ -934,10 +922,9 @@ class HighsPostsolveStack { } case ReductionType::kSlackColSubstitution: { SlackColSubstitution reduction; - reductionValues.pop(colValues); reductionValues.pop(rowValues); reductionValues.pop(reduction); - reduction.undo(options, rowValues, colValues, solution, basis); + reduction.undo(options, rowValues, solution, basis); break; } } diff --git a/src/qpsolver/dantzigpricing.hpp b/src/qpsolver/dantzigpricing.hpp index 5a62dce7fb..3c305529b2 100644 --- a/src/qpsolver/dantzigpricing.hpp +++ b/src/qpsolver/dantzigpricing.hpp @@ -52,7 +52,7 @@ class DantzigPricing : public Pricing { public: DantzigPricing(Runtime& rt, Basis& bas, ReducedCosts& rc) - // clang-format off + // clang-format off : runtime(rt), basis(bas), redcosts(rc) {}; // clang-format on HighsInt price(const QpVector& x, const QpVector& gradient) { diff --git a/src/qpsolver/devexpricing.hpp b/src/qpsolver/devexpricing.hpp index 014d8ce283..6664a98611 100644 --- a/src/qpsolver/devexpricing.hpp +++ b/src/qpsolver/devexpricing.hpp @@ -58,7 +58,7 @@ class DevexPricing : public Pricing { : runtime(rt), basis(bas), redcosts(rc), - // clang-format off + // clang-format off weights(std::vector(rt.instance.num_var, 1.0)) {}; // clang-format on