## Problem Description and Formulation

The problem is an optimization problem with three variables: 'bowls of cereal', 'bowls of instant ramen', and 'tomatoes'. The objective is to minimize the function $3 \times \text{bowls of cereal} + 3 \times \text{bowls of instant ramen} + 7 \times \text{tomatoes}$.

The problem has several constraints based on the umami index and grams of protein for each variable. The constraints are as follows:

- Umami index constraints:
  - Total combined umami index from bowls of cereal and bowls of instant ramen $\geq 108$.
  - Total combined umami index from bowls of cereal and tomatoes $\geq 90$.
  - Total combined umami index from all three $\geq 90$.
  - Total combined umami index from bowls of cereal and bowls of instant ramen $\leq 448$ and $\leq 319$ specifically for this combination.
  - Total combined umami index from bowls of cereal and tomatoes $\leq 303$.

- Grams of protein constraints:
  - Total combined grams of protein from bowls of cereal and bowls of instant ramen $\geq 42$.
  - Total combined grams of protein from bowls of cereal and tomatoes $\geq 67$.
  - Total combined grams of protein from bowls of instant ramen and tomatoes $\geq 106$.
  - Total combined grams of protein from all three $\geq 63$.

- Other constraints:
  - $-2 \times \text{bowls of cereal} + 6 \times \text{tomatoes} \geq 0$.
  - $9 \times \text{bowls of cereal} - 2 \times \text{bowls of instant ramen} \geq 0$.

## Gurobi Code Formulation

```python
import gurobipy as gp

# Create a new model
m = gp.Model("optimization_problem")

# Define variables
bowls_of_cereal = m.addVar(name="bowls_of_cereal", lb=0)  # Non-integer allowed
bowls_of_instant_ramen = m.addVar(name="bowls_of_instant_ramen", lb=0)  # Float allowed
tomatoes = m.addVar(name="tomatoes", lb=0)  # Fractional allowed

# Objective function
m.setObjective(3 * bowls_of_cereal + 3 * bowls_of_instant_ramen + 7 * tomatoes, gp.GRB.MINIMIZE)

# Umami index constraints
m.addConstr(11 * bowls_of_cereal + 13 * bowls_of_instant_ramen >= 108)
m.addConstr(11 * bowls_of_cereal + 24 * tomatoes >= 90)
m.addConstr(11 * bowls_of_cereal + 13 * bowls_of_instant_ramen + 24 * tomatoes >= 90)
m.addConstr(11 * bowls_of_cereal + 13 * bowls_of_instant_ramen <= 319)
m.addConstr(11 * bowls_of_cereal + 24 * tomatoes <= 303)

# Grams of protein constraints
m.addConstr(18 * bowls_of_cereal + 5 * bowls_of_instant_ramen >= 42)
m.addConstr(18 * bowls_of_cereal + 8 * tomatoes >= 67)
m.addConstr(5 * bowls_of_instant_ramen + 8 * tomatoes >= 106)
m.addConstr(18 * bowls_of_cereal + 5 * bowls_of_instant_ramen + 8 * tomatoes >= 63)

# Other constraints
m.addConstr(-2 * bowls_of_cereal + 6 * tomatoes >= 0)
m.addConstr(9 * bowls_of_cereal - 2 * bowls_of_instant_ramen >= 0)

# Umami and protein upper bounds
m.addConstr(11 * bowls_of_cereal + 13 * bowls_of_instant_ramen <= 448)

# Solve the model
m.optimize()

# Print solution
if m.status == gp.GRB.OPTIMAL:
    print("Optimal Solution:")
    print(f"Bowls of cereal: {bowls_of_cereal.varValue}")
    print(f"Bowls of instant ramen: {bowls_of_instant_ramen.varValue}")
    print(f"Tomatoes: {tomatoes.varValue}")
    print(f"Objective: {m.objVal}")
else:
    print("No optimal solution found")
```