@@ -1653,58 +1653,93 @@ double knapsackRecurrence(const std::vector<HighsInt>& weights,
16531653 const double rhs,
16541654 std::vector<std::vector<double >> &dp,
16551655 std::vector<std::vector<bool >> &use) {
1656- if (num_col == 0 || rhs == 0 )
1657- return 0 ; // Base case
1656+ if (num_col == 0 || rhs == 0 )
1657+ return 0 ; // Base case
16581658
1659- if (dp[num_col][rhs] != -1 ) return dp[num_col][rhs]; // Check if result is already computed
1659+ if (dp[num_col][rhs] != -1 ) return dp[num_col][rhs]; // Check if result is already computed
16601660
1661- // Exclude the item
1662- double exclude = knapsackRecurrence (weights, values, num_col - 1 , rhs, dp, use);
1661+ // Exclude the item
1662+ double exclude = knapsackRecurrence (weights, values, num_col- 1 , rhs, dp, use);
16631663
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);
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);
16681668
1669- use[num_col][rhs] = include > exclude;
1670- dp[num_col][rhs] = use[num_col][rhs] ? include : exclude; // Store the result
1669+ // Store whether the item is used with this RHS
1670+ use[num_col][rhs] = include > exclude;
1671+ // Store the result
1672+ dp[num_col][rhs] = use[num_col][rhs] ? include : exclude;
16711673
1672- return dp[num_col][rhs];
1674+ return dp[num_col][rhs];
16731675
16741676}
1677+ HighsStatus HighsPrimalHeuristics::solveKnapsackReturn (const HighsStatus& return_status) {
1678+ const HighsLp& lp = *(mipsolver.model_ );
1679+ if (mipsolver.modelstatus_ == HighsModelStatus::kOptimal ) {
1680+ // mipsolver.solution_objective_ is the objective value for the
1681+ // original problem - using the offset and ignoring the
1682+ // optimization sense. The mipdata_->lower/upper_bound values
1683+ // relate to the problem within the MIP solver. This is a
1684+ // minimization without offset
1685+ HighsInt sense = HighsInt (lp.sense_ );
1686+ double mipsolver_objective = sense * mipsolver.solution_objective_ - lp.offset_ ;
1687+ mipsolver.bound_violation_ = 0 ;
1688+ mipsolver.integrality_violation_ = 0 ;
1689+ mipsolver.row_violation_ = 0 ;
1690+ mipsolver.mipdata_ ->lower_bound = mipsolver_objective;
1691+ mipsolver.mipdata_ ->upper_bound = mipsolver_objective;
1692+ mipsolver.gap_ = 0 ;
1693+ }
1694+ return return_status;
1695+
1696+ }
1697+
16751698HighsStatus HighsPrimalHeuristics::solveKnapsack () {
1699+ HighsLp lp = *(mipsolver.model_ );
1700+ // const HighsLp& lp = mipsolver.mipdata_->model_;
16761701 HighsInt knapsack_rhs_;
1677- assert (mipsolver. orig_model_ -> isKnapsack (knapsack_rhs_));
1702+ assert (lp. isKnapsack (knapsack_rhs_));
16781703 const HighsInt knapsack_rhs = knapsack_rhs_;
16791704
1680- HighsLp lp = *(mipsolver.orig_model_ );
1681- // const HighsLp& lp = mipsolver.mipdata_->orig_model_;
16821705 const bool upper = lp.row_upper_ [0 ] < kHighsInf ;
1683- const HighsInt sign = upper ? 1 : -1 ;
1706+ const HighsInt constraint_sign = upper ? 1 : -1 ;
16841707 if (knapsack_rhs < 0 ) {
16851708 mipsolver.modelstatus_ = HighsModelStatus::kInfeasible ;
1686- return HighsStatus::kOk ;
1709+ return solveKnapsackReturn ( HighsStatus::kOk ) ;
16871710 } else if (knapsack_rhs == 0 ) {
16881711 // Trivial knapsack with zero solution
16891712 mipsolver.solution_ .assign (lp.num_col_ , 0 );
16901713 mipsolver.solution_objective_ = lp.offset_ ;
16911714 mipsolver.modelstatus_ = HighsModelStatus::kOptimal ;
1692- return HighsStatus::kOk ;
1715+ return solveKnapsackReturn ( HighsStatus::kOk ) ;
16931716 }
1717+ // Set up the weightsfor the knapsack solver. They might not all be
1718+ // nonzero, so have to scatter into a zeroed vector
16941719 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]);
1720+ assert (lp.a_matrix_ .format_ == MatrixFormat::kColwise );
1721+ for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++) {
1722+ for (HighsInt iEl = lp.a_matrix_ .start_ [iCol]; iEl < lp.a_matrix_ .start_ [iCol+1 ]; iEl++)
1723+ weights[iCol] = HighsInt (constraint_sign * lp.a_matrix_ .value_ [iEl]);
16981724 }
16991725 HighsInt sense = HighsInt (lp.sense_ );
1726+ // Set up the values for the knapsack solver. Since it solves a
1727+ // maximization problem, have to negate the costs if MIP is a
1728+ // minimization
17001729 std::vector<double > values;
17011730 for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++)
1702- values.push_back (sense*lp.col_cost_ [iCol]);
1731+ values.push_back (-sense * lp.col_cost_ [iCol]);
1732+ // Set up the DP array, indicating that no objectives are know
17031733 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 ));
1734+ // Set up the item use array, indicating that items are not used
1735+ std::vector<std::vector<bool >> use (lp.num_col_ + 1 , std::vector<bool >(knapsack_rhs + 1 , false ));
1736+ // Solve the knapsack problem by DP
17051737 double knapsack_optimal_objective_value = knapsackRecurrence (weights, values, lp.num_col_ , knapsack_rhs, dp, use);
17061738 // Deduce the solution
17071739 std::vector<HighsInt> knapsack_solution (lp.num_col_ , 0 );
1740+ // Variables are set to 1 if "used", and have to track the RHS of
1741+ // the subproblem after variables are assigned so that the correct
1742+ // entry of use is accessed
17081743 HighsInt knapsack_solution_rhs = knapsack_rhs;
17091744 for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++) {
17101745 if (use[iCol][knapsack_solution_rhs]) {
@@ -1717,39 +1752,33 @@ HighsStatus HighsPrimalHeuristics::solveKnapsack() {
17171752
17181753 if (rel_row_violation > 1e-12 ) {
17191754 highsLogUser (mipsolver.options_mip_ ->log_options , HighsLogType::kError ,
1720- " HighsPrimalHeuristics::solveKnapsack() Relative capacity violation of %g \n " , rel_row_violation);
1755+ " HighsPrimalHeuristics::solveKnapsack() (Abs; rel) capacity violation is (%g, %g) \n " , row_violation , rel_row_violation);
17211756 mipsolver.modelstatus_ = HighsModelStatus::kSolveError ;
1722- return HighsStatus::kError ;
1757+ return solveKnapsackReturn ( HighsStatus::kError ) ;
17231758 }
1724- const double solution_objective = lp.offset_ + sense * knapsack_optimal_objective_value;
1759+ // Get the objective value corresponding to the original problem
1760+ const double solution_objective = lp.offset_ - sense * knapsack_optimal_objective_value;
17251761
1726- // Compute the objective directly
1762+ // Compute the objective directly as a check
17271763 double check_objective = lp.offset_ ;
17281764 for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++)
1729- check_objective += knapsack_solution[iCol]* lp.col_cost_ [iCol];
1765+ check_objective += knapsack_solution[iCol] * lp.col_cost_ [iCol];
17301766
1731- double abs_dl_solution_objective = std::fabs (mipsolver. solution_objective_ - check_objective);
1767+ double abs_dl_solution_objective = std::fabs (solution_objective - check_objective);
17321768 double rel_dl_solution_objective = abs_dl_solution_objective / (1.0 + std::fabs (mipsolver.solution_objective_ ));
17331769 if (rel_dl_solution_objective > 1e-12 ) {
17341770 highsLogUser (mipsolver.options_mip_ ->log_options , HighsLogType::kError ,
17351771 " HighsPrimalHeuristics::solveKnapsack() Relative optimal objective value mismatch of %g\n " , rel_dl_solution_objective);
17361772 mipsolver.modelstatus_ = HighsModelStatus::kSolveError ;
1737- return HighsStatus::kError ;
1773+ return solveKnapsackReturn ( HighsStatus::kError ) ;
17381774 }
1739- // Copy in the solution and compute the objective directly
1775+ // Copy in the solution
17401776 mipsolver.solution_ .resize (lp.num_col_ );
17411777 for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++)
17421778 mipsolver.solution_ [iCol] = knapsack_solution[iCol];
17431779 mipsolver.solution_objective_ = solution_objective;
17441780
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-
17521781 mipsolver.modelstatus_ = HighsModelStatus::kOptimal ;
1753- return HighsStatus::kOk ;
1782+ return solveKnapsackReturn ( HighsStatus::kOk );
17541783}
17551784
0 commit comments