## 4. Mathematical Optimization Formulation

#### Decision Variables
- \( x_i \): Binary variable indicating whether game \( i \) is scheduled (1 if scheduled, 0 otherwise).
- \( y_j \): Integer variable representing the number of home games scheduled at stadium \( j \).

#### Objective Function
Maximize total attendance while minimizing injury risk:
\[ \text{Maximize } \sum_{j} \text{Average_Attendance}_j \times y_j - \sum_{i} \text{Risk}_i \times x_i \]

Data Source Verification:
- \(\text{Average_Attendance}_j\) from `stadium.Average_Attendance`
- \(\text{Risk}_i\) from `injury_risk.Risk`

#### Constraints
1. Total number of home games scheduled across all stadiums must not exceed the league's predefined limit:
   \[ \sum_{j} y_j \leq \text{Total_Home_Games_Limit} \]

2. Cumulative injury risk associated with the scheduled games must remain within the maximum allowable limit:
   \[ \sum_{i} \text{Risk}_i \times x_i \leq \text{Max_Allowable_Injury_Risk} \]

3. Number of home games scheduled at each stadium must not exceed the stadium's capacity:
   \[ y_j \leq \text{Capacity_Percentage}_j \times \text{Total_Home_Games_Limit} \]

4. Each game can only be scheduled once:
   \[ x_i \in \{0, 1\} \]

5. Number of home games scheduled at each stadium must be non-negative and integer:
   \[ y_j \geq 0, \quad y_j \in \mathbb{Z}^+ \]

Data Source Verification:
- \(\text{Capacity_Percentage}_j\) from `stadium.Capacity_Percentage`
- \(\text{Total_Home_Games_Limit}\) and \(\text{Max_Allowable_Injury_Risk}\) are parameters from business configuration.

This formulation ensures that the optimization problem is both meaningful and solvable by balancing attendance and injury risk while adhering to the constraints set by the league's operational parameters.

## 5. Gurobipy Implementation

```python
# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_game_injury():
    """Optimize game scheduling to maximize attendance and minimize injury risk."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("game_injury")
    
    # Data from the database
    average_attendance = [8000, 12000, 15000]
    capacity_percentage = [0.85, 0.9, 0.95]
    home_games = [6, 8, 6]
    injury_risk = [0.02, 0.03, 0.04, 0.01, 0.05]
    scheduled = [True, False, True, False, True]
    
    # Parameters
    total_home_games_limit = 20
    max_allowable_injury_risk = 0.1
    
    # Validate array lengths
    n_stadiums = len(average_attendance)
    n_games = len(injury_risk)
    assert len(capacity_percentage) == n_stadiums, "Array length mismatch for stadiums"
    assert len(home_games) == n_stadiums, "Array length mismatch for home games"
    assert len(scheduled) == n_games, "Array length mismatch for games"
    
    # 2. VARIABLES
    x = {i: model.addVar(vtype=GRB.BINARY, name=f"x_{i}") for i in range(n_games)}
    y = {j: model.addVar(vtype=GRB.INTEGER, name=f"y_{j}", lb=0) for j in range(n_stadiums)}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(
        gp.quicksum(average_attendance[j] * y[j] for j in range(n_stadiums)) -
        gp.quicksum(injury_risk[i] * x[i] for i in range(n_games)),
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    # Total number of home games scheduled across all stadiums
    model.addConstr(gp.quicksum(y[j] for j in range(n_stadiums)) <= total_home_games_limit, name="total_home_games_limit")
    
    # Cumulative injury risk
    model.addConstr(gp.quicksum(injury_risk[i] * x[i] for i in range(n_games)) <= max_allowable_injury_risk, name="max_injury_risk")
    
    # Stadium capacity constraints
    for j in range(n_stadiums):
        model.addConstr(y[j] <= capacity_percentage[j] * total_home_games_limit, name=f"capacity_{j}")
    
    # Each game can only be scheduled once
    for i in range(n_games):
        model.addConstr(x[i] <= 1, name=f"schedule_once_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for j in range(n_stadiums):
            if y[j].x > 1e-6:
                print(f"Home games at stadium {j}: {y[j].x:.0f}")
        for i in range(n_games):
            if x[i].x > 1e-6:
                print(f"Game {i} scheduled: {x[i].x:.0f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_game_injury()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 297000.0
**Execution Time**: 0.50 seconds
**Reliability**: high
**Analysis**: Gurobipy found an optimal solution quickly with a very short execution time, indicating efficient performance and reliability.

## 6. DOCplex Implementation

```python
# Complete DOCPLEX implementation

from docplex.mp.model import Model

def game_injury_optimization():
    """Optimize game scheduling to maximize attendance and minimize injury risk."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="game_injury")
    
    # Data from the problem context
    average_attendance = [8000, 12000, 15000]
    capacity_percentage = [0.85, 0.9, 0.95]
    home_games = [6, 8, 6]
    injury_risks = [0.02, 0.03, 0.04, 0.01, 0.05]
    total_home_games_limit = 20
    max_allowable_injury_risk = 0.1
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(average_attendance) == len(capacity_percentage) == len(home_games), "Array length mismatch"
    safe_range_stadiums = range(len(average_attendance))
    safe_range_games = range(len(injury_risks))
    
    # 2. VARIABLES
    x = {i: mdl.binary_var(name=f"x_{i}") for i in safe_range_games}
    y = {j: mdl.integer_var(name=f"y_{j}", lb=0) for j in safe_range_stadiums}
    
    # 3. OBJECTIVE FUNCTION
    objective = mdl.sum(average_attendance[j] * y[j] for j in safe_range_stadiums) - mdl.sum(injury_risks[i] * x[i] for i in safe_range_games)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    # Total number of home games constraint
    mdl.add_constraint(mdl.sum(y[j] for j in safe_range_stadiums) <= total_home_games_limit, ctname="total_home_games_limit")
    
    # Cumulative injury risk constraint
    mdl.add_constraint(mdl.sum(injury_risks[i] * x[i] for i in safe_range_games) <= max_allowable_injury_risk, ctname="max_injury_risk")
    
    # Stadium capacity constraints
    for j in safe_range_stadiums:
        mdl.add_constraint(y[j] <= capacity_percentage[j] * total_home_games_limit, ctname=f"capacity_{j}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for j in safe_range_stadiums:
            print(f"Home games at stadium {j}: {solution.get_value(y[j])}")
        for i in safe_range_games:
            print(f"Game {i} scheduled: {solution.get_value(x[i])}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
game_injury_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 297000.0
**Execution Time**: 5.81 seconds
**Reliability**: high
**Analysis**: DOCplex also found an optimal solution, but with a longer execution time compared to Gurobipy, suggesting it is reliable but less efficient.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

import pyomo.environ as pyo
from pyomo.opt import SolverFactory

def game_injury_optimization():
    """Optimization for scheduling games to maximize attendance and minimize injury risk."""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Assuming these are the given data from the database
    average_attendance = [8000, 12000, 15000]
    capacity_percentage = [0.85, 0.9, 0.95]
    home_games = [6, 8, 6]
    injury_risks = [0.02, 0.03, 0.04, 0.01, 0.05]
    total_home_games_limit = 20
    max_allowable_injury_risk = 0.1
    
    # Validate array lengths
    n_stadiums = len(average_attendance)
    n_games = len(injury_risks)
    assert len(capacity_percentage) == n_stadiums, "Array length mismatch for stadium data"
    assert len(home_games) == n_stadiums, "Array length mismatch for home games data"
    
    # 3. SETS
    model.J = pyo.RangeSet(1, n_stadiums)  # Stadiums
    model.I = pyo.RangeSet(1, n_games)     # Games
    
    # 4. PARAMETERS
    model.Average_Attendance = pyo.Param(model.J, initialize={j+1: average_attendance[j] for j in range(n_stadiums)})
    model.Capacity_Percentage = pyo.Param(model.J, initialize={j+1: capacity_percentage[j] for j in range(n_stadiums)})
    model.Risk = pyo.Param(model.I, initialize={i+1: injury_risks[i] for i in range(n_games)})
    
    # 5. VARIABLES
    model.x = pyo.Var(model.I, within=pyo.Binary)  # Game scheduling
    model.y = pyo.Var(model.J, within=pyo.NonNegativeIntegers)  # Home games at each stadium
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.Average_Attendance[j] * model.y[j] for j in model.J) - sum(model.Risk[i] * model.x[i] for i in model.I)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)
    
    # 7. CONSTRAINTS
    # Total number of home games constraint
    def total_home_games_rule(model):
        return sum(model.y[j] for j in model.J) <= total_home_games_limit
    model.total_home_games_constraint = pyo.Constraint(rule=total_home_games_rule)
    
    # Cumulative injury risk constraint
    def injury_risk_rule(model):
        return sum(model.Risk[i] * model.x[i] for i in model.I) <= max_allowable_injury_risk
    model.injury_risk_constraint = pyo.Constraint(rule=injury_risk_rule)
    
    # Stadium capacity constraint
    def capacity_rule(model, j):
        return model.y[j] <= model.Capacity_Percentage[j] * total_home_games_limit
    model.capacity_constraint = pyo.Constraint(model.J, rule=capacity_rule)
    
    # 8. SOLVING WITH GUROBI
    solver = SolverFactory('gurobi')
    
    # Optional: Set solver options
    solver.options['TimeLimit'] = 300  # 5 minutes
    solver.options['MIPGap'] = 0.01    # 1% gap
    
    # Solve the model
    results = solver.solve(model, tee=True)  # tee=True shows solver output
    
    # 9. RESULT PROCESSING
    # Check solver status
    if results.solver.termination_condition == pyo.TerminationCondition.optimal:
        print("Optimal solution found!")
        print(f"Optimal value: {pyo.value(model.objective)}")
        
        # Extract variable values
        print("\nVariable values:")
        for j in model.J:
            y_val = pyo.value(model.y[j])
            print(f"y[{j}] = {int(y_val)}")
        
        for i in model.I:
            x_val = pyo.value(model.x[i])
            if x_val > 1e-6:  # Only print non-zero values
                print(f"x[{i}] = {int(x_val)}")
        
    elif results.solver.termination_condition == pyo.TerminationCondition.infeasible:
        print("Problem is infeasible")
    elif results.solver.termination_condition == pyo.TerminationCondition.unbounded:
        print("Problem is unbounded")
    else:
        print(f"Solver terminated with condition: {results.solver.termination_condition}")
    
    return model

# Run the optimization
game_injury_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 297000.0
**Execution Time**: 2.15 seconds
**Reliability**: high
**Analysis**: Pyomo achieved an optimal solution with a moderate execution time, indicating a balance between efficiency and reliability.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 297000.00 | 0.50s | N/A | N/A |
| Docplex | OPTIMAL | 297000.00 | 5.81s | N/A | N/A |
| Pyomo | OPTIMAL | 297000.00 | 2.15s | N/A | N/A |

### Solver Consistency Analysis
**Result**: All solvers produced consistent results ✓
**Consistent Solvers**: gurobipy, docplex, pyomo
**Majority Vote Optimal Value**: 297000.0

### Final Recommendation
**Recommended Optimal Value**: 297000.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy is preferred due to its high reliability and the fastest execution time, making it the most efficient choice for this problem.

### Business Interpretation
**Overall Strategy**: The optimal solution maximizes attendance while minimizing injury risk, adhering to all constraints.
**Objective Value Meaning**: The optimal objective value of 297000.0 represents the maximum achievable attendance minus the weighted injury risk, reflecting the best trade-off between these factors.
**Resource Allocation Summary**: Resources should be allocated to schedule games that maximize attendance while keeping injury risk within acceptable limits.
**Implementation Recommendations**: Implement the schedule as determined by the optimal solution, ensuring compliance with all constraints and monitoring injury risk closely.