To solve the given problem, we first need to translate the natural language description into a symbolic representation. This involves defining variables for the quantities of tuna salad sandwiches and chicken salad sandwiches the boy should eat, formulating the objective function that represents the total cost, and listing the constraints that ensure he meets his daily protein and fat requirements.

Let's define:
- $x_1$ as the number of tuna salad sandwiches
- $x_2$ as the number of chicken salad sandwiches

The objective function is to minimize the total cost, which can be represented as:
\[5x_1 + 7x_2\]

The constraints are:
1. Protein requirement: $20x_1 + 25x_2 \geq 100$
2. Fat requirement: $25x_1 + 15x_2 \geq 150$
3. Non-negativity constraints: $x_1 \geq 0, x_2 \geq 0$ (since the boy cannot eat a negative number of sandwiches)

Now, let's represent this problem in the required symbolic notation format:

```json
{
    'sym_variables': [('x1', 'tuna salad sandwiches'), ('x2', 'chicken salad sandwiches')],
    'objective_function': '5*x1 + 7*x2',
    'constraints': ['20*x1 + 25*x2 >= 100', '25*x1 + 15*x2 >= 150', 'x1 >= 0', 'x2 >= 0']
}
```

To solve this problem using Gurobi in Python, we'll write the following code:

```python
from gurobipy import *

# Create a new model
m = Model("Weight_Gain_Problem")

# Define variables
x1 = m.addVar(name="tuna_salad_sandwiches", vtype=GRB.CONTINUOUS, lb=0)
x2 = m.addVar(name="chicken_salad_sandwiches", vtype=GRB.CONTINUOUS, lb=0)

# Set the objective function
m.setObjective(5*x1 + 7*x2, GRB.MINIMIZE)

# Add constraints
m.addConstr(20*x1 + 25*x2 >= 100, name="protein_requirement")
m.addConstr(25*x1 + 15*x2 >= 150, name="fat_requirement")

# Optimize the model
m.optimize()

# Print the results
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Number of tuna salad sandwiches: {x1.x}")
    print(f"Number of chicken salad sandwiches: {x2.x}")
    print(f"Total cost: {m.objVal}")
else:
    print("No optimal solution found")
```