## Symbolic Representation

The problem can be converted into a symbolic representation as follows:

- **Variables:**
  - $x_1$ : Number of fish tacos
  - $x_2$ : Number of chicken tacos

## Objective Function and Constraints

- **Objective Function:** Maximize $6x_1 + 4x_2$
- **Constraints:**
  1. $x_1 \geq 20$ (At least 20 fish tacos)
  2. $x_2 \geq 40$ (At least 40 chicken tacos)
  3. $x_1 \leq 50$ (At most 50 fish tacos)
  4. $x_2 \leq 60$ (At most 60 chicken tacos)
  5. $x_1 + x_2 \leq 80$ (Total tacos cannot exceed 80)

## JSON Representation

```json
{
  'sym_variables': [('x1', 'fish tacos'), ('x2', 'chicken tacos')],
  'objective_function': '6*x1 + 4*x2',
  'constraints': [
    'x1 >= 20',
    'x2 >= 40',
    'x1 <= 50',
    'x2 <= 60',
    'x1 + x2 <= 80'
  ]
}
```

## Gurobi Code

```python
import gurobipy as gp

# Create a new model
m = gp.Model("Taco Stand Optimization")

# Define variables
x1 = m.addVar(name="fish_tacos", lb=0, ub=gp.GRB.INFINITY, vtype=gp.GRB.INTEGER)
x2 = m.addVar(name="chicken_tacos", lb=0, ub=gp.GRB.INFINITY, vtype=gp.GRB.INTEGER)

# Objective function: Maximize 6*x1 + 4*x2
m.setObjective(6*x1 + 4*x2, gp.GRB.MAXIMIZE)

# Constraints
m.addConstr(x1 >= 20, name="min_fish_tacos")
m.addConstr(x2 >= 40, name="min_chicken_tacos")
m.addConstr(x1 <= 50, name="max_fish_tacos")
m.addConstr(x2 <= 60, name="max_chicken_tacos")
m.addConstr(x1 + x2 <= 80, name="total_tacos")

# Update model
m.update()

# Solve model
m.optimize()

# Print solution
if m.status == gp.GRB.OPTIMAL:
  print(f"Optimal solution: Fish tacos = {x1.varValue}, Chicken tacos = {x2.varValue}")
else:
  print("No optimal solution found")
```