Skip to content

Commit 644c9b5

Browse files
committed
More informative logging for error checking and KKT errors in Highs::postsolve
1 parent e1d1477 commit 644c9b5

File tree

6 files changed

+88
-18
lines changed

6 files changed

+88
-18
lines changed

check/TestPresolve.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,3 +734,27 @@ TEST_CASE("presolve-issue-2446", "[highs_test_presolve]") {
734734
REQUIRE(highs.presolve() == HighsStatus::kOk);
735735
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kReduced);
736736
}
737+
738+
TEST_CASE("presolve-solve-postsolve-no-col-dual", "[highs_test_presolve]") {
739+
Highs highs;
740+
// highs.setOptionValue("output_flag", dev_run);
741+
std::string model_file =
742+
std::string(HIGHS_DIR) + "/check/instances/afiro.mps";
743+
highs.readModel(model_file);
744+
highs.presolve();
745+
HighsLp presolved_lp = highs.getPresolvedLp();
746+
Highs highs1;
747+
// highs1.setOptionValue("output_flag", dev_run);
748+
highs1.setOptionValue("presolve", kHighsOffString);
749+
highs1.setOptionValue("solver", kPdlpString);
750+
highs1.passModel(presolved_lp);
751+
highs1.run();
752+
HighsSolution solution = highs1.getSolution();
753+
754+
// Perform postsolve using the optimal solution and basis for the
755+
// presolved model
756+
solution.col_dual.clear();
757+
highs.postsolve(solution);
758+
759+
highs.resetGlobalScheduler(true);
760+
}

highs/interfaces/highs_c_api.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ HighsInt Highs_mipCall(const HighsInt num_col, const HighsInt num_row,
108108
}
109109

110110
highs.resetGlobalScheduler(true);
111-
111+
112112
return (HighsInt)status;
113113
}
114114

@@ -173,9 +173,9 @@ HighsInt Highs_qpCall(
173173

174174
void* Highs_create(void) { return new Highs(); }
175175

176-
void Highs_destroy(void* highs) {
176+
void Highs_destroy(void* highs) {
177177
Highs::resetGlobalScheduler(true);
178-
delete (Highs*)highs;
178+
delete (Highs*)highs;
179179
}
180180

181181
const char* Highs_version(void) { return highsVersion(); }

highs/lp_data/Highs.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4105,8 +4105,10 @@ HighsStatus Highs::callRunPostsolve(const HighsSolution& solution,
41054105

41064106
// Must at least have a primal column solution of the right size
41074107
if (HighsInt(solution.col_value.size()) != presolved_lp.num_col_) {
4108-
highsLogUser(options_.log_options, HighsLogType::kError,
4109-
"Primal solution provided to postsolve is incorrect size\n");
4108+
highsLogUser(
4109+
options_.log_options, HighsLogType::kError,
4110+
"Primal solution provided to postsolve is of size %d rather than %d\n",
4111+
int(solution.col_value.size()), int(presolved_lp.num_col_));
41104112
return HighsStatus::kError;
41114113
}
41124114
// Check any basis that is supplied
@@ -4168,7 +4170,7 @@ HighsStatus Highs::callRunPostsolve(const HighsSolution& solution,
41684170
"Postsolve performed for MIP, but model status cannot be known\n");
41694171
} else {
41704172
highsLogUser(options_.log_options, HighsLogType::kError,
4171-
"Postsolve return status is %d\n", (int)postsolve_status);
4173+
"Postsolve return status is %d\n", int(postsolve_status));
41724174
setHighsModelStatusAndClearSolutionAndBasis(
41734175
HighsModelStatus::kPostsolveError);
41744176
}
@@ -4183,10 +4185,20 @@ HighsStatus Highs::callRunPostsolve(const HighsSolution& solution,
41834185
presolve_.data_.recovered_solution_.row_dual.size() > 0 ||
41844186
presolve_.data_.recovered_solution_.dual_valid;
41854187
if (dual_supplied) {
4186-
if (!isDualSolutionRightSize(presolved_lp,
4187-
presolve_.data_.recovered_solution_)) {
4188+
if (!isRowDualSolutionRightSize(presolved_lp,
4189+
presolve_.data_.recovered_solution_)) {
4190+
highsLogUser(options_.log_options, HighsLogType::kError,
4191+
"Row dual solution provided to postsolve is of size %d "
4192+
"rather than %d\n",
4193+
int(solution.row_dual.size()), int(presolved_lp.num_row_));
4194+
return HighsStatus::kError;
4195+
}
4196+
if (!isColDualSolutionRightSize(presolved_lp,
4197+
presolve_.data_.recovered_solution_)) {
41884198
highsLogUser(options_.log_options, HighsLogType::kError,
4189-
"Dual solution provided to postsolve is incorrect size\n");
4199+
"Column dual solution provided to postsolve is of size %d "
4200+
"rather than %d\n",
4201+
int(solution.col_dual.size()), int(presolved_lp.num_col_));
41904202
return HighsStatus::kError;
41914203
}
41924204
presolve_.data_.recovered_solution_.dual_valid = true;
@@ -4277,6 +4289,9 @@ HighsStatus Highs::callRunPostsolve(const HighsSolution& solution,
42774289
getKktFailures(this->options_, is_qp, this->model_.lp_,
42784290
this->model_.lp_.col_cost_, this->solution_, this->info_,
42794291
get_residuals);
4292+
highsLogUser(options_.log_options, HighsLogType::kInfo, "\n");
4293+
reportLpKktFailures(this->model_.lp_, this->options_, this->info_,
4294+
"After postsolve");
42804295
if (info_.num_primal_infeasibilities == 0 &&
42814296
info_.num_dual_infeasibilities == 0) {
42824297
model_status_ = HighsModelStatus::kOptimal;
@@ -4285,7 +4300,7 @@ HighsStatus Highs::callRunPostsolve(const HighsSolution& solution,
42854300
}
42864301
highsLogUser(
42874302
options_.log_options, HighsLogType::kInfo,
4288-
"Pure postsolve yields primal %ssolution, but no basis: model "
4303+
"\nPure postsolve yields primal %ssolution, but no basis: model "
42894304
"status is %s\n",
42904305
solution_.dual_valid ? "and dual " : "",
42914306
modelStatusToString(model_status_).c_str());

highs/lp_data/HighsInterface.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2665,7 +2665,7 @@ HighsStatus Highs::lpKktCheck(const std::string& message) {
26652665
// highsLogUser(options.log_options, HighsLogType::kInfo,
26662666
// "Highs::lpKktCheck: %s\n", message.c_str());
26672667
if (this->model_status_ == HighsModelStatus::kOptimal)
2668-
reportLpKktFailures(model_.lp_, options, info, "LP");
2668+
reportLpKktFailures(model_.lp_, options, info);
26692669
// get_residuals is false when there is a valid basis, since
26702670
// residual errors are assumed to be small, so
26712671
// info.num_primal_residual_errors = -1, since they aren't

highs/lp_data/HighsSolution.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,15 +1665,35 @@ bool isBasisConsistent(const HighsLp& lp, const HighsBasis& basis) {
16651665
return num_basic_variables == lp.num_row_;
16661666
}
16671667

1668+
bool isColPrimalSolutionRightSize(const HighsLp& lp,
1669+
const HighsSolution& solution) {
1670+
return solution.col_value.size() == static_cast<size_t>(lp.num_col_);
1671+
}
1672+
1673+
bool isRowPrimalSolutionRightSize(const HighsLp& lp,
1674+
const HighsSolution& solution) {
1675+
return solution.row_value.size() == static_cast<size_t>(lp.num_row_);
1676+
}
1677+
16681678
bool isPrimalSolutionRightSize(const HighsLp& lp,
16691679
const HighsSolution& solution) {
1670-
return solution.col_value.size() == static_cast<size_t>(lp.num_col_) &&
1671-
solution.row_value.size() == static_cast<size_t>(lp.num_row_);
1680+
return isColPrimalSolutionRightSize(lp, solution) &&
1681+
isRowPrimalSolutionRightSize(lp, solution);
1682+
}
1683+
1684+
bool isColDualSolutionRightSize(const HighsLp& lp,
1685+
const HighsSolution& solution) {
1686+
return solution.col_dual.size() == static_cast<size_t>(lp.num_col_);
1687+
}
1688+
1689+
bool isRowDualSolutionRightSize(const HighsLp& lp,
1690+
const HighsSolution& solution) {
1691+
return solution.row_dual.size() == static_cast<size_t>(lp.num_row_);
16721692
}
16731693

16741694
bool isDualSolutionRightSize(const HighsLp& lp, const HighsSolution& solution) {
1675-
return solution.col_dual.size() == static_cast<size_t>(lp.num_col_) &&
1676-
solution.row_dual.size() == static_cast<size_t>(lp.num_row_);
1695+
return isColDualSolutionRightSize(lp, solution) &&
1696+
isRowDualSolutionRightSize(lp, solution);
16771697
}
16781698

16791699
bool isSolutionRightSize(const HighsLp& lp, const HighsSolution& solution) {
@@ -1687,7 +1707,7 @@ bool isBasisRightSize(const HighsLp& lp, const HighsBasis& basis) {
16871707
}
16881708

16891709
void reportLpKktFailures(const HighsLp& lp, const HighsOptions& options,
1690-
const HighsInfo& info, const std::string& solver) {
1710+
const HighsInfo& info, const std::string& message) {
16911711
const HighsLogOptions& log_options = options.log_options;
16921712
double primal_feasibility_tolerance = options.primal_feasibility_tolerance;
16931713
double dual_feasibility_tolerance = options.dual_feasibility_tolerance;
@@ -1714,7 +1734,8 @@ void reportLpKktFailures(const HighsLp& lp, const HighsOptions& options,
17141734
HighsLogType log_type =
17151735
has_kkt_failures ? HighsLogType::kWarning : HighsLogType::kInfo;
17161736

1717-
highsLogUser(log_options, log_type, "LP solution KKT conditions\n");
1737+
highsLogUser(log_options, log_type, "LP solution KKT conditions%s%s\n",
1738+
message == "" ? "" : ": ", message == "" ? "" : message.c_str());
17181739

17191740
highsLogUser(
17201741
log_options, HighsLogType::kInfo,

highs/lp_data/HighsSolution.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,24 @@ void resetModelStatusAndHighsInfo(HighsModelStatus& model_status,
148148
HighsInfo& highs_info);
149149
bool isBasisConsistent(const HighsLp& lp, const HighsBasis& basis);
150150

151+
bool isColPrimalSolutionRightSize(const HighsLp& lp,
152+
const HighsSolution& solution);
153+
bool isRowPrimalSolutionRightSize(const HighsLp& lp,
154+
const HighsSolution& solution);
151155
bool isPrimalSolutionRightSize(const HighsLp& lp,
152156
const HighsSolution& solution);
157+
158+
bool isColDualSolutionRightSize(const HighsLp& lp,
159+
const HighsSolution& solution);
160+
bool isRowDualSolutionRightSize(const HighsLp& lp,
161+
const HighsSolution& solution);
153162
bool isDualSolutionRightSize(const HighsLp& lp, const HighsSolution& solution);
163+
154164
bool isSolutionRightSize(const HighsLp& lp, const HighsSolution& solution);
155165
bool isBasisRightSize(const HighsLp& lp, const HighsBasis& basis);
156166

157167
void reportLpKktFailures(const HighsLp& lp, const HighsOptions& options,
158168
const HighsInfo& highs_info,
159-
const std::string& solver = "");
169+
const std::string& message = "");
160170

161171
#endif // LP_DATA_HIGHSSOLUTION_H_

0 commit comments

Comments
 (0)