Skip to content

Commit b2e3f1d

Browse files
committed
Fixed bug extracting knapsack solver results; formatted
1 parent 64101a4 commit b2e3f1d

File tree

3 files changed

+47
-10
lines changed

3 files changed

+47
-10
lines changed

check/TestCheckSolution.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ TEST_CASE("check-set-illegal-solution", "[highs_check_solution]") {
412412

413413
TEST_CASE("read-miplib-solution", "[highs_check_solution]") {
414414
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
415+
// NB This also tests the knapsack solver
415416
HighsLp lp;
416417
lp.num_col_ = 5;
417418
lp.num_row_ = 1;

check/TestMipSolver.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1031,7 +1031,7 @@ TEST_CASE("knapsack", "[highs_test_mip_solver]") {
10311031
lp.a_matrix_.index_ = {0, 1, 2, 3, 4, 5};
10321032
lp.a_matrix_.value_ = weight;
10331033
Highs h;
1034-
// highs.setOptionValue("output_flag", dev_run);
1034+
h.setOptionValue("output_flag", dev_run);
10351035
h.setOptionValue("presolve", kHighsOffString);
10361036
// h.setOptionValue("threads", 1);
10371037
double required_objective_value = 0;
@@ -1061,5 +1061,21 @@ TEST_CASE("knapsack", "[highs_test_mip_solver]") {
10611061
REQUIRE(h.getInfo().objective_function_value == required_objective_value);
10621062
}
10631063
}
1064+
1065+
// Now test with an infeasible knapsack problem
1066+
lp.a_matrix_.value_ = weight;
1067+
lp.row_lower_ = {-kHighsInf};
1068+
lp.row_upper_ = {-1};
1069+
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
1070+
REQUIRE(h.run() == HighsStatus::kOk);
1071+
REQUIRE(h.getModelStatus() == HighsModelStatus::kInfeasible);
1072+
1073+
// Now test with an feasible knapsack problem with fractional
1074+
// capacity
1075+
lp.row_upper_ = {capacity + 0.2};
1076+
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
1077+
REQUIRE(h.run() == HighsStatus::kOk);
1078+
REQUIRE(h.getModelStatus() == HighsModelStatus::kOptimal);
1079+
10641080
h.resetGlobalScheduler(true);
10651081
}

highs/mip/HighsPrimalHeuristics.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,26 @@ double knapsackRecurrence(const HighsInt num_item,
16811681
return dp_result[num_item][capacity];
16821682
}
16831683

1684+
/*
1685+
void knapsackReport(const HighsInt num_item,
1686+
const double capacity,
1687+
std::vector<std::vector<double>>& dp_result,
1688+
std::vector<std::vector<bool>>& use_item) {
1689+
1690+
printf("Knapsack data:\n ");
1691+
for (HighsInt iCol = 0; iCol < num_item + 1; iCol++)
1692+
printf(" %2d ", int(iCol-1));
1693+
printf("\n");
1694+
for (HighsInt iCap = 0; iCap < capacity + 1; iCap++) {
1695+
printf(" %2d", int(iCap));
1696+
for (HighsInt iCol = 0; iCol < num_item + 1; iCol++)
1697+
printf(" %s %3s", use_item[iCol][iCap] ? "T" : " ",
1698+
dp_result[iCol][iCap] == -1 ? " " :
1699+
std::to_string(int(dp_result[iCol][iCap])).c_str()); printf("\n");
1700+
}
1701+
}
1702+
*/
1703+
16841704
HighsModelStatus solveKnapsack(const HighsLogOptions& log_options,
16851705
const HighsInt num_item,
16861706
const std::vector<double>& value,
@@ -1700,6 +1720,7 @@ HighsModelStatus solveKnapsack(const HighsLogOptions& log_options,
17001720

17011721
solution_objective = knapsackRecurrence(num_item, value, weight, capacity,
17021722
dp_result, use_item);
1723+
// knapsackReport(num_item, capacity, dp_result, use_item);
17031724

17041725
// Deduce the solution
17051726
std::vector<HighsInt> knapsack_solution(num_item, 0);
@@ -1708,13 +1729,13 @@ HighsModelStatus solveKnapsack(const HighsLogOptions& log_options,
17081729
// entry of use is accessed
17091730
solution.resize(num_item);
17101731
HighsInt capacity_slack = capacity;
1711-
for (HighsInt iCol = 0; iCol < num_item; iCol++) {
1732+
for (HighsInt iCol = num_item; iCol > 0; iCol--) {
17121733
if (use_item[iCol][capacity_slack]) {
1713-
solution[iCol] = 1.0;
1714-
capacity_slack -= weight[iCol];
1734+
solution[iCol - 1] = 1.0;
1735+
capacity_slack -= weight[iCol - 1];
17151736
}
17161737
}
1717-
const HighsInt capacity_violation = std::max(0, -capacity_slack);
1738+
const HighsInt capacity_violation = std::max(HighsInt(0), -capacity_slack);
17181739
if (capacity_violation > 0) {
17191740
highsLogUser(
17201741
log_options, HighsLogType::kError,
@@ -1826,13 +1847,12 @@ HighsStatus HighsPrimalHeuristics::solveMipKnapsack() {
18261847
double abs_dl_solution_objective =
18271848
std::fabs(solution_objective - check_objective);
18281849
double rel_dl_solution_objective =
1829-
abs_dl_solution_objective /
1830-
(1.0 + std::fabs(mipsolver.solution_objective_));
1850+
abs_dl_solution_objective / (1.0 + std::fabs(solution_objective));
18311851
if (rel_dl_solution_objective > 1e-12) {
18321852
highsLogUser(log_options, HighsLogType::kError,
1833-
"HighsPrimalHeuristics::solveMipKnapsack() Relative optimal "
1834-
"objective value mismatch of %g\n",
1835-
rel_dl_solution_objective);
1853+
"HighsPrimalHeuristics::solveMipKnapsack() Optimal "
1854+
"objective value mismatch (abs = %g; rel = %g)\n",
1855+
abs_dl_solution_objective, rel_dl_solution_objective);
18361856
mipsolver.modelstatus_ = HighsModelStatus::kSolveError;
18371857
return solveMipKnapsackReturn(HighsStatus::kError);
18381858
}

0 commit comments

Comments
 (0)