@@ -1646,3 +1646,110 @@ void HighsPrimalHeuristics::flushStatistics() {
16461646 mipsolver.mipdata_ ->total_lp_iterations += lp_iterations;
16471647 lp_iterations = 0 ;
16481648}
1649+
1650+ double knapsackRecurrence (const std::vector<HighsInt>& weights,
1651+ const std::vector<double >& values,
1652+ const HighsInt num_col,
1653+ const double rhs,
1654+ std::vector<std::vector<double >> &dp,
1655+ std::vector<std::vector<bool >> &use) {
1656+ if (num_col == 0 || rhs == 0 )
1657+ return 0 ; // Base case
1658+
1659+ if (dp[num_col][rhs] != -1 ) return dp[num_col][rhs]; // Check if result is already computed
1660+
1661+ // Exclude the item
1662+ double exclude = knapsackRecurrence (weights, values, num_col - 1 , rhs, dp, use);
1663+
1664+ // Include the item (if it fits in the knapsack)
1665+ double include = 0 ;
1666+ if (weights[num_col - 1 ] <= rhs)
1667+ include = values[num_col - 1 ] + knapsackRecurrence (weights, values, num_col - 1 , rhs - weights[num_col - 1 ], dp, use);
1668+
1669+ use[num_col][rhs] = include > exclude;
1670+ dp[num_col][rhs] = use[num_col][rhs] ? include : exclude; // Store the result
1671+
1672+ return dp[num_col][rhs];
1673+
1674+ }
1675+ HighsStatus HighsPrimalHeuristics::solveKnapsack () {
1676+ HighsInt knapsack_rhs_;
1677+ assert (mipsolver.orig_model_ ->isKnapsack (knapsack_rhs_));
1678+ const HighsInt knapsack_rhs = knapsack_rhs_;
1679+
1680+ HighsLp lp = *(mipsolver.orig_model_ );
1681+ // const HighsLp& lp = mipsolver.mipdata_->orig_model_;
1682+ const bool upper = lp.row_upper_ [0 ] < kHighsInf ;
1683+ const HighsInt sign = upper ? 1 : -1 ;
1684+ if (knapsack_rhs < 0 ) {
1685+ mipsolver.modelstatus_ = HighsModelStatus::kInfeasible ;
1686+ return HighsStatus::kOk ;
1687+ } else if (knapsack_rhs == 0 ) {
1688+ // Trivial knapsack with zero solution
1689+ mipsolver.solution_ .assign (lp.num_col_ , 0 );
1690+ mipsolver.solution_objective_ = lp.offset_ ;
1691+ mipsolver.modelstatus_ = HighsModelStatus::kOptimal ;
1692+ return HighsStatus::kOk ;
1693+ }
1694+ std::vector<HighsInt> weights (lp.num_col_ , 0 );
1695+ for (HighsInt iEl = 0 ; iEl < lp.a_matrix_ .numNz (); iEl++) {
1696+ HighsInt iCol = lp.a_matrix_ .index_ [iEl];
1697+ weights[iCol] = HighsInt (sign * lp.a_matrix_ .value_ [iEl]);
1698+ }
1699+ HighsInt sense = HighsInt (lp.sense_ );
1700+ std::vector<double > values;
1701+ for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++)
1702+ values.push_back (sense*lp.col_cost_ [iCol]);
1703+ std::vector<std::vector<double >> dp (lp.num_col_ + 1 , std::vector<double >(knapsack_rhs + 1 , -1 ));
1704+ std::vector<std::vector<bool >> use (lp.num_col_ + 1 , std::vector<bool >(knapsack_rhs + 1 , -1 ));
1705+ double knapsack_optimal_objective_value = knapsackRecurrence (weights, values, lp.num_col_ , knapsack_rhs, dp, use);
1706+ // Deduce the solution
1707+ std::vector<HighsInt> knapsack_solution (lp.num_col_ , 0 );
1708+ HighsInt knapsack_solution_rhs = knapsack_rhs;
1709+ for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++) {
1710+ if (use[iCol][knapsack_solution_rhs]) {
1711+ knapsack_solution[iCol] = 1 ;
1712+ knapsack_solution_rhs -= weights[iCol];
1713+ }
1714+ }
1715+ const double row_violation = std::max (0 , -knapsack_solution_rhs);
1716+ const double rel_row_violation = row_violation / (1.0 * knapsack_rhs);
1717+
1718+ if (rel_row_violation > 1e-12 ) {
1719+ highsLogUser (mipsolver.options_mip_ ->log_options , HighsLogType::kError ,
1720+ " HighsPrimalHeuristics::solveKnapsack() Relative capacity violation of %g\n " , rel_row_violation);
1721+ mipsolver.modelstatus_ = HighsModelStatus::kSolveError ;
1722+ return HighsStatus::kError ;
1723+ }
1724+ const double solution_objective = lp.offset_ + sense * knapsack_optimal_objective_value;
1725+
1726+ // Compute the objective directly
1727+ double check_objective = lp.offset_ ;
1728+ for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++)
1729+ check_objective += knapsack_solution[iCol]*lp.col_cost_ [iCol];
1730+
1731+ double abs_dl_solution_objective = std::fabs (mipsolver.solution_objective_ - check_objective);
1732+ double rel_dl_solution_objective = abs_dl_solution_objective / (1.0 + std::fabs (mipsolver.solution_objective_ ));
1733+ if (rel_dl_solution_objective > 1e-12 ) {
1734+ highsLogUser (mipsolver.options_mip_ ->log_options , HighsLogType::kError ,
1735+ " HighsPrimalHeuristics::solveKnapsack() Relative optimal objective value mismatch of %g\n " , rel_dl_solution_objective);
1736+ mipsolver.modelstatus_ = HighsModelStatus::kSolveError ;
1737+ return HighsStatus::kError ;
1738+ }
1739+ // Copy in the solution and compute the objective directly
1740+ mipsolver.solution_ .resize (lp.num_col_ );
1741+ for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++)
1742+ mipsolver.solution_ [iCol] = knapsack_solution[iCol];
1743+ mipsolver.solution_objective_ = solution_objective;
1744+
1745+ mipsolver.bound_violation_ = 0 ;
1746+ mipsolver.integrality_violation_ = 0 ;
1747+ mipsolver.row_violation_ = 0 ;
1748+ mipsolver.dual_bound_ = mipsolver.solution_objective_ ;
1749+ mipsolver.primal_bound_ = mipsolver.solution_objective_ ;
1750+ mipsolver.gap_ = 0 ;
1751+
1752+ mipsolver.modelstatus_ = HighsModelStatus::kOptimal ;
1753+ return HighsStatus::kOk ;
1754+ }
1755+
0 commit comments