# Complete Optimization Problem and Solution: student_1

## 1. Problem Context and Goals

### Context  
In a school setting, the administration is tasked with efficiently assigning students to classrooms. The primary decision involves determining which students are assigned to which classrooms, represented by a binary decision variable indicating if a student is assigned to a particular classroom. The operational goal is to minimize the maximum number of students in any classroom, ensuring that each classroom is adequately staffed with at least one teacher. The business configuration includes a parameter that sets the maximum number of students allowed in any classroom, which is a common standard to balance teacher workload and classroom management. This parameter is crucial for setting the upper limit of students per classroom in the optimization model. The data reflects current operational information, focusing on precise decision-making that aligns with linear optimization formulations. Resource limitations are expressed through constraints that ensure no classroom exceeds its capacity and each student is assigned to exactly one classroom.

### Goals  
The optimization goal is to minimize the maximum number of students assigned to any classroom. This objective is measured by the number of students in the most populated classroom, with success defined by achieving the smallest possible maximum. The aim is to distribute students in a way that balances classroom sizes, ensuring no classroom is overcrowded, thereby optimizing the learning environment and teacher effectiveness.

## 2. Constraints    

The constraints for this optimization problem are straightforward and align with linear mathematical forms. Each classroom has a capacity limit, meaning the total number of students assigned to a classroom cannot exceed its maximum capacity. This is represented by ensuring the sum of assignments for all students to a particular classroom does not surpass the classroom's capacity. Additionally, each student must be assigned to exactly one classroom, ensuring that every student is accounted for in the assignment process. These constraints are essential for maintaining a balanced and feasible distribution of students across classrooms.

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 1 Database Schema
-- Objective: Schema changes include creating new tables for decision variables and constraint bounds, modifying existing tables to fill mapping gaps, and moving scalar parameters to configuration logic.

CREATE TABLE DecisionVariables (
  student_id INTEGER,
  classroom_id INTEGER,
  assignment BOOLEAN
);

CREATE TABLE ClassroomCapacity (
  classroom_id INTEGER,
  max_students INTEGER
);
```

### Data Dictionary  
The data dictionary provides a comprehensive overview of the tables and columns used in the optimization problem, highlighting their business purposes and roles in the optimization process:

- **DecisionVariables Table**: This table captures the assignment of students to classrooms. It includes:
  - **student_id**: A unique identifier for each student, used to track individual assignments.
  - **classroom_id**: A unique identifier for each classroom, linking students to specific classrooms.
  - **assignment**: A binary indicator showing whether a student is assigned to a particular classroom.

- **ClassroomCapacity Table**: This table defines the capacity constraints for each classroom. It includes:
  - **classroom_id**: A unique identifier for each classroom, used to apply capacity constraints.
  - **max_students**: The maximum number of students allowed in each classroom, setting the upper bound for student assignments.

### Current Stored Values  
```sql
-- Iteration 1 Realistic Data
-- Generated by triple expert (business + data + optimization)
-- Values were determined based on typical classroom sizes and student distribution in a school setting, ensuring that the optimization problem remains solvable and realistic.

-- Realistic data for DecisionVariables
INSERT INTO DecisionVariables (student_id, classroom_id, assignment) VALUES (1, 101, True);
INSERT INTO DecisionVariables (student_id, classroom_id, assignment) VALUES (2, 102, True);
INSERT INTO DecisionVariables (student_id, classroom_id, assignment) VALUES (3, 103, True);
INSERT INTO DecisionVariables (student_id, classroom_id, assignment) VALUES (4, 101, True);
INSERT INTO DecisionVariables (student_id, classroom_id, assignment) VALUES (5, 102, True);

-- Realistic data for ClassroomCapacity
INSERT INTO ClassroomCapacity (classroom_id, max_students) VALUES (101, 25);
INSERT INTO ClassroomCapacity (classroom_id, max_students) VALUES (102, 30);
INSERT INTO ClassroomCapacity (classroom_id, max_students) VALUES (103, 35);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- Let \( x_{ij} \) be a binary decision variable where \( x_{ij} = 1 \) if student \( i \) is assigned to classroom \( j \), and \( x_{ij} = 0 \) otherwise.

#### Objective Function
- Minimize the maximum number of students in any classroom. Introduce an auxiliary variable \( M \) to represent this maximum number. The objective is to minimize \( M \).

\[
\text{Minimize } M
\]

#### Constraints
1. **Classroom Capacity Constraints**: Ensure that the number of students assigned to each classroom does not exceed its capacity.

   For each classroom \( j \):

   \[
   \sum_{i} x_{ij} \leq \text{max\_students}_j
   \]

   where \(\text{max\_students}_j\) is the maximum capacity of classroom \( j \) from the `ClassroomCapacity` table.

2. **Student Assignment Constraints**: Ensure each student is assigned to exactly one classroom.

   For each student \( i \):

   \[
   \sum_{j} x_{ij} = 1
   \]

3. **Maximum Students Constraint**: Ensure that the number of students in any classroom does not exceed \( M \).

   For each classroom \( j \):

   \[
   \sum_{i} x_{ij} \leq M
   \]

#### Data Source Verification:
- The coefficients for the classroom capacity constraints (\(\text{max\_students}_j\)) are sourced from the `ClassroomCapacity.max_students` column.
- The binary nature of the decision variables \( x_{ij} \) is derived from the `DecisionVariables.assignment` column, indicating whether a student is assigned to a classroom.

This formulation ensures that the optimization problem is linear and adheres to the constraints and objectives outlined in the business problem. The model can be solved using standard linear programming or mixed-integer programming solvers.

## 5. Gurobipy Implementation

```python
# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_classroom_assignment():
    """Optimize student assignments to classrooms to minimize the maximum number of students in any classroom."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("classroom_assignment")
    
    # Example data setup
    students = [1, 2, 3, 4, 5]
    classrooms = [101, 102, 103]
    max_students = {101: 25, 102: 30, 103: 35}
    
    # CRITICAL: Validate array lengths before loops
    assert len(students) > 0, "No students available"
    assert len(classrooms) > 0, "No classrooms available"
    
    # 2. VARIABLES
    # Binary decision variables for student assignments
    x = model.addVars(students, classrooms, vtype=GRB.BINARY, name="x")
    
    # Auxiliary variable for the maximum number of students in any classroom
    M = model.addVar(vtype=GRB.CONTINUOUS, name="M", lb=0)
    
    # 3. OBJECTIVE FUNCTION
    # Minimize the maximum number of students in any classroom
    model.setObjective(M, GRB.MINIMIZE)
    
    # 4. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Classroom capacity constraints
    model.addConstrs(
        (gp.quicksum(x[i, j] for i in students) <= max_students[j] for j in classrooms),
        name="classroom_capacity"
    )
    
    # Student assignment constraints
    model.addConstrs(
        (gp.quicksum(x[i, j] for j in classrooms) == 1 for i in students),
        name="student_assignment"
    )
    
    # Maximum students constraint
    model.addConstrs(
        (gp.quicksum(x[i, j] for i in students) <= M for j in classrooms),
        name="max_students"
    )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in students:
            for j in classrooms:
                if x[i, j].x > 1e-6:
                    print(f"Student {i} assigned to classroom {j}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_classroom_assignment()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 2.0
**Execution Time**: 0.16 seconds
**Reliability**: high
**Analysis**: Gurobipy found an optimal solution quickly with the lowest execution time, indicating efficient performance and reliability.

## 6. DOCplex Implementation

```python
# Complete DOCPLEX implementation

from docplex.mp.model import Model

def classroom_assignment_optimization():
    """Optimize student assignments to classrooms to minimize the maximum number of students in any classroom."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="classroom_assignment")
    
    # Data: Number of students and classrooms
    students = [1, 2, 3, 4, 5]
    classrooms = [101, 102, 103]
    
    # Classroom capacities
    classroom_capacities = {101: 25, 102: 30, 103: 35}
    
    # Validate data lengths
    assert len(classrooms) == len(classroom_capacities), "Mismatch in classroom data lengths"
    
    # Safe range for classrooms
    safe_classroom_range = range(len(classrooms))
    
    # 2. VARIABLES
    # Decision variables: x[i][j] = 1 if student i is assigned to classroom j, 0 otherwise
    x = {(i, j): mdl.binary_var(name=f"x_{i}_{j}") for i in students for j in classrooms}
    
    # Auxiliary variable for the maximum number of students in any classroom
    M = mdl.continuous_var(name="M", lb=0)
    
    # 3. OBJECTIVE FUNCTION
    # Minimize the maximum number of students in any classroom
    mdl.minimize(M)
    
    # 4. CONSTRAINTS
    
    # Classroom capacity constraints
    for j in classrooms:
        mdl.add_constraint(mdl.sum(x[i, j] for i in students) <= classroom_capacities[j], ctname=f"capacity_{j}")
    
    # Student assignment constraints
    for i in students:
        mdl.add_constraint(mdl.sum(x[i, j] for j in classrooms) == 1, ctname=f"assignment_{i}")
    
    # Maximum students constraint
    for j in classrooms:
        mdl.add_constraint(mdl.sum(x[i, j] for i in students) <= M, ctname=f"max_students_{j}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in students:
            for j in classrooms:
                if solution.get_value(x[i, j]) > 0.5:  # Check if student i is assigned to classroom j
                    print(f"Student {i} is assigned to classroom {j}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Run the optimization
classroom_assignment_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 2.0
**Execution Time**: 1.70 seconds
**Reliability**: high
**Analysis**: DOCplex also found an optimal solution, though it took longer than Gurobipy. The results are consistent with other solvers, indicating reliability.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

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

def classroom_assignment_optimization():
    """Optimize student assignments to classrooms to minimize the maximum number of students in any classroom."""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Example data based on the provided database schema and realistic data
    students = [1, 2, 3, 4, 5]
    classrooms = [101, 102, 103]
    max_students = {101: 25, 102: 30, 103: 35}
    
    # CRITICAL: Validate data lengths before indexing
    assert len(students) > 0, "No students available"
    assert len(classrooms) > 0, "No classrooms available"
    
    # 3. SETS
    model.I = pyo.Set(initialize=students)
    model.J = pyo.Set(initialize=classrooms)
    
    # 4. PARAMETERS
    model.max_students = pyo.Param(model.J, initialize=max_students)
    
    # 5. VARIABLES
    model.x = pyo.Var(model.I, model.J, within=pyo.Binary)
    model.M = pyo.Var(within=pyo.NonNegativeIntegers)
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return model.M
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.minimize)
    
    # 7. CONSTRAINTS
    
    # Classroom Capacity Constraints
    def capacity_rule(model, j):
        return sum(model.x[i, j] for i in model.I) <= model.max_students[j]
    model.capacity_constraint = pyo.Constraint(model.J, rule=capacity_rule)
    
    # Student Assignment Constraints
    def assignment_rule(model, i):
        return sum(model.x[i, j] for j in model.J) == 1
    model.assignment_constraint = pyo.Constraint(model.I, rule=assignment_rule)
    
    # Maximum Students Constraint
    def max_students_rule(model, j):
        return sum(model.x[i, j] for i in model.I) <= model.M
    model.max_students_constraint = pyo.Constraint(model.J, rule=max_students_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)
    
    # 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("\nAssignment of students to classrooms:")
        for i in model.I:
            for j in model.J:
                if pyo.value(model.x[i, j]) > 0.5:  # Binary variable check
                    print(f"Student {i} assigned to Classroom {j}")
        
    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
classroom_assignment_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 2.0
**Execution Time**: 1.98 seconds
**Reliability**: high
**Analysis**: Pyomo achieved an optimal solution with the longest execution time among the solvers, but the results are consistent, indicating reliability.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 2.00 | 0.16s | N/A | N/A |
| Docplex | OPTIMAL | 2.00 | 1.70s | N/A | N/A |
| Pyomo | OPTIMAL | 2.00 | 1.98s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 2.0
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy is preferred due to its fastest execution time and consistent results, making it efficient for large-scale problems.

### Business Interpretation
**Overall Strategy**: The optimal value of 2.0 indicates that the maximum number of students in any classroom is minimized to 2, ensuring balanced distribution across classrooms.
**Objective Value Meaning**: The optimal objective value of 2.0 means that no classroom will have more than 2 students, optimizing space utilization and maintaining manageable class sizes.
**Resource Allocation Summary**: Students are evenly distributed across available classrooms, ensuring no classroom exceeds its capacity.
**Implementation Recommendations**: Implement the solution by assigning students to classrooms as per the solver's output, ensuring compliance with capacity constraints.