In questa sezione, mostriamo come risolvere un problema classico chiamato dieta Stigler, che prende il nome dal premio Nobel per l'economia George Stigler, che calcolò un modo economico per soddisfare i bisogni nutrizionali di base in base a una serie di alimenti. Ha presentato questo come un esercizio di matematica, non come consigli sull'alimentazione, anche se la nozione di calcolare un'alimentazione ottimale è diventata di moda di recente.
La dieta Stigler imponeva il rispetto dei seguenti requisiti minimi:
Elenco di nutrienti
Nutriente | Assunzione giornaliera consigliata |
---|---|
Calorie | 3.000 calorie |
Proteine | 70 grammi |
Calcio | 0,8 grammi |
Ferro | 12 milligrammi |
Vitamina A | 5000 UI |
Tiamina (vitamina B1) | 1,8 milligrammi |
Riboflavina (vitamina B2) | 2,7 milligrammi |
Niacina | 18 milligrammi |
Acido ascorbico (vitamina C) | 75 milligrammi |
L'insieme di alimenti valutato da Stigler era un riflesso dell'epoca (1944). I dati nutrizionali riportati di seguito sono per dollaro, non per unità, quindi l'obiettivo è stabilire quanti dollari spendere per ogni alimento.
Elenco dei prodotti
Beni | Unità | Prezzo 1939 (centesimi) | Calorie (kcal) | Proteine (g) | Calcio (g) | Ferro (mg) | Vitamina A (KIU) | Tiamina (mg) | Riboflavina (mg) | Niacina (mg) | Acido ascorbico (mg) |
---|---|---|---|---|---|---|---|---|---|---|---|
Farina di grano (arricchita) | 4,5 kg | 36 | 44,7 | 1411 | 2 | 365 | 0 | 55.4 | 33.3 | 441 | 0 |
Senape | 0,65 kg | 14.1 | 11.6 | 418 | 0.7 | 54 | 0 | 3.2 | 1.9 | 68 | 0 |
Cereali di grano (arricchiti) | 28 oz | 24.2 | 11.8 | 377 | 14.4 | 175 | 0 | 14.4 | 8.8 | 114 | 0 |
Fiocchi di mais | 225 g | 7.1 | 11.4 | 252 | 0,1 | 56 | 0 | 13.5 | 2.3 | 68 | 0 |
Farina di mais | 0,65 kg | 4.6 | 36.0 | 897 | 1.7 | 99 | 30.9 | 17.4 | 7,9 | 106 | 0 |
Grana d'Hominy | 24 oz | 8.5 | 28.6 | 680 | 0,8 | 80 | 0 | 10.6 | 1.6 | 110 | 0 |
Riso | 0,65 kg | 7.5 | 21.2 | 460 | 0.6 | 41 | 0 | 2 | 4,8 | 60 | 0 |
Fiocchi d'avena | 0,65 kg | 7.1 | 25,3 | 907 | 5.1 | 341 | 0 | 37.1 | 8.9 | 64 | 0 |
Pane bianco (arricchito) | 0,65 kg | 7,9 | 15.0 | 488 | 2.5 | 115 | 0 | 13.8 | 8.5 | 126 | 0 |
Pane di grano integrale | 0,65 kg | 9.1 | 12.2 | 484 | 2.7 | 125 | 0 | 13.9 | 6.4 | 160 | 0 |
Pane di segale | 0,65 kg | 9.1 | 12,4 | 439 | 1.1 | 82 | 0 | 9.9 | 3 | 66 | 0 |
Torta da libbra | 0,65 kg | 24,8 | 8.0 | 130 | 0.4 | 31 | 18,9 | 2.8 | 3 | 17 | 0 |
Cracker soda | 0,65 kg | 15.1 | 12.5 | 288 | 0.5 | 50 | 0 | 0 | 0 | 0 | 0 |
Latte | 1 qt. | 11 | 6.1 | 310 | 10.5 | 18 | 16.8 | 4 | 16 | 7 | 177 |
Latte evaporato (lattina) | 14,5 oz | 6.7 | 8.4 | 422 | 15.1 | 9 | 26 | 3 | 23.5 | 11 | 60 |
Burro | 0,65 kg | 30.8 | 10.8 | 9 | 0,2 | 3 | 44.2 | 0 | 0,2 | 2 | 0 |
Oleomargarina | 0,65 kg | 16.1 | 20,6 | 17 | 0.6 | 6 | 55.8 | 0,2 | 0 | 0 | 0 |
Uova | 1 doz. | 32.6 | 2.9 | 238 | 1.0 | 52 | 18,6 | 2.8 | 6.5 | 1 | 0 |
Formaggio (cheddar) | 0,65 kg | 24.2 | 7.4 | 448 | 16.4 | 19 | 28.1 | 0,8 | 10.3 | 4 | 0 |
Crema | 1/2 pt | 14.1 | 3.5 | 49 | 1.7 | 3 | 16,9 | 0.6 | 2.5 | 0 | 17 |
Burro di arachidi | 0,65 kg | 17,9 | 15.7 | 661 | 1.0 | 48 | 0 | 9.6 | 8.1 | 471 | 0 |
Maionese | 1/2 pt | 16.7 | 8.6 | 18 | 0,2 | 8 | 2.7 | 0.4 | 0.5 | 0 | 0 |
Crisco | 0,65 kg | 20.3 | 20,1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Strutto | 0,65 kg | 9.8 | 41.7 | 0 | 0 | 0 | 0,2 | 0 | 0.5 | 5 | 0 |
Bistecca di lombata | 0,65 kg | 39.6 | 2.9 | 166 | 0,1 | 34 | 0,2 | 2.1 | 2.9 | 69 | 0 |
Bistecca tonda | 0,65 kg | 36.4 | 2.2 | 214 | 0,1 | 32 | 0.4 | 2.5 | 2.4 | 87 | 0 |
Costolette arrosto | 0,65 kg | 29.2 | 3.4 | 213 | 0,1 | 33 | 0 | 0 | 2 | 0 | 0 |
Manzo arrosto | 0,65 kg | 22,6 | 3.6 | 309 | 0,2 | 46 | 0.4 | 1 | 4 | 120 | 0 |
Piatto | 0,65 kg | 14.6 | 8.5 | 404 | 0,2 | 62 | 0 | 0,9 | 0 | 0 | 0 |
Fegato (manzo) | 0,65 kg | 26.8 | 2.2 | 333 | 0,2 | 139 | 169.2 | 6.4 | 50,8 | 316 | 525 |
Cosciotto d'agnello | 0,65 kg | 27.6 | 3.1 | 245 | 0,1 | 20 | 0 | 2.8 | 3,9 | 86 | 0 |
Costolette di agnello (costola) | 0,65 kg | 36,6 | 3.3 | 140 | 0,1 | 15 | 0 | 1.7 | 2.7 | 54 | 0 |
Braciole di maiale | 0,65 kg | 30,7 | 3.5 | 196 | 0,2 | 30 | 0 | 17.4 | 2.7 | 60 | 0 |
Lonza di maiale arrosto | 0,65 kg | 24.2 | 4.4 | 249 | 0.3 | 37 | 0 | 18.2 | 3.6 | 79 | 0 |
Bacon | 0,65 kg | 25,6 | 10.4 | 152 | 0,2 | 23 | 0 | 1.8 | 1.8 | 71 | 0 |
Prosciutto affumicato | 0,65 kg | 27.4 | 6.7 | 212 | 0,2 | 31 | 0 | 9.9 | 3.3 | 50 | 0 |
Maiale salato | 0,65 kg | 16 | 18,8 | 164 | 0,1 | 26 | 0 | 1.4 | 1.8 | 0 | 0 |
Pollo arrosto | 0,65 kg | 30.3 | 1.8 | 184 | 0,1 | 30 | 0,1 | 0,9 | 1.8 | 68 | 46 |
Cotolette di vitello | 0,65 kg | 42.3 | 1.7 | 156 | 0,1 | 24 | 0 | 1.4 | 2.4 | 57 | 0 |
Salmone, rosa (lattina) | 500 g | 13 | 5.8 | 705 | 6.8 | 45 | 3.5 | 1 | 4.9 | 209 | 0 |
Mele | 0,65 kg | 4.4 | 5.8 | 27 | 0.5 | 36 | 8.3 | 3.6 | 2.7 | 5 | 544 |
Banane | 0,65 kg | 6.1 | 4.9 | 60 | 0.4 | 30 | 17.4 | 2.5 | 3.5 | 28 | 498 |
Limoni | 1 doz. | 26 | 1.0 | 21 | 0.5 | 14 | 0 | 0.5 | 0 | 4 | 952 |
Arance | 1 doz. | 30.9 | 2.2 | 40 | 1.1 | 18 | 11.1 | 3.6 | 1.3 | 10 | 1998 |
Fagiolini | 0,65 kg | 7.1 | 2.4 | 138 | 3.7 | 80 | 69 | 4.3 | 5.8 | 37 | 862 |
Cavolo cappuccio | 0,65 kg | 3.7 | 2.6 | 125 | 4.0 | 36 | 7.2 | 9 | 4.5 | 26 | 5369 |
Carote | 1 gruppo | 4.7 | 2.7 | 73 | 2.8 | 43 | 188.5 | 6.1 | 4.3 | 89 | 608 |
Sedano | 1 stallo | 8.3 | 0,9 | 51 | 3.0 | 23 | 0,9 | 1.4 | 1.4 | 9 | 313 |
Qual è il colmo per un eschimese? | 1 testa | 8.2 | 0.4 | 27 | 1.1 | 22 | 112.4 | 1.8 | 3.4 | 11 | 449 |
Cipolle | 0,65 kg | 3.6 | 5.8 | 166 | 3,8 | 59 | 16.6 | 4.7 | 5.9 | 21 | 1184 |
Patate | 6,5 kg | 34 | 14.3 | 336 | 1.8 | 118 | 6.7 | 29.4 | 7.1 | 198 | 2522 |
Spinaci | 0,65 kg | 8.1 | 1.1 | 106 | 0 | 138 | 918,4 | 5.7 | 13.8 | 33 | 2755 |
Patate dolci | 0,65 kg | 5.1 | 9.6 | 138 | 2.7 | 54 | 290.7 | 8.4 | 5.4 | 83 | 1912 |
Pesche (lattina) | N. 2 1/2 | 16.8 | 3.7 | 20 | 0.4 | 10 | 21.5 | 0.5 | 1 | 31 | 196 |
Pere (lattina) | N. 2 1/2 | 20.4 | 3.0 | 8 | 0.3 | 8 | 0,8 | 0,8 | 0,8 | 5 | 81 |
Ananas (lattina) | N. 2 1/2 | 21.3 | 2.4 | 16 | 0.4 | 8 | 2 | 2.8 | 0,8 | 7 | 399 |
Asparagi (lattina) | N. 2 | 27,7 | 0.4 | 33 | 0.3 | 12 | 16.3 | 1.4 | 2.1 | 17 | 272 |
Fagiolini (lattina) | N. 2 | 10 | 1.0 | 54 | 2 | 65 | 53.9 | 1.6 | 4.3 | 32 | 431 |
Maiale e fagioli (lattina) | 500 g | 7.1 | 7.5 | 364 | 4 | 134 | 3.5 | 8.3 | 7.7 | 56 | 0 |
Mais (lattina) | N. 2 | 10.4 | 5.2 | 136 | 0,2 | 16 | 12 | 1.6 | 2.7 | 42 | 218 |
Piselli (lattina) | N. 2 | 13.8 | 2.3 | 136 | 0.6 | 45 | 34.9 | 4.9 | 2.5 | 37 | 370 |
Pomodori (lattina) | N. 2 | 8.6 | 1.3 | 63 | 0.7 | 38 | 53.2 | 3.4 | 2.5 | 36 | 1253 |
Zuppa di pomodoro (lattina) | 10 1/2 oz | 7.6 | 1.6 | 71 | 0.6 | 43 | 57.9 | 3.5 | 2.4 | 67 | 862 |
Pesche essiccate | 0,65 kg | 15.7 | 8.5 | 87 | 1.7 | 173 | 86.8 | 1.2 | 4.3 | 55 | 57 |
Prugne secche | 0,65 kg | 9 | 12,8 | 99 | 2.5 | 154 | 85.7 | 3,9 | 4.3 | 65 | 257 |
Uvetta, essiccata | 15 g | 9.4 | 13.5 | 104 | 2.5 | 136 | 4.5 | 6.3 | 1.4 | 24 | 136 |
Piselli essiccati | 0,65 kg | 7,9 | 20.0 | 1367 | 4.2 | 345 | 2.9 | 28.7 | 18.4 | 162 | 0 |
Fagioli Lima, secchi | 0,65 kg | 8.9 | 17.4 | 1055 | 3.7 | 459 | 5.1 | 26.9 | 38.2 | 93 | 0 |
Fagioli tondi, essiccati | 0,65 kg | 5.9 | 26.9 | 1691 | 11.4 | 792 | 0 | 38.4 | 24,6 | 217 | 0 |
Caffè | 0,65 kg | 22,4 | 0 | 0 | 0 | 0 | 0 | 4 | 5.1 | 50 | 0 |
Tè | 0,6 kg | 17.4 | 0 | 0 | 0 | 0 | 0 | 0 | 2.3 | 42 | 0 |
Cacao | 225 g | 8.6 | 8.7 | 237 | 3 | 72 | 0 | 2 | 11.9 | 40 | 0 |
Cioccolato | 225 g | 16.2 | 8.0 | 77 | 1.3 | 39 | 0 | 0,9 | 3.4 | 14 | 0 |
Zuccheri | 4,5 kg | 51,7 | 34.9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Sciroppo di mais | 24 oz | 13.7 | 14.7 | 0 | 0.5 | 74 | 0 | 0 | 0 | 5 | 0 |
Melassa | 500 g | 13.6 | 9.0 | 0 | 10.3 | 244 | 0 | 1.9 | 7.5 | 146 | 0 |
Conserve di fragole | 0,65 kg | 20.5 | 6.4 | 11 | 0.4 | 7 | 0,2 | 0,2 | 0.4 | 3 | 0 |
Dal momento che tutti i nutrienti sono stati normalizzati in base al prezzo, il nostro obiettivo è semplicemente ridurre al minimo la somma degli alimenti.
Nel 1944, Stigler calcolò la migliore risposta possibile, notando con tristezza:
...non sembra esserci un metodo diretto per trovare il minimo di una funzione lineare soggetta a condizioni lineari.
Ha trovato una dieta che costava 39,93 $all'anno, nel 1939 dollari. Nel 1947 Jack Laderman utilizzò il metodo simplex (allora di recente invenzione) per determinare la soluzione ottimale. Ci sono voluti 120 giorni lavorativi in cui nove impiegati su calcolatrici da tavolo arrivavano alla risposta.
Soluzione che utilizza il risolutore lineare
Le seguenti sezioni presentano un programma per risolvere il problema della dieta Stigler.
Importa il wrapper del risolutore lineare
Importa il wrapper del risolutore lineare OR-Tools, un'interfaccia per il risolutore lineare [GLOP](/ottimizzazione/mip/glop0), come mostrato di seguito.
Python
from ortools.linear_solver import pywraplp
C++
#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"
Java
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;
C#
using System; using System.Collections.Generic; using Google.OrTools.LinearSolver;
Dati relativi al problema
Il codice seguente crea un array nutrients
per i
requisiti minimi di nutrienti e un
array data
per la tabella dei dati nutrizionali
in qualsiasi soluzione.
Python
# 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 ]
C++
// 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}}};
Java
// 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}});
C#
// 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 }) };
Dichiara il risolutore LP
Il codice seguente crea un'istanza del wrapper MPsolver
.
Python
# Instantiate a Glop solver and naming it. solver = pywraplp.Solver.CreateSolver("GLOP") if not solver: return
C++
// Create the linear solver with the GLOP backend. std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("GLOP"));
Java
// 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; }
C#
// Create the linear solver with the GLOP backend. Solver solver = Solver.CreateSolver("GLOP"); if (solver is null) { return; }
Crea le variabili
Il codice seguente crea le variabili per il problema.
Python
# 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())
C++
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();
Java
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());
C#
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()}");
Il metodo MakeNumVar
crea una variabile, food[i]
, per ogni riga della tabella.
Come accennato in precedenza, i dati nutrizionali sono per dollaro, quindi food[i]
è l'importo da spendere per la materia prima i
.
Definisci i vincoli
I vincoli per la dieta Stigler richiedono che la quantità totale di sostanze nutritive
fornite da tutti gli alimenti sia almeno il fabbisogno minimo di ciascun nutriente.
Successivamente, scriviamo questi vincoli come disuguaglianze che coinvolgono gli array data
e nutrients
e le variabili food[i]
.
Innanzitutto, la quantità di sostanze nutritive i
fornite dagli alimenti j
per dollaro è
data[j][i+3]
(aggiungiamo 3 all'indice della colonna perché i dati nutrizionali iniziano nella
quarta colonna di data
). Poiché l'importo da spendere per l'alimentazione j
è food[j]
, la quantità di nutrienti i
fornita dall'alimentazione j
è
\(data[j][i+3] \cdot food[j]\).
Infine, poiché il requisito minimo per la sostanza i
di nutrizione è nutrients[i][1]
, possiamo scrivere il vincolo i come segue:
Python
# 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())
C++
// 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();
Java
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());
C#
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()}");
Il metodo Python Constraint
(corrispondente al metodo C++ MakeRowConstraint
) crea i vincoli per il problema. Per ogni i
,
constraint(nutrients[i][1], solver.infinity)
Questo crea un vincolo in cui una combinazione lineare delle variabili food[j]
(definite di seguito) è maggiore o uguale a nutrients[i][1]
.
I coefficienti dell'espressione lineare sono definiti dal metodo
SetCoefficient
come segue: SetCoefficient(food[j], data[j][i+3]
Imposta il coefficiente di food[j]
su data[j][i+3]
.
Per riassumere, il codice definisce i vincoli espressi al punto (1) sopra.
Crea l'obiettivo
Il codice seguente definisce la funzione obiettivo per il problema.
Python
# Objective function: Minimize the sum of (price-normalized) foods. objective = solver.Objective() for food in foods: objective.SetCoefficient(food, 1) objective.SetMinimization()
C++
MPObjective* const objective = solver->MutableObjective(); for (size_t i = 0; i < data.size(); ++i) { objective->SetCoefficient(foods[i], 1); } objective->SetMinimization();
Java
MPObjective objective = solver.objective(); for (int i = 0; i < data.size(); ++i) { objective.setCoefficient(foods.get(i), 1); } objective.setMinimization();
C#
Objective objective = solver.Objective(); for (int i = 0; i < data.Length; ++i) { objective.SetCoefficient(foods[i], 1); } objective.SetMinimization();
La funzione obiettivo è il costo totale del cibo, ovvero la somma delle
variabili food[i]
.
Il metodo SetCoefficient
imposta i coefficienti della funzione obiettivo, che in questo caso sono tutti 1
.
Infine, il SetMinimization
dichiara che si tratta di un problema di minimizzazione.
Richiama il risolutore
Il codice seguente richiama il risolutore.
Python
print(f"Solving with {solver.SolverVersion()}") status = solver.Solve()
C++
const MPSolver::ResultStatus result_status = solver->Solve();
Java
final MPSolver.ResultStatus resultStatus = solver.solve();
C#
Solver.ResultStatus resultStatus = solver.Solve();
Glop risolve il problema su un computer tipico in meno di 300 millisecondi:
Visualizza la soluzione
Il codice seguente mostra la soluzione.
Python
# 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]) )
C++
// 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) << ")"; }
Java
// 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] + ")"); }
C#
// 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})"); }
Ecco l'output del programma.
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
Codice completo del programma
Il codice completo del programma di dieta Stigler è mostrato di seguito.
Python
"""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()
C++
// 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; }
Java
// 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() {} }
C#
// 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"); } }