## 4. Mathematical Optimization Formulation

#### Decision Variables
- Let \( x_i \) represent the budget allocation to city \( i \) (continuous variable), where \( i \in \{1, 2, 3\} \).

#### Objective Function
Maximize the total population served:
\[
\text{Maximize } Z = 150000x_1 + 250000x_2 + 100000x_3
\]
**Data Source Verification**: Coefficients come from `city.Population`.

#### Constraints
1. **Total Budget Limit**:
\[
x_1 + x_2 + x_3 \leq 1000000
\]
**Data Source Verification**: Constant comes from the total budget available for allocation.

2. **Minimum Allocation per City**:
\[
x_1 \geq 50000, \quad x_2 \geq 50000, \quad x_3 \geq 50000
\]
**Data Source Verification**: Constant comes from the minimum budget allocation per city.

3. **Minimum Allocation per District**:
   - District 1 (North): \( x_1 \geq 200000 \)
   - District 2 (South): \( x_2 \geq 200000 \)
   - District 3 (East): \( x_3 \geq 200000 \)
**Data Source Verification**: Constants come from the minimum budget allocation per district.

#### Complete Linear Programming Model
\[
\text{Maximize } Z = 150000x_1 + 250000x_2 + 100000x_3
\]
Subject to:
\[
\begin{cases}
x_1 + x_2 + x_3 \leq 1000000 \\
x_1 \geq 50000, \quad x_2 \geq 50000, \quad x_3 \geq 50000 \\
x_1 \geq 200000, \quad x_2 \geq 200000, \quad x_3 \geq 200000 \\
\end{cases}
\]

This is a complete, immediately solvable linear programming model with all numerical coefficients derived from the provided data.

## 5. Gurobipy Implementation

```python
#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Budget Allocation Problem
"""

import gurobipy as gp
from gurobipy import GRB

def budget_allocation_optimization():
    """Optimize budget allocation to maximize population served."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("budget_allocation")
    
    # Data from the problem
    cities = [1, 2, 3]
    populations = {1: 150000, 2: 250000, 3: 100000}
    districts = {1: 1, 2: 2, 3: 3}
    total_budget = 1000000
    min_city_allocation = 50000
    min_district_allocation = 200000
    
    # CRITICAL: Validate array lengths before loops
    assert len(cities) == len(populations) == len(districts), "Array length mismatch"
    
    # 2. VARIABLES
    # Decision variables: budget allocation to each city
    x = {i: model.addVar(vtype=GRB.CONTINUOUS, name=f"x_{i}", lb=min_city_allocation) 
         for i in cities}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total population served
    model.setObjective(gp.quicksum(populations[i] * x[i] for i in cities), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    
    # Total Budget Limit
    model.addConstr(gp.quicksum(x[i] for i in cities) <= total_budget, name="total_budget_limit")
    
    # Minimum Allocation per District
    for i in cities:
        model.addConstr(x[i] >= min_district_allocation, name=f"district_min_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in cities:
            print(f"x[{i}] = {x[i].x:.3f}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Execute the optimization
if __name__ == "__main__":
    budget_allocation_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 200000000000.0
**Execution Time**: 0.22 seconds
**Reliability**: high
**Analysis**: Gurobipy successfully found an optimal solution with a high objective value and fast execution time.

## 6. DOCplex Implementation

```python
#!/usr/bin/env python3
"""
DOCPLEX Implementation for Budget Allocation Optimization Problem
"""

from docplex.mp.model import Model

def budget_allocation_optimization():
    """Optimize budget allocation to maximize population served."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="budget_allocation")
    
    # Data from the problem
    cities = [1, 2, 3]
    populations = {1: 150000, 2: 250000, 3: 100000}
    districts = {1: 'North', 2: 'South', 3: 'East'}
    city_district = {1: 1, 2: 2, 3: 3}
    
    # Parameters
    total_budget = 1000000
    min_city_allocation = 50000
    min_district_allocation = 200000
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(cities) == len(populations) == len(city_district), "Array length mismatch"
    safe_range = range(min(len(cities), len(populations), len(city_district)))  # Safe indexing
    
    # 2. VARIABLES
    # Decision variables: budget allocation to each city
    x = {i: mdl.continuous_var(name=f"x_{i}", lb=0) for i in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total population served
    objective = mdl.sum(populations[i] * x[i] for i in safe_range)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    
    # Total Budget Limit
    total_allocation = mdl.sum(x[i] for i in safe_range)
    mdl.add_constraint(total_allocation <= total_budget, ctname="total_budget_limit")
    
    # Minimum Allocation per City
    for i in safe_range:
        mdl.add_constraint(x[i] >= min_city_allocation, ctname=f"min_city_allocation_{i}")
    
    # Minimum Allocation per District
    for i in safe_range:
        district_id = city_district[i]
        mdl.add_constraint(x[i] >= min_district_allocation, ctname=f"min_district_allocation_{district_id}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_range:
            value = solution.get_value(x[i])
            print(f"x[{i}] = {value:.3f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Execute the optimization
if __name__ == "__main__":
    budget_allocation_optimization()
```

### Execution Results
**Status**: ERROR
**Error**: Traceback (most recent call last):
  File "/tmp/tmpuq3t1pd4.py", line 69, in <module>
    budget_allocation_optimization()
  File "/tmp/tmpuq3t1pd4.py", line 35, in budget_allocation_optimization
    objective = mdl.sum(populations[i] * x[i] for i in safe_range)
  File "/dccstor/nl2opt/miniforge3/envs/nl2opt_optim/lib/python3.10/site-packages/docplex/mp/model.py", line 3342, in sum
    return self._aggregator.sum(args)
  File "/dccstor/nl2opt/miniforge3/envs/nl2opt_optim/lib/python3.10/site-packages/docplex/mp/aggregator.py", line 198, in sum
    sum_res = self._sum_with_iter(sum_args)
  File "/dccstor/nl2opt/miniforge3/envs/nl2opt_optim/lib/python3.10/site-packages/docplex/mp/aggregator.py", line 221, in _sum_with_iter
    for item in args:
  File "/tmp/tmpuq3t1pd4.py", line 35, in <genexpr>
    objective = mdl.sum(populations[i] * x[i] for i in safe_range)
KeyError: 0

**Analysis**: DOCplex encountered a KeyError, likely due to an issue with indexing or data handling in the implementation.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

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

def optimize_budget_allocation():
    """Optimize budget allocation to maximize population served."""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # City data: CityID, Population, DistrictID
    city_data = {
        1: {'Population': 150000, 'DistrictID': 1},
        2: {'Population': 250000, 'DistrictID': 2},
        3: {'Population': 100000, 'DistrictID': 3}
    }
    
    # Total budget and minimum allocations
    total_budget = 1000000
    min_city_allocation = 50000
    min_district_allocation = 200000
    
    # Validate data consistency
    assert len(city_data) == 3, "City data length mismatch"
    
    # 3. SETS
    model.I = pyo.Set(initialize=city_data.keys())  # Set of cities
    
    # 4. PARAMETERS
    model.population = pyo.Param(model.I, initialize={i: city_data[i]['Population'] for i in model.I})
    model.district = pyo.Param(model.I, initialize={i: city_data[i]['DistrictID'] for i in model.I})
    
    # 5. VARIABLES
    model.x = pyo.Var(model.I, within=pyo.NonNegativeReals)
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.population[i] * model.x[i] for i in model.I)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)
    
    # 7. CONSTRAINTS
    
    # Total Budget Limit
    def total_budget_rule(model):
        return sum(model.x[i] for i in model.I) <= total_budget
    model.total_budget_constraint = pyo.Constraint(rule=total_budget_rule)
    
    # Minimum Allocation per City
    def min_city_allocation_rule(model, i):
        return model.x[i] >= min_city_allocation
    model.min_city_allocation_constraint = pyo.Constraint(model.I, rule=min_city_allocation_rule)
    
    # Minimum Allocation per District
    def min_district_allocation_rule(model, i):
        return model.x[i] >= min_district_allocation
    model.min_district_allocation_constraint = pyo.Constraint(model.I, rule=min_district_allocation_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("\nBudget allocations:")
        for i in model.I:
            x_val = pyo.value(model.x[i])
            print(f"City {i}: {x_val:.2f}")
        
    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

# Execute the optimization
if __name__ == "__main__":
    optimize_budget_allocation()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 200000000000.0
**Execution Time**: 0.96 seconds
**Reliability**: high
**Analysis**: Pyomo also found an optimal solution with the same objective value as Gurobipy, though with a slightly longer execution time.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 200000000000.00 | 0.22s | N/A | N/A |
| Docplex | ERROR | N/A | 1.24s | N/A | N/A |
| Pyomo | OPTIMAL | 200000000000.00 | 0.96s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 200000000000.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy provided the fastest and most reliable solution, while Pyomo also confirmed the same optimal value. DOCplex failed due to an implementation error.

### Business Interpretation
**Overall Strategy**: The optimal solution maximizes the total population served by allocating the budget efficiently across the cities.
**Objective Value Meaning**: The optimal objective value of 200,000,000,000 represents the total population served by the budget allocation.
**Resource Allocation Summary**: The budget should be allocated to meet the minimum requirements for each city and district, ensuring maximum population coverage.
**Implementation Recommendations**: Allocate the budget as per the optimal solution, ensuring compliance with minimum allocation constraints. Use Gurobipy for future optimizations due to its reliability and speed.