{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# BEE 4750 Lab 3: Linear Programming with JuMP\n", "\n", "**Name**:\n", "\n", "**ID**:\n", "\n", "> **Due Date**\n", ">\n", "> Wednesday, 10/16/24, 9:00pm\n", "\n", "## Setup\n", "\n", "The following code should go at the top of most Julia scripts; it will\n", "load the local package environment and install any needed packages. You\n", "will see this often and shouldn’t need to touch it." ], "id": "6e7bbd0f-fc87-4111-b896-d764ccd9a36a" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import Pkg\n", "Pkg.activate(\".\")\n", "Pkg.instantiate()" ], "id": "2" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "using JuMP # optimization modeling syntax\n", "using HiGHS # optimization solver" ], "id": "4" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview\n", "\n", "In this lab, you will write and solve a resource allocation example\n", "using `JuMP.jl`. `JuMP.jl` provides an intuitive syntax for writing,\n", "solving, and querying optimization problems.\n", "\n", "`JuMP` requires the loading of a solver. \\[Each supported solver works\n", "for certain classes of problems, and some are open source while others\n", "require a commercial license\\]. We will use the `HiGHS` solver, which is\n", "open source and works for linear, mixed integer linear, and quadratic\n", "programs.\n", "\n", "In this lab we will walk through the steps involved in coding a linear\n", "program in HiGHS, solving it, and querying the solution.\n", "\n", "## Exercise (3 points)\n", "\n", "Your task is to decide how much lumber to produce to maximize profit\n", "from wood sales. You can purchase wood from a managed forest, which\n", "consists of spruce (320,000 bf) and fir (720,000 bf). Spruce costs\n", "$\\$0.12$ per bf to purchase and fir costs $\\$0.08$ per bf.\n", "\n", "At the lumber mill, wood can be turned into plywood of various grades\n", "(see Table 1 for how much\n", "wood of each type is required for and the revenue from each grade). Any\n", "excess wood is sent to be recycled into particle board, which yields no\n", "revenue for the mill.\n", "\n", "| Plywood Grade | Inputs (bf/bf plywood) | Revenue (\\$/1000 bf) |\n", "|:-------------:|:----------------------:|:--------------------:|\n", "| 1 | 0.5 (S) + 1.5 (F) | 400 |\n", "| 2 | 1.0 (S) + 2.0 (F) | 520 |\n", "| 3 | 1.5 (S) + 2.0 (F) | 700 |\n", "\n", "Table 1: Wood inputs and revenue by plywood grade. S refers to spruce\n", "inputs, F fir inputs.\n", "\n", "First, we need to identify our decision variables. While there are\n", "several options, we will use $G_i$, the amount of each grade the mill\n", "produces (in 1000 bf).\n", "\n", "Using these decision variables, formulate a linear program to maximize\n", "the profit of the mill subject to the supply constraints on spruce and\n", "fir.\n", "\n", "> **JuMP Syntax**\n", ">\n", "> The core pieces of setting up a `JuMP` model involve specifying the\n", "> model and adding variables, the objective, and constraints. At the\n", "> most simple level, this syntax looks like this:\n", ">\n", "> ``` julia\n", "> m = Model(HiGHS.Optimizer)\n", "> @variable(m, lb <= x <= ub) # if you do not have upper or lower bounds, you can drop those accordingly\n", "> @variable(m, lb <= y <= ub)\n", "> @objective(m, Max, 100x + 250y) # replace Max with Min depending on the problem\n", "> @constraint(m, label, 6x + 12y <= 80) # replace \"label\" with some meaningful string you would like to use later to query shadow prices, or drop it\n", "> ```\n", ">\n", "> You can add more constraints or more variables as needed.\n", "\n", "> **Using Array Syntax**\n", ">\n", "> You can set up multiple variables or constraints at once using array\n", "> syntax. For example, the following are equivalent:\n", ">\n", "> ``` julia\n", "> @variable(m, G1 >= 0)\n", "> @variable(m, G2 >= 0)\n", "> @variable(m, G3 >= 0)\n", "> ```\n", ">\n", "> and\n", ">\n", "> ``` julia\n", "> @variable(m, G[1:3] >= 0)\n", "> ```\n", ">\n", "> You can also set up multiple constraints using arrays of coefficients\n", "> and/or bounds. For example:\n", ">\n", "> ``` julia\n", "> I = 1:3\n", "> d = [0; 3; 5]\n", "> @constraint(m, demand[i in I], G[i] >= d[i])\n", "> ```\n", "\n", "`JuMP` is finicky about changing objects and constraints, so I recommend\n", "setting up all of the model syntax in one notebook cell, which is what\n", "we will do here." ], "id": "32825b85-310e-46be-a0f4-77757dc01fb4" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Feasibility\n", "Subject to\n", " G[1] ≥ 0\n", " G[2] ≥ 0\n", " G[3] ≥ 0" ] } ], "source": [ "forest_model = Model(HiGHS.Optimizer) # initialize model object\n", "@variable(forest_model, G[1:3] >= 0) # non-negativity constraints\n", "# uncomment the following lines and add the objective and constraints as needed for the model\n", "# @objective(forest_model, )\n", "# @constraint(forest_model, )\n", "print(forest_model) # this outputs a nicely formatted summary of the model so you can check your specification" ], "id": "6" }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, to optimize, use the `optimize!()` function:" ], "id": "7ea6ed33-6429-4b8f-af26-4eebeb8d1215" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Running HiGHS 1.7.2 (git hash: 5ce7a2753): Copyright (c) 2024 HiGHS under MIT licence terms\n", "Coefficient ranges:\n", " Cost [0e+00, 0e+00]\n", " Bound [0e+00, 0e+00]\n", "Solving LP without presolve, or with basis, or unconstrained\n", "Solving an unconstrained LP with 3 columns\n", "Model status : Optimal\n", "Objective value : 0.0000000000e+00\n", "HiGHS run time : 0.00" ] } ], "source": [ "optimize!(forest_model)" ], "id": "8" }, { "cell_type": "markdown", "metadata": {}, "source": [ "You should get confirmation that a solution was found; if one was not,\n", "there’s a chance something was wrong with your model formulation.\n", "\n", "To find the values of the decision variables, use `value()` (which can\n", "be broadcasted over variable arrays):" ], "id": "82fd6511-c812-4aaa-bf89-97c675da2d69" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "value.(G) = [0.0, 0.0, 0.0]" ] } ], "source": [ "@show value.(G);" ], "id": "10" }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, `objective_value()` finds the optimal value of the objective:" ], "id": "e15406b2-a117-4447-af58-f27f1510d5ce" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "objective_value(forest_model) = 0.0" ] } ], "source": [ "@show objective_value(forest_model);" ], "id": "12" }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we can find the dual values of the constraints with\n", "`shadow_price()`. Do this for the constraints in your model using the\n", "block below." ], "id": "a747cdc1-c7d2-469a-8c21-86663bf308dc" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# @show shadow_price(name_of_constraint);" ], "id": "14" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`JuMP` also lets you evaluate other expressions that you might be\n", "interested in based on the solutions. For example, you can use the\n", "following block to calculate the total amount of plywood the mill would\n", "produce under the optimal solution:" ], "id": "0f14a607-c14b-40cc-ab5c-96fa68fe997a" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "value.(total_plywood) = 0.0" ] } ], "source": [ "@expression(forest_model, total_plywood, sum(G))\n", "@show value.(total_plywood);" ], "id": "16" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## References\n", "\n", "Put any consulted sources here, including classmates you worked with/who\n", "helped you." ], "id": "8ebc4504-05f9-4e40-a22f-34026b79a43d" } ], "nbformat": 4, "nbformat_minor": 5, "metadata": { "kernel_info": { "name": "julia" }, "kernelspec": { "name": "julia", "display_name": "Julia", "language": "julia" }, "language_info": { "name": "julia", "codemirror_mode": "julia", "version": "1.10.4" } } }