Port Stigler Diet to all languages supported
This commit is contained in:
@@ -1,226 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# This Python file uses the following encoding: utf-8
|
||||
# Copyright 2018 Google LLC
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Stigler diet example"""
|
||||
|
||||
from ortools.linear_solver import pywraplp
|
||||
|
||||
|
||||
def main():
|
||||
"""Entry point of the program"""
|
||||
# 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 = [[
|
||||
'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
|
||||
]]
|
||||
|
||||
# Instantiate a Glop solver, naming it LinearExample.
|
||||
solver = pywraplp.Solver('StiglerDietExample',
|
||||
pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)
|
||||
|
||||
# Declare an array to hold our variables.
|
||||
foods = [solver.NumVar(0.0, solver.infinity(), item[0]) for item in data]
|
||||
|
||||
# Objective function: Minimize the sum of (price-normalized) foods.
|
||||
objective = solver.Objective()
|
||||
for food in foods:
|
||||
objective.SetCoefficient(food, 1)
|
||||
objective.SetMinimization()
|
||||
|
||||
# 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 variables =', solver.NumVariables())
|
||||
print('Number of constraints =', solver.NumConstraints())
|
||||
|
||||
# Solve the system.
|
||||
status = solver.Solve()
|
||||
# Check that the problem has an optimal solution.
|
||||
if status != pywraplp.Solver.OPTIMAL:
|
||||
print("The problem does not have an optimal solution!")
|
||||
exit(1)
|
||||
|
||||
nutrients_result = [0] * len(nutrients)
|
||||
print('')
|
||||
print('Annual Foods:')
|
||||
for i, food in enumerate(foods):
|
||||
if food.solution_value() > 0.0:
|
||||
print('{}: ${}'.format(data[i][0], 365. * food.solution_value()))
|
||||
for j, nutrient in enumerate(nutrients):
|
||||
nutrients_result[j] += data[i][j + 3] * food.solution_value()
|
||||
print('')
|
||||
print('Optimal annual price: ${:.4f}'.format(365. * objective.Value()))
|
||||
print('')
|
||||
print('Nutrients per day:')
|
||||
for i, nutrient in enumerate(nutrients):
|
||||
print('{}: {:.2f} (min {})'.format(nutrient[0], nutrients_result[i],
|
||||
nutrient[1]))
|
||||
print('')
|
||||
print('Advanced usage:')
|
||||
print('Problem solved in ', solver.wall_time(), ' milliseconds')
|
||||
print('Problem solved in ', solver.iterations(), ' iterations')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -419,7 +419,8 @@ test_cc_linear_solver_samples: \
|
||||
rcc_mip_var_array \
|
||||
rcc_multiple_knapsack_mip \
|
||||
rcc_simple_lp_program \
|
||||
rcc_simple_mip_program
|
||||
rcc_simple_mip_program \
|
||||
rcc_stigler_diet
|
||||
|
||||
.PHONY: test_cc_constraint_solver_samples # Build and Run all C++ CP Samples (located in ortools/constraint_solver/samples)
|
||||
test_cc_constraint_solver_samples: \
|
||||
@@ -480,7 +481,6 @@ check_cc_pimpl: \
|
||||
test_cc_sat_samples \
|
||||
\
|
||||
rcc_linear_programming \
|
||||
rcc_stigler_diet \
|
||||
rcc_constraint_programming_cp \
|
||||
rcc_integer_programming \
|
||||
rcc_knapsack \
|
||||
|
||||
@@ -624,6 +624,7 @@ test_dotnet_linear_solver_samples:
|
||||
$(MAKE) run SOURCE=ortools/linear_solver/samples/MultipleKnapsackMip.cs
|
||||
$(MAKE) run SOURCE=ortools/linear_solver/samples/SimpleLpProgram.cs
|
||||
$(MAKE) run SOURCE=ortools/linear_solver/samples/SimpleMipProgram.cs
|
||||
$(MAKE) run SOURCE=ortools/linear_solver/samples/StiglerDiet.cs
|
||||
|
||||
.PHONY: test_dotnet_sat_samples # Build and Run all .Net SAT Samples (located in ortools/sat/samples)
|
||||
test_dotnet_sat_samples:
|
||||
|
||||
@@ -711,7 +711,8 @@ test_java_linear_solver_samples: \
|
||||
rjava_MipVarArray \
|
||||
rjava_MultipleKnapsackMip \
|
||||
rjava_SimpleLpProgram \
|
||||
rjava_SimpleMipProgram
|
||||
rjava_SimpleMipProgram \
|
||||
rjava_StiglerDiet
|
||||
|
||||
.PHONY: test_java_sat_samples # Build and Run all Java SAT Samples (located in ortools/sat/samples)
|
||||
test_java_sat_samples: \
|
||||
|
||||
@@ -632,7 +632,8 @@ test_python_linear_solver_samples: \
|
||||
rpy_mip_var_array \
|
||||
rpy_multiple_knapsack_mip \
|
||||
rpy_simple_lp_program \
|
||||
rpy_simple_mip_program
|
||||
rpy_simple_mip_program \
|
||||
rpy_stigler_diet
|
||||
|
||||
.PHONY: test_python_sat_samples # Run all Python Sat Samples (located in ortools/sat/samples)
|
||||
test_python_sat_samples: \
|
||||
@@ -666,8 +667,6 @@ check_python_pimpl: \
|
||||
test_python_graph_samples \
|
||||
test_python_linear_solver_samples \
|
||||
test_python_sat_samples \
|
||||
\
|
||||
rpy_stigler_diet
|
||||
# rpy_rabbits_pheasants_cp \
|
||||
# rpy_cryptarithmetic_cp \
|
||||
# rpy_cryptarithmetic_sat \
|
||||
@@ -802,7 +801,7 @@ test_python_contrib: \
|
||||
rpy_stable_marriage \
|
||||
rpy_steel_lns \
|
||||
rpy_steel \
|
||||
rpy_stigler \
|
||||
rpy_stigler_contrib \
|
||||
rpy_strimko2 \
|
||||
rpy_subset_sum \
|
||||
rpy_survo_puzzle \
|
||||
@@ -850,7 +849,6 @@ test_python_python: \
|
||||
rpy_shift_scheduling_sat \
|
||||
rpy_single_machine_scheduling_with_setup_release_due_dates_sat \
|
||||
rpy_steel_mill_slab_sat \
|
||||
rpy_stigler_diet \
|
||||
rpy_sudoku_sat \
|
||||
rpy_tasks_and_workers_assignment_sat \
|
||||
rpy_transit_time \
|
||||
|
||||
@@ -17,3 +17,5 @@ code_sample_cc(name = "multiple_knapsack_mip")
|
||||
code_sample_cc(name = "simple_lp_program")
|
||||
|
||||
code_sample_cc(name = "simple_mip_program")
|
||||
|
||||
code_sample_cc(name = "stigler_diet")
|
||||
|
||||
201
ortools/linear_solver/samples/StiglerDiet.cs
Normal file
201
ortools/linear_solver/samples/StiglerDiet.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
// Copyright 2010-2021 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// [START program]
|
||||
// The Stigler diet problem.
|
||||
// [START import]
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Google.OrTools.LinearSolver;
|
||||
// [END import]
|
||||
|
||||
public class StiglerDiet
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
// [START data_model]
|
||||
// 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 })
|
||||
};
|
||||
// [END data_model]
|
||||
|
||||
// [START solver]
|
||||
// Create the linear solver with the GLOP backend.
|
||||
Solver solver = Solver.CreateSolver("GLOP");
|
||||
// [END solver]
|
||||
|
||||
// [START variables]
|
||||
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()}");
|
||||
// [END variables]
|
||||
|
||||
// [START constraints]
|
||||
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()}");
|
||||
// [END constraints]
|
||||
|
||||
// [START objective]
|
||||
Objective objective = solver.Objective();
|
||||
for (int i = 0; i < data.Length; ++i)
|
||||
{
|
||||
objective.SetCoefficient(foods[i], 1);
|
||||
}
|
||||
objective.SetMinimization();
|
||||
// [END objective]
|
||||
|
||||
// [START solve]
|
||||
Solver.ResultStatus resultStatus = solver.Solve();
|
||||
// [END solve]
|
||||
|
||||
// [START print_solution]
|
||||
// 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})");
|
||||
}
|
||||
// [END print_solution]
|
||||
|
||||
// [START advanced]
|
||||
Console.WriteLine("\nAdvanced usage:");
|
||||
Console.WriteLine($"Problem solved in {solver.WallTime()} milliseconds");
|
||||
Console.WriteLine($"Problem solved in {solver.Iterations()} iterations");
|
||||
// [END advanced]
|
||||
}
|
||||
}
|
||||
// [END program]
|
||||
24
ortools/linear_solver/samples/StiglerDiet.csproj
Normal file
24
ortools/linear_solver/samples/StiglerDiet.csproj
Normal file
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<EnableDefaultItems>false</EnableDefaultItems>
|
||||
<!-- see https://github.com/dotnet/docs/issues/12237 -->
|
||||
<RollForward>LatestMajor</RollForward>
|
||||
<RestoreSources>../../../temp_dotnet/packages;$(RestoreSources);https://api.nuget.org/v3/index.json</RestoreSources>
|
||||
<AssemblyName>Google.OrTools.StiglerDiet</AssemblyName>
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<GenerateTailCalls>true</GenerateTailCalls>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="StiglerDiet.cs" />
|
||||
<PackageReference Include="Google.OrTools" Version="9.0.*" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
280
ortools/linear_solver/samples/StiglerDiet.java
Normal file
280
ortools/linear_solver/samples/StiglerDiet.java
Normal file
@@ -0,0 +1,280 @@
|
||||
// Copyright 2010-2021 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// [START program]
|
||||
// The Stigler diet problem.
|
||||
package com.google.ortools.linearsolver.samples;
|
||||
// [START import]
|
||||
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.AbstractMap.SimpleEntry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
// [END import]
|
||||
|
||||
public final class StiglerDiet {
|
||||
public static void main(String[] args) {
|
||||
Loader.loadNativeLibraries();
|
||||
// [START data_model]
|
||||
// Nutrient minimums.
|
||||
List<Object[]> nutrients = new ArrayList<Object[]>();
|
||||
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<Object[]>();
|
||||
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}});
|
||||
|
||||
// [END data_model]
|
||||
|
||||
// [START solver]
|
||||
// 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;
|
||||
}
|
||||
// [END solver]
|
||||
|
||||
// [START variables]
|
||||
double infinity = java.lang.Double.POSITIVE_INFINITY;
|
||||
List<MPVariable> foods = new ArrayList<MPVariable>();
|
||||
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());
|
||||
// [END variables]
|
||||
|
||||
// [START constraints]
|
||||
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());
|
||||
// [END constraints]
|
||||
|
||||
// [START objective]
|
||||
MPObjective objective = solver.objective();
|
||||
for (int i = 0; i < data.size(); ++i) {
|
||||
objective.setCoefficient(foods.get(i), 1);
|
||||
}
|
||||
objective.setMinimization();
|
||||
// [END objective]
|
||||
|
||||
// [START solve]
|
||||
final MPSolver.ResultStatus resultStatus = solver.solve();
|
||||
// [END solve]
|
||||
|
||||
// [START print_solution]
|
||||
// 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] + ")");
|
||||
}
|
||||
// [END print_solution]
|
||||
|
||||
// [START advanced]
|
||||
System.out.println("\nAdvanced usage:");
|
||||
System.out.println("Problem solved in " + solver.wallTime() + " milliseconds");
|
||||
System.out.println("Problem solved in " + solver.iterations() + " iterations");
|
||||
// [END advanced]
|
||||
}
|
||||
|
||||
private StiglerDiet() {}
|
||||
}
|
||||
// [END program]
|
||||
@@ -1,3 +1,4 @@
|
||||
// Copyright 2010-2021 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -9,42 +10,48 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// [START program]
|
||||
// The Stigler diet problem.
|
||||
// [START import]
|
||||
#include <array>
|
||||
#include <utility> // std::pair
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/linear_solver/linear_solver.h"
|
||||
#include "ortools/linear_solver/linear_solver.pb.h"
|
||||
// [END import]
|
||||
|
||||
namespace operations_research {
|
||||
void RunStiglerDietExample() {
|
||||
void StiglerDiet() {
|
||||
// [START data_model]
|
||||
// Nutrient minimums.
|
||||
std::vector<std::pair<std::string, double> > nutrients = {
|
||||
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},
|
||||
{"Thiamine (Vitamin B1) (mg)", 1.8},
|
||||
{"Riboflavin (Vitamin B2) (mg)", 2.7},
|
||||
{"Vitamin B1 (mg)", 1.8},
|
||||
{"Vitamin B2 (mg)", 2.7},
|
||||
{"Niacin (mg)", 18.0},
|
||||
{"Ascorbic Acid (Vitamin C) (mg)", 75.0}};
|
||||
{"Vitamin C (mg)", 75.0}
|
||||
};
|
||||
|
||||
struct Commodity {
|
||||
// Commodity name
|
||||
std::string name;
|
||||
// Unit
|
||||
std::string unit;
|
||||
// 1939 price per unit (cents)
|
||||
double price;
|
||||
// Calories (kcal)
|
||||
// Protein (g)
|
||||
// Calcium (g)
|
||||
// Iron (mg)
|
||||
// Vitamin A (kIU)
|
||||
// Vitamin B1 (mg)
|
||||
// Vitamin B2 (mg)
|
||||
// Niacin (mg)
|
||||
// Vitamin C (mg)
|
||||
std::vector<double> nutrients;
|
||||
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 = {
|
||||
@@ -223,38 +230,50 @@ void RunStiglerDietExample() {
|
||||
{"Strawberry Preserves",
|
||||
"1 lb.",
|
||||
20.5,
|
||||
{6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}}};
|
||||
{6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}}
|
||||
};
|
||||
// [END data_model]
|
||||
|
||||
// Instantiate the solver
|
||||
MPSolver solver("StiglerDietExample", MPSolver::GLOP_LINEAR_PROGRAMMING);
|
||||
// [START solver]
|
||||
// Create the linear solver with the GLOP backend.
|
||||
std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("GLOP"));
|
||||
// [END solver]
|
||||
|
||||
// Declare an array to hold our nutritional data.
|
||||
std::vector<MPVariable*> food;
|
||||
|
||||
// Objective: minimize the sum of (price-normalized) foods.
|
||||
MPObjective* const objective = solver.MutableObjective();
|
||||
const double infinity = solver.infinity();
|
||||
// [START variables]
|
||||
std::vector<MPVariable*> foods;
|
||||
const double infinity = solver->infinity();
|
||||
for (const Commodity& commodity : data) {
|
||||
food.push_back(solver.MakeNumVar(0.0, infinity, commodity.name));
|
||||
objective->SetCoefficient(food.back(), 1);
|
||||
foods.push_back(solver->MakeNumVar(0.0, infinity, commodity.name));
|
||||
}
|
||||
objective->SetMinimization();
|
||||
LOG(INFO) << "Number of variables = " << solver->NumVariables();
|
||||
// [END variables]
|
||||
|
||||
// [START constraints]
|
||||
// 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));
|
||||
solver->MakeRowConstraint(nutrients[i].second, infinity));
|
||||
for (std::size_t j = 0; j < data.size(); ++j) {
|
||||
constraints.back()->SetCoefficient(food[j], data[j].nutrients[i]);
|
||||
constraints.back()->SetCoefficient(foods[j], data[j].nutrients[i]);
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "Number of constraints = " << solver->NumConstraints();
|
||||
// [END constraints]
|
||||
|
||||
LOG(INFO) << "Number of variables = " << solver.NumVariables();
|
||||
LOG(INFO) << "Number of constraints = " << solver.NumConstraints();
|
||||
// [START objective]
|
||||
MPObjective* const objective = solver->MutableObjective();
|
||||
for (size_t i=0; i < data.size(); ++i) {
|
||||
objective->SetCoefficient(foods[i], 1);
|
||||
}
|
||||
objective->SetMinimization();
|
||||
// [END objective]
|
||||
|
||||
// Solve!
|
||||
const MPSolver::ResultStatus result_status = solver.Solve();
|
||||
// [START solve]
|
||||
const MPSolver::ResultStatus result_status = solver->Solve();
|
||||
// [END solve]
|
||||
|
||||
// [START print_solution]
|
||||
// Check that the problem has an optimal solution.
|
||||
if (result_status != MPSolver::OPTIMAL) {
|
||||
LOG(INFO) << "The problem does not have an optimal solution!";
|
||||
@@ -262,39 +281,44 @@ void RunStiglerDietExample() {
|
||||
LOG(INFO) << "A potentially suboptimal solution was found";
|
||||
} else {
|
||||
LOG(INFO) << "The solver could not solve the problem.";
|
||||
return;
|
||||
}
|
||||
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 (food[i]->solution_value() > 0.0) {
|
||||
LOG(INFO) << data[i].name << ": $" << 365. * food[i]->solution_value();
|
||||
}
|
||||
for (std::size_t j = 0; j < nutrients.size(); ++j) {
|
||||
nutrients_result[j] += data[i].nutrients[j] * food[i]->solution_value();
|
||||
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: $" << 365. * objective->Value();
|
||||
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 << ": " << nutrients_result[i] << " (min "
|
||||
<< nutrients[i].second << ")";
|
||||
LOG(INFO) << nutrients[i].first << ": " << std::to_string(nutrients_result[i]) << " (min "
|
||||
<< std::to_string(nutrients[i].second) << ")";
|
||||
}
|
||||
// [END print_solution]
|
||||
|
||||
// [START advanced]
|
||||
LOG(INFO) << "";
|
||||
LOG(INFO) << "Advanced usage:";
|
||||
LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds";
|
||||
LOG(INFO) << "Problem solved in " << solver.iterations() << " iterations";
|
||||
LOG(INFO) << "Problem solved in " << solver->wall_time() << " milliseconds";
|
||||
LOG(INFO) << "Problem solved in " << solver->iterations() << " iterations";
|
||||
// [END advanced]
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
absl::SetFlag(&FLAGS_logtostderr, 1);
|
||||
operations_research::RunStiglerDietExample();
|
||||
operations_research::StiglerDiet();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
// [END program]
|
||||
316
ortools/linear_solver/samples/stigler_diet.py
Executable file
316
ortools/linear_solver/samples/stigler_diet.py
Executable file
@@ -0,0 +1,316 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2010-2021 Google LLC
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# [START program]
|
||||
"""The Stigler diet problem.
|
||||
|
||||
A description of the problem can be found here:
|
||||
https://en.wikipedia.org/wiki/Stigler_diet.
|
||||
"""
|
||||
# [START import]
|
||||
from ortools.linear_solver import pywraplp
|
||||
# [END import]
|
||||
|
||||
|
||||
def main():
|
||||
"""Entry point of the program."""
|
||||
# Instantiate the data problem.
|
||||
# [START data_model]
|
||||
# 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 = [
|
||||
[
|
||||
'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
|
||||
],
|
||||
]
|
||||
# [END data_model]
|
||||
|
||||
# [START solver]
|
||||
# Instantiate a Glop solver and naming it.
|
||||
solver = pywraplp.Solver('StiglerDietExample',
|
||||
pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)
|
||||
# [END solver]
|
||||
|
||||
# [START variables]
|
||||
# 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())
|
||||
# [END variables]
|
||||
|
||||
# [START constraints]
|
||||
# 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())
|
||||
# [END constraints]
|
||||
|
||||
# [START objective]
|
||||
# Objective function: Minimize the sum of (price-normalized) foods.
|
||||
objective = solver.Objective()
|
||||
for food in foods:
|
||||
objective.SetCoefficient(food, 1)
|
||||
objective.SetMinimization()
|
||||
# [END objective]
|
||||
|
||||
# [START solve]
|
||||
status = solver.Solve()
|
||||
# [END solve]
|
||||
|
||||
# [START print_solution]
|
||||
# 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. * 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. * objective.Value()))
|
||||
|
||||
print('\nNutrients per day:')
|
||||
for i, nutrient in enumerate(nutrients):
|
||||
print('{}: {:.2f} (min {})'.format(nutrient[0], nutrients_result[i],
|
||||
nutrient[1]))
|
||||
# [END print_solution]
|
||||
|
||||
# [START advanced]
|
||||
print('\nAdvanced usage:')
|
||||
print('Problem solved in ', solver.wall_time(), ' milliseconds')
|
||||
print('Problem solved in ', solver.iterations(), ' iterations')
|
||||
# [END advanced]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
# [END program]
|
||||
Reference in New Issue
Block a user