Diet Optimization
Select foods to satisfy nutritional requirements at minimum cost.
Browse files
Directorydiet/
What this template is for
Choosing a balanced diet that meets nutritional requirements while staying within a budget is a classic optimization problem. Given a set of foods with known costs and nutrient contents, and a set of nutrients with minimum and maximum daily intake bounds, the goal is to find the cheapest combination of foods that satisfies all nutritional constraints. It also shows how the same model answers a “what if” question — how cost moves as requirements tighten or loosen — without re-modeling anything.
The template uses prescriptive reasoning to formulate the diet problem as a linear program and solve several requirement scenarios in a single solve.
Who this is for
- Data scientists and analysts learning prescriptive optimization with RelationalAI
- Operations researchers looking for a clean LP formulation example
- Anyone interested in nutritional planning or cost minimization problems
- Beginners who want to understand scenario analysis in optimization
What you’ll build
- A least-cost diet plan — the amount of each food that meets every nutrient bound at minimum total cost — produced by prescriptive reasoning (a linear program).
- Nutritional constraints holding total intake within minimum and maximum daily bounds for calories, protein, fat, and sodium.
- A scenario comparison showing how least-cost changes as requirements scale, built with a first-class
Scenarioconcept so all cases solve at once.
Built using prescriptive reasoning (linear programming with continuous decision variables and a Scenario concept for multi-case solves).
What’s included
- Model: two concepts (
Food,Nutrient), aScenarioconcept, per-food decision variables, nutrient-bound constraints, and a cost-minimizing objective — all indiet.py. - Runner:
diet.py, a single Python script that runs end-to-end against a Snowflake-connected RAI account. - Runbook:
runbook.md— a paste-testable walkthrough that reproduces the template step by step with the RAI skills; as important a reference as the script itself. - Sample data:
data/foods.csv(foods with cost and per-nutrient content) anddata/nutrients.csv(nutrient min/max bounds). - Outputs: per-scenario termination status, objective cost, and a table of the foods (and amounts) in each least-cost basket, printed to stdout.
Prerequisites
Access
- A Snowflake account that has the RAI Native App installed.
- A Snowflake user with permissions to access the RAI Native App.
Tools
- Python >= 3.10
Quickstart
-
Download ZIP:
Terminal window curl -O https://docs.relational.ai/templates/zips/v1/diet.zipunzip diet.zipcd diet -
Create venv:
Terminal window python -m venv .venvsource .venv/bin/activatepython -m pip install --upgrade pip -
Install:
Terminal window python -m pip install . -
Configure:
Terminal window rai init -
Run:
Terminal window python diet.py -
Expected output — a few lines confirm a successful run:
Solve result:• status: OPTIMAL• objective: 35.49Diet plan per scenario (0.8 / 1.0 / 1.2 demand): the same baselinebasket — hamburger + icecream + milk — scaled per scenario, for aper-scenario cost of $9.46 / $11.83 / $14.19.The full per-scenario diet plan prints above; see
runbook.mdfor the complete log.
Template structure
.├── README.md # this file├── runbook.md # step-by-step analyst walkthrough├── pyproject.toml # dependencies├── diet.py # main script (model, constraints, scenarios, solve)└── data/ ├── foods.csv # foods with cost and per-nutrient content └── nutrients.csv # nutrient min/max boundsStart here: run python diet.py for the full model and scenario solve end to end, or follow runbook.md to rebuild it step by step.
Sample data
The bundled data is small and illustrative — a handful of foods and four nutrients, sized to teach the linear-program formulation, not to represent a clinically complete diet.
data/foods.csv— one row per food, with acostper serving and one column per nutrient (calories,protein,fat,sodium) giving that food’s content per serving. Each food’s nutrient columns must match the nutrientnames innutrients.csv.data/nutrients.csv— one row per nutrient, withminandmaxdaily-intake bounds. The scenario scaling factor multiplies these bounds up and down.
Model overview
The model is small and self-contained: two source concepts plus a Scenario concept that parameterizes the solve.
- Key entities:
Food— a food with a per-serving cost and a per-nutrient content, carrying a continuous decision variable for the amount to include;Nutrient— a nutrient with minimum and maximum daily-intake bounds (the constraint bounds, scaled per scenario); andScenario— a requirement-scaling case that scales every nutrient bound by its factor, with all scenarios solving together in one solve. - Primary identifiers:
Food.nameandNutrient.name(both strings);Scenario.scenario_name(string). - Important invariants: nutrient
minandmaxbounds are non-negative andmin <= max; each food’s decision amount is non-negative (lower=0); each food’s per-nutrient content is keyed by a nutrient that exists innutrients.csv.
For the full concept and property definitions, see diet.py; runbook.md builds them step by step with the RAI skills.
How it works
The model reads two source tables, adds a scenario axis, and hands a single parameterized linear program to the prescriptive solver:
foods.csv + nutrients.csv → concepts → decision variables → constraints + objective → multi-scenario solve → per-scenario baskets-
Define concepts and map data.
Nutrientcarries min/max daily-intake bounds;Foodcarries a per-serving cost and a per-nutrient content (a ternarycontainsproperty linking each food to a nutrient quantity). -
Decision variables. Each food gets a continuous, non-negative decision variable — the amount to include in the diet — created per scenario so all cases share one formulation.
-
Constraints and objective. For each nutrient, total intake across foods (quantity times amount, summed) must fall between the scenario-scaled min and max bounds. The objective minimizes total cost (cost times amount, summed over foods).
-
Scenario analysis. A first-class
Scenarioconcept scales every nutrient bound by a factor (0.8 / 1.0 / 1.2 here), so tighter and looser requirements solve together in a single solve and their costs are directly comparable.
The prescriptive decision variable appears in the model schema alongside the source-data properties — a unified view of everything the model knows, including variables added by solve_for(). See diet.py for the implementation and runbook.md for the skill-driven reproduction.
Customize this template
Focus on the first changes most users will make.
Use your own data
- Replace
data/foods.csvanddata/nutrients.csvwith your own; keep the column names described in Sample data above. Each food’s nutrient columns must match the nutrientnames innutrients.csv— the model reads one food column per nutrient row. - For Snowflake-backed runs, swap the
read_csv(...)calls formodel.data(snowflake_table)calls.
Tune parameters
- Edit the scenario rows in
diet.py(the("scaling_80pct", 0.8),("baseline", 1.0),("scaling_120pct", 1.2)tuples) to test different scaling factors, or add rows for finer resolution. - Adjust the solver time limit (
time_limit_sec) if you scale up to many foods and nutrients.
Extend the model
- Add dietary preferences: introduce upper bounds on specific foods (for example, limiting red meat), or add binary variables to model food inclusion/exclusion.
- Weight the objective: add a secondary term to penalize undesirable foods alongside cost minimization.
- Add a second scenario axis (for example, budget caps) as another
Scenario-style concept.
Scale up / productionize
- Pin
relationalaiand schedule the run as a pipeline step for reproducible, deterministic re-runs. - Size the prescriptive engine up if the food and nutrient counts grow the linear program substantially.
Troubleshooting
Problem is infeasible
The nutritional bounds may be too tight for the available foods. Check that at least one combination of foods can satisfy all min/max constraints simultaneously. Try relaxing the scaling factor to a lower value (e.g., 0.5).
rai init fails or connection errors
Ensure your Snowflake credentials are configured correctly and that the RAI Native App is installed on your account. Run rai init again and verify the connection settings.
ModuleNotFoundError for relationalai
Make sure you activated the virtual environment and ran python -m pip install . from the template directory. The pyproject.toml declares the required dependencies.
Unexpected zero values in solution
Foods with zero in the solution are not cost-effective given the constraints. This is expected behavior. If you want to force inclusion of specific foods, add a minimum bound on their decision variables.
Learn more
Core concepts
- PyRel v1 query language —
model.where(...)/model.select(...)/.per(...)and result extraction. - Concepts and properties — modeling entities like
FoodandNutrientwith typed properties.
Reasoner reference
- Prescriptive reasoner —
ProblemAPI, decision variables, constraints, and objectives. - Scenario modeling — parameterizing one solve across cases with a
Scenarioconcept.
CLI / SDK guides
- RelationalAI setup —
rai init, profiles, andraiconfig.yaml.
Support
- File issues at the RelationalAI templates repository.