Hide navigation sidebar
Hide table of contents sidebar
Back to top
Toggle table of contents sidebar

# diet.py

    #!/usr/bin/env python3

    # Copyright 2025, Gurobi Optimization, LLC

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

    import gurobipy as gp
    from gurobipy import GRB

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

    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,
    }

    # Model
    m = gp.Model("diet")

    # Create decision variables for the foods to buy
    buy = m.addVars(foods, name="buy")

    # You could use Python looping constructs and m.addVar() to create
    # these decision variables instead.  The following would be equivalent
    #
    # buy = {}
    # for f in foods:
    #   buy[f] = m.addVar(name=f)

    # The objective is to minimize the costs
    m.setObjective(buy.prod(cost), GRB.MINIMIZE)

    # Using looping constructs, the preceding statement would be:
    #
    # m.setObjective(sum(buy[f]*cost[f] for f in foods), GRB.MINIMIZE)

    # Nutrition constraints
    m.addConstrs(
        (
            gp.quicksum(nutritionValues[f, c] * buy[f] for f in foods)
            == [minNutrition[c], maxNutrition[c]]
            for c in categories
        ),
        "_",
    )

    # Using looping constructs, the preceding statement would be:
    #
    # for c in categories:
    #  m.addRange(sum(nutritionValues[f, c] * buy[f] for f in foods),
    #             minNutrition[c], maxNutrition[c], c)

    def printSolution():
        if m.status == GRB.OPTIMAL:
            print(f"\nCost: {m.ObjVal:g}")
            print("\nBuy:")
            for f in foods:
                if buy[f].X > 0.0001:
                    print(f"{f} {buy[f].X:g}")
        else:
            print("No solution")

    # Solve
    m.optimize()
    printSolution()

    print("\nAdding constraint: at most 6 servings of dairy")
    m.addConstr(buy.sum(["milk", "ice cream"]) <= 6, "limit_dairy")

    # Solve
    m.optimize()
    printSolution()

Help and Feedback

Press `/` or click to search this documentation | Gurobi website | Gurobi community forum
Go to other Gurobi documentation | Gurobi download | Contact support