|
3 | 3 | # v.2.0. If a copy of the MPL was not distributed with this file, You can #src |
4 | 4 | # obtain one at https://mozilla.org/MPL/2.0/. #src |
5 | 5 |
|
6 | | -# # The knapsack problem |
| 6 | +# # The knapsack problem example |
7 | 7 |
|
8 | | -# Formulate and solve a simple knapsack problem: |
9 | | -# |
10 | | -# max sum(p_j x_j) |
11 | | -# st sum(w_j x_j) <= C |
12 | | -# x binary |
| 8 | +# The purpose of this example is demonstrate how to formulate and solve a |
| 9 | +# simple optimization problem. |
| 10 | +# We use the knapsack problem for this purpose. |
| 11 | + |
| 12 | +# ## Required packages |
| 13 | + |
| 14 | +# This tutorial requires the following packages: |
13 | 15 |
|
14 | 16 | using JuMP |
15 | 17 | import HiGHS |
16 | 18 | import Test |
17 | 19 |
|
18 | | -function example_knapsack() |
19 | | - profit = [5, 3, 2, 7, 4] |
20 | | - weight = [2, 8, 4, 2, 5] |
21 | | - capacity = 10 |
| 20 | +# ## Formulation |
| 21 | + |
| 22 | +# The simple [knapsack problem](https://en.wikipedia.org/wiki/Knapsack_problem) |
| 23 | +# is a well-known type of optimization problem: given a set of items and |
| 24 | +# a container with a fixed capacity, choose a subset of items having the greatest combined |
| 25 | +# value that will fit within the container without exceeding the capacity. |
| 26 | +# The name of the problem suggests its analogy to packing for a trip, |
| 27 | +# where the baggage weight limit is the capacity and the goal is to pack the |
| 28 | +# most profitable combination of belongings. |
| 29 | + |
| 30 | +# We can formulate the problem as an integer linear program |
| 31 | + |
| 32 | +# ```math |
| 33 | +# \begin{aligned} |
| 34 | +# \max \; & \sum_{i=1}^n c_i x_i \\ |
| 35 | +# s.t. \; & \sum_{i=1}^n w_i x_i \le C, \\ |
| 36 | +# & x_i \in \{0,1\},\quad \forall i=1,\ldots,n |
| 37 | +# \end{aligned} |
| 38 | +# ``` |
| 39 | + |
| 40 | +# or more compactly as |
| 41 | + |
| 42 | +# ```math |
| 43 | +# \begin{aligned} |
| 44 | +# \max \; & c^\top x \\ |
| 45 | +# s.t. \; & w^\top x \le C \\ |
| 46 | +# & x \text{ binary }, |
| 47 | +# \end{aligned} |
| 48 | +# ``` |
| 49 | + |
| 50 | +# where there is a choice between ``n`` items, with item ``i`` having weight ``w_i``, |
| 51 | +# profit ``c_i`` and a decision variable ``x_i`` equal to 1 if the item is chosen |
| 52 | +# and 0 if not. |
| 53 | + |
| 54 | +# ## Data |
| 55 | + |
| 56 | +# The data for the problem is two vectors (one for the profits |
| 57 | +# and one for the weights) along with a capacity. |
| 58 | +# For our example, we use a capacity of 10 units |
| 59 | +capacity = 10; |
| 60 | +# and vector data |
| 61 | +profit = [5, 3, 2, 7, 4]; |
| 62 | +weight = [2, 8, 4, 2, 5]; |
| 63 | + |
| 64 | +# ## JuMP formulation |
| 65 | + |
| 66 | +# Let's begin constructing the JuMP model for our knapsack problem. |
| 67 | +# First, we'll create a `Model` object for holding model elements as |
| 68 | +# we construct each part. We'll also set the solver that will |
| 69 | +# ultimately be called to solve the model, once it's constructed. |
| 70 | +model = Model(HiGHS.Optimizer) |
| 71 | + |
| 72 | +# Next we need the decision variables for which items are chosen. |
| 73 | +@variable(model, x[1:5], Bin) |
| 74 | + |
| 75 | +# We now want to constrain those variables so that their combined |
| 76 | +# weight is less than or equal to the given capacity. |
| 77 | +@constraint(model, sum(weight[i] * x[i] for i in 1:5) <= capacity) |
| 78 | + |
| 79 | +# Finally, we set an objective: maximise the combined profit of the |
| 80 | +# selected items. |
| 81 | +@objective(model, Max, sum(profit[i] * x[i] for i in 1:5)) |
| 82 | + |
| 83 | +# Let's print a human-readable description of the model and |
| 84 | +# check that the model looks as expected: |
| 85 | +print(model) |
| 86 | + |
| 87 | +# We can now solve the optimization problem and inspect the results. |
| 88 | +optimize!(model) |
| 89 | +solution_summary(model) |
| 90 | + |
| 91 | +# The items chosen are |
| 92 | + |
| 93 | +items_chosen = [i for i in 1:5 if value(x[i]) > 0.5] |
| 94 | + |
| 95 | +# After working interactively, it is good practice to implement |
| 96 | +# your model in a function. |
| 97 | +# A function can be used to ensure that the model is given |
| 98 | +# well-defined input data by validation checks, and that the |
| 99 | +# solution process went as expected. |
| 100 | + |
| 101 | +function solve_knapsack_problem(; |
| 102 | + profit, |
| 103 | + weight::Vector{T}, |
| 104 | + capacity::T, |
| 105 | +) where {T<:Real} |
| 106 | + N = length(weight) |
| 107 | + |
| 108 | + ## The profit and weight vectors must be of equal length. |
| 109 | + @assert length(profit) == N |
| 110 | + |
22 | 111 | model = Model(HiGHS.Optimizer) |
23 | 112 | set_silent(model) |
24 | | - @variable(model, x[1:5], Bin) |
25 | | - ## Objective: maximize profit |
| 113 | + |
| 114 | + ## Declare the decision variables as binary (0 or 1). |
| 115 | + @variable(model, x[1:N], Bin) |
| 116 | + |
| 117 | + ## Objective: maximize profit. |
26 | 118 | @objective(model, Max, profit' * x) |
27 | | - ## Constraint: can carry all |
| 119 | + |
| 120 | + ## Constraint: can carry all items. |
28 | 121 | @constraint(model, weight' * x <= capacity) |
| 122 | + |
29 | 123 | ## Solve problem using MIP solver |
30 | 124 | optimize!(model) |
31 | 125 | println("Objective is: ", objective_value(model)) |
32 | 126 | println("Solution is:") |
33 | | - for i in 1:5 |
34 | | - print("x[$i] = ", value(x[i])) |
35 | | - println(", p[$i]/w[$i] = ", profit[i] / weight[i]) |
| 127 | + for i in 1:N |
| 128 | + print("x[$i] = ", Int(value(x[i]))) |
| 129 | + println(", c[$i]/w[$i] = ", profit[i] / weight[i]) |
36 | 130 | end |
37 | 131 | Test.@test termination_status(model) == OPTIMAL |
38 | 132 | Test.@test primal_status(model) == FEASIBLE_POINT |
39 | 133 | Test.@test objective_value(model) == 16.0 |
40 | 134 | return |
41 | 135 | end |
42 | 136 |
|
43 | | -example_knapsack() |
| 137 | +solve_knapsack_problem(; profit = profit, weight = weight, capacity = capacity) |
| 138 | + |
| 139 | +# We observe that the chosen items (1, 4 and 5) have the best |
| 140 | +# profit to weight ratio for in this particular example. |
0 commit comments