## 4. Mathematical Optimization Formulation

#### Decision Variables
- \( \text{Invested}_i \): Continuous variable representing the amount invested in school \( i \).

#### Objective Function
Maximize the total amount invested across all schools:
\[ \text{Maximize} \quad \sum_{i} \text{Invested}_i \]

#### Constraints
1. Investment should not exceed the budgeted amount for each school:
   \[
   \text{Invested}_i \leq \text{Budgeted}_i \quad \forall i
   \]

2. Investment should be at least the minimum percentage of the budgeted amount for each school:
   \[
   \text{Invested}_i \geq \text{min\_investment\_percent}_i \times \text{Budgeted}_i \quad \forall i
   \]

Data Source Verification:
- \(\text{Invested}_i\) is the decision variable from the `budget.Invested` column.
- \(\text{Budgeted}_i\) is the constraint bound from the `budget.Budgeted` column.
- \(\text{min\_investment\_percent}_i\) is the constraint parameter from the `budget.min_investment_percent` column.

This linear model is immediately solvable using standard linear programming techniques, ensuring that the total investment is maximized while adhering to the budgetary constraints and minimum investment requirements for each school.

## 5. Gurobipy Implementation

```python
# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_school_finance():
    """Optimize school budget allocation using Gurobi"""

    # 1. MODEL & DATA SETUP
    model = gp.Model("school_finance")

    # Data from the database
    budget_data = [
        {"Invested": 4500.0, "Budgeted": 5000.0, "min_investment_percent": 0.1},
        {"Invested": 5400.0, "Budgeted": 6000.0, "min_investment_percent": 0.15},
        {"Invested": 6300.0, "Budgeted": 7000.0, "min_investment_percent": 0.2}
    ]

    n_schools = len(budget_data)

    # Extracting data into lists
    budgeted = [entry["Budgeted"] for entry in budget_data]
    min_investment_percent = [entry["min_investment_percent"] for entry in budget_data]

    # CRITICAL: Validate array lengths before loops
    assert len(budgeted) == len(min_investment_percent) == n_schools, "Array length mismatch"

    # 2. VARIABLES
    invested = model.addVars(n_schools, vtype=GRB.CONTINUOUS, name="Invested", lb=0)

    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum(invested[i] for i in range(n_schools)), GRB.MAXIMIZE)

    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS

    # Constraint: Investment should not exceed the budgeted amount for each school
    model.addConstrs((invested[i] <= budgeted[i] for i in range(n_schools)), name="budget_limit")

    # Constraint: Investment should be at least the minimum percentage of the budgeted amount
    model.addConstrs((invested[i] >= min_investment_percent[i] * budgeted[i] for i in range(n_schools)), name="min_investment")

    # 5. SOLVING & RESULTS
    model.optimize()

    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_schools):
            if invested[i].x > 1e-6:
                print(f"Invested[{i}] = {invested[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_school_finance()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 18000.0
**Execution Time**: 1.42 seconds
**Reliability**: high
**Analysis**: Gurobipy found an optimal solution quickly with the shortest execution time, indicating efficient performance.

## 6. DOCplex Implementation

```python
# Complete DOCPLEX implementation

from docplex.mp.model import Model

def school_finance_optimization():
    """Optimize school budget allocation using DOCPLEX"""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="school_finance")
    
    # Data from the database
    budgeted = [5000.0, 6000.0, 7000.0]
    min_investment_percent = [0.1, 0.15, 0.2]
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(budgeted) == len(min_investment_percent), "Array length mismatch"
    safe_range = range(len(budgeted))  # Safe indexing
    
    # 2. VARIABLES
    invested = {i: mdl.continuous_var(name=f"Invested_{i}", lb=0) for i in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total amount invested across all schools
    objective = mdl.sum(invested[i] for i in safe_range)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Investment should not exceed the budgeted amount for each school
    for i in safe_range:
        mdl.add_constraint(invested[i] <= budgeted[i], ctname=f"budget_limit_{i}")
    
    # Investment should be at least the minimum percentage of the budgeted amount
    for i in safe_range:
        mdl.add_constraint(invested[i] >= min_investment_percent[i] * budgeted[i], ctname=f"min_investment_{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(invested[i])
            if value > 1e-6:
                print(f"Invested[{i}] = {value:.3f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
school_finance_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 18000.0
**Execution Time**: 4.03 seconds
**Reliability**: high
**Analysis**: DOCplex also found an optimal solution, albeit with a longer execution time compared to Gurobipy.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

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

def school_finance_optimization():
    """Optimize school budget allocation using Pyomo"""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Example data from the database
    budgeted = [5000.0, 6000.0, 7000.0]
    min_investment_percent = [0.1, 0.15, 0.2]
    
    # CRITICAL: Validate array lengths before indexing
    n_schools = len(budgeted)
    assert len(min_investment_percent) == n_schools, "Array length mismatch"
    
    # 3. SETS (Pyomo way to define indices)
    model.S = pyo.RangeSet(1, n_schools)  # 1-based indexing
    
    # 4. PARAMETERS (data containers)
    model.Budgeted = pyo.Param(model.S, initialize={i+1: budgeted[i] for i in range(n_schools)})
    model.MinInvestmentPercent = pyo.Param(model.S, initialize={i+1: min_investment_percent[i] for i in range(n_schools)})
    
    # 5. VARIABLES
    model.Invested = pyo.Var(model.S, within=pyo.NonNegativeReals)
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.Invested[i] for i in model.S)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.maximize)
    
    # 7. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Constraint: Investment should not exceed the budgeted amount for each school
    def budget_constraint_rule(model, i):
        return model.Invested[i] <= model.Budgeted[i]
    model.budget_constraint = pyo.Constraint(model.S, rule=budget_constraint_rule)
    
    # Constraint: Investment should be at least the minimum percentage of the budgeted amount
    def min_investment_constraint_rule(model, i):
        return model.Invested[i] >= model.MinInvestmentPercent[i] * model.Budgeted[i]
    model.min_investment_constraint = pyo.Constraint(model.S, rule=min_investment_constraint_rule)
    
    # 8. SOLVING WITH GUROBI (your available solver)
    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("\nInvestment values:")
        for i in model.S:
            invested_val = pyo.value(model.Invested[i])
            print(f"Invested[{i}] = {invested_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

# Run the optimization
school_finance_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 18000.0
**Execution Time**: 3.70 seconds
**Reliability**: high
**Analysis**: Pyomo achieved an optimal solution with a slightly faster execution time than DOCplex but slower than Gurobipy.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 18000.00 | 1.42s | N/A | N/A |
| Docplex | OPTIMAL | 18000.00 | 4.03s | N/A | N/A |
| Pyomo | OPTIMAL | 18000.00 | 3.70s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 18000.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy is recommended due to its efficient performance and shortest execution time, providing reliable results quickly.

### Business Interpretation
**Overall Strategy**: The optimal investment strategy ensures maximum utilization of available budgets across all schools.
**Objective Value Meaning**: The optimal objective value of 18000.0 represents the total investment distributed across all schools, maximizing the use of available funds.
**Resource Allocation Summary**: Resources should be allocated to each school such that each receives at least the minimum required investment while not exceeding its budget.
**Implementation Recommendations**: Implement the investment strategy by allocating funds according to the solver's optimal solution, ensuring compliance with budgetary constraints and minimum investment requirements.