Skip to content

Commit b9b74de

Browse files
committed
Clean up Knapsack MIPs logging
1 parent 0dde780 commit b9b74de

File tree

4 files changed

+66
-16
lines changed

4 files changed

+66
-16
lines changed

check/TestMipSolver.cpp

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,30 +1003,65 @@ TEST_CASE("issue-2432", "[highs_test_mip_solver]") {
10031003
}
10041004

10051005
TEST_CASE("knapsack", "[highs_test_mip_solver]") {
1006-
std::vector<double> cost = {10, 20, 25, 40, 60, 70};
1007-
std::vector<double> weight = {1, 2, 3, 6, 7, 4};
1008-
HighsInt num_item = cost.size();
1006+
const std::vector<double> value = {10, 20, 25, 40, 60, 70};
1007+
const std::vector<double> weight = {1, 2, 3, 6, 7, 4};
1008+
HighsInt num_item = value.size();
10091009
REQUIRE(num_item == weight.size());
1010-
1010+
const double capacity = 7;
1011+
const double offset = -100;
1012+
std::vector<double> neg_value(num_item);
1013+
std::vector<double> neg_weight(num_item);
1014+
for (HighsInt iItem = 0; iItem < num_item; iItem++) {
1015+
neg_value[iItem] = -value[iItem];
1016+
neg_weight[iItem] = -weight[iItem];
1017+
}
10111018
HighsLp lp;
10121019
lp.sense_ = ObjSense::kMaximize;
1020+
lp.offset_ = offset;
10131021
lp.num_col_ = 6;
10141022
lp.num_row_ = 1;
1015-
lp.col_cost_ = cost;
1023+
lp.col_cost_ = value;
10161024
lp.col_lower_.assign(lp.num_col_, 0);
10171025
lp.col_upper_.assign(lp.num_col_, 1);
10181026
lp.integrality_.assign(lp.num_col_, HighsVarType::kInteger);
10191027
lp.row_lower_ = {-kHighsInf};
1020-
lp.row_upper_ = {7};
1028+
lp.row_upper_ = {capacity};
10211029
lp.a_matrix_.format_ = MatrixFormat::kRowwise;
10221030
lp.a_matrix_.start_ = {0, 6};
10231031
lp.a_matrix_.index_ = {0, 1, 2, 3, 4, 5};
10241032
lp.a_matrix_.value_ = weight;
10251033
Highs h;
1034+
// highs.setOptionValue("output_flag", dev_run);
10261035
h.setOptionValue("presolve", kHighsOffString);
1027-
h.setOptionValue("threads", 1);
1028-
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
1029-
REQUIRE(h.run() == HighsStatus::kOk);
1036+
// h.setOptionValue("threads", 1);
1037+
double required_objective_value = 0;
1038+
for (int sense = 0; sense < 2; sense++) {
1039+
for (int sign = 0; sign < 2; sign++) {
1040+
if (sense == 0) {
1041+
lp.sense_ = ObjSense::kMaximize;
1042+
lp.col_cost_ = value;
1043+
required_objective_value = 0;
1044+
} else {
1045+
lp.sense_ = ObjSense::kMinimize;
1046+
lp.col_cost_ = neg_value;
1047+
required_objective_value = 2.0e0 * offset;
1048+
}
1049+
if (sign == 0) {
1050+
lp.a_matrix_.value_ = weight;
1051+
lp.row_lower_ = {-kHighsInf};
1052+
lp.row_upper_ = {capacity};
1053+
} else {
1054+
lp.a_matrix_.value_ = neg_weight;
1055+
lp.row_lower_ = {-capacity};
1056+
lp.row_upper_ = {kHighsInf};
1057+
}
1058+
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
1059+
REQUIRE(h.run() == HighsStatus::kOk);
1060+
REQUIRE(h.getModelStatus() == HighsModelStatus::kOptimal);
1061+
REQUIRE(h.getInfo().objective_function_value == required_objective_value);
1062+
}
1063+
}
1064+
h.resetGlobalScheduler(true);
10301065
}
10311066

10321067

highs/mip/HighsMipSolver.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include "mip/HighsMipSolver.h"
99

1010
#include "lp_data/HighsLpUtils.h"
11-
#include "lp_data/HighsModelUtils.h"
11+
#include "lp_data/HighsModelUtils.h" // For utilModelStatusToString
1212
#include "mip/HighsCliqueTable.h"
1313
#include "mip/HighsCutPool.h"
1414
#include "mip/HighsDomain.h"
@@ -98,7 +98,8 @@ void HighsMipSolver::run() {
9898
// Solve as a knapsack
9999
HighsStatus call_status = mipdata_->heuristics.solveMipKnapsack();
100100
assert(call_status == HighsStatus::kOk);
101-
cleanupSolve();
101+
const bool mip_logging = false;
102+
cleanupSolve(mip_logging);
102103
return;
103104
}
104105

@@ -704,9 +705,9 @@ void HighsMipSolver::run() {
704705
cleanupSolve();
705706
}
706707

707-
void HighsMipSolver::cleanupSolve() {
708-
// Force a final logging line
709-
mipdata_->printDisplayLine(kSolutionSourceCleanup);
708+
void HighsMipSolver::cleanupSolve(const bool mip_logging) {
709+
// Generally force a final MIP logging line
710+
if (mip_logging) mipdata_->printDisplayLine(kSolutionSourceCleanup);
710711
// Stop the solve clock - which won't be running if presolve
711712
// determines the model status
712713
if (analysis_.mipTimerRunning(kMipClockSolve))
@@ -865,7 +866,7 @@ void HighsMipSolver::cleanupSolve() {
865866
(long long unsigned)mipdata_->heuristic_lp_iterations);
866867
const HighsKnapsackData& knapsack_data = this->mipdata_->knapsack_data_;
867868
highsLogUser(options_mip_->log_options, HighsLogType::kInfo,
868-
" Knapsack sub-MIPs %d\n", knapsack_data.num_problem);
869+
" Knapsack MIPs %d\n", knapsack_data.num_problem);
869870
if (knapsack_data.num_problem > 0)
870871
highsLogUser(options_mip_->log_options, HighsLogType::kInfo,
871872
" Mean var count %d\n Mean capacity %d\n",

highs/mip/HighsMipSolver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class HighsMipSolver {
9595
}
9696

9797
mutable HighsTimer timer_;
98-
void cleanupSolve();
98+
void cleanupSolve(const bool mip_logging = true);
9999

100100
void runPresolve(const HighsInt presolve_reduction_limit);
101101
const HighsLp& getPresolvedModel() const;

highs/mip/HighsPrimalHeuristics.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "io/HighsIO.h"
1515
#include "lp_data/HConst.h"
1616
#include "lp_data/HighsLpUtils.h"
17+
#include "lp_data/HighsModelUtils.h" // For utilModelStatusToString
1718
#include "mip/HighsCutGeneration.h"
1819
#include "mip/HighsDomainChange.h"
1920
#include "mip/HighsLpRelaxation.h"
@@ -1717,6 +1718,11 @@ HighsModelStatus solveKnapsack(const HighsLogOptions& log_options,
17171718

17181719
HighsStatus HighsPrimalHeuristics::solveMipKnapsackReturn(const HighsStatus& return_status) {
17191720
const HighsLp& lp = *(mipsolver.model_);
1721+
std::stringstream ss;
1722+
if (!mipsolver.submip) {
1723+
ss.str(std::string());
1724+
ss << "MIP is a knapsack problem: ";
1725+
}
17201726
if (mipsolver.modelstatus_ == HighsModelStatus::kOptimal) {
17211727
// mipsolver.solution_objective_ is the objective value for the
17221728
// original problem - using the offset and ignoring the
@@ -1731,9 +1737,17 @@ HighsStatus HighsPrimalHeuristics::solveMipKnapsackReturn(const HighsStatus& ret
17311737
mipsolver.mipdata_->lower_bound = mipsolver_objective;
17321738
mipsolver.mipdata_->upper_bound = mipsolver_objective;
17331739
mipsolver.gap_ = 0;
1740+
if (!mipsolver.submip)
1741+
ss << highsFormatToString("optimal objective by dynamic programming is %g",
1742+
mipsolver.solution_objective_);
17341743
} else {
1744+
if (!mipsolver.submip)
1745+
ss << highsFormatToString("model status is %s",
1746+
utilModelStatusToString(mipsolver.modelstatus_).c_str());
17351747
mipsolver.solution_.clear();
17361748
}
1749+
if (!mipsolver.submip) highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
1750+
"\n%s\n", ss.str().c_str());
17371751
return return_status;
17381752
}
17391753

0 commit comments

Comments
 (0)