Diet Examples#

This section includes source code for all of the Gurobi diet examples. The same source code can be found in the examples directory of the Gurobi distribution.

diet#

/* Copyright 2024, Gurobi Optimization, LLC */

/* Solve the classic diet model, showing how to add constraints
   to an existing model. */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "gurobi_c.h"

int printSolution(GRBmodel* model, int nCategories, int nFoods);


int
main(int   argc,
     char *argv[])
{
  GRBenv   *env   = NULL;
  GRBmodel *model = NULL;
  int       error = 0;
  int       i, j;
  int      *cbeg, *cind, idx;
  double   *cval, *rhs;
  char     *sense;

  /* Nutrition guidelines, based on
     USDA Dietary Guidelines for Americans, 2005
     http://www.health.gov/DietaryGuidelines/dga2005/ */

  const int nCategories = 4;
  char *Categories[] =
    { "calories", "protein", "fat", "sodium" };
  double minNutrition[] = { 1800, 91, 0, 0 };
  double maxNutrition[] = { 2200, GRB_INFINITY, 65, 1779 };

  /* Set of foods */
  const int nFoods = 9;
  char* Foods[] =
    { "hamburger", "chicken", "hot dog", "fries",
      "macaroni", "pizza", "salad", "milk", "ice cream" };
  double cost[] =
    { 2.49, 2.89, 1.50, 1.89, 2.09, 1.99, 2.49, 0.89, 1.59 };

  /* Nutrition values for the foods */
  double nutritionValues[][4] = {
                                  { 410, 24, 26, 730 },
                                  { 420, 32, 10, 1190 },
                                  { 560, 20, 32, 1800 },
                                  { 380, 4, 19, 270 },
                                  { 320, 12, 10, 930 },
                                  { 320, 15, 12, 820 },
                                  { 320, 31, 12, 1230 },
                                  { 100, 8, 2.5, 125 },
                                  { 330, 8, 10, 180 }
                                };

  /* Create environment */
  error = GRBloadenv(&env, "diet.log");
  if (error) goto QUIT;

  /* Create initial model */
  error = GRBnewmodel(env, &model, "diet", nFoods + nCategories,
                      NULL, NULL, NULL, NULL, NULL);
  if (error) goto QUIT;

  /* Initialize decision variables for the foods to buy */
  for (j = 0; j < nFoods; ++j)
  {
    error = GRBsetdblattrelement(model, "Obj", j, cost[j]);
    if (error) goto QUIT;
    error = GRBsetstrattrelement(model, "VarName", j, Foods[j]);
    if (error) goto QUIT;
  }

  /* Initialize decision variables for the nutrition information,
     which we limit via bounds */
  for (j = 0; j < nCategories; ++j)
  {
    error = GRBsetdblattrelement(model, "LB", j + nFoods, minNutrition[j]);
    if (error) goto QUIT;
    error = GRBsetdblattrelement(model, "UB", j + nFoods, maxNutrition[j]);
    if (error) goto QUIT;
    error = GRBsetstrattrelement(model, "VarName", j + nFoods, Categories[j]);
    if (error) goto QUIT;
  }

  /* The objective is to minimize the costs */
  error = GRBsetintattr(model, "ModelSense", GRB_MINIMIZE);
  if (error) goto QUIT;

  /* Nutrition constraints */
  cbeg = malloc(sizeof(int) * nCategories);
  if (!cbeg) goto QUIT;
  cind = malloc(sizeof(int) * nCategories * (nFoods + 1));
  if (!cind) goto QUIT;
  cval = malloc(sizeof(double) * nCategories * (nFoods + 1));
  if (!cval) goto QUIT;
  rhs = malloc(sizeof(double) * nCategories);
  if (!rhs) goto QUIT;
  sense = malloc(sizeof(char) * nCategories);
  if (!sense) goto QUIT;
  idx = 0;
  for (i = 0; i < nCategories; ++i)
  {
    cbeg[i] = idx;
    rhs[i] = 0.0;
    sense[i] = GRB_EQUAL;
    for (j = 0; j < nFoods; ++j)
    {
      cind[idx] = j;
      cval[idx++] = nutritionValues[j][i];
    }
    cind[idx] = nFoods + i;
    cval[idx++] = -1.0;
  }

  error = GRBaddconstrs(model, nCategories, idx, cbeg, cind, cval, sense,
                        rhs, Categories);
  if (error) goto QUIT;

  /* Solve */
  error = GRBoptimize(model);
  if (error) goto QUIT;
  error = printSolution(model, nCategories, nFoods);
  if (error) goto QUIT;

  printf("\nAdding constraint: at most 6 servings of dairy\n");
  cind[0] = 7;
  cval[0] = 1.0;
  cind[1] = 8;
  cval[1] = 1.0;
  error = GRBaddconstr(model, 2, cind, cval, GRB_LESS_EQUAL, 6.0,
                       "limit_dairy");
  if (error) goto QUIT;

  /* Solve */
  error = GRBoptimize(model);
  if (error) goto QUIT;
  error = printSolution(model, nCategories, nFoods);
  if (error) goto QUIT;



QUIT:

  /* Error reporting */

  if (error)
  {
    printf("ERROR: %s\n", GRBgeterrormsg(env));
    exit(1);
  }

  /* Free data */

  free(cbeg);
  free(cind);
  free(cval);
  free(rhs);
  free(sense);

  /* Free model */

  GRBfreemodel(model);

  /* Free environment */

  GRBfreeenv(env);

  return 0;
}

int printSolution(GRBmodel* model, int nCategories, int nFoods)
{
  int error, status, i, j;
  double obj, x;
  char* vname;

  error = GRBgetintattr(model, "Status", &status);
  if (error) return error;
  if (status == GRB_OPTIMAL)
  {
    error = GRBgetdblattr(model, "ObjVal", &obj);
    if (error) return error;
    printf("\nCost: %f\n\nBuy:\n", obj);
    for (j = 0; j < nFoods; ++j)
    {
      error = GRBgetdblattrelement(model, "X", j, &x);
      if (error) return error;
      if (x > 0.0001)
      {
        error = GRBgetstrattrelement(model, "VarName", j, &vname);
        if (error) return error;
        printf("%s %f\n", vname, x);
      }
    }
    printf("\nNutrition:\n");
    for (i = 0; i < nCategories; ++i)
    {
      error = GRBgetdblattrelement(model, "X", i + nFoods, &x);
      if (error) return error;
      error = GRBgetstrattrelement(model, "VarName", i + nFoods, &vname);
      if (error) return error;
      printf("%s %f\n", vname, x);
    }
  }
  else
  {
    printf("No solution\n");
  }

  return 0;
}

diet2#

#!/usr/bin/env python3.11

# Copyright 2024, Gurobi Optimization, LLC

# Separate the model (dietmodel.py) from the data file (diet2.py), so
# that the model can be solved with different data files.
#
# Nutrition guidelines, based on
# USDA Dietary Guidelines for Americans, 2005
# http://www.health.gov/DietaryGuidelines/dga2005/

import dietmodel
import gurobipy as gp
from gurobipy import GRB


categories, minNutrition, maxNutrition = gp.multidict(
    {
        "calories": [1800, 2200],
        "protein": [91, GRB.INFINITY],
        "fat": [0, 65],
        "sodium": [0, 1779],
    }
)

foods, cost = gp.multidict(
    {
        "hamburger": 2.49,
        "chicken": 2.89,
        "hot dog": 1.50,
        "fries": 1.89,
        "macaroni": 2.09,
        "pizza": 1.99,
        "salad": 2.49,
        "milk": 0.89,
        "ice cream": 1.59,
    }
)

# Nutrition values for the foods
nutritionValues = {
    ("hamburger", "calories"): 410,
    ("hamburger", "protein"): 24,
    ("hamburger", "fat"): 26,
    ("hamburger", "sodium"): 730,
    ("chicken", "calories"): 420,
    ("chicken", "protein"): 32,
    ("chicken", "fat"): 10,
    ("chicken", "sodium"): 1190,
    ("hot dog", "calories"): 560,
    ("hot dog", "protein"): 20,
    ("hot dog", "fat"): 32,
    ("hot dog", "sodium"): 1800,
    ("fries", "calories"): 380,
    ("fries", "protein"): 4,
    ("fries", "fat"): 19,
    ("fries", "sodium"): 270,
    ("macaroni", "calories"): 320,
    ("macaroni", "protein"): 12,
    ("macaroni", "fat"): 10,
    ("macaroni", "sodium"): 930,
    ("pizza", "calories"): 320,
    ("pizza", "protein"): 15,
    ("pizza", "fat"): 12,
    ("pizza", "sodium"): 820,
    ("salad", "calories"): 320,
    ("salad", "protein"): 31,
    ("salad", "fat"): 12,
    ("salad", "sodium"): 1230,
    ("milk", "calories"): 100,
    ("milk", "protein"): 8,
    ("milk", "fat"): 2.5,
    ("milk", "sodium"): 125,
    ("ice cream", "calories"): 330,
    ("ice cream", "protein"): 8,
    ("ice cream", "fat"): 10,
    ("ice cream", "sodium"): 180,
}

dietmodel.solve(categories, minNutrition, maxNutrition, foods, cost, nutritionValues)

diet3#

#!/usr/bin/env python3.11

# Copyright 2024, Gurobi Optimization, LLC

# Use a SQLite database with the diet model (dietmodel.py).  The database
# (diet.db) can be recreated using the included SQL script (diet.sql).
#
# Note that this example reads an external data file (..\data\diet.db).
# As a result, it must be run from the Gurobi examples/python directory.

import os
import sqlite3
import dietmodel
import gurobipy as gp


con = sqlite3.connect(os.path.join("..", "data", "diet.db"))
cur = con.cursor()

cur.execute("select category,minnutrition,maxnutrition from categories")
result = cur.fetchall()
categories, minNutrition, maxNutrition = gp.multidict(
    (cat, [minv, maxv]) for cat, minv, maxv in result
)

cur.execute("select food,cost from foods")
result = cur.fetchall()
foods, cost = gp.multidict(result)

cur.execute("select food,category,value from nutrition")
result = cur.fetchall()
nutritionValues = dict(((f, c), v) for f, c, v in result)

con.close()

dietmodel.solve(categories, minNutrition, maxNutrition, foods, cost, nutritionValues)

diet4#

#!/usr/bin/env python3.11

# Copyright 2024, Gurobi Optimization, LLC

# Read diet model data from an Excel spreadsheet (diet.xlsx).
# Pass the imported data into the diet model (dietmodel.py).
#
# Note that this example reads an external data file (..\data\diet.xlsx).
# As a result, it must be run from the Gurobi examples/python directory.
#
# This example uses Python package 'openpyxl', which isn't included
# in most Python distributions.  You can install it with
# 'pip install openpyxl'.

import os
import openpyxl
import dietmodel

# Open 'diet.xlsx'
book = openpyxl.load_workbook(os.path.join("..", "data", "diet.xlsx"))

# Read min/max nutrition info from 'Categories' sheet
sheet = book["Categories"]
categories = []
minNutrition = {}
maxNutrition = {}
for row in sheet.iter_rows():
    category = row[0].value
    if category != "Categories":
        categories.append(category)
        minNutrition[category] = row[1].value
        maxNutrition[category] = row[2].value

# Read food costs from 'Foods' sheet
sheet = book["Foods"]
foods = []
cost = {}
for row in sheet.iter_rows():
    food = row[0].value
    if food != "Foods":
        foods.append(food)
        cost[food] = row[1].value

# Read food nutrition info from 'Nutrition' sheet
sheet = book["Nutrition"]
nutritionValues = {}
for row in sheet.iter_rows():
    if row[0].value == None:  # column labels - categories
        cats = [v.value for v in row]
    else:  # nutrition values
        food = row[0].value
        for col in range(1, len(row)):
            nutritionValues[food, cats[col]] = row[col].value


dietmodel.solve(categories, minNutrition, maxNutrition, foods, cost, nutritionValues)