# Complete Optimization Problem and Solution: race_track

## 1. Problem Context and Goals

### Context  
The racing organization is focused on optimizing the number of spectators attending races across various tracks. The primary decision involves determining the number of races to hold at each track, represented by the variable races[track_id] for each track_id. The objective is to maximize the total number of spectators, which is directly influenced by the seating capacity of each track. The organization must also adhere to a constraint on the total number of races that can be held across all tracks, ensuring operational feasibility and maintaining spectator engagement. This constraint is defined by a business configuration parameter, the total_races_limit, which sets the maximum allowable races across all tracks. The operational parameters and constraints are structured to align with a linear optimization framework, focusing on maximizing the product of seating capacity and the number of races, without involving any nonlinear relationships.

### Goals  
The primary goal of the optimization is to maximize the total number of spectators attending the races. This is achieved by optimizing the allocation of races across different tracks, taking into account the seating capacity of each track. The success of this optimization is measured by the total number of spectators, calculated as the sum of the product of seating capacity and the number of races held at each track. The objective is clearly defined in linear terms, focusing on maximizing the potential audience while adhering to the constraints set by the business configuration.

## 2. Constraints    

The optimization problem is subject to several key constraints that ensure the solution is feasible and aligns with business requirements:

- The total number of races held across all tracks must not exceed the total_races_limit. This constraint ensures that the number of races is distributed in a way that is operationally feasible and maintains spectator interest.
- For each track, the product of the seating capacity and the number of races must not exceed the maximum number of spectators allowed at that track. This constraint ensures that the number of spectators does not surpass the track's capacity, maintaining safety and comfort for attendees.

These constraints are expressed in business terms that naturally lead to linear mathematical forms, avoiding any nonlinear relationships.

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 1 Database Schema
-- Objective: Schema changes include creating new tables for missing optimization data requirements and updating configuration logic for scalar parameters and formulas.

CREATE TABLE track (
  Seating INTEGER,
  max_spectators INTEGER
);

CREATE TABLE TrackRaces (
  races INTEGER
);
```

### Data Dictionary  
The data dictionary provides a comprehensive mapping of tables and columns to their business purposes and roles in the optimization process:

- **Track Table**: This table stores information about each racing track.
  - **Seating**: Represents the seating capacity of each track. It is used to calculate the potential number of spectators per race, playing a crucial role in the optimization objective.
  - **Max Spectators**: Indicates the maximum number of spectators allowed at each track. This serves as a constraint to ensure that the number of spectators does not exceed the track's capacity.

- **TrackRaces Table**: This table records the number of races to be held at each track.
  - **Races**: Represents the decision variable for the optimization, indicating the number of races scheduled at each track.

### Current Stored Values  
```sql
-- Iteration 1 Realistic Data
-- Generated by triple expert (business + data + optimization)
-- Values were determined based on typical seating capacities and spectator limits for medium-sized racing tracks, ensuring a balance between maximizing spectators and adhering to constraints.

-- Realistic data for track
INSERT INTO track (Seating, max_spectators) VALUES (5000, 4500);
INSERT INTO track (Seating, max_spectators) VALUES (10000, 9500);
INSERT INTO track (Seating, max_spectators) VALUES (15000, 14500);

-- Realistic data for TrackRaces
INSERT INTO TrackRaces (races) VALUES (3);
INSERT INTO TrackRaces (races) VALUES (5);
INSERT INTO TrackRaces (races) VALUES (7);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- Let \( x_i \) represent the number of races to be held at track \( i \).
- \( x_i \) is an integer variable for each track \( i \).

#### Objective Function
Maximize the total number of spectators across all tracks:
\[ \text{Maximize } Z = \sum_{i} (\text{Seating}_i \times x_i) \]

Data Source Verification:
- Coefficient \(\text{Seating}_i\) comes from the `track.Seating` column.

#### Constraints
1. Total number of races across all tracks must not exceed the total_races_limit:
   \[ \sum_{i} x_i \leq \text{total\_races\_limit} \]

2. For each track, the number of spectators must not exceed the maximum allowed:
   \[ \text{Seating}_i \times x_i \leq \text{max\_spectators}_i \quad \forall i \]

Data Source Verification:
- Coefficient \(\text{max\_spectators}_i\) comes from the `track.max_spectators` column.
- The parameter \(\text{total\_races\_limit}\) is a business configuration parameter.

#### Complete Model
Given the data:

- Track 1: Seating = 5000, max_spectators = 4500
- Track 2: Seating = 10000, max_spectators = 9500
- Track 3: Seating = 15000, max_spectators = 14500
- Assume \(\text{total\_races\_limit} = 10\) (for example)

The complete model is:

Maximize:
\[ Z = 5000x_1 + 10000x_2 + 15000x_3 \]

Subject to:
\[ x_1 + x_2 + x_3 \leq 10 \]
\[ 5000x_1 \leq 4500 \]
\[ 10000x_2 \leq 9500 \]
\[ 15000x_3 \leq 14500 \]

\[ x_1, x_2, x_3 \geq 0 \]
\[ x_1, x_2, x_3 \text{ are integers} \]

This model can be solved using a linear or mixed-integer programming solver to determine the optimal number of races to hold at each track to maximize spectator attendance.

## 5. Gurobipy Implementation

```python
# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_race_track():
    """Optimize the number of races to maximize spectators"""

    # 1. MODEL & DATA SETUP
    model = gp.Model("race_track")
    
    # Data from the problem statement
    seating = [5000, 10000, 15000]
    max_spectators = [4500, 9500, 14500]
    total_races_limit = 10
    n_tracks = len(seating)
    
    # CRITICAL: Validate array lengths before loops
    assert len(seating) == len(max_spectators) == n_tracks, "Array length mismatch"
    
    # 2. VARIABLES
    # Variable dictionaries for number of races at each track
    races = {i: model.addVar(vtype=GRB.INTEGER, name=f"races_{i}", lb=0) 
             for i in range(n_tracks)}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total number of spectators
    model.setObjective(gp.quicksum(seating[i] * races[i] for i in range(n_tracks)), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Total number of races constraint
    model.addConstr(gp.quicksum(races[i] for i in range(n_tracks)) <= total_races_limit, name="total_races_limit")
    
    # Maximum spectators constraint for each track
    for i in range(n_tracks):
        model.addConstr(seating[i] * races[i] <= max_spectators[i], name=f"max_spectators_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_tracks):
            if races[i].x > 1e-6:
                print(f"races[{i}] = {races[i].x:.3f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_race_track()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: -0.0
**Execution Time**: 0.74 seconds
**Reliability**: high
**Analysis**: Gurobipy found an optimal solution with all decision variables set to zero, which is consistent with the constraints that prevent any races from being held due to the spectator limits.

## 6. DOCplex Implementation

```python
# Complete DOCPLEX implementation

from docplex.mp.model import Model

def optimize_race_track():
    """Optimize the number of races to maximize spectators"""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="race_track_optimization")
    
    # Data from the problem statement
    seating = [5000, 10000, 15000]
    max_spectators = [4500, 9500, 14500]
    total_races_limit = 10
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(seating) == len(max_spectators), "Array length mismatch"
    safe_range = range(min(len(seating), len(max_spectators)))  # Safe indexing
    
    # 2. VARIABLES
    # Integer variables for the number of races at each track
    races = {i: mdl.integer_var(name=f"races_{i}", lb=0) for i in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total number of spectators
    objective = mdl.sum(seating[i] * races[i] for i in safe_range)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Total number of races constraint
    total_races = mdl.sum(races[i] for i in safe_range)
    mdl.add_constraint(total_races <= total_races_limit, ctname="total_races_limit")
    
    # Spectator capacity constraints for each track
    for i in safe_range:
        mdl.add_constraint(seating[i] * races[i] <= max_spectators[i], ctname=f"capacity_{i}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_range:
            value = solution.get_value(races[i])
            if value > 1e-6:
                print(f"races[{i}] = {value:.0f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
optimize_race_track()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 0.0
**Execution Time**: 3.76 seconds
**Reliability**: high
**Analysis**: DOCplex also found an optimal solution with all decision variables set to zero, aligning with the constraints.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

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

def race_track_optimization():
    """Optimize the number of races to maximize spectators"""

    # 1. MODEL CREATION
    model = pyo.ConcreteModel()

    # 2. DATA SETUP
    seating = [5000, 10000, 15000]
    max_spectators = [4500, 9500, 14500]
    total_races_limit = 10

    # CRITICAL: Validate array lengths before indexing
    assert len(seating) == len(max_spectators), "Array length mismatch"

    # 3. SETS (Pyomo way to define indices)
    model.I = pyo.RangeSet(1, len(seating))  # 1-based indexing

    # 4. PARAMETERS (data containers)
    model.seating = pyo.Param(model.I, initialize={i+1: seating[i] for i in range(len(seating))})
    model.max_spectators = pyo.Param(model.I, initialize={i+1: max_spectators[i] for i in range(len(max_spectators))})

    # 5. VARIABLES
    model.x = pyo.Var(model.I, within=pyo.NonNegativeIntegers)

    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.seating[i] * model.x[i] for i in model.I)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)

    # 7. CONSTRAINTS

    # Total races constraint
    def total_races_rule(model):
        return sum(model.x[i] for i in model.I) <= total_races_limit
    model.total_races_constraint = pyo.Constraint(rule=total_races_rule)

    # Spectator capacity constraints
    def spectator_capacity_rule(model, i):
        return model.seating[i] * model.x[i] <= model.max_spectators[i]
    model.spectator_capacity_constraint = pyo.Constraint(model.I, rule=spectator_capacity_rule)

    # 8. SOLVING WITH GUROBI
    solver = SolverFactory('gurobi')

    # Solve the model
    results = solver.solve(model, tee=True)

    # 9. RESULT PROCESSING
    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 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}] = {x_val:.3f}")

    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
race_track_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 0.0
**Execution Time**: 3.83 seconds
**Reliability**: high
**Analysis**: Pyomo's results are consistent with the other solvers, indicating no races can be held due to the constraints.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | -0.00 | 0.74s | N/A | N/A |
| Docplex | OPTIMAL | 0.00 | 3.76s | N/A | N/A |
| Pyomo | OPTIMAL | 0.00 | 3.83s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 0.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: multiple
**Reasoning**: All solvers provided consistent results, confirming the constraints prevent any races from being held.

### Optimal Decision Variables
- **x_1** = 0.000
  - *Business Meaning*: Number of races at Track 2, which is zero due to spectator constraints.
- **x_2** = 0.000
  - *Business Meaning*: Number of races at Track 3, which is zero due to spectator constraints.
- **x_3** = 0.000
  - *Business Meaning*: Resource allocation for x_3

### Business Interpretation
**Overall Strategy**: No races can be held at any track due to the spectator constraints, resulting in zero total spectators.
**Objective Value Meaning**: The optimal objective value of 0 indicates no spectators can be accommodated given the constraints.
**Resource Allocation Summary**: No resources should be allocated to holding races as the constraints prevent any races from occurring.
**Implementation Recommendations**: Review and potentially adjust the spectator constraints or total race limits to allow for feasible race scheduling.