Skip to content

Commit f1f54b8

Browse files
committed
Improved LP KKT failure logging
1 parent 8a31680 commit f1f54b8

File tree

4 files changed

+42
-32
lines changed

4 files changed

+42
-32
lines changed

highs/Highs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1700,7 +1700,7 @@ class Highs {
17001700
bool qFormatOk(const HighsInt num_nz, const HighsInt format);
17011701
void clearZeroHessian();
17021702
HighsStatus checkOptimality(const std::string& solver_type);
1703-
HighsStatus lpKktCheck(const std::string& message);
1703+
HighsStatus lpKktCheck(const HighsLp& lp, const std::string& message = "");
17041704
HighsStatus invertRequirementError(std::string method_name) const;
17051705

17061706
HighsStatus handleInfCost();

highs/lp_data/Highs.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,6 +1626,9 @@ HighsStatus Highs::optimizeModel() {
16261626
presolve_.data_.recovered_solution_ = solution_;
16271627
presolve_.data_.recovered_basis_ = basis_;
16281628

1629+
if (model_presolve_status_ == HighsPresolveStatus::kReduced)
1630+
this->lpKktCheck(presolve_.getReducedProblem(), "Before postsolve");
1631+
16291632
this_postsolve_time = -timer_.read(timer_.postsolve_clock);
16301633
timer_.start(timer_.postsolve_clock);
16311634
HighsPostsolveStatus postsolve_status = runPostsolve();
@@ -1634,8 +1637,11 @@ HighsStatus Highs::optimizeModel() {
16341637
presolve_.info_.postsolve_time = this_postsolve_time;
16351638

16361639
if (postsolve_status == HighsPostsolveStatus::kSolutionRecovered) {
1637-
highsLogDev(log_options, HighsLogType::kVerbose,
1638-
"Postsolve finished\n");
1640+
// Indicate that nontrivial postsolve has been performed
1641+
if (model_presolve_status_ == HighsPresolveStatus::kReduced ||
1642+
model_presolve_status_ == HighsPresolveStatus::kReducedToEmpty)
1643+
highsLogUser(log_options, HighsLogType::kInfo,
1644+
"Performed postsolve\n");
16391645
// Set solution and its status
16401646
solution_.clear();
16411647
solution_ = presolve_.data_.recovered_solution_;
@@ -1647,7 +1653,6 @@ HighsStatus Highs::optimizeModel() {
16471653
// and IPX determined optimality
16481654
solution_.dual_valid = true;
16491655
this->invalidateBasis();
1650-
this->lpKktCheck("After postsolve");
16511656
} else {
16521657
//
16531658
// Hot-start the simplex solver for the incumbent LP
@@ -1780,7 +1785,7 @@ HighsStatus Highs::optimizeModel() {
17801785
// Unless the model status was determined using the strictly reduced LP, the
17811786
// HiGHS info is valid
17821787
if (!no_incumbent_lp_solution_or_basis) {
1783-
this->lpKktCheck("On exit from optimizeModel()");
1788+
this->lpKktCheck(this->model_.lp_);
17841789
info_.valid = true;
17851790
}
17861791

@@ -4301,9 +4306,6 @@ HighsStatus Highs::callRunPostsolve(const HighsSolution& solution,
43014306
getKktFailures(this->options_, is_qp, this->model_.lp_,
43024307
this->model_.lp_.col_cost_, this->solution_, this->info_,
43034308
get_residuals);
4304-
highsLogUser(options_.log_options, HighsLogType::kInfo, "\n");
4305-
reportLpKktFailures(this->model_.lp_, this->options_, this->info_,
4306-
"After postsolve");
43074309
if (info_.num_primal_infeasibilities == 0 &&
43084310
info_.num_dual_infeasibilities == 0) {
43094311
model_status_ = HighsModelStatus::kOptimal;

highs/lp_data/HighsInterface.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ void Highs::reportModelStats() const {
5151
if (non_continuous) {
5252
problem_type = "MIQP";
5353
} else {
54-
problem_type = "QP ";
54+
problem_type = "QP";
5555
}
5656
} else {
5757
if (non_continuous) {
58-
problem_type = "MIP ";
58+
problem_type = "MIP";
5959
} else {
60-
problem_type = "LP ";
60+
problem_type = "LP";
6161
}
6262
}
6363
const HighsInt a_num_nz = lp.a_matrix_.numNz();
@@ -66,17 +66,20 @@ void Highs::reportModelStats() const {
6666
highsLogDev(log_options, HighsLogType::kInfo, "%4s : %s\n",
6767
problem_type.c_str(), lp.model_name_.c_str());
6868
highsLogDev(log_options, HighsLogType::kInfo,
69-
"Rows : %" HIGHSINT_FORMAT "\n", lp.num_row_);
69+
"Row%s : %" HIGHSINT_FORMAT "\n",
70+
lp.num_row_, lp.num_row_ > 1 ? "s" : "");
7071
highsLogDev(log_options, HighsLogType::kInfo,
71-
"Cols : %" HIGHSINT_FORMAT "\n", lp.num_col_);
72+
"Col%s : %" HIGHSINT_FORMAT "\n",
73+
lp.num_col_, lp.num_col_ > 1 ? "s" : "");
7274
if (q_num_nz) {
7375
highsLogDev(log_options, HighsLogType::kInfo,
7476
"Matrix Nz : %" HIGHSINT_FORMAT "\n", a_num_nz);
7577
highsLogDev(log_options, HighsLogType::kInfo,
7678
"Hessian Nz: %" HIGHSINT_FORMAT "\n", q_num_nz);
7779
} else {
7880
highsLogDev(log_options, HighsLogType::kInfo,
79-
"Nonzeros : %" HIGHSINT_FORMAT "\n", a_num_nz);
81+
"Nonzero%s : %" HIGHSINT_FORMAT "\n",
82+
a_num_nz, a_num_nz > 1 ? "s" : "");
8083
}
8184
if (num_integer)
8285
highsLogDev(log_options, HighsLogType::kInfo,
@@ -93,16 +96,19 @@ void Highs::reportModelStats() const {
9396
std::stringstream stats_line;
9497
stats_line << problem_type;
9598
if (lp.model_name_.length()) stats_line << " " << lp.model_name_;
96-
stats_line << " has " << lp.num_row_ << " rows; " << lp.num_col_ << " cols";
99+
stats_line << " has "
100+
<< lp.num_row_ << " row" << (lp.num_row_ > 1 ? "s" : "") << "; "
101+
<< lp.num_col_ << " col" << (lp.num_col_ > 1 ? "s" : "");
97102
if (q_num_nz) {
98-
stats_line << "; " << a_num_nz << " matrix nonzeros";
99-
stats_line << "; " << q_num_nz << " Hessian nonzeros";
103+
stats_line << "; " << a_num_nz << " matrix nonzero" << (a_num_nz > 1 ? "s" : "");
104+
stats_line << "; " << q_num_nz << " Hessian nonzero" << (q_num_nz > 1 ? "s" : "");
100105
} else {
101-
stats_line << "; " << a_num_nz << " nonzeros";
106+
stats_line << "; " << a_num_nz << " nonzero" << (a_num_nz > 1 ? "s" : "");
102107
}
103108
if (num_integer)
104-
stats_line << "; " << num_integer << " integer variables (" << num_binary
105-
<< " binary)";
109+
stats_line << "; "
110+
<< num_integer << " integer variable" << (a_num_nz > 1 ? "s" : "") << " ("
111+
<< num_binary << " binary)";
106112
if (num_semi_continuous)
107113
stats_line << "; " << num_semi_continuous << " semi-continuous variables";
108114
if (num_semi_integer)
@@ -2636,7 +2642,7 @@ HighsStatus Highs::checkOptimality(const std::string& solver_type) {
26362642
return HighsStatus::kError;
26372643
}
26382644

2639-
HighsStatus Highs::lpKktCheck(const std::string& message) {
2645+
HighsStatus Highs::lpKktCheck(const HighsLp& lp, const std::string& message) {
26402646
if (!this->solution_.value_valid) return HighsStatus::kOk;
26412647
// Must have dual values for an LP if there are primal values
26422648
assert(this->solution_.dual_valid);
@@ -2657,15 +2663,13 @@ HighsStatus Highs::lpKktCheck(const std::string& message) {
26572663
optimality_tolerance = options.kkt_tolerance;
26582664
}
26592665
info.objective_function_value =
2660-
model_.lp_.objectiveValue(solution_.col_value);
2666+
lp.objectiveValue(solution_.col_value);
26612667
HighsPrimalDualErrors primal_dual_errors;
26622668
const bool get_residuals = !basis_.valid;
2663-
getLpKktFailures(options, model_.lp_, solution, basis_, info,
2669+
getLpKktFailures(options, lp, solution, basis_, info,
26642670
primal_dual_errors, get_residuals);
2665-
// highsLogUser(options.log_options, HighsLogType::kInfo,
2666-
// "Highs::lpKktCheck: %s\n", message.c_str());
26672671
if (this->model_status_ == HighsModelStatus::kOptimal)
2668-
reportLpKktFailures(model_.lp_, options, info);
2672+
reportLpKktFailures(lp, options, info, message);
26692673
// get_residuals is false when there is a valid basis, since
26702674
// residual errors are assumed to be small, so
26712675
// info.num_primal_residual_errors = -1, since they aren't
@@ -2727,7 +2731,7 @@ HighsStatus Highs::lpKktCheck(const std::string& message) {
27272731
if (info.primal_dual_objective_error > optimality_tolerance) {
27282732
// Ignore primal-dual objective errors if both objectives are small
27292733
const bool ok_dual_objective = computeDualObjectiveValue(
2730-
nullptr, this->model_.lp_, this->solution_, local_dual_objective);
2734+
nullptr, lp, this->solution_, local_dual_objective);
27312735
assert(ok_dual_objective);
27322736
if (info.objective_function_value * info.objective_function_value >
27332737
optimality_tolerance &&
@@ -2921,6 +2925,7 @@ HighsStatus Highs::lpKktCheck(const std::string& message) {
29212925
highsLogUser(log_options, HighsLogType::kWarning,
29222926
"Model status changed from \"Unknown\" to \"Optimal\"\n");
29232927
}
2928+
highsLogUser(log_options, HighsLogType::kInfo, "\n");
29242929
return HighsStatus::kOk;
29252930
}
29262931

highs/lp_data/HighsLpUtils.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,17 +1808,20 @@ void reportLpDimensions(const HighsLogOptions& log_options, const HighsLp& lp) {
18081808
else
18091809
lp_num_nz = lp.a_matrix_.start_[lp.num_col_];
18101810
highsLogUser(log_options, HighsLogType::kInfo,
1811-
"LP has %" HIGHSINT_FORMAT " rows, %" HIGHSINT_FORMAT " columns",
1812-
lp.num_row_, lp.num_col_);
1811+
"LP has %" HIGHSINT_FORMAT " row%s, %" HIGHSINT_FORMAT " column%s",
1812+
lp.num_row_, lp.num_row_ > 1 ? "s" : "",
1813+
lp.num_col_, lp.num_col_ > 1 ? "s" : "");
18131814
HighsInt num_int = getNumInt(lp);
18141815
if (num_int) {
18151816
highsLogUser(log_options, HighsLogType::kInfo,
18161817
", %" HIGHSINT_FORMAT " nonzeros and %" HIGHSINT_FORMAT
1817-
" integer columns\n",
1818-
lp_num_nz, num_int);
1818+
" integer column%s\n",
1819+
lp_num_nz, lp_num_nz > 1 ? "s" : "",
1820+
num_int, num_int > 1 ? "s" : "");
18191821
} else {
18201822
highsLogUser(log_options, HighsLogType::kInfo,
1821-
" and %" HIGHSINT_FORMAT " nonzeros\n", lp_num_nz, num_int);
1823+
" and %" HIGHSINT_FORMAT " nonzero%s\n",
1824+
lp_num_nz, lp_num_nz > 1 ? "s" : "");
18221825
}
18231826
}
18241827

0 commit comments

Comments
 (0)