В этом разделе мы покажем, как решить классическую проблему, называемую диетой Стиглера , названной в честь лауреата Нобелевской премии по экономике Джорджа Стиглера, который рассчитал недорогой способ удовлетворения основных потребностей в питании при наличии набора продуктов. Он представил это как математическое упражнение, а не как рекомендации по питанию, хотя идея расчета оптимального питания недавно вошла в моду .
Диета Стиглера требовала соблюдения этих минимумов:
Список питательных веществ
Питательное вещество | Рекомендуемая суточная доза |
---|---|
Калории | 3000 калорий |
Белок | 70 грамм |
Кальций | 0,8 грамма |
Железо | 12 миллиграмм |
Витамин А | 5000 МЕ |
Тиамин (витамин B1) | 1,8 миллиграммы |
Рибофлавин (витамин B2) | 2,7 миллиграмма |
Ниацин | 18 миллиграмм |
Аскорбиновая кислота (витамин С) | 75 миллиграмм |
Набор продуктов, которые оценивал Стиглер, был отражением времени (1944 г.). Приведенные ниже данные о питательной ценности приведены на доллар, а не на единицу, поэтому цель состоит в том, чтобы определить, сколько долларов потратить на каждый продукт.
Список товаров
Товар | Единица | Цена 1939 года (центов) | Калории (ккал) | Белок (г) | Кальций (г) | Железо (мг) | Витамин А (КИУ) | Тиамин (мг) | Рибофлавин (мг) | Ниацин (мг) | Аскорбиновая кислота (мг) |
---|---|---|---|---|---|---|---|---|---|---|---|
Пшеничная мука (обогащенная) | 10 фунтов. | 36 | 44,7 | 1411 | 2 | 365 | 0 | 55,4 | 33,3 | 441 | 0 |
Макароны | 1 фунт. | 14.1 | 11,6 | 418 | 0,7 | 54 | 0 | 3.2 | 1,9 | 68 | 0 |
Пшеничные хлопья (обогащенные) | 28 унций. | 24.2 | 11,8 | 377 | 14,4 | 175 | 0 | 14,4 | 8,8 | 114 | 0 |
Кукурузные хлопья | 8 унций. | 7.1 | 11.4 | 252 | 0,1 | 56 | 0 | 13,5 | 2.3 | 68 | 0 |
Кукурузная мука | 1 фунт. | 4.6 | 36,0 | 897 | 1,7 | 99 | 30,9 | 17,4 | 7,9 | 106 | 0 |
Мамалыга крупа | 24 унции. | 8,5 | 28,6 | 680 | 0,8 | 80 | 0 | 10,6 | 1,6 | 110 | 0 |
Рис | 1 фунт. | 7,5 | 21.2 | 460 | 0,6 | 41 | 0 | 2 | 4,8 | 60 | 0 |
Овсяные хлопья | 1 фунт. | 7.1 | 25,3 | 907 | 5.1 | 341 | 0 | 37,1 | 8,9 | 64 | 0 |
Белый Хлеб (обогащенный) | 1 фунт. | 7,9 | 15,0 | 488 | 2,5 | 115 | 0 | 13,8 | 8,5 | 126 | 0 |
Цельнозерновой хлеб | 1 фунт. | 9.1 | 12.2 | 484 | 2,7 | 125 | 0 | 13,9 | 6.4 | 160 | 0 |
Ржаной хлеб | 1 фунт. | 9.1 | 12.4 | 439 | 1.1 | 82 | 0 | 9,9 | 3 | 66 | 0 |
Фунтовый пирог | 1 фунт. | 24,8 | 8.0 | 130 | 0,4 | 31 | 18,9 | 2,8 | 3 | 17 | 0 |
Содовые крекеры | 1 фунт. | 15.1 | 12,5 | 288 | 0,5 | 50 | 0 | 0 | 0 | 0 | 0 |
Молоко | 1 кварта. | 11 | 6.1 | 310 | 10,5 | 18 | 16,8 | 4 | 16 | 7 | 177 |
Сгущенное молоко (банка) | 14,5 унций. | 6,7 | 8.4 | 422 | 15.1 | 9 | 26 | 3 | 23,5 | 11 | 60 |
Масло | 1 фунт. | 30,8 | 10,8 | 9 | 0,2 | 3 | 44,2 | 0 | 0,2 | 2 | 0 |
Олеомаргарин | 1 фунт. | 16.1 | 20,6 | 17 | 0,6 | 6 | 55,8 | 0,2 | 0 | 0 | 0 |
Яйца | 1 доза. | 32,6 | 2,9 | 238 | 1.0 | 52 | 18,6 | 2,8 | 6,5 | 1 | 0 |
Сыр (Чеддер) | 1 фунт. | 24.2 | 7.4 | 448 | 16,4 | 19 | 28,1 | 0,8 | 10.3 | 4 | 0 |
Крем | 1/2 пт. | 14.1 | 3,5 | 49 | 1,7 | 3 | 16,9 | 0,6 | 2,5 | 0 | 17 |
Арахисовое масло | 1 фунт. | 17,9 | 15,7 | 661 | 1.0 | 48 | 0 | 9,6 | 8.1 | 471 | 0 |
Майонез | 1/2 пт. | 16,7 | 8,6 | 18 | 0,2 | 8 | 2,7 | 0,4 | 0,5 | 0 | 0 |
Криско | 1 фунт. | 20.3 | 20.1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Сало | 1 фунт. | 9,8 | 41,7 | 0 | 0 | 0 | 0,2 | 0 | 0,5 | 5 | 0 |
Стейк без костей | 1 фунт. | 39,6 | 2,9 | 166 | 0,1 | 34 | 0,2 | 2.1 | 2,9 | 69 | 0 |
Круглый стейк | 1 фунт. | 36,4 | 2.2 | 214 | 0,1 | 32 | 0,4 | 2,5 | 2.4 | 87 | 0 |
Жаркое из ребрышек | 1 фунт. | 29,2 | 3.4 | 213 | 0,1 | 33 | 0 | 0 | 2 | 0 | 0 |
Чак Рост | 1 фунт. | 22,6 | 3.6 | 309 | 0,2 | 46 | 0,4 | 1 | 4 | 120 | 0 |
Тарелка | 1 фунт. | 14,6 | 8,5 | 404 | 0,2 | 62 | 0 | 0,9 | 0 | 0 | 0 |
Печень (говяжья) | 1 фунт. | 26,8 | 2.2 | 333 | 0,2 | 139 | 169,2 | 6.4 | 50,8 | 316 | 525 |
Баранья нога | 1 фунт. | 27,6 | 3.1 | 245 | 0,1 | 20 | 0 | 2,8 | 3,9 | 86 | 0 |
Бараньи отбивные (ребрышки) | 1 фунт. | 36,6 | 3.3 | 140 | 0,1 | 15 | 0 | 1,7 | 2,7 | 54 | 0 |
Свиные отбивные | 1 фунт. | 30,7 | 3,5 | 196 | 0,2 | 30 | 0 | 17,4 | 2,7 | 60 | 0 |
Жареная свиная корейка | 1 фунт. | 24.2 | 4.4 | 249 | 0,3 | 37 | 0 | 18.2 | 3.6 | 79 | 0 |
Бекон | 1 фунт. | 25,6 | 10.4 | 152 | 0,2 | 23 | 0 | 1,8 | 1,8 | 71 | 0 |
Ветчина, копченая | 1 фунт. | 27,4 | 6,7 | 212 | 0,2 | 31 | 0 | 9,9 | 3.3 | 50 | 0 |
Соленая свинина | 1 фунт. | 16 | 18,8 | 164 | 0,1 | 26 | 0 | 1,4 | 1,8 | 0 | 0 |
Жареная курица | 1 фунт. | 30,3 | 1,8 | 184 | 0,1 | 30 | 0,1 | 0,9 | 1,8 | 68 | 46 |
Котлеты из телятины | 1 фунт. | 42,3 | 1,7 | 156 | 0,1 | 24 | 0 | 1,4 | 2.4 | 57 | 0 |
Лосось, Розовый (банка) | 16 унций. | 13 | 5,8 | 705 | 6,8 | 45 | 3,5 | 1 | 4,9 | 209 | 0 |
Яблоки | 1 фунт. | 4.4 | 5,8 | 27 | 0,5 | 36 | 7.3 | 3.6 | 2,7 | 5 | 544 |
Бананы | 1 фунт. | 6.1 | 4,9 | 60 | 0,4 | 30 | 17,4 | 2,5 | 3,5 | 28 | 498 |
Лимоны | 1 доза. | 26 | 1.0 | 21 | 0,5 | 14 | 0 | 0,5 | 0 | 4 | 952 |
Апельсины | 1 доза. | 30,9 | 2.2 | 40 | 1.1 | 18 | 11.1 | 3.6 | 1.3 | 10 | 1998 год |
Зеленая фасоль | 1 фунт. | 7.1 | 2.4 | 138 | 3.7 | 80 | 69 | 4.3 | 5,8 | 37 | 862 |
Капуста | 1 фунт. | 3.7 | 2.6 | 125 | 4.0 | 36 | 7.2 | 9 | 4,5 | 26 | 5369 |
Морковь | 1 пучок | 4.7 | 2,7 | 73 | 2,8 | 43 | 188,5 | 6.1 | 4.3 | 89 | 608 |
Сельдерей | 1 стебель | 7.3 | 0,9 | 51 | 3.0 | 23 | 0,9 | 1,4 | 1,4 | 9 | 313 |
Латук | 1 голова | 8.2 | 0,4 | 27 | 1.1 | 22 | 112,4 | 1,8 | 3.4 | 11 | 449 |
Лук | 1 фунт. | 3.6 | 5,8 | 166 | 3,8 | 59 | 16,6 | 4.7 | 5,9 | 21 | 1184 |
Картофель | 15 фунтов. | 34 | 14.3 | 336 | 1,8 | 118 | 6,7 | 29,4 | 7.1 | 198 | 2522 |
Шпинат | 1 фунт. | 8.1 | 1.1 | 106 | 0 | 138 | 918,4 | 5,7 | 13,8 | 33 | 2755 |
Сладкий картофель | 1 фунт. | 5.1 | 9,6 | 138 | 2,7 | 54 | 290,7 | 8.4 | 5.4 | 83 | 1912 год |
Персики (банка) | № 2 1/2 | 16,8 | 3.7 | 20 | 0,4 | 10 | 21,5 | 0,5 | 1 | 31 | 196 |
Груши (можно) | № 2 1/2 | 20,4 | 3.0 | 8 | 0,3 | 8 | 0,8 | 0,8 | 0,8 | 5 | 81 |
Ананас (банка) | № 2 1/2 | 21,3 | 2.4 | 16 | 0,4 | 8 | 2 | 2,8 | 0,8 | 7 | 399 |
Спаржа (можно) | № 2 | 27,7 | 0,4 | 33 | 0,3 | 12 | 16.3 | 1,4 | 2.1 | 17 | 272 |
Зеленая фасоль (банка) | № 2 | 10 | 1.0 | 54 | 2 | 65 | 53,9 | 1,6 | 4.3 | 32 | 431 |
Свинина и фасоль (банка) | 16 унций. | 7.1 | 7,5 | 364 | 4 | 134 | 3,5 | 8.3 | 7,7 | 56 | 0 |
Кукуруза (банка) | № 2 | 10.4 | 5.2 | 136 | 0,2 | 16 | 12 | 1,6 | 2,7 | 42 | 218 |
Горох (банка) | № 2 | 13,8 | 2.3 | 136 | 0,6 | 45 | 34,9 | 4,9 | 2,5 | 37 | 370 |
Помидоры (банка) | № 2 | 8,6 | 1.3 | 63 | 0,7 | 38 | 53,2 | 3.4 | 2,5 | 36 | 1253 |
Томатный суп (банка) | 10 1/2 унции. | 7,6 | 1,6 | 71 | 0,6 | 43 | 57,9 | 3,5 | 2.4 | 67 | 862 |
Персики сушеные | 1 фунт. | 15,7 | 8,5 | 87 | 1,7 | 173 | 86,8 | 1.2 | 4.3 | 55 | 57 |
Чернослив сушеный | 1 фунт. | 9 | 12,8 | 99 | 2,5 | 154 | 85,7 | 3,9 | 4.3 | 65 | 257 |
Изюм сушеный | 15 унций. | 9.4 | 13,5 | 104 | 2,5 | 136 | 4,5 | 6.3 | 1,4 | 24 | 136 |
Горох сушеный | 1 фунт. | 7,9 | 20,0 | 1367 | 4.2 | 345 | 2,9 | 28,7 | 18,4 | 162 | 0 |
Лимская фасоль, сушеная | 1 фунт. | 8,9 | 17,4 | 1055 | 3.7 | 459 | 5.1 | 26,9 | 38,2 | 93 | 0 |
Фасоль темно-синяя, сушеная | 1 фунт. | 5,9 | 26,9 | 1691 г. | 11.4 | 792 | 0 | 38,4 | 24,6 | 217 | 0 |
Кофе | 1 фунт. | 22,4 | 0 | 0 | 0 | 0 | 0 | 4 | 5.1 | 50 | 0 |
Чай | 1/4 фунта. | 17,4 | 0 | 0 | 0 | 0 | 0 | 0 | 2.3 | 42 | 0 |
Какао | 8 унций. | 8,6 | 8,7 | 237 | 3 | 72 | 0 | 2 | 11,9 | 40 | 0 |
Шоколад | 8 унций. | 16.2 | 8.0 | 77 | 1.3 | 39 | 0 | 0,9 | 3.4 | 14 | 0 |
Сахар | 10 фунтов. | 51,7 | 34,9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Кукурузный сироп | 24 унции. | 13,7 | 14,7 | 0 | 0,5 | 74 | 0 | 0 | 0 | 5 | 0 |
Патока | 18 унций. | 13,6 | 9,0 | 0 | 10.3 | 244 | 0 | 1,9 | 7,5 | 146 | 0 |
Клубничное варенье | 1 фунт. | 20,5 | 6.4 | 11 | 0,4 | 7 | 0,2 | 0,2 | 0,4 | 3 | 0 |
Поскольку все питательные вещества нормализованы по цене, наша цель — просто свести к минимуму количество продуктов.
В 1944 году Стиглер вычислил лучший ответ, который только мог, и с грустью отметил:
...похоже, не существует какого-либо прямого метода нахождения минимума линейной функции при соблюдении линейных условий.
Он нашел диету, которая стоила 39,93 доллара в год в долларах 1939 года. В 1947 году Джек Ладерман применил симплексный метод (тогда это было недавнее изобретение!) для определения оптимального решения. Чтобы найти ответ, потребовалось 120 человеко-дней работы девяти клерков с настольными калькуляторами.
Решение с использованием линейного решателя
В следующих разделах представлена программа, решающая проблему диеты Стиглера.
Импортируйте оболочку линейного решателя
Импортируйте оболочку линейного решателя OR-Tools, интерфейс для линейного решателя [GLOP](/optimization/mip/glop0, как показано ниже.
Питон
from ortools.linear_solver import pywraplp
С++
#include <array> #include <memory> #include <string> #include <utility> // std::pair #include <vector> #include "absl/flags/flag.h" #include "absl/log/flags.h" #include "ortools/base/init_google.h" #include "ortools/base/logging.h" #include "ortools/linear_solver/linear_solver.h"
Ява
import com.google.ortools.Loader; import com.google.ortools.linearsolver.MPConstraint; import com.google.ortools.linearsolver.MPObjective; import com.google.ortools.linearsolver.MPSolver; import com.google.ortools.linearsolver.MPVariable; import java.util.ArrayList; import java.util.List;
С#
using System; using System.Collections.Generic; using Google.OrTools.LinearSolver;
Данные по проблеме
Следующий код создает массив nutrients
для минимальных потребностей в питательных веществах и массив data
для таблицы данных о питательных веществах в любом растворе.
Питон
# Nutrient minimums. nutrients = [ ["Calories (kcal)", 3], ["Protein (g)", 70], ["Calcium (g)", 0.8], ["Iron (mg)", 12], ["Vitamin A (KIU)", 5], ["Vitamin B1 (mg)", 1.8], ["Vitamin B2 (mg)", 2.7], ["Niacin (mg)", 18], ["Vitamin C (mg)", 75], ] # Commodity, Unit, 1939 price (cents), Calories (kcal), Protein (g), # Calcium (g), Iron (mg), Vitamin A (KIU), Vitamin B1 (mg), Vitamin B2 (mg), # Niacin (mg), Vitamin C (mg) data = [ # fmt: off ['Wheat Flour (Enriched)', '10 lb.', 36, 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0], ['Macaroni', '1 lb.', 14.1, 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0], ['Wheat Cereal (Enriched)', '28 oz.', 24.2, 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0], ['Corn Flakes', '8 oz.', 7.1, 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0], ['Corn Meal', '1 lb.', 4.6, 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0], ['Hominy Grits', '24 oz.', 8.5, 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0], ['Rice', '1 lb.', 7.5, 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0], ['Rolled Oats', '1 lb.', 7.1, 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0], ['White Bread (Enriched)', '1 lb.', 7.9, 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0], ['Whole Wheat Bread', '1 lb.', 9.1, 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0], ['Rye Bread', '1 lb.', 9.1, 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0], ['Pound Cake', '1 lb.', 24.8, 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0], ['Soda Crackers', '1 lb.', 15.1, 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0], ['Milk', '1 qt.', 11, 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177], ['Evaporated Milk (can)', '14.5 oz.', 6.7, 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60], ['Butter', '1 lb.', 30.8, 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0], ['Oleomargarine', '1 lb.', 16.1, 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0], ['Eggs', '1 doz.', 32.6, 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0], ['Cheese (Cheddar)', '1 lb.', 24.2, 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0], ['Cream', '1/2 pt.', 14.1, 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17], ['Peanut Butter', '1 lb.', 17.9, 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0], ['Mayonnaise', '1/2 pt.', 16.7, 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0], ['Crisco', '1 lb.', 20.3, 20.1, 0, 0, 0, 0, 0, 0, 0, 0], ['Lard', '1 lb.', 9.8, 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0], ['Sirloin Steak', '1 lb.', 39.6, 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0], ['Round Steak', '1 lb.', 36.4, 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0], ['Rib Roast', '1 lb.', 29.2, 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0], ['Chuck Roast', '1 lb.', 22.6, 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0], ['Plate', '1 lb.', 14.6, 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0], ['Liver (Beef)', '1 lb.', 26.8, 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525], ['Leg of Lamb', '1 lb.', 27.6, 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0], ['Lamb Chops (Rib)', '1 lb.', 36.6, 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0], ['Pork Chops', '1 lb.', 30.7, 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0], ['Pork Loin Roast', '1 lb.', 24.2, 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0], ['Bacon', '1 lb.', 25.6, 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0], ['Ham, smoked', '1 lb.', 27.4, 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0], ['Salt Pork', '1 lb.', 16, 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0], ['Roasting Chicken', '1 lb.', 30.3, 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46], ['Veal Cutlets', '1 lb.', 42.3, 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0], ['Salmon, Pink (can)', '16 oz.', 13, 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0], ['Apples', '1 lb.', 4.4, 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544], ['Bananas', '1 lb.', 6.1, 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498], ['Lemons', '1 doz.', 26, 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952], ['Oranges', '1 doz.', 30.9, 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998], ['Green Beans', '1 lb.', 7.1, 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862], ['Cabbage', '1 lb.', 3.7, 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369], ['Carrots', '1 bunch', 4.7, 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608], ['Celery', '1 stalk', 7.3, 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313], ['Lettuce', '1 head', 8.2, 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449], ['Onions', '1 lb.', 3.6, 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184], ['Potatoes', '15 lb.', 34, 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522], ['Spinach', '1 lb.', 8.1, 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755], ['Sweet Potatoes', '1 lb.', 5.1, 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912], ['Peaches (can)', 'No. 2 1/2', 16.8, 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196], ['Pears (can)', 'No. 2 1/2', 20.4, 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81], ['Pineapple (can)', 'No. 2 1/2', 21.3, 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399], ['Asparagus (can)', 'No. 2', 27.7, 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272], ['Green Beans (can)', 'No. 2', 10, 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431], ['Pork and Beans (can)', '16 oz.', 7.1, 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0], ['Corn (can)', 'No. 2', 10.4, 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218], ['Peas (can)', 'No. 2', 13.8, 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370], ['Tomatoes (can)', 'No. 2', 8.6, 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253], ['Tomato Soup (can)', '10 1/2 oz.', 7.6, 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862], ['Peaches, Dried', '1 lb.', 15.7, 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57], ['Prunes, Dried', '1 lb.', 9, 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257], ['Raisins, Dried', '15 oz.', 9.4, 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136], ['Peas, Dried', '1 lb.', 7.9, 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0], ['Lima Beans, Dried', '1 lb.', 8.9, 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0], ['Navy Beans, Dried', '1 lb.', 5.9, 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0], ['Coffee', '1 lb.', 22.4, 0, 0, 0, 0, 0, 4, 5.1, 50, 0], ['Tea', '1/4 lb.', 17.4, 0, 0, 0, 0, 0, 0, 2.3, 42, 0], ['Cocoa', '8 oz.', 8.6, 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0], ['Chocolate', '8 oz.', 16.2, 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0], ['Sugar', '10 lb.', 51.7, 34.9, 0, 0, 0, 0, 0, 0, 0, 0], ['Corn Syrup', '24 oz.', 13.7, 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0], ['Molasses', '18 oz.', 13.6, 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0], ['Strawberry Preserves', '1 lb.', 20.5, 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0], # fmt: on ]
С++
// Nutrient minimums. const std::vector<std::pair<std::string, double>> nutrients = { {"Calories (kcal)", 3.0}, {"Protein (g)", 70.0}, {"Calcium (g)", 0.8}, {"Iron (mg)", 12.0}, {"Vitamin A (kIU)", 5.0}, {"Vitamin B1 (mg)", 1.8}, {"Vitamin B2 (mg)", 2.7}, {"Niacin (mg)", 18.0}, {"Vitamin C (mg)", 75.0}}; struct Commodity { std::string name; //!< Commodity name std::string unit; //!< Unit double price; //!< 1939 price per unit (cents) //! Calories (kcal), //! Protein (g), //! Calcium (g), //! Iron (mg), //! Vitamin A (kIU), //! Vitamin B1 (mg), //! Vitamin B2 (mg), //! Niacin (mg), //! Vitamin C (mg) std::array<double, 9> nutrients; }; std::vector<Commodity> data = { {"Wheat Flour (Enriched)", "10 lb.", 36, {44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0}}, {"Macaroni", "1 lb.", 14.1, {11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0}}, {"Wheat Cereal (Enriched)", "28 oz.", 24.2, {11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0}}, {"Corn Flakes", "8 oz.", 7.1, {11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0}}, {"Corn Meal", "1 lb.", 4.6, {36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0}}, {"Hominy Grits", "24 oz.", 8.5, {28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0}}, {"Rice", "1 lb.", 7.5, {21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0}}, {"Rolled Oats", "1 lb.", 7.1, {25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0}}, {"White Bread (Enriched)", "1 lb.", 7.9, {15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0}}, {"Whole Wheat Bread", "1 lb.", 9.1, {12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0}}, {"Rye Bread", "1 lb.", 9.1, {12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0}}, {"Pound Cake", "1 lb.", 24.8, {8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0}}, {"Soda Crackers", "1 lb.", 15.1, {12.5, 288, 0.5, 50, 0, 0, 0, 0, 0}}, {"Milk", "1 qt.", 11, {6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177}}, {"Evaporated Milk (can)", "14.5 oz.", 6.7, {8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60}}, {"Butter", "1 lb.", 30.8, {10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0}}, {"Oleomargarine", "1 lb.", 16.1, {20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0}}, {"Eggs", "1 doz.", 32.6, {2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0}}, {"Cheese (Cheddar)", "1 lb.", 24.2, {7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0}}, {"Cream", "1/2 pt.", 14.1, {3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17}}, {"Peanut Butter", "1 lb.", 17.9, {15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0}}, {"Mayonnaise", "1/2 pt.", 16.7, {8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0}}, {"Crisco", "1 lb.", 20.3, {20.1, 0, 0, 0, 0, 0, 0, 0, 0}}, {"Lard", "1 lb.", 9.8, {41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0}}, {"Sirloin Steak", "1 lb.", 39.6, {2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0}}, {"Round Steak", "1 lb.", 36.4, {2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0}}, {"Rib Roast", "1 lb.", 29.2, {3.4, 213, 0.1, 33, 0, 0, 2, 0, 0}}, {"Chuck Roast", "1 lb.", 22.6, {3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0}}, {"Plate", "1 lb.", 14.6, {8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0}}, {"Liver (Beef)", "1 lb.", 26.8, {2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525}}, {"Leg of Lamb", "1 lb.", 27.6, {3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0}}, {"Lamb Chops (Rib)", "1 lb.", 36.6, {3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0}}, {"Pork Chops", "1 lb.", 30.7, {3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0}}, {"Pork Loin Roast", "1 lb.", 24.2, {4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0}}, {"Bacon", "1 lb.", 25.6, {10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0}}, {"Ham, smoked", "1 lb.", 27.4, {6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0}}, {"Salt Pork", "1 lb.", 16, {18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0}}, {"Roasting Chicken", "1 lb.", 30.3, {1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46}}, {"Veal Cutlets", "1 lb.", 42.3, {1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0}}, {"Salmon, Pink (can)", "16 oz.", 13, {5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0}}, {"Apples", "1 lb.", 4.4, {5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544}}, {"Bananas", "1 lb.", 6.1, {4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498}}, {"Lemons", "1 doz.", 26, {1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952}}, {"Oranges", "1 doz.", 30.9, {2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998}}, {"Green Beans", "1 lb.", 7.1, {2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862}}, {"Cabbage", "1 lb.", 3.7, {2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369}}, {"Carrots", "1 bunch", 4.7, {2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608}}, {"Celery", "1 stalk", 7.3, {0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313}}, {"Lettuce", "1 head", 8.2, {0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449}}, {"Onions", "1 lb.", 3.6, {5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184}}, {"Potatoes", "15 lb.", 34, {14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522}}, {"Spinach", "1 lb.", 8.1, {1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755}}, {"Sweet Potatoes", "1 lb.", 5.1, {9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912}}, {"Peaches (can)", "No. 2 1/2", 16.8, {3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196}}, {"Pears (can)", "No. 2 1/2", 20.4, {3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81}}, {"Pineapple (can)", "No. 2 1/2", 21.3, {2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399}}, {"Asparagus (can)", "No. 2", 27.7, {0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272}}, {"Green Beans (can)", "No. 2", 10, {1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431}}, {"Pork and Beans (can)", "16 oz.", 7.1, {7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0}}, {"Corn (can)", "No. 2", 10.4, {5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218}}, {"Peas (can)", "No. 2", 13.8, {2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370}}, {"Tomatoes (can)", "No. 2", 8.6, {1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253}}, {"Tomato Soup (can)", "10 1/2 oz.", 7.6, {1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862}}, {"Peaches, Dried", "1 lb.", 15.7, {8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57}}, {"Prunes, Dried", "1 lb.", 9, {12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257}}, {"Raisins, Dried", "15 oz.", 9.4, {13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136}}, {"Peas, Dried", "1 lb.", 7.9, {20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0}}, {"Lima Beans, Dried", "1 lb.", 8.9, {17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0}}, {"Navy Beans, Dried", "1 lb.", 5.9, {26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0}}, {"Coffee", "1 lb.", 22.4, {0, 0, 0, 0, 0, 4, 5.1, 50, 0}}, {"Tea", "1/4 lb.", 17.4, {0, 0, 0, 0, 0, 0, 2.3, 42, 0}}, {"Cocoa", "8 oz.", 8.6, {8.7, 237, 3, 72, 0, 2, 11.9, 40, 0}}, {"Chocolate", "8 oz.", 16.2, {8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0}}, {"Sugar", "10 lb.", 51.7, {34.9, 0, 0, 0, 0, 0, 0, 0, 0}}, {"Corn Syrup", "24 oz.", 13.7, {14.7, 0, 0.5, 74, 0, 0, 0, 5, 0}}, {"Molasses", "18 oz.", 13.6, {9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0}}, {"Strawberry Preserves", "1 lb.", 20.5, {6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}}};
Ява
// Nutrient minimums. List<Object[]> nutrients = new ArrayList<>(); nutrients.add(new Object[] {"Calories (kcal)", 3.0}); nutrients.add(new Object[] {"Protein (g)", 70.0}); nutrients.add(new Object[] {"Calcium (g)", 0.8}); nutrients.add(new Object[] {"Iron (mg)", 12.0}); nutrients.add(new Object[] {"Vitamin A (kIU)", 5.0}); nutrients.add(new Object[] {"Vitamin B1 (mg)", 1.8}); nutrients.add(new Object[] {"Vitamin B2 (mg)", 2.7}); nutrients.add(new Object[] {"Niacin (mg)", 18.0}); nutrients.add(new Object[] {"Vitamin C (mg)", 75.0}); List<Object[]> data = new ArrayList<>(); data.add(new Object[] {"Wheat Flour (Enriched)", "10 lb.", 36, new double[] {44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0}}); data.add(new Object[] { "Macaroni", "1 lb.", 14.1, new double[] {11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0}}); data.add(new Object[] {"Wheat Cereal (Enriched)", "28 oz.", 24.2, new double[] {11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0}}); data.add(new Object[] { "Corn Flakes", "8 oz.", 7.1, new double[] {11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0}}); data.add(new Object[] { "Corn Meal", "1 lb.", 4.6, new double[] {36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0}}); data.add(new Object[] { "Hominy Grits", "24 oz.", 8.5, new double[] {28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0}}); data.add( new Object[] {"Rice", "1 lb.", 7.5, new double[] {21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0}}); data.add(new Object[] { "Rolled Oats", "1 lb.", 7.1, new double[] {25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0}}); data.add(new Object[] {"White Bread (Enriched)", "1 lb.", 7.9, new double[] {15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0}}); data.add(new Object[] {"Whole Wheat Bread", "1 lb.", 9.1, new double[] {12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0}}); data.add(new Object[] { "Rye Bread", "1 lb.", 9.1, new double[] {12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0}}); data.add(new Object[] { "Pound Cake", "1 lb.", 24.8, new double[] {8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0}}); data.add(new Object[] { "Soda Crackers", "1 lb.", 15.1, new double[] {12.5, 288, 0.5, 50, 0, 0, 0, 0, 0}}); data.add( new Object[] {"Milk", "1 qt.", 11, new double[] {6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177}}); data.add(new Object[] {"Evaporated Milk (can)", "14.5 oz.", 6.7, new double[] {8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60}}); data.add( new Object[] {"Butter", "1 lb.", 30.8, new double[] {10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0}}); data.add(new Object[] { "Oleomargarine", "1 lb.", 16.1, new double[] {20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0}}); data.add(new Object[] { "Eggs", "1 doz.", 32.6, new double[] {2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0}}); data.add(new Object[] {"Cheese (Cheddar)", "1 lb.", 24.2, new double[] {7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0}}); data.add(new Object[] { "Cream", "1/2 pt.", 14.1, new double[] {3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17}}); data.add(new Object[] { "Peanut Butter", "1 lb.", 17.9, new double[] {15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0}}); data.add(new Object[] { "Mayonnaise", "1/2 pt.", 16.7, new double[] {8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0}}); data.add(new Object[] {"Crisco", "1 lb.", 20.3, new double[] {20.1, 0, 0, 0, 0, 0, 0, 0, 0}}); data.add(new Object[] {"Lard", "1 lb.", 9.8, new double[] {41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0}}); data.add(new Object[] { "Sirloin Steak", "1 lb.", 39.6, new double[] {2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0}}); data.add(new Object[] { "Round Steak", "1 lb.", 36.4, new double[] {2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0}}); data.add( new Object[] {"Rib Roast", "1 lb.", 29.2, new double[] {3.4, 213, 0.1, 33, 0, 0, 2, 0, 0}}); data.add(new Object[] { "Chuck Roast", "1 lb.", 22.6, new double[] {3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0}}); data.add( new Object[] {"Plate", "1 lb.", 14.6, new double[] {8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0}}); data.add(new Object[] {"Liver (Beef)", "1 lb.", 26.8, new double[] {2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525}}); data.add(new Object[] { "Leg of Lamb", "1 lb.", 27.6, new double[] {3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0}}); data.add(new Object[] { "Lamb Chops (Rib)", "1 lb.", 36.6, new double[] {3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0}}); data.add(new Object[] { "Pork Chops", "1 lb.", 30.7, new double[] {3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0}}); data.add(new Object[] { "Pork Loin Roast", "1 lb.", 24.2, new double[] {4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0}}); data.add(new Object[] { "Bacon", "1 lb.", 25.6, new double[] {10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0}}); data.add(new Object[] { "Ham, smoked", "1 lb.", 27.4, new double[] {6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0}}); data.add(new Object[] { "Salt Pork", "1 lb.", 16, new double[] {18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0}}); data.add(new Object[] {"Roasting Chicken", "1 lb.", 30.3, new double[] {1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46}}); data.add(new Object[] { "Veal Cutlets", "1 lb.", 42.3, new double[] {1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0}}); data.add(new Object[] { "Salmon, Pink (can)", "16 oz.", 13, new double[] {5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0}}); data.add(new Object[] { "Apples", "1 lb.", 4.4, new double[] {5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544}}); data.add(new Object[] { "Bananas", "1 lb.", 6.1, new double[] {4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498}}); data.add( new Object[] {"Lemons", "1 doz.", 26, new double[] {1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952}}); data.add(new Object[] { "Oranges", "1 doz.", 30.9, new double[] {2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998}}); data.add(new Object[] { "Green Beans", "1 lb.", 7.1, new double[] {2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862}}); data.add(new Object[] { "Cabbage", "1 lb.", 3.7, new double[] {2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369}}); data.add(new Object[] { "Carrots", "1 bunch", 4.7, new double[] {2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608}}); data.add(new Object[] { "Celery", "1 stalk", 7.3, new double[] {0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313}}); data.add(new Object[] { "Lettuce", "1 head", 8.2, new double[] {0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449}}); data.add(new Object[] { "Onions", "1 lb.", 3.6, new double[] {5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184}}); data.add(new Object[] { "Potatoes", "15 lb.", 34, new double[] {14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522}}); data.add(new Object[] { "Spinach", "1 lb.", 8.1, new double[] {1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755}}); data.add(new Object[] {"Sweet Potatoes", "1 lb.", 5.1, new double[] {9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912}}); data.add(new Object[] {"Peaches (can)", "No. 2 1/2", 16.8, new double[] {3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196}}); data.add(new Object[] { "Pears (can)", "No. 2 1/2", 20.4, new double[] {3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81}}); data.add(new Object[] { "Pineapple (can)", "No. 2 1/2", 21.3, new double[] {2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399}}); data.add(new Object[] {"Asparagus (can)", "No. 2", 27.7, new double[] {0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272}}); data.add(new Object[] { "Green Beans (can)", "No. 2", 10, new double[] {1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431}}); data.add(new Object[] {"Pork and Beans (can)", "16 oz.", 7.1, new double[] {7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0}}); data.add(new Object[] { "Corn (can)", "No. 2", 10.4, new double[] {5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218}}); data.add(new Object[] { "Peas (can)", "No. 2", 13.8, new double[] {2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370}}); data.add(new Object[] { "Tomatoes (can)", "No. 2", 8.6, new double[] {1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253}}); data.add(new Object[] {"Tomato Soup (can)", "10 1/2 oz.", 7.6, new double[] {1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862}}); data.add(new Object[] { "Peaches, Dried", "1 lb.", 15.7, new double[] {8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57}}); data.add(new Object[] { "Prunes, Dried", "1 lb.", 9, new double[] {12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257}}); data.add(new Object[] {"Raisins, Dried", "15 oz.", 9.4, new double[] {13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136}}); data.add(new Object[] { "Peas, Dried", "1 lb.", 7.9, new double[] {20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0}}); data.add(new Object[] {"Lima Beans, Dried", "1 lb.", 8.9, new double[] {17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0}}); data.add(new Object[] {"Navy Beans, Dried", "1 lb.", 5.9, new double[] {26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0}}); data.add(new Object[] {"Coffee", "1 lb.", 22.4, new double[] {0, 0, 0, 0, 0, 4, 5.1, 50, 0}}); data.add(new Object[] {"Tea", "1/4 lb.", 17.4, new double[] {0, 0, 0, 0, 0, 0, 2.3, 42, 0}}); data.add( new Object[] {"Cocoa", "8 oz.", 8.6, new double[] {8.7, 237, 3, 72, 0, 2, 11.9, 40, 0}}); data.add(new Object[] { "Chocolate", "8 oz.", 16.2, new double[] {8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0}}); data.add(new Object[] {"Sugar", "10 lb.", 51.7, new double[] {34.9, 0, 0, 0, 0, 0, 0, 0, 0}}); data.add(new Object[] { "Corn Syrup", "24 oz.", 13.7, new double[] {14.7, 0, 0.5, 74, 0, 0, 0, 5, 0}}); data.add(new Object[] { "Molasses", "18 oz.", 13.6, new double[] {9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0}}); data.add(new Object[] {"Strawberry Preserves", "1 lb.", 20.5, new double[] {6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}});
С#
// Nutrient minimums. (String Name, double Value)[] nutrients = new[] { ("Calories (kcal)", 3.0), ("Protein (g)", 70.0), ("Calcium (g)", 0.8), ("Iron (mg)", 12.0), ("Vitamin A (kIU)", 5.0), ("Vitamin B1 (mg)", 1.8), ("Vitamin B2 (mg)", 2.7), ("Niacin (mg)", 18.0), ("Vitamin C (mg)", 75.0) }; (String Name, String Unit, double Price, double[] Nutrients)[] data = new[] { ("Wheat Flour (Enriched)", "10 lb.", 36, new double[] { 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0 }), ("Macaroni", "1 lb.", 14.1, new double[] { 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0 }), ("Wheat Cereal (Enriched)", "28 oz.", 24.2, new double[] { 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0 }), ("Corn Flakes", "8 oz.", 7.1, new double[] { 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0 }), ("Corn Meal", "1 lb.", 4.6, new double[] { 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0 }), ("Hominy Grits", "24 oz.", 8.5, new double[] { 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0 }), ("Rice", "1 lb.", 7.5, new double[] { 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0 }), ("Rolled Oats", "1 lb.", 7.1, new double[] { 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0 }), ("White Bread (Enriched)", "1 lb.", 7.9, new double[] { 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0 }), ("Whole Wheat Bread", "1 lb.", 9.1, new double[] { 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0 }), ("Rye Bread", "1 lb.", 9.1, new double[] { 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0 }), ("Pound Cake", "1 lb.", 24.8, new double[] { 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0 }), ("Soda Crackers", "1 lb.", 15.1, new double[] { 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0 }), ("Milk", "1 qt.", 11, new double[] { 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177 }), ("Evaporated Milk (can)", "14.5 oz.", 6.7, new double[] { 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60 }), ("Butter", "1 lb.", 30.8, new double[] { 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0 }), ("Oleomargarine", "1 lb.", 16.1, new double[] { 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0 }), ("Eggs", "1 doz.", 32.6, new double[] { 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0 }), ("Cheese (Cheddar)", "1 lb.", 24.2, new double[] { 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0 }), ("Cream", "1/2 pt.", 14.1, new double[] { 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17 }), ("Peanut Butter", "1 lb.", 17.9, new double[] { 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0 }), ("Mayonnaise", "1/2 pt.", 16.7, new double[] { 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0 }), ("Crisco", "1 lb.", 20.3, new double[] { 20.1, 0, 0, 0, 0, 0, 0, 0, 0 }), ("Lard", "1 lb.", 9.8, new double[] { 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0 }), ("Sirloin Steak", "1 lb.", 39.6, new double[] { 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0 }), ("Round Steak", "1 lb.", 36.4, new double[] { 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0 }), ("Rib Roast", "1 lb.", 29.2, new double[] { 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0 }), ("Chuck Roast", "1 lb.", 22.6, new double[] { 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0 }), ("Plate", "1 lb.", 14.6, new double[] { 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0 }), ("Liver (Beef)", "1 lb.", 26.8, new double[] { 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525 }), ("Leg of Lamb", "1 lb.", 27.6, new double[] { 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0 }), ("Lamb Chops (Rib)", "1 lb.", 36.6, new double[] { 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0 }), ("Pork Chops", "1 lb.", 30.7, new double[] { 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0 }), ("Pork Loin Roast", "1 lb.", 24.2, new double[] { 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0 }), ("Bacon", "1 lb.", 25.6, new double[] { 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0 }), ("Ham, smoked", "1 lb.", 27.4, new double[] { 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0 }), ("Salt Pork", "1 lb.", 16, new double[] { 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0 }), ("Roasting Chicken", "1 lb.", 30.3, new double[] { 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46 }), ("Veal Cutlets", "1 lb.", 42.3, new double[] { 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0 }), ("Salmon, Pink (can)", "16 oz.", 13, new double[] { 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0 }), ("Apples", "1 lb.", 4.4, new double[] { 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544 }), ("Bananas", "1 lb.", 6.1, new double[] { 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498 }), ("Lemons", "1 doz.", 26, new double[] { 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952 }), ("Oranges", "1 doz.", 30.9, new double[] { 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998 }), ("Green Beans", "1 lb.", 7.1, new double[] { 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862 }), ("Cabbage", "1 lb.", 3.7, new double[] { 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369 }), ("Carrots", "1 bunch", 4.7, new double[] { 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608 }), ("Celery", "1 stalk", 7.3, new double[] { 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313 }), ("Lettuce", "1 head", 8.2, new double[] { 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449 }), ("Onions", "1 lb.", 3.6, new double[] { 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184 }), ("Potatoes", "15 lb.", 34, new double[] { 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522 }), ("Spinach", "1 lb.", 8.1, new double[] { 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755 }), ("Sweet Potatoes", "1 lb.", 5.1, new double[] { 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912 }), ("Peaches (can)", "No. 2 1/2", 16.8, new double[] { 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196 }), ("Pears (can)", "No. 2 1/2", 20.4, new double[] { 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81 }), ("Pineapple (can)", "No. 2 1/2", 21.3, new double[] { 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399 }), ("Asparagus (can)", "No. 2", 27.7, new double[] { 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272 }), ("Green Beans (can)", "No. 2", 10, new double[] { 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431 }), ("Pork and Beans (can)", "16 oz.", 7.1, new double[] { 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0 }), ("Corn (can)", "No. 2", 10.4, new double[] { 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218 }), ("Peas (can)", "No. 2", 13.8, new double[] { 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370 }), ("Tomatoes (can)", "No. 2", 8.6, new double[] { 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253 }), ("Tomato Soup (can)", "10 1/2 oz.", 7.6, new double[] { 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862 }), ("Peaches, Dried", "1 lb.", 15.7, new double[] { 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57 }), ("Prunes, Dried", "1 lb.", 9, new double[] { 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257 }), ("Raisins, Dried", "15 oz.", 9.4, new double[] { 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136 }), ("Peas, Dried", "1 lb.", 7.9, new double[] { 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0 }), ("Lima Beans, Dried", "1 lb.", 8.9, new double[] { 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0 }), ("Navy Beans, Dried", "1 lb.", 5.9, new double[] { 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0 }), ("Coffee", "1 lb.", 22.4, new double[] { 0, 0, 0, 0, 0, 4, 5.1, 50, 0 }), ("Tea", "1/4 lb.", 17.4, new double[] { 0, 0, 0, 0, 0, 0, 2.3, 42, 0 }), ("Cocoa", "8 oz.", 8.6, new double[] { 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0 }), ("Chocolate", "8 oz.", 16.2, new double[] { 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0 }), ("Sugar", "10 lb.", 51.7, new double[] { 34.9, 0, 0, 0, 0, 0, 0, 0, 0 }), ("Corn Syrup", "24 oz.", 13.7, new double[] { 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0 }), ("Molasses", "18 oz.", 13.6, new double[] { 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0 }), ("Strawberry Preserves", "1 lb.", 20.5, new double[] { 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0 }) };
Объявить решатель LP
Следующий код создает экземпляр оболочки MPsolver
.
Питон
# Instantiate a Glop solver and naming it. solver = pywraplp.Solver.CreateSolver("GLOP") if not solver: return
С++
// Create the linear solver with the GLOP backend. std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("GLOP"));
Ява
// Create the linear solver with the GLOP backend. MPSolver solver = MPSolver.createSolver("GLOP"); if (solver == null) { System.out.println("Could not create solver GLOP"); return; }
С#
// Create the linear solver with the GLOP backend. Solver solver = Solver.CreateSolver("GLOP"); if (solver is null) { return; }
Создайте переменные
Следующий код создает переменные для проблемы.
Питон
# Declare an array to hold our variables. foods = [solver.NumVar(0.0, solver.infinity(), item[0]) for item in data] print("Number of variables =", solver.NumVariables())
С++
std::vector<MPVariable*> foods; const double infinity = solver->infinity(); for (const Commodity& commodity : data) { foods.push_back(solver->MakeNumVar(0.0, infinity, commodity.name)); } LOG(INFO) << "Number of variables = " << solver->NumVariables();
Ява
double infinity = java.lang.Double.POSITIVE_INFINITY; List<MPVariable> foods = new ArrayList<>(); for (int i = 0; i < data.size(); ++i) { foods.add(solver.makeNumVar(0.0, infinity, (String) data.get(i)[0])); } System.out.println("Number of variables = " + solver.numVariables());
С#
List<Variable> foods = new List<Variable>(); for (int i = 0; i < data.Length; ++i) { foods.Add(solver.MakeNumVar(0.0, double.PositiveInfinity, data[i].Name)); } Console.WriteLine($"Number of variables = {solver.NumVariables()}");
Метод MakeNumVar
создает одну переменную food[i]
для каждой строки таблицы. Как упоминалось ранее, данные о питании указаны на доллар, поэтому food[i]
— это сумма денег, которую можно потратить на товар i
.
Определите ограничения
Ограничения диеты Стиглера требуют, чтобы общее количество питательных веществ, содержащихся во всех продуктах, соответствовало, по крайней мере, минимальной потребности для каждого питательного вещества. Далее мы запишем эти ограничения в виде неравенств, включающих массивы data
и nutrients
, а также переменные food[i]
.
Во-первых, количество питательных веществ i
, обеспечиваемых пищей j
на доллар, равно data[j][i+3]
(мы добавляем 3 к индексу столбца, поскольку данные о питательных веществах начинаются в четвертом столбце data
). будет потрачено на еду j
— food[j]
, количество питательных веществ i
обеспечиваемых пищей j
, равно\(data[j][i+3] \cdot food[j]\). Наконец, поскольку минимальное требование к питательному веществу i
— это nutrients[i][1]
, мы можем записать ограничение i следующим образом:
Питон
# Create the constraints, one per nutrient. constraints = [] for i, nutrient in enumerate(nutrients): constraints.append(solver.Constraint(nutrient[1], solver.infinity())) for j, item in enumerate(data): constraints[i].SetCoefficient(foods[j], item[i + 3]) print("Number of constraints =", solver.NumConstraints())
С++
// Create the constraints, one per nutrient. std::vector<MPConstraint*> constraints; for (std::size_t i = 0; i < nutrients.size(); ++i) { constraints.push_back( solver->MakeRowConstraint(nutrients[i].second, infinity)); for (std::size_t j = 0; j < data.size(); ++j) { constraints.back()->SetCoefficient(foods[j], data[j].nutrients[i]); } } LOG(INFO) << "Number of constraints = " << solver->NumConstraints();
Ява
MPConstraint[] constraints = new MPConstraint[nutrients.size()]; for (int i = 0; i < nutrients.size(); ++i) { constraints[i] = solver.makeConstraint( (double) nutrients.get(i)[1], infinity, (String) nutrients.get(i)[0]); for (int j = 0; j < data.size(); ++j) { constraints[i].setCoefficient(foods.get(j), ((double[]) data.get(j)[3])[i]); } // constraints.add(constraint); } System.out.println("Number of constraints = " + solver.numConstraints());
С#
List<Constraint> constraints = new List<Constraint>(); for (int i = 0; i < nutrients.Length; ++i) { Constraint constraint = solver.MakeConstraint(nutrients[i].Value, double.PositiveInfinity, nutrients[i].Name); for (int j = 0; j < data.Length; ++j) { constraint.SetCoefficient(foods[j], data[j].Nutrients[i]); } constraints.Add(constraint); } Console.WriteLine($"Number of constraints = {solver.NumConstraints()}");
Метод Constraint
Python (соответствующий методу C++ MakeRowConstraint
) создает ограничения для проблемы. Для каждого i
constraint(nutrients[i][1], solver.infinity)
Это создает ограничение, при котором линейная комбинация переменных food[j]
(определенных далее) больше или равна nutrients[i][1]
. Коэффициенты линейного выражения определяются методом SetCoefficient
следующим образом: SetCoefficient(food[j], data[j][i+3]
Это устанавливает коэффициент food[j]
как data[j][i+3]
.
Объединив все это, код определяет ограничения, выраженные в (1) выше.
Создайте цель
Следующий код определяет целевую функцию для задачи.
Питон
# Objective function: Minimize the sum of (price-normalized) foods. objective = solver.Objective() for food in foods: objective.SetCoefficient(food, 1) objective.SetMinimization()
С++
MPObjective* const objective = solver->MutableObjective(); for (size_t i = 0; i < data.size(); ++i) { objective->SetCoefficient(foods[i], 1); } objective->SetMinimization();
Ява
MPObjective objective = solver.objective(); for (int i = 0; i < data.size(); ++i) { objective.setCoefficient(foods.get(i), 1); } objective.setMinimization();
С#
Objective objective = solver.Objective(); for (int i = 0; i < data.Length; ++i) { objective.SetCoefficient(foods[i], 1); } objective.SetMinimization();
Целевая функция — это общая стоимость еды, которая представляет собой сумму переменных food[i]
.
Метод SetCoefficient
устанавливает коэффициенты целевой функции, которые в данном случае равны 1
. Наконец, SetMinimization
объявляет это проблемой минимизации.
Вызов решателя
Следующий код вызывает решатель.
Питон
print(f"Solving with {solver.SolverVersion()}") status = solver.Solve()
С++
const MPSolver::ResultStatus result_status = solver->Solve();
Ява
final MPSolver.ResultStatus resultStatus = solver.solve();
С#
Solver.ResultStatus resultStatus = solver.Solve();
Glop решает проблему на обычном компьютере менее чем за 300 миллисекунд:
Показать решение
Следующий код отображает решение.
Питон
# Check that the problem has an optimal solution. if status != solver.OPTIMAL: print("The problem does not have an optimal solution!") if status == solver.FEASIBLE: print("A potentially suboptimal solution was found.") else: print("The solver could not solve the problem.") exit(1) # Display the amounts (in dollars) to purchase of each food. nutrients_result = [0] * len(nutrients) print("\nAnnual Foods:") for i, food in enumerate(foods): if food.solution_value() > 0.0: print("{}: ${}".format(data[i][0], 365.0 * food.solution_value())) for j, _ in enumerate(nutrients): nutrients_result[j] += data[i][j + 3] * food.solution_value() print("\nOptimal annual price: ${:.4f}".format(365.0 * objective.Value())) print("\nNutrients per day:") for i, nutrient in enumerate(nutrients): print( "{}: {:.2f} (min {})".format(nutrient[0], nutrients_result[i], nutrient[1]) )
С++
// Check that the problem has an optimal solution. if (result_status != MPSolver::OPTIMAL) { LOG(INFO) << "The problem does not have an optimal solution!"; if (result_status == MPSolver::FEASIBLE) { LOG(INFO) << "A potentially suboptimal solution was found"; } else { LOG(INFO) << "The solver could not solve the problem."; return; } } std::vector<double> nutrients_result(nutrients.size()); LOG(INFO) << ""; LOG(INFO) << "Annual Foods:"; for (std::size_t i = 0; i < data.size(); ++i) { if (foods[i]->solution_value() > 0.0) { LOG(INFO) << data[i].name << ": $" << std::to_string(365. * foods[i]->solution_value()); for (std::size_t j = 0; j < nutrients.size(); ++j) { nutrients_result[j] += data[i].nutrients[j] * foods[i]->solution_value(); } } } LOG(INFO) << ""; LOG(INFO) << "Optimal annual price: $" << std::to_string(365. * objective->Value()); LOG(INFO) << ""; LOG(INFO) << "Nutrients per day:"; for (std::size_t i = 0; i < nutrients.size(); ++i) { LOG(INFO) << nutrients[i].first << ": " << std::to_string(nutrients_result[i]) << " (min " << std::to_string(nutrients[i].second) << ")"; }
Ява
// Check that the problem has an optimal solution. if (resultStatus != MPSolver.ResultStatus.OPTIMAL) { System.err.println("The problem does not have an optimal solution!"); if (resultStatus == MPSolver.ResultStatus.FEASIBLE) { System.err.println("A potentially suboptimal solution was found."); } else { System.err.println("The solver could not solve the problem."); return; } } // Display the amounts (in dollars) to purchase of each food. double[] nutrientsResult = new double[nutrients.size()]; System.out.println("\nAnnual Foods:"); for (int i = 0; i < foods.size(); ++i) { if (foods.get(i).solutionValue() > 0.0) { System.out.println((String) data.get(i)[0] + ": $" + 365 * foods.get(i).solutionValue()); for (int j = 0; j < nutrients.size(); ++j) { nutrientsResult[j] += ((double[]) data.get(i)[3])[j] * foods.get(i).solutionValue(); } } } System.out.println("\nOptimal annual price: $" + 365 * objective.value()); System.out.println("\nNutrients per day:"); for (int i = 0; i < nutrients.size(); ++i) { System.out.println( nutrients.get(i)[0] + ": " + nutrientsResult[i] + " (min " + nutrients.get(i)[1] + ")"); }
С#
// Check that the problem has an optimal solution. if (resultStatus != Solver.ResultStatus.OPTIMAL) { Console.WriteLine("The problem does not have an optimal solution!"); if (resultStatus == Solver.ResultStatus.FEASIBLE) { Console.WriteLine("A potentially suboptimal solution was found."); } else { Console.WriteLine("The solver could not solve the problem."); return; } } // Display the amounts (in dollars) to purchase of each food. double[] nutrientsResult = new double[nutrients.Length]; Console.WriteLine("\nAnnual Foods:"); for (int i = 0; i < foods.Count; ++i) { if (foods[i].SolutionValue() > 0.0) { Console.WriteLine($"{data[i].Name}: ${365 * foods[i].SolutionValue():N2}"); for (int j = 0; j < nutrients.Length; ++j) { nutrientsResult[j] += data[i].Nutrients[j] * foods[i].SolutionValue(); } } } Console.WriteLine($"\nOptimal annual price: ${365 * objective.Value():N2}"); Console.WriteLine("\nNutrients per day:"); for (int i = 0; i < nutrients.Length; ++i) { Console.WriteLine($"{nutrients[i].Name}: {nutrientsResult[i]:N2} (min {nutrients[i].Value})"); }
Вот результат работы программы.
make rpy_stigler_diet "/usr/bin/python3.11" ortools/linear_solver/samples/stigler_diet.py Number of variables = 77 Number of constraints = 9 Annual Foods: Wheat Flour (Enriched): $10.774457511918223 Liver (Beef): $0.6907834111074193 Cabbage: $4.093268864842877 Spinach: $1.8277960703546996 Navy Beans, Dried: $22.275425687243036 Optimal annual price: $39.6617 Nutrients per day: Calories (kcal): 3.00 (min 3) Protein (g): 147.41 (min 70) Calcium (g): 0.80 (min 0.8) Iron (mg): 60.47 (min 12) Vitamin A (KIU): 5.00 (min 5) Vitamin B1 (mg): 4.12 (min 1.8) Vitamin B2 (mg): 2.70 (min 2.7) Niacin (mg): 27.32 (min 18) Vitamin C (mg): 75.00 (min 75) Advanced usage: Problem solved in 1 milliseconds Problem solved in 14 iterations
Полный код программы
Полный код программы диеты Стиглера показан ниже.
Питон
"""The Stigler diet problem. A description of the problem can be found here: https://en.wikipedia.org/wiki/Stigler_diet. """ from ortools.linear_solver import pywraplp def main(): """Entry point of the program.""" # Instantiate the data problem. # Nutrient minimums. nutrients = [ ["Calories (kcal)", 3], ["Protein (g)", 70], ["Calcium (g)", 0.8], ["Iron (mg)", 12], ["Vitamin A (KIU)", 5], ["Vitamin B1 (mg)", 1.8], ["Vitamin B2 (mg)", 2.7], ["Niacin (mg)", 18], ["Vitamin C (mg)", 75], ] # Commodity, Unit, 1939 price (cents), Calories (kcal), Protein (g), # Calcium (g), Iron (mg), Vitamin A (KIU), Vitamin B1 (mg), Vitamin B2 (mg), # Niacin (mg), Vitamin C (mg) data = [ # fmt: off ['Wheat Flour (Enriched)', '10 lb.', 36, 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0], ['Macaroni', '1 lb.', 14.1, 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0], ['Wheat Cereal (Enriched)', '28 oz.', 24.2, 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0], ['Corn Flakes', '8 oz.', 7.1, 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0], ['Corn Meal', '1 lb.', 4.6, 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0], ['Hominy Grits', '24 oz.', 8.5, 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0], ['Rice', '1 lb.', 7.5, 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0], ['Rolled Oats', '1 lb.', 7.1, 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0], ['White Bread (Enriched)', '1 lb.', 7.9, 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0], ['Whole Wheat Bread', '1 lb.', 9.1, 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0], ['Rye Bread', '1 lb.', 9.1, 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0], ['Pound Cake', '1 lb.', 24.8, 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0], ['Soda Crackers', '1 lb.', 15.1, 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0], ['Milk', '1 qt.', 11, 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177], ['Evaporated Milk (can)', '14.5 oz.', 6.7, 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60], ['Butter', '1 lb.', 30.8, 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0], ['Oleomargarine', '1 lb.', 16.1, 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0], ['Eggs', '1 doz.', 32.6, 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0], ['Cheese (Cheddar)', '1 lb.', 24.2, 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0], ['Cream', '1/2 pt.', 14.1, 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17], ['Peanut Butter', '1 lb.', 17.9, 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0], ['Mayonnaise', '1/2 pt.', 16.7, 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0], ['Crisco', '1 lb.', 20.3, 20.1, 0, 0, 0, 0, 0, 0, 0, 0], ['Lard', '1 lb.', 9.8, 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0], ['Sirloin Steak', '1 lb.', 39.6, 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0], ['Round Steak', '1 lb.', 36.4, 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0], ['Rib Roast', '1 lb.', 29.2, 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0], ['Chuck Roast', '1 lb.', 22.6, 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0], ['Plate', '1 lb.', 14.6, 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0], ['Liver (Beef)', '1 lb.', 26.8, 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525], ['Leg of Lamb', '1 lb.', 27.6, 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0], ['Lamb Chops (Rib)', '1 lb.', 36.6, 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0], ['Pork Chops', '1 lb.', 30.7, 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0], ['Pork Loin Roast', '1 lb.', 24.2, 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0], ['Bacon', '1 lb.', 25.6, 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0], ['Ham, smoked', '1 lb.', 27.4, 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0], ['Salt Pork', '1 lb.', 16, 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0], ['Roasting Chicken', '1 lb.', 30.3, 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46], ['Veal Cutlets', '1 lb.', 42.3, 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0], ['Salmon, Pink (can)', '16 oz.', 13, 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0], ['Apples', '1 lb.', 4.4, 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544], ['Bananas', '1 lb.', 6.1, 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498], ['Lemons', '1 doz.', 26, 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952], ['Oranges', '1 doz.', 30.9, 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998], ['Green Beans', '1 lb.', 7.1, 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862], ['Cabbage', '1 lb.', 3.7, 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369], ['Carrots', '1 bunch', 4.7, 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608], ['Celery', '1 stalk', 7.3, 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313], ['Lettuce', '1 head', 8.2, 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449], ['Onions', '1 lb.', 3.6, 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184], ['Potatoes', '15 lb.', 34, 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522], ['Spinach', '1 lb.', 8.1, 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755], ['Sweet Potatoes', '1 lb.', 5.1, 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912], ['Peaches (can)', 'No. 2 1/2', 16.8, 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196], ['Pears (can)', 'No. 2 1/2', 20.4, 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81], ['Pineapple (can)', 'No. 2 1/2', 21.3, 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399], ['Asparagus (can)', 'No. 2', 27.7, 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272], ['Green Beans (can)', 'No. 2', 10, 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431], ['Pork and Beans (can)', '16 oz.', 7.1, 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0], ['Corn (can)', 'No. 2', 10.4, 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218], ['Peas (can)', 'No. 2', 13.8, 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370], ['Tomatoes (can)', 'No. 2', 8.6, 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253], ['Tomato Soup (can)', '10 1/2 oz.', 7.6, 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862], ['Peaches, Dried', '1 lb.', 15.7, 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57], ['Prunes, Dried', '1 lb.', 9, 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257], ['Raisins, Dried', '15 oz.', 9.4, 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136], ['Peas, Dried', '1 lb.', 7.9, 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0], ['Lima Beans, Dried', '1 lb.', 8.9, 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0], ['Navy Beans, Dried', '1 lb.', 5.9, 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0], ['Coffee', '1 lb.', 22.4, 0, 0, 0, 0, 0, 4, 5.1, 50, 0], ['Tea', '1/4 lb.', 17.4, 0, 0, 0, 0, 0, 0, 2.3, 42, 0], ['Cocoa', '8 oz.', 8.6, 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0], ['Chocolate', '8 oz.', 16.2, 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0], ['Sugar', '10 lb.', 51.7, 34.9, 0, 0, 0, 0, 0, 0, 0, 0], ['Corn Syrup', '24 oz.', 13.7, 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0], ['Molasses', '18 oz.', 13.6, 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0], ['Strawberry Preserves', '1 lb.', 20.5, 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0], # fmt: on ] # Instantiate a Glop solver and naming it. solver = pywraplp.Solver.CreateSolver("GLOP") if not solver: return # Declare an array to hold our variables. foods = [solver.NumVar(0.0, solver.infinity(), item[0]) for item in data] print("Number of variables =", solver.NumVariables()) # Create the constraints, one per nutrient. constraints = [] for i, nutrient in enumerate(nutrients): constraints.append(solver.Constraint(nutrient[1], solver.infinity())) for j, item in enumerate(data): constraints[i].SetCoefficient(foods[j], item[i + 3]) print("Number of constraints =", solver.NumConstraints()) # Objective function: Minimize the sum of (price-normalized) foods. objective = solver.Objective() for food in foods: objective.SetCoefficient(food, 1) objective.SetMinimization() print(f"Solving with {solver.SolverVersion()}") status = solver.Solve() # Check that the problem has an optimal solution. if status != solver.OPTIMAL: print("The problem does not have an optimal solution!") if status == solver.FEASIBLE: print("A potentially suboptimal solution was found.") else: print("The solver could not solve the problem.") exit(1) # Display the amounts (in dollars) to purchase of each food. nutrients_result = [0] * len(nutrients) print("\nAnnual Foods:") for i, food in enumerate(foods): if food.solution_value() > 0.0: print("{}: ${}".format(data[i][0], 365.0 * food.solution_value())) for j, _ in enumerate(nutrients): nutrients_result[j] += data[i][j + 3] * food.solution_value() print("\nOptimal annual price: ${:.4f}".format(365.0 * objective.Value())) print("\nNutrients per day:") for i, nutrient in enumerate(nutrients): print( "{}: {:.2f} (min {})".format(nutrient[0], nutrients_result[i], nutrient[1]) ) print("\nAdvanced usage:") print(f"Problem solved in {solver.wall_time():d} milliseconds") print(f"Problem solved in {solver.iterations():d} iterations") if __name__ == "__main__": main()
С++
// The Stigler diet problem. #include <array> #include <memory> #include <string> #include <utility> // std::pair #include <vector> #include "absl/flags/flag.h" #include "absl/log/flags.h" #include "ortools/base/init_google.h" #include "ortools/base/logging.h" #include "ortools/linear_solver/linear_solver.h" namespace operations_research { void StiglerDiet() { // Nutrient minimums. const std::vector<std::pair<std::string, double>> nutrients = { {"Calories (kcal)", 3.0}, {"Protein (g)", 70.0}, {"Calcium (g)", 0.8}, {"Iron (mg)", 12.0}, {"Vitamin A (kIU)", 5.0}, {"Vitamin B1 (mg)", 1.8}, {"Vitamin B2 (mg)", 2.7}, {"Niacin (mg)", 18.0}, {"Vitamin C (mg)", 75.0}}; struct Commodity { std::string name; //!< Commodity name std::string unit; //!< Unit double price; //!< 1939 price per unit (cents) //! Calories (kcal), //! Protein (g), //! Calcium (g), //! Iron (mg), //! Vitamin A (kIU), //! Vitamin B1 (mg), //! Vitamin B2 (mg), //! Niacin (mg), //! Vitamin C (mg) std::array<double, 9> nutrients; }; std::vector<Commodity> data = { {"Wheat Flour (Enriched)", "10 lb.", 36, {44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0}}, {"Macaroni", "1 lb.", 14.1, {11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0}}, {"Wheat Cereal (Enriched)", "28 oz.", 24.2, {11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0}}, {"Corn Flakes", "8 oz.", 7.1, {11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0}}, {"Corn Meal", "1 lb.", 4.6, {36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0}}, {"Hominy Grits", "24 oz.", 8.5, {28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0}}, {"Rice", "1 lb.", 7.5, {21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0}}, {"Rolled Oats", "1 lb.", 7.1, {25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0}}, {"White Bread (Enriched)", "1 lb.", 7.9, {15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0}}, {"Whole Wheat Bread", "1 lb.", 9.1, {12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0}}, {"Rye Bread", "1 lb.", 9.1, {12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0}}, {"Pound Cake", "1 lb.", 24.8, {8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0}}, {"Soda Crackers", "1 lb.", 15.1, {12.5, 288, 0.5, 50, 0, 0, 0, 0, 0}}, {"Milk", "1 qt.", 11, {6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177}}, {"Evaporated Milk (can)", "14.5 oz.", 6.7, {8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60}}, {"Butter", "1 lb.", 30.8, {10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0}}, {"Oleomargarine", "1 lb.", 16.1, {20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0}}, {"Eggs", "1 doz.", 32.6, {2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0}}, {"Cheese (Cheddar)", "1 lb.", 24.2, {7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0}}, {"Cream", "1/2 pt.", 14.1, {3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17}}, {"Peanut Butter", "1 lb.", 17.9, {15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0}}, {"Mayonnaise", "1/2 pt.", 16.7, {8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0}}, {"Crisco", "1 lb.", 20.3, {20.1, 0, 0, 0, 0, 0, 0, 0, 0}}, {"Lard", "1 lb.", 9.8, {41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0}}, {"Sirloin Steak", "1 lb.", 39.6, {2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0}}, {"Round Steak", "1 lb.", 36.4, {2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0}}, {"Rib Roast", "1 lb.", 29.2, {3.4, 213, 0.1, 33, 0, 0, 2, 0, 0}}, {"Chuck Roast", "1 lb.", 22.6, {3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0}}, {"Plate", "1 lb.", 14.6, {8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0}}, {"Liver (Beef)", "1 lb.", 26.8, {2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525}}, {"Leg of Lamb", "1 lb.", 27.6, {3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0}}, {"Lamb Chops (Rib)", "1 lb.", 36.6, {3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0}}, {"Pork Chops", "1 lb.", 30.7, {3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0}}, {"Pork Loin Roast", "1 lb.", 24.2, {4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0}}, {"Bacon", "1 lb.", 25.6, {10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0}}, {"Ham, smoked", "1 lb.", 27.4, {6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0}}, {"Salt Pork", "1 lb.", 16, {18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0}}, {"Roasting Chicken", "1 lb.", 30.3, {1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46}}, {"Veal Cutlets", "1 lb.", 42.3, {1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0}}, {"Salmon, Pink (can)", "16 oz.", 13, {5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0}}, {"Apples", "1 lb.", 4.4, {5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544}}, {"Bananas", "1 lb.", 6.1, {4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498}}, {"Lemons", "1 doz.", 26, {1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952}}, {"Oranges", "1 doz.", 30.9, {2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998}}, {"Green Beans", "1 lb.", 7.1, {2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862}}, {"Cabbage", "1 lb.", 3.7, {2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369}}, {"Carrots", "1 bunch", 4.7, {2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608}}, {"Celery", "1 stalk", 7.3, {0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313}}, {"Lettuce", "1 head", 8.2, {0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449}}, {"Onions", "1 lb.", 3.6, {5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184}}, {"Potatoes", "15 lb.", 34, {14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522}}, {"Spinach", "1 lb.", 8.1, {1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755}}, {"Sweet Potatoes", "1 lb.", 5.1, {9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912}}, {"Peaches (can)", "No. 2 1/2", 16.8, {3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196}}, {"Pears (can)", "No. 2 1/2", 20.4, {3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81}}, {"Pineapple (can)", "No. 2 1/2", 21.3, {2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399}}, {"Asparagus (can)", "No. 2", 27.7, {0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272}}, {"Green Beans (can)", "No. 2", 10, {1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431}}, {"Pork and Beans (can)", "16 oz.", 7.1, {7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0}}, {"Corn (can)", "No. 2", 10.4, {5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218}}, {"Peas (can)", "No. 2", 13.8, {2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370}}, {"Tomatoes (can)", "No. 2", 8.6, {1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253}}, {"Tomato Soup (can)", "10 1/2 oz.", 7.6, {1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862}}, {"Peaches, Dried", "1 lb.", 15.7, {8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57}}, {"Prunes, Dried", "1 lb.", 9, {12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257}}, {"Raisins, Dried", "15 oz.", 9.4, {13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136}}, {"Peas, Dried", "1 lb.", 7.9, {20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0}}, {"Lima Beans, Dried", "1 lb.", 8.9, {17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0}}, {"Navy Beans, Dried", "1 lb.", 5.9, {26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0}}, {"Coffee", "1 lb.", 22.4, {0, 0, 0, 0, 0, 4, 5.1, 50, 0}}, {"Tea", "1/4 lb.", 17.4, {0, 0, 0, 0, 0, 0, 2.3, 42, 0}}, {"Cocoa", "8 oz.", 8.6, {8.7, 237, 3, 72, 0, 2, 11.9, 40, 0}}, {"Chocolate", "8 oz.", 16.2, {8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0}}, {"Sugar", "10 lb.", 51.7, {34.9, 0, 0, 0, 0, 0, 0, 0, 0}}, {"Corn Syrup", "24 oz.", 13.7, {14.7, 0, 0.5, 74, 0, 0, 0, 5, 0}}, {"Molasses", "18 oz.", 13.6, {9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0}}, {"Strawberry Preserves", "1 lb.", 20.5, {6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}}}; // Create the linear solver with the GLOP backend. std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("GLOP")); std::vector<MPVariable*> foods; const double infinity = solver->infinity(); for (const Commodity& commodity : data) { foods.push_back(solver->MakeNumVar(0.0, infinity, commodity.name)); } LOG(INFO) << "Number of variables = " << solver->NumVariables(); // Create the constraints, one per nutrient. std::vector<MPConstraint*> constraints; for (std::size_t i = 0; i < nutrients.size(); ++i) { constraints.push_back( solver->MakeRowConstraint(nutrients[i].second, infinity)); for (std::size_t j = 0; j < data.size(); ++j) { constraints.back()->SetCoefficient(foods[j], data[j].nutrients[i]); } } LOG(INFO) << "Number of constraints = " << solver->NumConstraints(); MPObjective* const objective = solver->MutableObjective(); for (size_t i = 0; i < data.size(); ++i) { objective->SetCoefficient(foods[i], 1); } objective->SetMinimization(); const MPSolver::ResultStatus result_status = solver->Solve(); // Check that the problem has an optimal solution. if (result_status != MPSolver::OPTIMAL) { LOG(INFO) << "The problem does not have an optimal solution!"; if (result_status == MPSolver::FEASIBLE) { LOG(INFO) << "A potentially suboptimal solution was found"; } else { LOG(INFO) << "The solver could not solve the problem."; return; } } std::vector<double> nutrients_result(nutrients.size()); LOG(INFO) << ""; LOG(INFO) << "Annual Foods:"; for (std::size_t i = 0; i < data.size(); ++i) { if (foods[i]->solution_value() > 0.0) { LOG(INFO) << data[i].name << ": $" << std::to_string(365. * foods[i]->solution_value()); for (std::size_t j = 0; j < nutrients.size(); ++j) { nutrients_result[j] += data[i].nutrients[j] * foods[i]->solution_value(); } } } LOG(INFO) << ""; LOG(INFO) << "Optimal annual price: $" << std::to_string(365. * objective->Value()); LOG(INFO) << ""; LOG(INFO) << "Nutrients per day:"; for (std::size_t i = 0; i < nutrients.size(); ++i) { LOG(INFO) << nutrients[i].first << ": " << std::to_string(nutrients_result[i]) << " (min " << std::to_string(nutrients[i].second) << ")"; } LOG(INFO) << ""; LOG(INFO) << "Advanced usage:"; LOG(INFO) << "Problem solved in " << solver->wall_time() << " milliseconds"; LOG(INFO) << "Problem solved in " << solver->iterations() << " iterations"; } } // namespace operations_research int main(int argc, char** argv) { InitGoogle(argv[0], &argc, &argv, true); absl::SetFlag(&FLAGS_stderrthreshold, 0); operations_research::StiglerDiet(); return EXIT_SUCCESS; }
Ява
// The Stigler diet problem. package com.google.ortools.linearsolver.samples; import com.google.ortools.Loader; import com.google.ortools.linearsolver.MPConstraint; import com.google.ortools.linearsolver.MPObjective; import com.google.ortools.linearsolver.MPSolver; import com.google.ortools.linearsolver.MPVariable; import java.util.ArrayList; import java.util.List; /** Stigler diet example. */ public final class StiglerDiet { public static void main(String[] args) { Loader.loadNativeLibraries(); // Nutrient minimums. List<Object[]> nutrients = new ArrayList<>(); nutrients.add(new Object[] {"Calories (kcal)", 3.0}); nutrients.add(new Object[] {"Protein (g)", 70.0}); nutrients.add(new Object[] {"Calcium (g)", 0.8}); nutrients.add(new Object[] {"Iron (mg)", 12.0}); nutrients.add(new Object[] {"Vitamin A (kIU)", 5.0}); nutrients.add(new Object[] {"Vitamin B1 (mg)", 1.8}); nutrients.add(new Object[] {"Vitamin B2 (mg)", 2.7}); nutrients.add(new Object[] {"Niacin (mg)", 18.0}); nutrients.add(new Object[] {"Vitamin C (mg)", 75.0}); List<Object[]> data = new ArrayList<>(); data.add(new Object[] {"Wheat Flour (Enriched)", "10 lb.", 36, new double[] {44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0}}); data.add(new Object[] { "Macaroni", "1 lb.", 14.1, new double[] {11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0}}); data.add(new Object[] {"Wheat Cereal (Enriched)", "28 oz.", 24.2, new double[] {11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0}}); data.add(new Object[] { "Corn Flakes", "8 oz.", 7.1, new double[] {11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0}}); data.add(new Object[] { "Corn Meal", "1 lb.", 4.6, new double[] {36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0}}); data.add(new Object[] { "Hominy Grits", "24 oz.", 8.5, new double[] {28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0}}); data.add( new Object[] {"Rice", "1 lb.", 7.5, new double[] {21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0}}); data.add(new Object[] { "Rolled Oats", "1 lb.", 7.1, new double[] {25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0}}); data.add(new Object[] {"White Bread (Enriched)", "1 lb.", 7.9, new double[] {15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0}}); data.add(new Object[] {"Whole Wheat Bread", "1 lb.", 9.1, new double[] {12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0}}); data.add(new Object[] { "Rye Bread", "1 lb.", 9.1, new double[] {12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0}}); data.add(new Object[] { "Pound Cake", "1 lb.", 24.8, new double[] {8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0}}); data.add(new Object[] { "Soda Crackers", "1 lb.", 15.1, new double[] {12.5, 288, 0.5, 50, 0, 0, 0, 0, 0}}); data.add( new Object[] {"Milk", "1 qt.", 11, new double[] {6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177}}); data.add(new Object[] {"Evaporated Milk (can)", "14.5 oz.", 6.7, new double[] {8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60}}); data.add( new Object[] {"Butter", "1 lb.", 30.8, new double[] {10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0}}); data.add(new Object[] { "Oleomargarine", "1 lb.", 16.1, new double[] {20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0}}); data.add(new Object[] { "Eggs", "1 doz.", 32.6, new double[] {2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0}}); data.add(new Object[] {"Cheese (Cheddar)", "1 lb.", 24.2, new double[] {7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0}}); data.add(new Object[] { "Cream", "1/2 pt.", 14.1, new double[] {3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17}}); data.add(new Object[] { "Peanut Butter", "1 lb.", 17.9, new double[] {15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0}}); data.add(new Object[] { "Mayonnaise", "1/2 pt.", 16.7, new double[] {8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0}}); data.add(new Object[] {"Crisco", "1 lb.", 20.3, new double[] {20.1, 0, 0, 0, 0, 0, 0, 0, 0}}); data.add(new Object[] {"Lard", "1 lb.", 9.8, new double[] {41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0}}); data.add(new Object[] { "Sirloin Steak", "1 lb.", 39.6, new double[] {2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0}}); data.add(new Object[] { "Round Steak", "1 lb.", 36.4, new double[] {2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0}}); data.add( new Object[] {"Rib Roast", "1 lb.", 29.2, new double[] {3.4, 213, 0.1, 33, 0, 0, 2, 0, 0}}); data.add(new Object[] { "Chuck Roast", "1 lb.", 22.6, new double[] {3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0}}); data.add( new Object[] {"Plate", "1 lb.", 14.6, new double[] {8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0}}); data.add(new Object[] {"Liver (Beef)", "1 lb.", 26.8, new double[] {2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525}}); data.add(new Object[] { "Leg of Lamb", "1 lb.", 27.6, new double[] {3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0}}); data.add(new Object[] { "Lamb Chops (Rib)", "1 lb.", 36.6, new double[] {3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0}}); data.add(new Object[] { "Pork Chops", "1 lb.", 30.7, new double[] {3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0}}); data.add(new Object[] { "Pork Loin Roast", "1 lb.", 24.2, new double[] {4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0}}); data.add(new Object[] { "Bacon", "1 lb.", 25.6, new double[] {10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0}}); data.add(new Object[] { "Ham, smoked", "1 lb.", 27.4, new double[] {6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0}}); data.add(new Object[] { "Salt Pork", "1 lb.", 16, new double[] {18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0}}); data.add(new Object[] {"Roasting Chicken", "1 lb.", 30.3, new double[] {1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46}}); data.add(new Object[] { "Veal Cutlets", "1 lb.", 42.3, new double[] {1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0}}); data.add(new Object[] { "Salmon, Pink (can)", "16 oz.", 13, new double[] {5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0}}); data.add(new Object[] { "Apples", "1 lb.", 4.4, new double[] {5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544}}); data.add(new Object[] { "Bananas", "1 lb.", 6.1, new double[] {4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498}}); data.add( new Object[] {"Lemons", "1 doz.", 26, new double[] {1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952}}); data.add(new Object[] { "Oranges", "1 doz.", 30.9, new double[] {2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998}}); data.add(new Object[] { "Green Beans", "1 lb.", 7.1, new double[] {2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862}}); data.add(new Object[] { "Cabbage", "1 lb.", 3.7, new double[] {2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369}}); data.add(new Object[] { "Carrots", "1 bunch", 4.7, new double[] {2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608}}); data.add(new Object[] { "Celery", "1 stalk", 7.3, new double[] {0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313}}); data.add(new Object[] { "Lettuce", "1 head", 8.2, new double[] {0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449}}); data.add(new Object[] { "Onions", "1 lb.", 3.6, new double[] {5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184}}); data.add(new Object[] { "Potatoes", "15 lb.", 34, new double[] {14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522}}); data.add(new Object[] { "Spinach", "1 lb.", 8.1, new double[] {1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755}}); data.add(new Object[] {"Sweet Potatoes", "1 lb.", 5.1, new double[] {9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912}}); data.add(new Object[] {"Peaches (can)", "No. 2 1/2", 16.8, new double[] {3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196}}); data.add(new Object[] { "Pears (can)", "No. 2 1/2", 20.4, new double[] {3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81}}); data.add(new Object[] { "Pineapple (can)", "No. 2 1/2", 21.3, new double[] {2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399}}); data.add(new Object[] {"Asparagus (can)", "No. 2", 27.7, new double[] {0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272}}); data.add(new Object[] { "Green Beans (can)", "No. 2", 10, new double[] {1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431}}); data.add(new Object[] {"Pork and Beans (can)", "16 oz.", 7.1, new double[] {7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0}}); data.add(new Object[] { "Corn (can)", "No. 2", 10.4, new double[] {5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218}}); data.add(new Object[] { "Peas (can)", "No. 2", 13.8, new double[] {2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370}}); data.add(new Object[] { "Tomatoes (can)", "No. 2", 8.6, new double[] {1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253}}); data.add(new Object[] {"Tomato Soup (can)", "10 1/2 oz.", 7.6, new double[] {1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862}}); data.add(new Object[] { "Peaches, Dried", "1 lb.", 15.7, new double[] {8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57}}); data.add(new Object[] { "Prunes, Dried", "1 lb.", 9, new double[] {12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257}}); data.add(new Object[] {"Raisins, Dried", "15 oz.", 9.4, new double[] {13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136}}); data.add(new Object[] { "Peas, Dried", "1 lb.", 7.9, new double[] {20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0}}); data.add(new Object[] {"Lima Beans, Dried", "1 lb.", 8.9, new double[] {17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0}}); data.add(new Object[] {"Navy Beans, Dried", "1 lb.", 5.9, new double[] {26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0}}); data.add(new Object[] {"Coffee", "1 lb.", 22.4, new double[] {0, 0, 0, 0, 0, 4, 5.1, 50, 0}}); data.add(new Object[] {"Tea", "1/4 lb.", 17.4, new double[] {0, 0, 0, 0, 0, 0, 2.3, 42, 0}}); data.add( new Object[] {"Cocoa", "8 oz.", 8.6, new double[] {8.7, 237, 3, 72, 0, 2, 11.9, 40, 0}}); data.add(new Object[] { "Chocolate", "8 oz.", 16.2, new double[] {8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0}}); data.add(new Object[] {"Sugar", "10 lb.", 51.7, new double[] {34.9, 0, 0, 0, 0, 0, 0, 0, 0}}); data.add(new Object[] { "Corn Syrup", "24 oz.", 13.7, new double[] {14.7, 0, 0.5, 74, 0, 0, 0, 5, 0}}); data.add(new Object[] { "Molasses", "18 oz.", 13.6, new double[] {9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0}}); data.add(new Object[] {"Strawberry Preserves", "1 lb.", 20.5, new double[] {6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}}); // Create the linear solver with the GLOP backend. MPSolver solver = MPSolver.createSolver("GLOP"); if (solver == null) { System.out.println("Could not create solver GLOP"); return; } double infinity = java.lang.Double.POSITIVE_INFINITY; List<MPVariable> foods = new ArrayList<>(); for (int i = 0; i < data.size(); ++i) { foods.add(solver.makeNumVar(0.0, infinity, (String) data.get(i)[0])); } System.out.println("Number of variables = " + solver.numVariables()); MPConstraint[] constraints = new MPConstraint[nutrients.size()]; for (int i = 0; i < nutrients.size(); ++i) { constraints[i] = solver.makeConstraint( (double) nutrients.get(i)[1], infinity, (String) nutrients.get(i)[0]); for (int j = 0; j < data.size(); ++j) { constraints[i].setCoefficient(foods.get(j), ((double[]) data.get(j)[3])[i]); } // constraints.add(constraint); } System.out.println("Number of constraints = " + solver.numConstraints()); MPObjective objective = solver.objective(); for (int i = 0; i < data.size(); ++i) { objective.setCoefficient(foods.get(i), 1); } objective.setMinimization(); final MPSolver.ResultStatus resultStatus = solver.solve(); // Check that the problem has an optimal solution. if (resultStatus != MPSolver.ResultStatus.OPTIMAL) { System.err.println("The problem does not have an optimal solution!"); if (resultStatus == MPSolver.ResultStatus.FEASIBLE) { System.err.println("A potentially suboptimal solution was found."); } else { System.err.println("The solver could not solve the problem."); return; } } // Display the amounts (in dollars) to purchase of each food. double[] nutrientsResult = new double[nutrients.size()]; System.out.println("\nAnnual Foods:"); for (int i = 0; i < foods.size(); ++i) { if (foods.get(i).solutionValue() > 0.0) { System.out.println((String) data.get(i)[0] + ": $" + 365 * foods.get(i).solutionValue()); for (int j = 0; j < nutrients.size(); ++j) { nutrientsResult[j] += ((double[]) data.get(i)[3])[j] * foods.get(i).solutionValue(); } } } System.out.println("\nOptimal annual price: $" + 365 * objective.value()); System.out.println("\nNutrients per day:"); for (int i = 0; i < nutrients.size(); ++i) { System.out.println( nutrients.get(i)[0] + ": " + nutrientsResult[i] + " (min " + nutrients.get(i)[1] + ")"); } System.out.println("\nAdvanced usage:"); System.out.println("Problem solved in " + solver.wallTime() + " milliseconds"); System.out.println("Problem solved in " + solver.iterations() + " iterations"); } private StiglerDiet() {} }
С#
// The Stigler diet problem. using System; using System.Collections.Generic; using Google.OrTools.LinearSolver; public class StiglerDiet { static void Main() { // Nutrient minimums. (String Name, double Value)[] nutrients = new[] { ("Calories (kcal)", 3.0), ("Protein (g)", 70.0), ("Calcium (g)", 0.8), ("Iron (mg)", 12.0), ("Vitamin A (kIU)", 5.0), ("Vitamin B1 (mg)", 1.8), ("Vitamin B2 (mg)", 2.7), ("Niacin (mg)", 18.0), ("Vitamin C (mg)", 75.0) }; (String Name, String Unit, double Price, double[] Nutrients)[] data = new[] { ("Wheat Flour (Enriched)", "10 lb.", 36, new double[] { 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0 }), ("Macaroni", "1 lb.", 14.1, new double[] { 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0 }), ("Wheat Cereal (Enriched)", "28 oz.", 24.2, new double[] { 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0 }), ("Corn Flakes", "8 oz.", 7.1, new double[] { 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0 }), ("Corn Meal", "1 lb.", 4.6, new double[] { 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0 }), ("Hominy Grits", "24 oz.", 8.5, new double[] { 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0 }), ("Rice", "1 lb.", 7.5, new double[] { 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0 }), ("Rolled Oats", "1 lb.", 7.1, new double[] { 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0 }), ("White Bread (Enriched)", "1 lb.", 7.9, new double[] { 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0 }), ("Whole Wheat Bread", "1 lb.", 9.1, new double[] { 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0 }), ("Rye Bread", "1 lb.", 9.1, new double[] { 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0 }), ("Pound Cake", "1 lb.", 24.8, new double[] { 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0 }), ("Soda Crackers", "1 lb.", 15.1, new double[] { 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0 }), ("Milk", "1 qt.", 11, new double[] { 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177 }), ("Evaporated Milk (can)", "14.5 oz.", 6.7, new double[] { 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60 }), ("Butter", "1 lb.", 30.8, new double[] { 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0 }), ("Oleomargarine", "1 lb.", 16.1, new double[] { 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0 }), ("Eggs", "1 doz.", 32.6, new double[] { 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0 }), ("Cheese (Cheddar)", "1 lb.", 24.2, new double[] { 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0 }), ("Cream", "1/2 pt.", 14.1, new double[] { 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17 }), ("Peanut Butter", "1 lb.", 17.9, new double[] { 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0 }), ("Mayonnaise", "1/2 pt.", 16.7, new double[] { 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0 }), ("Crisco", "1 lb.", 20.3, new double[] { 20.1, 0, 0, 0, 0, 0, 0, 0, 0 }), ("Lard", "1 lb.", 9.8, new double[] { 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0 }), ("Sirloin Steak", "1 lb.", 39.6, new double[] { 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0 }), ("Round Steak", "1 lb.", 36.4, new double[] { 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0 }), ("Rib Roast", "1 lb.", 29.2, new double[] { 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0 }), ("Chuck Roast", "1 lb.", 22.6, new double[] { 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0 }), ("Plate", "1 lb.", 14.6, new double[] { 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0 }), ("Liver (Beef)", "1 lb.", 26.8, new double[] { 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525 }), ("Leg of Lamb", "1 lb.", 27.6, new double[] { 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0 }), ("Lamb Chops (Rib)", "1 lb.", 36.6, new double[] { 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0 }), ("Pork Chops", "1 lb.", 30.7, new double[] { 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0 }), ("Pork Loin Roast", "1 lb.", 24.2, new double[] { 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0 }), ("Bacon", "1 lb.", 25.6, new double[] { 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0 }), ("Ham, smoked", "1 lb.", 27.4, new double[] { 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0 }), ("Salt Pork", "1 lb.", 16, new double[] { 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0 }), ("Roasting Chicken", "1 lb.", 30.3, new double[] { 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46 }), ("Veal Cutlets", "1 lb.", 42.3, new double[] { 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0 }), ("Salmon, Pink (can)", "16 oz.", 13, new double[] { 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0 }), ("Apples", "1 lb.", 4.4, new double[] { 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544 }), ("Bananas", "1 lb.", 6.1, new double[] { 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498 }), ("Lemons", "1 doz.", 26, new double[] { 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952 }), ("Oranges", "1 doz.", 30.9, new double[] { 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998 }), ("Green Beans", "1 lb.", 7.1, new double[] { 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862 }), ("Cabbage", "1 lb.", 3.7, new double[] { 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369 }), ("Carrots", "1 bunch", 4.7, new double[] { 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608 }), ("Celery", "1 stalk", 7.3, new double[] { 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313 }), ("Lettuce", "1 head", 8.2, new double[] { 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449 }), ("Onions", "1 lb.", 3.6, new double[] { 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184 }), ("Potatoes", "15 lb.", 34, new double[] { 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522 }), ("Spinach", "1 lb.", 8.1, new double[] { 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755 }), ("Sweet Potatoes", "1 lb.", 5.1, new double[] { 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912 }), ("Peaches (can)", "No. 2 1/2", 16.8, new double[] { 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196 }), ("Pears (can)", "No. 2 1/2", 20.4, new double[] { 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81 }), ("Pineapple (can)", "No. 2 1/2", 21.3, new double[] { 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399 }), ("Asparagus (can)", "No. 2", 27.7, new double[] { 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272 }), ("Green Beans (can)", "No. 2", 10, new double[] { 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431 }), ("Pork and Beans (can)", "16 oz.", 7.1, new double[] { 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0 }), ("Corn (can)", "No. 2", 10.4, new double[] { 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218 }), ("Peas (can)", "No. 2", 13.8, new double[] { 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370 }), ("Tomatoes (can)", "No. 2", 8.6, new double[] { 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253 }), ("Tomato Soup (can)", "10 1/2 oz.", 7.6, new double[] { 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862 }), ("Peaches, Dried", "1 lb.", 15.7, new double[] { 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57 }), ("Prunes, Dried", "1 lb.", 9, new double[] { 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257 }), ("Raisins, Dried", "15 oz.", 9.4, new double[] { 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136 }), ("Peas, Dried", "1 lb.", 7.9, new double[] { 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0 }), ("Lima Beans, Dried", "1 lb.", 8.9, new double[] { 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0 }), ("Navy Beans, Dried", "1 lb.", 5.9, new double[] { 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0 }), ("Coffee", "1 lb.", 22.4, new double[] { 0, 0, 0, 0, 0, 4, 5.1, 50, 0 }), ("Tea", "1/4 lb.", 17.4, new double[] { 0, 0, 0, 0, 0, 0, 2.3, 42, 0 }), ("Cocoa", "8 oz.", 8.6, new double[] { 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0 }), ("Chocolate", "8 oz.", 16.2, new double[] { 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0 }), ("Sugar", "10 lb.", 51.7, new double[] { 34.9, 0, 0, 0, 0, 0, 0, 0, 0 }), ("Corn Syrup", "24 oz.", 13.7, new double[] { 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0 }), ("Molasses", "18 oz.", 13.6, new double[] { 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0 }), ("Strawberry Preserves", "1 lb.", 20.5, new double[] { 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0 }) }; // Create the linear solver with the GLOP backend. Solver solver = Solver.CreateSolver("GLOP"); if (solver is null) { return; } List<Variable> foods = new List<Variable>(); for (int i = 0; i < data.Length; ++i) { foods.Add(solver.MakeNumVar(0.0, double.PositiveInfinity, data[i].Name)); } Console.WriteLine($"Number of variables = {solver.NumVariables()}"); List<Constraint> constraints = new List<Constraint>(); for (int i = 0; i < nutrients.Length; ++i) { Constraint constraint = solver.MakeConstraint(nutrients[i].Value, double.PositiveInfinity, nutrients[i].Name); for (int j = 0; j < data.Length; ++j) { constraint.SetCoefficient(foods[j], data[j].Nutrients[i]); } constraints.Add(constraint); } Console.WriteLine($"Number of constraints = {solver.NumConstraints()}"); Objective objective = solver.Objective(); for (int i = 0; i < data.Length; ++i) { objective.SetCoefficient(foods[i], 1); } objective.SetMinimization(); Solver.ResultStatus resultStatus = solver.Solve(); // Check that the problem has an optimal solution. if (resultStatus != Solver.ResultStatus.OPTIMAL) { Console.WriteLine("The problem does not have an optimal solution!"); if (resultStatus == Solver.ResultStatus.FEASIBLE) { Console.WriteLine("A potentially suboptimal solution was found."); } else { Console.WriteLine("The solver could not solve the problem."); return; } } // Display the amounts (in dollars) to purchase of each food. double[] nutrientsResult = new double[nutrients.Length]; Console.WriteLine("\nAnnual Foods:"); for (int i = 0; i < foods.Count; ++i) { if (foods[i].SolutionValue() > 0.0) { Console.WriteLine($"{data[i].Name}: ${365 * foods[i].SolutionValue():N2}"); for (int j = 0; j < nutrients.Length; ++j) { nutrientsResult[j] += data[i].Nutrients[j] * foods[i].SolutionValue(); } } } Console.WriteLine($"\nOptimal annual price: ${365 * objective.Value():N2}"); Console.WriteLine("\nNutrients per day:"); for (int i = 0; i < nutrients.Length; ++i) { Console.WriteLine($"{nutrients[i].Name}: {nutrientsResult[i]:N2} (min {nutrients[i].Value})"); } Console.WriteLine("\nAdvanced usage:"); Console.WriteLine($"Problem solved in {solver.WallTime()} milliseconds"); Console.WriteLine($"Problem solved in {solver.Iterations()} iterations"); } }