## Step 1: Define the symbolic variables and the optimization problem

Let's define the symbolic variables:
- $x_1$ represents the investment in company M
- $x_2$ represents the investment in company P

The objective is to maximize earnings, which can be represented as $0.09x_1 + 0.12x_2$.

## Step 2: Translate the natural language description into semi-algebraic constraints

The constraints based on the problem description are:
1. The total investment is at most $100,000: $x_1 + x_2 \leq 100,000$
2. The investment in company M is at least three times the investment in company P: $x_1 \geq 3x_2$
3. The investment in company M is at most $80,000: $x_1 \leq 80,000$
4. Non-negativity constraints: $x_1 \geq 0, x_2 \geq 0$

## 3: Symbolic representation of the problem

```json
{
'sym_variables': [('x1', 'investment in company M'), ('x2', 'investment in company P')],
'objective_function': '0.09*x1 + 0.12*x2',
'constraints': [
    'x1 + x2 <= 100000',
    'x1 >= 3*x2',
    'x1 <= 80000',
    'x1 >= 0',
    'x2 >= 0'
]
}
```

## 4: Convert the problem into Gurobi code

```python
import gurobi

def solve_vaccine_investment_problem():
    # Create a new model
    model = gurobi.Model()

    # Define the variables
    x1 = model.addVar(name="investment_in_M", lb=0)
    x2 = model.addVar(name="investment_in_P", lb=0)

    # Objective function: maximize 0.09*x1 + 0.12*x2
    model.setObjective(0.09*x1 + 0.12*x2, gurobi.GRB.MAXIMIZE)

    # Constraints
    model.addConstr(x1 + x2 <= 100000, name="total_investment")
    model.addConstr(x1 >= 3*x2, name="M_to_P_ratio")
    model.addConstr(x1 <= 80000, name="max_investment_in_M")

    # Solve the model
    model.optimize()

    # Print the solution
    if model.status == gurobi.GRB.OPTIMAL:
        print(f"Optimal investment in M: {x1.varValue}")
        print(f"Optimal investment in P: {x2.varValue}")
        print(f"Max earnings: {0.09*x1.varValue + 0.12*x2.varValue}")
    else:
        print("The model is infeasible")

solve_vaccine_investment_problem()
```