{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "case_2_student_notebook.ipynb", "provenance": [], "toc_visible": true, "collapsed_sections": [] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "markdown", "source": [ "# Introduction to PuLP\n", "\n", "For case 2, you will need to define and solve optimization problems. In this notebook, I'll help you understand how to use `pulp`, a Python package for modeling optimization problems. You might want to check the following links:\n", "\n", "- Documentation: https://coin-or.github.io/pulp/\n", "- Homepage: https://github.com/coin-or/pulp\n", "\n" ], "metadata": { "id": "eLvjUuJdzS7z" } }, { "cell_type": "markdown", "source": [ "# Installing and checking all is in place" ], "metadata": { "id": "HFavOEVS0dbY" } }, { "cell_type": "markdown", "source": [ "The first thing you need to do is to install `pulp`. `pulp` is not in the standard available packages in Colab, so you need to run the following cell once. " ], "metadata": { "id": "HgZwpjUG0PsK" } }, { "cell_type": "code", "source": [ "!pip install pulp" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "ni6Q_YiO0nIm", "outputId": "405d3f57-4502-4ed5-dcb9-d3204b585bb8" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Collecting pulp\n", " Downloading PuLP-2.6.0-py3-none-any.whl (14.2 MB)\n", "\u001b[K |████████████████████████████████| 14.2 MB 8.9 MB/s \n", "\u001b[?25hInstalling collected packages: pulp\n", "Successfully installed pulp-2.6.0\n" ] } ] }, { "cell_type": "markdown", "source": [ "After doing that, you can import the library." ], "metadata": { "id": "k9YI0Kzw0qLT" } }, { "cell_type": "code", "source": [ "import pulp" ], "metadata": { "id": "hw6keX7x0tZ1" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "If all is good, running the following command will print a large log testing `pulp`. The last line should read \"OK\"." ], "metadata": { "id": "vD_rXehL1KXX" } }, { "cell_type": "code", "source": [ "pulp.pulpTestAll()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Ney2a8mu1JqQ", "outputId": "a6b32d96-b163-4fc5-b4fc-3d5673e5a40a" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss.........." ] }, { "output_type": "stream", "name": "stdout", "text": [ "\t Test that logic put in place for deprecation handling of indexs works\n", "\t Testing 'indexs' param continues to work for LpVariable.dicts\n", "\t Testing 'indexs' param continues to work for LpVariable.matrix\n", "\t Testing 'indices' argument works in LpVariable.dicts\n", "\t Testing 'indices' param continues to work for LpVariable.matrix\n", "\t Testing invalid status\n", "\t Testing continuous LP solution - export dict\n", "\t Testing export dict for LP\n", "\t Testing export dict MIP\n", "\t Testing maximize continuous LP solution\n", "\t Testing continuous LP solution - export JSON\n", "\t Testing continuous LP solution - export solver dict\n", "\t Testing continuous LP solution - export solver JSON\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ ".........." ] }, { "output_type": "stream", "name": "stdout", "text": [ "\t Testing reading MPS files - binary variable, no constraint names\n", "\t Testing reading MPS files - integer variable\n", "\t Testing reading MPS files - maximize\n", "\t Testing invalid var names\n", "\t Testing logPath argument\n", "\t Testing makeDict general behavior\n", "\t Testing makeDict default value behavior\n", "\t Testing measuring optimization time\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "............." ] }, { "output_type": "stream", "name": "stdout", "text": [ "\t Testing the availability of the function pulpTestAll\n", "\t Testing zero subtraction\n", "\t Testing inconsistent lp solution\n", "\t Testing continuous LP solution\n", "\t Testing maximize continuous LP solution\n", "\t Testing unbounded continuous LP solution\n", "\t Testing Long Names\n", "\t Testing repeated Names\n", "\t Testing zero constraint\n", "\t Testing zero objective\n", "\t Testing LpVariable (not LpAffineExpression) objective\n", "\t Testing Long lines in LP\n", "\t Testing LpAffineExpression divide\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "............." ] }, { "output_type": "stream", "name": "stdout", "text": [ "\t Testing MIP solution\n", "\t Testing MIP solution with floats in objective\n", "\t Testing Initial value in MIP solution\n", "\t Testing fixing value in MIP solution\n", "\t Testing MIP relaxation\n", "\t Testing feasibility problem (no objective)\n", "\t Testing an infeasible problem\n", "\t Testing an integer infeasible problem\n", "\t Testing another integer infeasible problem\n", "\t Testing column based modelling\n", "\t Testing dual variables and slacks reporting\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "..........ssssssssssssssssssssssssssssssssssssssssssssssssssssss" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\t Testing fractional constraints\n", "\t Testing elastic constraints (no change)\n", "\t Testing elastic constraints (freebound)\n", "\t Testing elastic constraints (penalty unchanged)\n", "\t Testing elastic constraints (penalty unbounded)\n", "\t Testing timeLimit argument\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\n", "----------------------------------------------------------------------\n", "Ran 840 tests in 15.681s\n", "\n", "OK (skipped=784)\n" ] } ] }, { "cell_type": "markdown", "source": [ "# Defining and solving problems\n", "\n", "The following cells show you the absolute minimum to model and solve a problem with `pulp`. The steps are:\n", "\n", "1. Define decision variables\n", "2. Define the target function\n", "3. Define the constraints\n", "4. Assemble the problem\n", "5. Solve it\n", "6. Examine results\n", "\n", "For more flexibility, options and interesting stuff, please check up the PuLP documentation." ], "metadata": { "id": "oiXz40NR1whf" } }, { "cell_type": "markdown", "source": [ "## Define decision variables" ], "metadata": { "id": "nq5bcQs03g0j" } }, { "cell_type": "code", "source": [ "x = pulp.LpVariable(\n", " name=\"x\",\n", " cat=pulp.LpContinuous \n", " )\n", "\n", "y = pulp.LpVariable(\n", " name=\"y\",\n", " cat=pulp.LpInteger # This will make the variable integer only\n", " )\n", "\n", "z = pulp.LpVariable(\n", " name=\"z\",\n", " cat=pulp.LpBinary # This will make the variable binary (only 0 or 1)\n", ")" ], "metadata": { "id": "0SPhww4L3buh" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Define the target function" ], "metadata": { "id": "uhlbq2oO35kp" } }, { "cell_type": "code", "source": [ "target_function = 10 * x - 5 * y + z" ], "metadata": { "id": "pu3Im9DH39CN" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Define constraints" ], "metadata": { "id": "lqD0dD474Izw" } }, { "cell_type": "code", "source": [ "constraint_1 = x >= 0\n", "constraint_2 = y >= 0\n", "constraint_3 = x >= 10\n", "constraint_4 = y <= 50" ], "metadata": { "id": "5Cu51lYj4OUC" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Assemble the problem\n", "\n", "To put all the parts together, you need to declare a problem and specify if you want to minimize or maximize the target function.\n", "\n", "Once you have that:\n", "- First, you \"add\" the target function.\n", "- After, you \"add\" all the constraints you want to include." ], "metadata": { "id": "d5nq94IM4kSU" } }, { "cell_type": "code", "source": [ "problem = pulp.LpProblem(\"my_silly_problem\", pulp.LpMinimize)\n", "\n", "problem += target_function\n", "\n", "for constraint in (\n", " constraint_1,\n", " constraint_2,\n", " constraint_3,\n", " constraint_4\n", " ):\n", " problem += constraint" ], "metadata": { "id": "yI-Oiwh64mRc" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Solve it\n", "\n", "The problem object is now unsolved. You can call the `solve` method on it to find a solution." ], "metadata": { "id": "RJTWfR8-5fBd" } }, { "cell_type": "code", "source": [ "f\"Status: {pulp.LpStatus[problem.status]}\"\n", "problem.solve()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "4Fbltpbp5mRi", "outputId": "07f9c959-e9b0-4fe7-e7ea-c698703111ff" }, "execution_count": null, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "1" ] }, "metadata": {}, "execution_count": 9 } ] }, { "cell_type": "markdown", "source": [ "## Examine results\n", "\n", "After calling `solve` on a problem, you can access:\n", "- The status of the problem. It can be solved, but also it might show to be not feasible.\n", "- The values assigned to each decision variable.\n", "- The final value for the target function.\n", "\n" ], "metadata": { "id": "0pc9RmrO7FKo" } }, { "cell_type": "code", "source": [ "print(f\"Status: {pulp.LpStatus[problem.status]}\")\n", "for v in problem.variables():\n", " print(v.name, \"=\", v.varValue)\n", " \n", "print(pulp.value(problem.objective))" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "8U4xVvUg9W07", "outputId": "32a330f1-65ab-4903-f29b-368f2bacaf94" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Status: Optimal\n", "x = 10.0\n", "y = 50.0\n", "z = 0.0\n", "-150.0\n" ] } ] }, { "cell_type": "markdown", "source": [ "# Peanut Butter Example\n", "\n", "As an additional example, you can find below the model and solver for the Peanut Butter Sandwich example we discussed on lecture 6." ], "metadata": { "id": "I2lNaFm2XVK1" } }, { "cell_type": "code", "source": [ "pb = pulp.LpVariable(\n", " name=\"Peanut Butter grams\",\n", " cat=pulp.LpContinuous \n", " )\n", "\n", "b = pulp.LpVariable(\n", " name=\"Bread grams\",\n", " cat=pulp.LpContinuous \n", " )" ], "metadata": { "id": "HI4E2dNoXVK4" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "target_function = 5.88 * pb + 2.87 * b" ], "metadata": { "id": "PfTxq8R0XVLB" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "no_negative_pb = pb >= 0\n", "no_negative_b = b >= 0\n", "max_pb_we_have = pb <= 200\n", "max_b_we_have = b <= 300\n", "doctors_dietary_restriction = pb <= 0.13 * b" ], "metadata": { "id": "2X1AzQM8XVLD" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "problem = pulp.LpProblem(\"sandwich_problem\", pulp.LpMaximize)\n", "\n", "problem += target_function\n", "\n", "for constraint in (\n", " no_negative_pb,\n", " no_negative_b,\n", " max_pb_we_have,\n", " max_b_we_have,\n", " doctors_dietary_restriction\n", " ):\n", " problem += constraint" ], "metadata": { "id": "3oEoQXebXVLE" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "f\"Status: {pulp.LpStatus[problem.status]}\"\n", "problem.solve()\n", "print(f\"Status: {pulp.LpStatus[problem.status]}\")\n", "for v in problem.variables():\n", " print(v.name, \"=\", v.varValue)\n", " \n", "print(f\"Final calories: {pulp.value(problem.objective)}\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "d873d58d-6d9e-459e-d66f-127f436b1aab", "id": "u1vI73kiXVLF" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Status: Optimal\n", "Bread_grams = 300.0\n", "Peanut_Butter_grams = 39.0\n", "1090.32\n" ] } ] }, { "cell_type": "markdown", "source": [ "# Case 2\n", "\n", "You can use the rest of the notebook to work on the different parts of case 2." ], "metadata": { "id": "6kWgbTjU-LaN" } }, { "cell_type": "code", "source": [ "# Good luck!" ], "metadata": { "id": "aYzseTWh-Sal" }, "execution_count": null, "outputs": [] } ] }