Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] tweak diet.jl tutorial to use more DataFrame logic #3213

Merged
merged 4 commits into from
Feb 11, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions docs/src/tutorials/linear/diet.jl
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ limits = DataFrames.DataFrame(
"fat" 0 65
"sodium" 0 1779
],
["name", "min", "max"],
["nutrient", "min", "max"],
)

# ## JuMP formulation
Expand All @@ -90,32 +90,30 @@ limits = DataFrames.DataFrame(
# HiGHS as our optimizer:

model = Model(HiGHS.Optimizer)
set_silent(model)

# Next, we create a set of decision variables `x`, indexed over the foods in the
# `data` DataFrame. Each `x` has a lower bound of `0`.
# Next, we create a set of decision variables `x`, with one element for each row
# in the DataFrame, and each `x` has a lower bound of `0`:

@variable(model, x[foods.name] >= 0);
@variable(model, x[foods.name] >= 0)

# Our objective is to minimize the total cost of purchasing food. We can write
# that as a sum over the rows in `data`.
# To simplify things later on, we store the vector as a new column `x` in the
# DataFrame `foods`:

@objective(
model,
Min,
sum(food["cost"] * x[food["name"]] for food in eachrow(foods)),
);
foods.x = Array(x)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jd-foster: I changed it to this so that x has meaningful indices instead of x[1] through x[n]`. Too magical?

Copy link
Collaborator

@jd-foster jd-foster Feb 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this change, and concluded it didn't matter if the index matched the name since it's row already has the key column. It matters if you split the JuMP variable column off the dataframe.

But personally prefer the way you've changed it to now.


# Our objective is to minimize the total cost of purchasing food:

@objective(model, Min, sum(foods.cost .* foods.x));

# For the next component, we need to add a constraint that our total intake of
# each component is within the limits contained in the `limits` DataFrame.
# To make this more readable, we introduce a JuMP `@expression`

for limit in eachrow(limits)
intake = @expression(
model,
sum(food[limit["name"]] * x[food["name"]] for food in eachrow(foods)),
)
@constraint(model, limit.min <= intake <= limit.max)
end
# each component is within the limits contained in the `limits` DataFrame:

@constraint(
model,
[row in eachrow(limits)],
row.min <= sum(foods[!, row.nutrient] .* foods.x) <= row.max,
);

# What does our model look like?

Expand All @@ -132,8 +130,8 @@ solution_summary(model)

# Success! We found an optimal solution. Let's see what the optimal solution is:

for food in foods.name
println(food, " = ", value(x[food]))
for row in eachrow(foods)
println(row.name, " = ", value(row.x))
end

# That's a lot of milk and ice cream! And sadly, we only get `0.6` of a
Expand All @@ -155,7 +153,9 @@ filter!(row -> row.quantity > 0.0, solution)
# constraints. Let's see what happens if we add a constraint that we can buy at
# most 6 units of milk or ice cream combined.

@constraint(model, x["milk"] + x["ice cream"] <= 6)
dairy_foods = ["milk", "ice cream"]
is_dairy = map(name -> name in dairy_foods, foods.name)
@constraint(model, sum(foods[is_dairy, :x]) <= 6)
optimize!(model)
Test.@test termination_status(model) == INFEASIBLE #hide
Test.@test primal_status(model) == NO_SOLUTION #hide
Expand Down