## Step 1: Define the symbolic variables
Let's define the symbolic variables as follows:
- $x_1$ represents the number of ads placed in airports
- $x_2$ represents the number of ads placed in malls
- $x_3$ represents the number of ads placed in movie theatres

## Step 2: Convert the natural language description into a symbolic representation
The objective is to maximize viewership. The viewership from each location is given as:
- Airports: $100000x_1$
- Malls: $40000x_2$
- Movie theatres: $10000x_3$

So, the objective function to maximize is: $100000x_1 + 40000x_2 + 10000x_3$

## 3: Define the constraints
1. The airport authority limits the number of ads from a single company to 5: $x_1 \leq 5$
2. At most half the number of ads should be at movie theatres: $x_3 \leq \frac{1}{2}(x_1 + x_2 + x_3)$ or $2x_3 \leq x_1 + x_2 + x_3$ which simplifies to $x_3 \leq x_1 + x_2$
3. At least 30% of ads should be at malls: $x_2 \geq 0.3(x_1 + x_2 + x_3)$
4. The company has a budget of $100000:
- Airports: $10000x_1$
- Malls: $3000x_2$
- Movie theatres: $2000x_3$
So, the budget constraint is: $10000x_1 + 3000x_2 + 2000x_3 \leq 100000$

## 4: Symbolic Representation
```json
{
'sym_variables': [('x1', 'ads in airports'), ('x2', 'ads in malls'), ('x3', 'ads in movie theatres')],
'objective_function': '100000*x1 + 40000*x2 + 10000*x3',
'constraints': [
'x1 <= 5',
'x3 <= x1 + x2',
'x2 >= 0.3*(x1 + x2 + x3)',
'10000*x1 + 3000*x2 + 2000*x3 <= 100000',
'x1 >= 0', 'x2 >= 0', 'x3 >= 0'
]
}
```

## 5: Gurobi Code
```python
import gurobi

def solve_ads_optimization():
    model = gurobi.Model()

    # Define variables
    x1 = model.addVar(lb=0, name="x1")  # ads in airports
    x2 = model.addVar(lb=0, name="x2")  # ads in malls
    x3 = model.addVar(lb=0, name="x3")  # ads in movie theatres

    # Objective function: maximize viewership
    model.setObjective(100000*x1 + 40000*x2 + 10000*x3, gurobi.GRB.MAXIMIZE)

    # Constraints
    model.addConstr(x1 <= 5, name="airport_limit")
    model.addConstr(x3 <= x1 + x2, name="movie_theatre_limit")
    model.addConstr(x2 >= 0.3*(x1 + x2 + x3), name="mall_percentage")
    model.addConstr(10000*x1 + 3000*x2 + 2000*x3 <= 100000, name="budget")

    # Solve the model
    model.optimize()

    if model.status == gurobi.GRB.OPTIMAL:
        print("Optimal Solution:")
        print(f"Ads in airports: {x1.varValue}")
        print(f"Ads in malls: {x2.varValue}")
        print(f"Ads in movie theatres: {x3.varValue}")
        print(f"Max viewership: {model.objVal}")
    else:
        print("The model is infeasible")

solve_ads_optimization()
```