265 lines
13 KiB
Plaintext
265 lines
13 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "google",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Copyright 2025 Google LLC."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "apache",
|
|
"metadata": {},
|
|
"source": [
|
|
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
|
"you may not use this file except in compliance with the License.\n",
|
|
"You may obtain a copy of the License at\n",
|
|
"\n",
|
|
" http://www.apache.org/licenses/LICENSE-2.0\n",
|
|
"\n",
|
|
"Unless required by applicable law or agreed to in writing, software\n",
|
|
"distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
|
"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
|
"See the License for the specific language governing permissions and\n",
|
|
"limitations under the License.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "basename",
|
|
"metadata": {},
|
|
"source": [
|
|
"# stigler_diet"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "link",
|
|
"metadata": {},
|
|
"source": [
|
|
"<table align=\"left\">\n",
|
|
"<td>\n",
|
|
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/main/examples/notebook/linear_solver/stigler_diet.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
|
"</td>\n",
|
|
"<td>\n",
|
|
"<a href=\"https://github.com/google/or-tools/blob/main/ortools/linear_solver/samples/stigler_diet.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
|
"</td>\n",
|
|
"</table>"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "doc",
|
|
"metadata": {},
|
|
"source": [
|
|
"First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "install",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%pip install ortools"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "description",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n",
|
|
"The Stigler diet problem.\n",
|
|
"\n",
|
|
"A description of the problem can be found here:\n",
|
|
"https://en.wikipedia.org/wiki/Stigler_diet.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "code",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from ortools.linear_solver import pywraplp\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"def main():\n",
|
|
" \"\"\"Entry point of the program.\"\"\"\n",
|
|
" # Instantiate the data problem.\n",
|
|
" # Nutrient minimums.\n",
|
|
" nutrients = [\n",
|
|
" [\"Calories (kcal)\", 3],\n",
|
|
" [\"Protein (g)\", 70],\n",
|
|
" [\"Calcium (g)\", 0.8],\n",
|
|
" [\"Iron (mg)\", 12],\n",
|
|
" [\"Vitamin A (KIU)\", 5],\n",
|
|
" [\"Vitamin B1 (mg)\", 1.8],\n",
|
|
" [\"Vitamin B2 (mg)\", 2.7],\n",
|
|
" [\"Niacin (mg)\", 18],\n",
|
|
" [\"Vitamin C (mg)\", 75],\n",
|
|
" ]\n",
|
|
"\n",
|
|
" # Commodity, Unit, 1939 price (cents), Calories (kcal), Protein (g),\n",
|
|
" # Calcium (g), Iron (mg), Vitamin A (KIU), Vitamin B1 (mg), Vitamin B2 (mg),\n",
|
|
" # Niacin (mg), Vitamin C (mg)\n",
|
|
" data = [\n",
|
|
" # fmt: off\n",
|
|
" ['Wheat Flour (Enriched)', '10 lb.', 36, 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0],\n",
|
|
" ['Macaroni', '1 lb.', 14.1, 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0],\n",
|
|
" ['Wheat Cereal (Enriched)', '28 oz.', 24.2, 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0],\n",
|
|
" ['Corn Flakes', '8 oz.', 7.1, 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0],\n",
|
|
" ['Corn Meal', '1 lb.', 4.6, 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0],\n",
|
|
" ['Hominy Grits', '24 oz.', 8.5, 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0],\n",
|
|
" ['Rice', '1 lb.', 7.5, 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0],\n",
|
|
" ['Rolled Oats', '1 lb.', 7.1, 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0],\n",
|
|
" ['White Bread (Enriched)', '1 lb.', 7.9, 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0],\n",
|
|
" ['Whole Wheat Bread', '1 lb.', 9.1, 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0],\n",
|
|
" ['Rye Bread', '1 lb.', 9.1, 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0],\n",
|
|
" ['Pound Cake', '1 lb.', 24.8, 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0],\n",
|
|
" ['Soda Crackers', '1 lb.', 15.1, 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0],\n",
|
|
" ['Milk', '1 qt.', 11, 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177],\n",
|
|
" ['Evaporated Milk (can)', '14.5 oz.', 6.7, 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60],\n",
|
|
" ['Butter', '1 lb.', 30.8, 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0],\n",
|
|
" ['Oleomargarine', '1 lb.', 16.1, 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0],\n",
|
|
" ['Eggs', '1 doz.', 32.6, 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0],\n",
|
|
" ['Cheese (Cheddar)', '1 lb.', 24.2, 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0],\n",
|
|
" ['Cream', '1/2 pt.', 14.1, 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17],\n",
|
|
" ['Peanut Butter', '1 lb.', 17.9, 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0],\n",
|
|
" ['Mayonnaise', '1/2 pt.', 16.7, 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0],\n",
|
|
" ['Crisco', '1 lb.', 20.3, 20.1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
|
" ['Lard', '1 lb.', 9.8, 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0],\n",
|
|
" ['Sirloin Steak', '1 lb.', 39.6, 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0],\n",
|
|
" ['Round Steak', '1 lb.', 36.4, 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0],\n",
|
|
" ['Rib Roast', '1 lb.', 29.2, 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0],\n",
|
|
" ['Chuck Roast', '1 lb.', 22.6, 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0],\n",
|
|
" ['Plate', '1 lb.', 14.6, 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0],\n",
|
|
" ['Liver (Beef)', '1 lb.', 26.8, 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525],\n",
|
|
" ['Leg of Lamb', '1 lb.', 27.6, 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0],\n",
|
|
" ['Lamb Chops (Rib)', '1 lb.', 36.6, 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0],\n",
|
|
" ['Pork Chops', '1 lb.', 30.7, 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0],\n",
|
|
" ['Pork Loin Roast', '1 lb.', 24.2, 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0],\n",
|
|
" ['Bacon', '1 lb.', 25.6, 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0],\n",
|
|
" ['Ham, smoked', '1 lb.', 27.4, 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0],\n",
|
|
" ['Salt Pork', '1 lb.', 16, 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0],\n",
|
|
" ['Roasting Chicken', '1 lb.', 30.3, 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46],\n",
|
|
" ['Veal Cutlets', '1 lb.', 42.3, 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0],\n",
|
|
" ['Salmon, Pink (can)', '16 oz.', 13, 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0],\n",
|
|
" ['Apples', '1 lb.', 4.4, 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544],\n",
|
|
" ['Bananas', '1 lb.', 6.1, 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498],\n",
|
|
" ['Lemons', '1 doz.', 26, 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952],\n",
|
|
" ['Oranges', '1 doz.', 30.9, 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998],\n",
|
|
" ['Green Beans', '1 lb.', 7.1, 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862],\n",
|
|
" ['Cabbage', '1 lb.', 3.7, 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369],\n",
|
|
" ['Carrots', '1 bunch', 4.7, 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608],\n",
|
|
" ['Celery', '1 stalk', 7.3, 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313],\n",
|
|
" ['Lettuce', '1 head', 8.2, 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449],\n",
|
|
" ['Onions', '1 lb.', 3.6, 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184],\n",
|
|
" ['Potatoes', '15 lb.', 34, 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522],\n",
|
|
" ['Spinach', '1 lb.', 8.1, 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755],\n",
|
|
" ['Sweet Potatoes', '1 lb.', 5.1, 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912],\n",
|
|
" ['Peaches (can)', 'No. 2 1/2', 16.8, 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196],\n",
|
|
" ['Pears (can)', 'No. 2 1/2', 20.4, 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81],\n",
|
|
" ['Pineapple (can)', 'No. 2 1/2', 21.3, 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399],\n",
|
|
" ['Asparagus (can)', 'No. 2', 27.7, 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272],\n",
|
|
" ['Green Beans (can)', 'No. 2', 10, 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431],\n",
|
|
" ['Pork and Beans (can)', '16 oz.', 7.1, 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0],\n",
|
|
" ['Corn (can)', 'No. 2', 10.4, 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218],\n",
|
|
" ['Peas (can)', 'No. 2', 13.8, 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370],\n",
|
|
" ['Tomatoes (can)', 'No. 2', 8.6, 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253],\n",
|
|
" ['Tomato Soup (can)', '10 1/2 oz.', 7.6, 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862],\n",
|
|
" ['Peaches, Dried', '1 lb.', 15.7, 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57],\n",
|
|
" ['Prunes, Dried', '1 lb.', 9, 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257],\n",
|
|
" ['Raisins, Dried', '15 oz.', 9.4, 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136],\n",
|
|
" ['Peas, Dried', '1 lb.', 7.9, 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0],\n",
|
|
" ['Lima Beans, Dried', '1 lb.', 8.9, 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0],\n",
|
|
" ['Navy Beans, Dried', '1 lb.', 5.9, 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0],\n",
|
|
" ['Coffee', '1 lb.', 22.4, 0, 0, 0, 0, 0, 4, 5.1, 50, 0],\n",
|
|
" ['Tea', '1/4 lb.', 17.4, 0, 0, 0, 0, 0, 0, 2.3, 42, 0],\n",
|
|
" ['Cocoa', '8 oz.', 8.6, 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0],\n",
|
|
" ['Chocolate', '8 oz.', 16.2, 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0],\n",
|
|
" ['Sugar', '10 lb.', 51.7, 34.9, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
|
" ['Corn Syrup', '24 oz.', 13.7, 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0],\n",
|
|
" ['Molasses', '18 oz.', 13.6, 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0],\n",
|
|
" ['Strawberry Preserves', '1 lb.', 20.5, 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0],\n",
|
|
" # fmt: on\n",
|
|
" ]\n",
|
|
"\n",
|
|
" # Instantiate a Glop solver and naming it.\n",
|
|
" solver = pywraplp.Solver.CreateSolver(\"GLOP\")\n",
|
|
" if not solver:\n",
|
|
" return\n",
|
|
"\n",
|
|
" # Declare an array to hold our variables.\n",
|
|
" foods = [solver.NumVar(0.0, solver.infinity(), item[0]) for item in data]\n",
|
|
"\n",
|
|
" print(\"Number of variables =\", solver.NumVariables())\n",
|
|
"\n",
|
|
" # Create the constraints, one per nutrient.\n",
|
|
" constraints = []\n",
|
|
" for i, nutrient in enumerate(nutrients):\n",
|
|
" constraints.append(solver.Constraint(nutrient[1], solver.infinity()))\n",
|
|
" for j, item in enumerate(data):\n",
|
|
" constraints[i].SetCoefficient(foods[j], item[i + 3])\n",
|
|
"\n",
|
|
" print(\"Number of constraints =\", solver.NumConstraints())\n",
|
|
"\n",
|
|
" # Objective function: Minimize the sum of (price-normalized) foods.\n",
|
|
" objective = solver.Objective()\n",
|
|
" for food in foods:\n",
|
|
" objective.SetCoefficient(food, 1)\n",
|
|
" objective.SetMinimization()\n",
|
|
"\n",
|
|
" print(f\"Solving with {solver.SolverVersion()}\")\n",
|
|
" status = solver.Solve()\n",
|
|
"\n",
|
|
" # Check that the problem has an optimal solution.\n",
|
|
" if status != solver.OPTIMAL:\n",
|
|
" print(\"The problem does not have an optimal solution!\")\n",
|
|
" if status == solver.FEASIBLE:\n",
|
|
" print(\"A potentially suboptimal solution was found.\")\n",
|
|
" else:\n",
|
|
" print(\"The solver could not solve the problem.\")\n",
|
|
" exit(1)\n",
|
|
"\n",
|
|
" # Display the amounts (in dollars) to purchase of each food.\n",
|
|
" nutrients_result = [0] * len(nutrients)\n",
|
|
" print(\"\\nAnnual Foods:\")\n",
|
|
" for i, food in enumerate(foods):\n",
|
|
" if food.solution_value() > 0.0:\n",
|
|
" print(\"{}: ${}\".format(data[i][0], 365.0 * food.solution_value()))\n",
|
|
" for j, _ in enumerate(nutrients):\n",
|
|
" nutrients_result[j] += data[i][j + 3] * food.solution_value()\n",
|
|
" print(\"\\nOptimal annual price: ${:.4f}\".format(365.0 * objective.Value()))\n",
|
|
"\n",
|
|
" print(\"\\nNutrients per day:\")\n",
|
|
" for i, nutrient in enumerate(nutrients):\n",
|
|
" print(\n",
|
|
" \"{}: {:.2f} (min {})\".format(nutrient[0], nutrients_result[i], nutrient[1])\n",
|
|
" )\n",
|
|
"\n",
|
|
" print(\"\\nAdvanced usage:\")\n",
|
|
" print(f\"Problem solved in {solver.wall_time():d} milliseconds\")\n",
|
|
" print(f\"Problem solved in {solver.iterations():d} iterations\")\n",
|
|
"\n",
|
|
"\n",
|
|
"main()\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"language_info": {
|
|
"name": "python"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|