Mixed Integer Goal Programming for Personalized Meal Optimization with User-Defined Serving Granularity
Abstract
Determining what to eat to satisfy nutritional requirements is one of the oldest optimization problems in operations research, yet existing formulations have two persistent limitations: continuous variables produce impractical fractional servings (1.7 eggs, 0.37 bananas), and hard nutrient constraints cause infeasibility when targets conflict. A systematic review of 56 diet optimization papers found that none combine integer programming with goal programming to address both issues. We propose Mixed Integer Goal Programming (MIGP) for personalized meal optimization. The formulation uses integer variables for practical serving counts and goal programming deviations for soft nutrient targets, with inverse-target normalization to balance multi-nutrient optimization. Per-food serving granularity allows natural units (one egg, one tablespoon of oil) without post-hoc rounding. We characterize the integrality gap in the goal programming context and identify a deviation absorption property: GP deviation variables buffer the cost of requiring integer servings, making the gap structurally smaller than in hard-constraint MIP. For meals with 15+ foods, the integer solution matches the continuous optimum in every benchmark instance. A computational evaluation across 810 instances (30 USDA foods, 9 configurations, 3 methods) shows MIGP finds strictly better solutions than GP with post-hoc rounding in 66% of cases (never worse) while maintaining 100% feasibility; hard-constraint IP achieves only 48%. Solve times stay under 100 ms for typical meal sizes using the open-source HiGHS solver. The implementation is available as an open-source Python module integrated into an interactive meal planning application.
Figures & tables
| Approach | Variables | Constraints | Feasible | Servings | Optimal |
|---|---|---|---|---|---|
| Classical LP | Continuous | Hard | No | Fractional | Yes |
| GP (Gerdessen) | Continuous | Soft | Yes | Fractional | Yes |
| IP (Benvenuti) | Binary | Hard | No | Binary | Yes |
| AI/ML | — | Soft | Yes | Varies | No |
| MIGP (ours) | Integer | Soft | Yes | Integer | Yes |
| Symbol | Description |
|---|---|
| Sets | |
| Selected foods | |
| Macronutrients | |
| Parameters | |
| Nutrient per 100 g of food (kcal or grams) | |
| Serving size in grams for food | |
| Config | Foods | Serving range | Calories | Macro split |
|---|---|---|---|---|
| Small | 8 | Loose: | 600 | 30/45/25 |
| Medium | 15 | 800 | 30/45/25 | |
| Large | 25 | 1000 | 30/45/25 | |
| Small | 8 | Tight: | 600 | 35/40/25 |
| Medium | 15 | 800 | 35/40/25 | |
| Large | 25 | 1000 | 35/40/25 |
| Method | Feasibility | Median Obj. | Median Max Dev. | Macros 5% | Median Time |
|---|---|---|---|---|---|
| MIGP | 100% | 0.1410 | 6.3% | 75% | 19.9 |
| GP+Round | 100% | 0.5286 | 21.6% | 0% | 1.0 |
| Hard-IP | 48% | 0.0911 | 4.0% | 100% | 3.5 |
| Macro | % split | kcal/g | Calculation | Target |
|---|---|---|---|---|
| Calories | — | — | 600.0 kcal | |
| Protein | 30% | 4 | 45.0 g | |
| Carbs | 45% | 4 | 67.5 g | |
| Fat | 25% | 9 | 16.7 g |
| Per 100 g | Per serving | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Food | Srv (g) | Range | kcal | P | C | F | kcal | P | C | F |
| Chicken breast | 50 | [0, 10] | 165 | 31.0 | 0.0 | 3.6 | 82.5 | 15.5 | 0.0 | 1.8 |
| White rice | 50 | [0, 10] | 130 | 2.7 | 28.2 | 0.3 | 65.0 | 1.4 | 14.1 | 0.1 |
| Broccoli | 50 | [0, 8] | 35 | 2.4 | 7.2 | 0.4 | 17.5 | 1.2 | 3.6 | 0.2 |
| Avocado | 30 | [0, 6] | 160 | 2.0 | 8.5 | 14.7 | 48.0 | 0.6 | 2.5 | 4.4 |
| Olive oil | 15 | [0, 4] | 884 | 0.0 | 0.0 | 100.0 | 132.6 | 0.0 | 0.0 | 15.0 |
| Food (serving) | Qty | kcal | P (g) | C (g) | F (g) |
|---|---|---|---|---|---|
| Chicken breast (50 g) | 2 | 165.0 | 31.0 | 0.0 | 3.6 |
| White rice (50 g) | 3 | 195.0 | 4.0 | 42.3 | 0.5 |
| Broccoli (50 g) | 5 | 87.5 | 6.0 | 18.0 | 1.0 |
| Avocado (30 g) | 3 | 144.0 | 1.8 | 7.7 | 13.2 |
| Total | 591.5 | 42.9 | 68.0 | 18.3 | |
| Target | 600.0 | 45.0 | 67.5 | 16.7 |
| LP Continuous | GP+Round | MIGP | |
|---|---|---|---|
| Chicken breast | 2.33 | 2 | 2 |
| White rice | 3.88 | 4 | 3 |
| Broccoli | 1.71 | 2 | 5 |
| Avocado | 2.62 | 3 | 3 |
| kcal | 600.0 (+0.0%) | 604.0 (+0.7%) | 591.5 (-1.4%) |
| P (g) | 45.0 (+0.0%) | 40.6 (-9.8%) | 42.9 (-4.8%) |
| Method | Feasible | Obj. | Max dev. | Cal | Prot | Carbs | Fat |
|---|---|---|---|---|---|---|---|
| MIGP | Yes | 0.1654 | +9.7% | -1.4 | -4.8 | +0.7 | +9.7 |
| GP+Round | Yes | 0.2298 | 9.8% | 0.7 | 9.8 | 5.6 | 7.0 |
| Hard-IP | No | — | — | — | — | — | — |
| Macro | % split | kcal/g | Calculation | Target |
|---|---|---|---|---|
| Calories | — | — | 800.0 kcal | |
| Protein | 35% | 4 | 70.0 g | |
| Carbs | 40% | 4 | 80.0 g | |
| Fat | 25% | 9 | 22.2 g |
| Per 100 g | Per serving | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Food | Srv (g) | Range | kcal | P | C | F | kcal | P | C | F |
| Chicken breast | 50 | [0, 8] | 165 | 31.0 | 0.0 | 3.6 | 82.5 | 15.5 | 0.0 | 1.8 |
| Salmon fillet | 50 | [0, 8] | 208 | 20.4 | 0.0 | 13.4 | 104.0 | 10.2 | 0.0 | 6.7 |
| White rice | 50 | [0, 8] | 130 | 2.7 | 28.2 | 0.3 | 65.0 | 1.4 | 14.1 | 0.1 |
| Sweet potato | 50 | [0, 8] | 90 | 2.0 | 20.7 | 0.1 | 45.0 | 1.0 | 10.3 | 0.1 |
| Broccoli | 50 | [0, 8] | 35 | 2.4 | 7.2 | 0.4 | 17.5 | 1.2 | 3.6 | 0.2 |
| Food (serving) | Qty | kcal | P (g) | C (g) | F (g) |
|---|---|---|---|---|---|
| Chicken breast (50 g) | 4 | 330.0 | 62.0 | 0.0 | 7.2 |
| White rice (50 g) | 2 | 130.0 | 2.7 | 28.2 | 0.3 |
| Sweet potato (50 g) | 5 | 225.0 | 5.0 | 51.8 | 0.2 |
| Olive oil (15 g) | 1 | 132.6 | 0.0 | 0.0 | 15.0 |
| Total | 817.6 | 69.7 | 80.0 | 22.8 | |
| Target | 800.0 | 70.0 | 80.0 | 22.2 |
| LP Continuous | GP+Round | MIGP | |
|---|---|---|---|
| Chicken breast | 2.55 | 3 | 4 |
| White rice | 0.00 | 0 | 2 |
| Sweet potato | 6.26 | 6 | 5 |
| Broccoli | 3.76 | 4 | 0 |
| Olive oil | 0.00 | 0 | 1 |
| Whole eggs | 3.13 | 3 | 0 |
| Method | Feasible | Obj. | Max dev. | Cal | Prot | Carbs | Fat |
|---|---|---|---|---|---|---|---|
| MIGP | Yes | 0.0507 | +2.4% | +2.2 | -0.4 | -0.1 | +2.4 |
| GP+Round | Yes | 0.1447 | 8.9% | 2.5 | 8.9 | 2.3 | 0.8 |
| Hard-IP | Yes | 0.0899 | 4.1% | 4.1 | 0.4 | 1.1 | 3.5 |
| Macro | % split | kcal/g | Calculation | Target |
|---|---|---|---|---|
| Calories | — | — | 600.0 kcal | |
| Protein | 40% | 4 | 60.0 g | |
| Carbs | 35% | 4 | 52.5 g | |
| Fat | 25% | 9 | 16.7 g |
| Per 100 g | Per serving | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Food | Srv (g) | Range | kcal | P | C | F | kcal | P | C | F |
| Chicken breast | 50 | [1, 6] | 165 | 31.0 | 0.0 | 3.6 | 82.5 | 15.5 | 0.0 | 1.8 |
| Salmon fillet | 50 | [1, 6] | 208 | 20.4 | 0.0 | 13.4 | 104.0 | 10.2 | 0.0 | 6.7 |
| White rice | 50 | [1, 6] | 130 | 2.7 | 28.2 | 0.3 | 65.0 | 1.4 | 14.1 | 0.1 |
| Quinoa | 50 | [1, 6] | 120 | 4.4 | 21.3 | 1.9 | 60.0 | 2.2 | 10.7 | 0.9 |
| Avocado | 30 | [1, 6] | 160 | 2.0 | 8.5 | 14.7 | 48.0 | 0.6 | 2.5 | 4.4 |
| Food (serving) | Qty | kcal | P (g) | C (g) | F (g) |
|---|---|---|---|---|---|
| Chicken breast (50 g) | 2 | 165.0 | 31.0 | 0.0 | 3.6 |
| Salmon fillet (50 g) | 1 | 104.0 | 10.2 | 0.0 | 6.7 |
| White rice (50 g) | 2 | 130.0 | 2.7 | 28.2 | 0.3 |
| Quinoa (50 g) | 1 | 60.0 | 2.2 | 10.7 | 0.9 |
| Avocado (30 g) | 1 | 48.0 | 0.6 | 2.5 | 4.4 |
| Olive oil (15 g) | 1 | 132.6 | 0.0 | 0.0 | 15.0 |
| LP Continuous | GP+Round | MIGP | |
|---|---|---|---|
| Chicken breast | 2.06 | 2 | 2 |
| Salmon fillet | 1.00 | 1 | 1 |
| White rice | 1.22 | 1 | 2 |
| Quinoa | 1.00 | 1 | 1 |
| Avocado | 1.00 | 1 | 1 |
| Olive oil | 1.00 | 1 | 1 |
| Method | Feasible | Obj. | Max dev. | Cal | Prot | Carbs | Fat |
|---|---|---|---|---|---|---|---|
| MIGP | Yes | 1.5557 | +121.2% | +28.3 | -5.7 | +0.5 | +121.2 |
| GP+Round | Yes | 1.5777 | 123.9% | 26.2 | 1.9 | 5.8 | 123.9 |
| Hard-IP | No | — | — | — | — | — | — |
| Macro | % split | kcal/g | Calculation | Target |
|---|---|---|---|---|
| Calories | — | — | 1000.0 kcal | |
| Protein | 10% | 4 | 25.0 g | |
| Carbs | 75% | 4 | 187.5 g | |
| Fat | 15% | 9 | 16.7 g |
| Per 100 g | Per serving | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Food | Srv (g) | Range | kcal | P | C | F | kcal | P | C | F |
| Oats | 40 | [0, 8] | 389 | 16.9 | 66.3 | 6.9 | 155.6 | 6.8 | 26.5 | 2.8 |
| Honey | 15 | [0, 10] | 304 | 0.3 | 82.4 | 0.0 | 45.6 | 0.0 | 12.4 | 0.0 |
| Banana | 120 | [0, 3] | 89 | 1.1 | 22.8 | 0.3 | 106.8 | 1.3 | 27.4 | 0.4 |
| Dates | 30 | [0, 8] | 282 | 2.5 | 75.0 | 0.4 | 84.6 | 0.8 | 22.5 | 0.1 |
| Peanut butter | 32 | [0, 4] | 588 | 25.1 | 19.6 | 50.4 | 188.2 | 8.0 | 6.3 | 16.1 |
| Food (serving) | Qty | kcal | P (g) | C (g) | F (g) |
|---|---|---|---|---|---|
| Oats (40 g) | 3 | 466.8 | 20.3 | 79.6 | 8.3 |
| Honey (15 g) | 1 | 45.6 | 0.0 | 12.4 | 0.0 |
| Banana (120 g) | 3 | 320.4 | 4.0 | 82.1 | 1.1 |
| Dark chocolate chips (20 g) | 1 | 109.2 | 1.1 | 12.1 | 6.3 |
| Total | 942.0 | 25.4 | 186.1 | 15.6 | |
| Target | 1000.0 | 25.0 | 187.5 | 16.7 |
| LP Continuous | GP+Round | MIGP | |
|---|---|---|---|
| Oats | 3.47 | 3 | 3 |
| Honey | 6.62 | 7 | 1 |
| Banana | 0.00 | 0 | 3 |
| Dark chocolate chips | 1.13 | 1 | 1 |
| kcal | 965.3 (-3.5%) | 895.2 (-10.5%) | 942.0 (-5.8%) |
| P (g) | 25.0 (+0.0%) | 21.7 (-13.2%) | 25.4 (+1.6%) |
| Method | Feasible | Obj. | Max dev. | Cal | Prot | Carbs | Fat |
|---|---|---|---|---|---|---|---|
| MIGP | Yes | 0.1437 | -6.3% | -5.8 | +1.5 | -0.7 | -6.3 |
| GP+Round | Yes | 0.4143 | 13.2% | 10.5 | 13.2 | 5.0 | 12.8 |
| Hard-IP | No | — | — | — | — | — | — |
| Macro | % split | kcal/g | Calculation | Target |
|---|---|---|---|---|
| Calories | — | — | 600.0 kcal | |
| Protein | 45% | 4 | 67.5 g | |
| Carbs | 30% | 4 | 45.0 g | |
| Fat | 25% | 9 | 16.7 g |
| Per 100 g | Per serving | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Food | Srv (g) | Range | kcal | P | C | F | kcal | P | C | F |
| Whey protein powder | 30 | [1, 2] | 400 | 80.0 | 10.0 | 3.3 | 120.0 | 24.0 | 3.0 | 1.0 |
| Tuna (canned) | 80 | [0, 3] | 116 | 25.5 | 0.0 | 0.8 | 92.8 | 20.4 | 0.0 | 0.6 |
| Greek yogurt | 150 | [0, 2] | 59 | 10.2 | 3.6 | 0.7 | 88.5 | 15.3 | 5.4 | 1.1 |
| White rice | 50 | [0, 6] | 130 | 2.7 | 28.2 | 0.3 | 65.0 | 1.4 | 14.1 | 0.1 |
| Banana | 120 | [0, 2] | 89 | 1.1 | 22.8 | 0.3 | 106.8 | 1.3 | 27.4 | 0.4 |
| Food (serving) | Qty | kcal | P (g) | C (g) | F (g) |
|---|---|---|---|---|---|
| Whey protein powder (30 g) | 1 | 120.0 | 24.0 | 3.0 | 1.0 |
| Tuna (canned) (80 g) | 2 | 185.6 | 40.8 | 0.0 | 1.3 |
| White rice (50 g) | 1 | 65.0 | 1.4 | 14.1 | 0.1 |
| Banana (120 g) | 1 | 106.8 | 1.3 | 27.4 | 0.4 |
| Olive oil (5 g) | 3 | 132.6 | 0.0 | 0.0 | 15.0 |
| Total | 610.0 | 67.5 | 44.5 | 17.8 |
| LP Continuous | GP+Round | MIGP | |
|---|---|---|---|
| Whey protein powder | 2.00 | 2 | 1 |
| Tuna (canned) | 0.83 | 1 | 2 |
| White rice | 0.97 | 1 | 1 |
| Banana | 0.92 | 1 | 1 |
| Olive oil | 2.74 | 3 | 3 |
| kcal | 600.0 (+0.0%) | 637.2 (+6.2%) | 610.0 (+1.7%) |
| Method | Feasible | Obj. | Max dev. | Cal | Prot | Carbs | Fat |
|---|---|---|---|---|---|---|---|
| MIGP | Yes | 0.0959 | +6.7% | +1.7 | -0.0 | -1.2 | +6.7 |
| GP+Round | Yes | 0.2574 | 8.8% | 6.2 | 5.3 | 5.5 | 8.8 |
| Hard-IP | No | — | — | — | — | — | — |
| Serving size | Median obj. | Max dev. % | Within 5% | Median time |
|---|---|---|---|---|
| 25 g | 0.001 | 0.1% | 100% | 2651 ms |
| 50 g | 0.008 | 0.3% | 100% | 131 ms |
| 100 g | 0.039 | 1.9% | 100% | 50 ms |
| 200 g | 0.108 | 6.2% | 75% | 30 ms |
Mixed-Integer Linear Programming
Mixed-integer linear programming (MILP) optimizes linear objectives and constraints when some decisions must be integer-valued.
See all 50 papers