## Problem Description and Symbolic Representation

The problem involves maximizing profit by determining the number of batches of donuts and cookies to produce given the time constraints of Jake and Jill.

### Symbolic Variables:
- $x_1$ = batches of donuts
- $x_2$ = batches of cookies

### Objective Function:
The profit per batch of donuts is $20, and the profit per batch of cookies is $15. The objective is to maximize the total profit:
\[ \text{Maximize:} \quad 20x_1 + 15x_2 \]

### Constraints:
1. Jake's time constraint: $20x_1 + 5x_2 \leq 200$
2. Jill's time constraint: $10x_1 + 25x_2 \leq 300$
3. Non-negativity constraints: $x_1 \geq 0, x_2 \geq 0$

## Symbolic Representation in JSON Format

```json
{
  'sym_variables': [('x1', 'batches of donuts'), ('x2', 'batches of cookies')],
  'objective_function': '20*x1 + 15*x2',
  'constraints': [
    '20*x1 + 5*x2 <= 200',
    '10*x1 + 25*x2 <= 300',
    'x1 >= 0',
    'x2 >= 0'
  ]
}
```

## Gurobi Code in Python

```python
import gurobipy as gp

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

# Define variables
x1 = model.addVar(name="donuts", lb=0, vtype=gp.GRB.INTEGER)  # batches of donuts
x2 = model.addVar(name="cookies", lb=0, vtype=gp.GRB.INTEGER)  # batches of cookies

# Objective function: maximize profit
model.setObjective(20*x1 + 15*x2, gp.GRB.MAXIMIZE)

# Jake's time constraint
model.addConstr(20*x1 + 5*x2 <= 200, name="Jake_time")

# Jill's time constraint
model.addConstr(10*x1 + 25*x2 <= 300, name="Jill_time")

# Solve the model
model.optimize()

# Print the solution
if model.status == gp.GRB.OPTIMAL:
    print(f"Optimal batches of donuts: {x1.varValue}")
    print(f"Optimal batches of cookies: {x2.varValue}")
    print(f"Maximum profit: ${model.objVal:.2f}")
else:
    print("The model is infeasible.")
```