Quick Start using lists and dictionaries

nativediet.ipynb Open In Colab Kaggle Gradient Open In SageMaker Studio Lab Hits

Description: Quick Start using lists and dictionaries to load and retrieve data

Tags: amplpy, quick-start, highlights

Notebook author: Filipe Brandão <fdabrandao@gmail.com>

# Install dependencies
%pip install -q amplpy pandas numpy
# Google Colab & Kaggle integration
from amplpy import AMPL, ampl_notebook

ampl = ampl_notebook(
    modules=["highs"],  # modules to install
    license_uuid="default",  # license to use
)  # instantiate AMPL object and register magics

Diet Model

Consider the problem of choosing prepared foods to meet certain nutritional requirements.

Sets:

  • NUTR: set of nutrients to consider

  • FOOD: set of food to consider

Parameters:

  • cost {FOOD}: cost of each food

  • f_min {FOOD}: minimum amount of food to buy

  • f_max {FOOD}: maximum amount of food to buy

  • n_min {NUTR}: minimum amount required of each nutrient

  • n_max {NUTR}: maximum amount allowed of each nutrient

  • amt {NUTR, FOOD}: amount of each nutrient in each food

Variables:

  • Buy {FOOD}: amount of food to buy

Objective:

  • Total_Cost: total cost of the diet

Constraints:

  • Diet {NUTR}: ensure that the nutritional requirements are satisfied by the diet.

The problem is then modeled as follows:

%%ampl_eval
reset;
set NUTR;
set FOOD;

param cost {FOOD} > 0;
param f_min {FOOD} >= 0;
param f_max {j in FOOD} >= f_min[j];

param n_min {NUTR} >= 0;
param n_max {i in NUTR} >= n_min[i];

param amt {NUTR,FOOD} >= 0;

var Buy {j in FOOD} >= f_min[j], <= f_max[j];

minimize Total_Cost:  sum {j in FOOD} cost[j] * Buy[j];

subject to Diet {i in NUTR}:
n_min[i] <= sum {j in FOOD} amt[i,j] * Buy[j] <= n_max[i];

Load the data using lists and dictionaries

# foods[food] = (cost, f_min, f_max)
foods = {
    "BEEF": (3.59, 2, 10),
    "CHK": (2.59, 2, 10),
    "FISH": (2.29, 2, 10),
    "HAM": (2.89, 2, 10),
    "MCH": (1.89, 2, 10),
    "MTL": (1.99, 2, 10),
    "SPG": (1.99, 2, 10),
    "TUR": (2.49, 2, 10),
}
# nutrients[nutr] = (n_min, n_max)
nutrients = {
    "A": (700, 20000),
    "C": (700, 20000),
    "B1": (700, 20000),
    "B2": (700, 20000),
    "NA": (0, 50000),
    "CAL": (16000, 24000),
}
ampl.set["FOOD"] = list(foods.keys())
ampl.param["cost"] = {food: cost for food, (cost, _, _) in foods.items()}
ampl.param["f_min"] = {food: f_min for food, (_, f_min, _) in foods.items()}
ampl.param["f_max"] = {food: f_max for food, (_, _, f_max) in foods.items()}
ampl.set["NUTR"] = list(nutrients.keys())
ampl.param["n_min"] = {nutr: n_min for nutr, (n_min, _) in nutrients.items()}
ampl.param["n_max"] = {nutr: n_max for nutr, (_, n_max) in nutrients.items()}
amounts = [
    [60, 8, 8, 40, 15, 70, 25, 60],
    [20, 0, 10, 40, 35, 30, 50, 20],
    [10, 20, 15, 35, 15, 15, 25, 15],
    [15, 20, 10, 10, 15, 15, 15, 10],
    [928, 2180, 945, 278, 1182, 896, 1329, 1397],
    [295, 770, 440, 430, 315, 400, 379, 450],
]
ampl.param["amt"] = {
    (nutrient, food): amounts[i][j]
    for i, nutrient in enumerate(nutrients)
    for j, food in enumerate(foods)
}

Solve with HiGHS

# Specify the solver to use (e.g., HiGHS)
ampl.option["solver"] = "highs"
# Solve
ampl.solve()
# Stop if the model was not solved
assert ampl.get_value("solve_result") == "solved"
# Get objective entity by AMPL name
totalcost = ampl.get_objective("Total_Cost")
# Print it
print("Objective is:", totalcost.value())
HiGHS 1.4.0:HiGHS 1.4.0: optimal solution; objective 119.9897589
4 simplex iterations
0 barrier iterations
absmipgap=119.99, relmipgap=inf
Objective is: 119.98975893599335

Reassign data for specific instances and resolve

# Reassign data - specific instances
cost = ampl.get_parameter("cost")
cost.set_values({"BEEF": 5.01, "HAM": 4.55})
print("Increased costs of beef and ham.")

# Resolve and display objective
ampl.solve()
# Stop if the model was not solved
assert ampl.get_value("solve_result") == "solved"
print("New objective value:", totalcost.value())
Increased costs of beef and ham.
HiGHS 1.4.0:HiGHS 1.4.0: optimal solution; objective 144.0120033
0 simplex iterations
0 barrier iterations
absmipgap=144.012, relmipgap=inf
New objective value: 144.01200332502077

Reassign data for all instances and resolve

# Reassign data - all instances
cost.set_values(
    {
        "BEEF": 3,
        "CHK": 5,
        "FISH": 5,
        "HAM": 6,
        "MCH": 1,
        "MTL": 2,
        "SPG": 5.01,
        "TUR": 4.55,
    }
)
print("Updated all costs.")

# Resolve and display objective
ampl.solve()
# Stop if the model was not solved
assert ampl.get_value("solve_result") == "solved"
print("New objective value:", totalcost.value())
Updated all costs.
HiGHS 1.4.0:HiGHS 1.4.0: optimal solution; objective 164.10625
4 simplex iterations
0 barrier iterations
absmipgap=164.106, relmipgap=inf
New objective value: 164.10625

Get the values of the variable Buy in a pandas.DataFrame object

df = ampl.get_variable("Buy").to_pandas()
df
Buy.val
BEEF 10.000000
CHK 2.000000
FISH 2.000000
HAM 6.851974
MCH 10.000000
MTL 10.000000
SPG 6.765351
TUR 2.000000

Get the values of an expression into a pandas.DataFrame object

df = ampl.get_data("{j in FOOD} 100*Buy[j]/Buy[j].ub").to_pandas()
df
100*Buy[j]/(Buy[j].ub)
BEEF 100.000000
CHK 20.000000
FISH 20.000000
HAM 68.519737
MCH 100.000000
MTL 100.000000
SPG 67.653509
TUR 20.000000