Skip to content

Commit c7cdd52

Browse files
committed
After refactoring it still works
1 parent d7dd70c commit c7cdd52

File tree

3 files changed

+75
-54
lines changed

3 files changed

+75
-54
lines changed

highs/mip/HighsMipSolver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ void HighsMipSolver::run() {
9696
mipdata_->knapsack_data_.sum_variables += orig_model_->num_col_;
9797
mipdata_->knapsack_data_.sum_capacity += capacity;
9898
// Solve as a knapsack
99-
HighsStatus call_status = mipdata_->heuristics.solveKnapsack();
99+
HighsStatus call_status = mipdata_->heuristics.solveMipKnapsack();
100100
assert(call_status == HighsStatus::kOk);
101101
cleanupSolve();
102102
return;

highs/mip/HighsPrimalHeuristics.cpp

Lines changed: 72 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,31 +1650,72 @@ void HighsPrimalHeuristics::flushStatistics() {
16501650
double knapsackRecurrence(const std::vector<HighsInt>& weight,
16511651
const std::vector<double>& value,
16521652
const HighsInt num_item,
1653-
const double rhs,
1653+
const double capacity,
16541654
std::vector<std::vector<double>> &dp_result,
16551655
std::vector<std::vector<bool>> &use_item) {
1656-
if (num_item == 0 || rhs == 0)
1656+
if (num_item == 0 || capacity == 0)
16571657
return 0; // Base case
16581658

1659-
if (dp_result[num_item][rhs] != -1) return dp_result[num_item][rhs]; // Check if result is already computed
1659+
if (dp_result[num_item][capacity] != -1) return dp_result[num_item][capacity]; // Check if result is already computed
16601660

16611661
// Exclude the item
1662-
double exclude = knapsackRecurrence(weight, value, num_item-1, rhs, dp_result, use_item);
1662+
double exclude = knapsackRecurrence(weight, value, num_item-1, capacity, dp_result, use_item);
16631663

16641664
// Include the item (if it fits in the knapsack)
16651665
double include = 0;
1666-
if (weight[num_item-1] <= rhs)
1667-
include = value[num_item-1] + knapsackRecurrence(weight, value, num_item-1, rhs - weight[num_item-1], dp_result, use_item);
1666+
if (weight[num_item-1] <= capacity)
1667+
include = value[num_item-1] + knapsackRecurrence(weight, value, num_item-1, capacity - weight[num_item-1], dp_result, use_item);
16681668

1669-
// Store whether the item is used with this RHS
1670-
use_item[num_item][rhs] = include > exclude;
1669+
// Store whether the item is used with this capacity
1670+
use_item[num_item][capacity] = include > exclude;
16711671
// Store the result
1672-
dp_result[num_item][rhs] = use_item[num_item][rhs] ? include : exclude;
1672+
dp_result[num_item][capacity] = use_item[num_item][capacity] ? include : exclude;
16731673

1674-
return dp_result[num_item][rhs];
1674+
return dp_result[num_item][capacity];
16751675

16761676
}
1677-
HighsStatus HighsPrimalHeuristics::solveKnapsackReturn(const HighsStatus& return_status) {
1677+
1678+
HighsModelStatus solveKnapsack(const HighsLogOptions& log_options,
1679+
const HighsInt num_item,
1680+
const std::vector<double>& value,
1681+
const std::vector<HighsInt>& weight,
1682+
const HighsInt capacity,
1683+
double& solution_objective,
1684+
std::vector<double>& solution) {
1685+
assert(capacity > 0);
1686+
1687+
// Set up the DP result array, indicating that no optimal objective
1688+
// values are known
1689+
std::vector<std::vector<double>> dp_result(num_item + 1, std::vector<double>(capacity + 1, -1));
1690+
// Set up the item use array, indicating that items are not used
1691+
std::vector<std::vector<bool>> use_item(num_item + 1, std::vector<bool>(capacity + 1, false));
1692+
1693+
solution_objective = knapsackRecurrence(weight, value, num_item, capacity, dp_result, use_item);
1694+
1695+
// Deduce the solution
1696+
std::vector<HighsInt> knapsack_solution(num_item, 0);
1697+
// Variables are set to 1 if "used", and have to track the RHS of
1698+
// the subproblem after variables are assigned so that the correct
1699+
// entry of use is accessed
1700+
solution.resize(num_item);
1701+
HighsInt capacity_slack = capacity;
1702+
for (HighsInt iCol = 0; iCol < num_item; iCol++) {
1703+
if (use_item[iCol][capacity_slack]) {
1704+
solution[iCol] = 1.0;
1705+
capacity_slack -= weight[iCol];
1706+
}
1707+
}
1708+
const HighsInt capacity_violation = std::max(0, -capacity_slack);
1709+
if (capacity_violation > 0) {
1710+
highsLogUser(log_options, HighsLogType::kError,
1711+
"HighsPrimalHeuristics::solveKnapsack() Capacity violation is (%d)\n",
1712+
int(capacity_violation));
1713+
return HighsModelStatus::kSolveError;
1714+
}
1715+
return HighsModelStatus::kOptimal;
1716+
}
1717+
1718+
HighsStatus HighsPrimalHeuristics::solveMipKnapsackReturn(const HighsStatus& return_status) {
16781719
const HighsLp& lp = *(mipsolver.model_);
16791720
if (mipsolver.modelstatus_ == HighsModelStatus::kOptimal) {
16801721
// mipsolver.solution_objective_ is the objective value for the
@@ -1690,14 +1731,16 @@ HighsStatus HighsPrimalHeuristics::solveKnapsackReturn(const HighsStatus& return
16901731
mipsolver.mipdata_->lower_bound = mipsolver_objective;
16911732
mipsolver.mipdata_->upper_bound = mipsolver_objective;
16921733
mipsolver.gap_ = 0;
1734+
} else {
1735+
mipsolver.solution_.clear();
16931736
}
16941737
return return_status;
1695-
16961738
}
16971739

1698-
HighsStatus HighsPrimalHeuristics::solveKnapsack() {
1740+
HighsStatus HighsPrimalHeuristics::solveMipKnapsack() {
16991741
HighsLp lp = *(mipsolver.model_);
17001742
// const HighsLp& lp = mipsolver.mipdata_->model_;
1743+
const HighsLogOptions& log_options = mipsolver.options_mip_->log_options;
17011744
HighsInt capacity_;
17021745
assert(lp.isKnapsack(capacity_));
17031746
const HighsInt capacity = capacity_;
@@ -1706,13 +1749,13 @@ HighsStatus HighsPrimalHeuristics::solveKnapsack() {
17061749
const HighsInt constraint_sign = upper ? 1 : -1;
17071750
if (capacity < 0) {
17081751
mipsolver.modelstatus_ = HighsModelStatus::kInfeasible;
1709-
return solveKnapsackReturn(HighsStatus::kOk);
1752+
return solveMipKnapsackReturn(HighsStatus::kOk);
17101753
} else if (capacity == 0) {
17111754
// Trivial knapsack with zero solution
17121755
mipsolver.solution_.assign(lp.num_col_, 0);
17131756
mipsolver.solution_objective_ = lp.offset_;
17141757
mipsolver.modelstatus_ = HighsModelStatus::kOptimal;
1715-
return solveKnapsackReturn(HighsStatus::kOk);
1758+
return solveMipKnapsackReturn(HighsStatus::kOk);
17161759
}
17171760
// Set up the weights for the knapsack solver. They might not all be
17181761
// nonzero, so have to scatter into a zeroed vector
@@ -1729,57 +1772,35 @@ HighsStatus HighsPrimalHeuristics::solveKnapsack() {
17291772
std::vector<double> value;
17301773
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
17311774
value.push_back(-sense * lp.col_cost_[iCol]);
1732-
// Set up the DP result array, indicating that no objectives are
1733-
// know
1734-
std::vector<std::vector<double>> dp_result(lp.num_col_ + 1, std::vector<double>(capacity + 1, -1));
1735-
// Set up the item use array, indicating that items are not used
1736-
std::vector<std::vector<bool>> use_item(lp.num_col_ + 1, std::vector<bool>(capacity + 1, false));
17371775
// Solve the knapsack problem by DP
1738-
double knapsack_optimal_objective_value = knapsackRecurrence(weight, value, lp.num_col_, capacity, dp_result, use_item);
1739-
// Deduce the solution
1740-
std::vector<HighsInt> knapsack_solution(lp.num_col_, 0);
1741-
// Variables are set to 1 if "used", and have to track the RHS of
1742-
// the subproblem after variables are assigned so that the correct
1743-
// entry of use is accessed
1744-
HighsInt knapsack_solution_rhs = capacity;
1745-
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
1746-
if (use_item[iCol][knapsack_solution_rhs]) {
1747-
knapsack_solution[iCol] = 1;
1748-
knapsack_solution_rhs -= weight[iCol];
1749-
}
1750-
}
1751-
const double row_violation = std::max(0, -knapsack_solution_rhs);
1752-
const double rel_row_violation = row_violation / (1.0 * capacity);
1776+
double knapsack_optimal_objective_value;
1777+
std::vector<double>& solution = mipsolver.solution_;
1778+
mipsolver.modelstatus_ = solveKnapsack(log_options,
1779+
lp.num_col_, value, weight, capacity,
1780+
knapsack_optimal_objective_value, solution);
1781+
if (mipsolver.modelstatus_ != HighsModelStatus::kOptimal)
1782+
return solveMipKnapsackReturn(HighsStatus::kError);
17531783

1754-
if (rel_row_violation > 1e-12) {
1755-
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kError,
1756-
"HighsPrimalHeuristics::solveKnapsack() (Abs; rel) capacity violation is (%g, %g)\n", row_violation, rel_row_violation);
1757-
mipsolver.modelstatus_ = HighsModelStatus::kSolveError;
1758-
return solveKnapsackReturn(HighsStatus::kError);
1759-
}
17601784
// Get the objective value corresponding to the original problem
17611785
const double solution_objective = lp.offset_ - sense * knapsack_optimal_objective_value;
17621786

17631787
// Compute the objective directly as a check
17641788
double check_objective = lp.offset_;
17651789
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
1766-
check_objective += knapsack_solution[iCol] * lp.col_cost_[iCol];
1790+
check_objective += solution[iCol] * lp.col_cost_[iCol];
17671791

17681792
double abs_dl_solution_objective = std::fabs(solution_objective - check_objective);
17691793
double rel_dl_solution_objective = abs_dl_solution_objective / (1.0 + std::fabs(mipsolver.solution_objective_));
17701794
if (rel_dl_solution_objective > 1e-12) {
1771-
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kError,
1772-
"HighsPrimalHeuristics::solveKnapsack() Relative optimal objective value mismatch of %g\n", rel_dl_solution_objective);
1795+
highsLogUser(log_options, HighsLogType::kError,
1796+
"HighsPrimalHeuristics::solveMipKnapsack() Relative optimal objective value mismatch of %g\n",
1797+
rel_dl_solution_objective);
17731798
mipsolver.modelstatus_ = HighsModelStatus::kSolveError;
1774-
return solveKnapsackReturn(HighsStatus::kError);
1799+
return solveMipKnapsackReturn(HighsStatus::kError);
17751800
}
1776-
// Copy in the solution
1777-
mipsolver.solution_.resize(lp.num_col_);
1778-
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
1779-
mipsolver.solution_[iCol] = knapsack_solution[iCol];
17801801
mipsolver.solution_objective_ = solution_objective;
17811802

1782-
mipsolver.modelstatus_ = HighsModelStatus::kOptimal;
1783-
return solveKnapsackReturn(HighsStatus::kOk);
1803+
assert(mipsolver.modelstatus_ == HighsModelStatus::kOptimal);
1804+
return solveMipKnapsackReturn(HighsStatus::kOk);
17841805
}
17851806

highs/mip/HighsPrimalHeuristics.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ class HighsPrimalHeuristics {
7070

7171
void ziRound(const std::vector<double>& relaxationsol);
7272

73-
HighsStatus solveKnapsackReturn(const HighsStatus& return_status);
74-
HighsStatus solveKnapsack();
73+
HighsStatus solveMipKnapsackReturn(const HighsStatus& return_status);
74+
HighsStatus solveMipKnapsack();
7575
};
7676

7777
#endif

0 commit comments

Comments
 (0)