# Complete Optimization Problem and Solution: dorm_1

## 1. Problem Context and Goals

### Context  
The dormitory assignment problem involves optimizing the allocation of students to dormitories based on specific operational criteria. The primary business decision is whether to assign a student to a particular dorm, represented as a binary choice. The goal is to minimize the total distance students travel from their home cities to their assigned dorms. This distance is a key operational parameter, as it directly impacts the objective function. 

The problem must respect two critical constraints:  
1. **Dorm Capacity**: Each dorm has a maximum number of students it can accommodate, and this limit must not be exceeded.  
2. **Gender Matching**: Students can only be assigned to dorms that match their gender.  

The data used in this optimization includes the distance between each student's home city and each dorm, the capacity of each dorm, and the gender constraints for both students and dorms. These parameters are stored in the database and are essential for calculating the objective and enforcing constraints.

### Goals  
The optimization goal is to minimize the total distance traveled by all students to their assigned dorms. This is achieved by ensuring that each student is assigned to exactly one dorm, while respecting dorm capacities and gender constraints. Success is measured by the total distance metric, which is calculated as the sum of the distances for all assigned student-dorm pairs. The objective is linear, as it involves summing the product of binary assignment decisions and their corresponding distances.

## 2. Constraints  

The optimization problem is subject to the following constraints, described in business terms:  
1. **Single Assignment**: Each student must be assigned to exactly one dorm. This ensures that all students have a place to stay and no student is left unassigned.  
2. **Dorm Capacity**: The number of students assigned to a dorm cannot exceed its maximum capacity. This ensures that dorms are not overcrowded and can accommodate all assigned students comfortably.  
3. **Gender Matching**: A student can only be assigned to a dorm if the dorm's gender constraint matches the student's gender. This ensures that gender-specific dorm policies are respected.  

These constraints are linear in nature, as they involve sums of binary variables and comparisons with fixed values, without requiring any nonlinear relationships such as variable products or divisions.

## 3. Available Data  

### Database Schema  
```sql
-- Iteration 2 Database Schema
-- Objective: Added Assignment table for decision variables, updated data dictionary, and ensured all optimization mappings are complete.

CREATE TABLE DistanceMatrix (
  student_id INTEGER,
  dorm_id INTEGER,
  distance FLOAT
);

CREATE TABLE GenderInfo (
  student_id INTEGER,
  dorm_id INTEGER,
  gender STRING
);

CREATE TABLE Dorm (
  dorm_id INTEGER,
  student_capacity INTEGER,
  gender STRING
);

CREATE TABLE Assignment (
  student_id INTEGER,
  dorm_id INTEGER,
  assign BOOLEAN
);
```

### Data Dictionary  
The following tables and columns are used in the optimization problem, with their business purposes and optimization roles clearly defined:  

- **DistanceMatrix**:  
  - **student_id**: Unique identifier for a student, linking them to their home city.  
  - **dorm_id**: Unique identifier for a dorm, linking it to its location.  
  - **distance**: The distance from a student's home city to a dorm, used in the objective function to minimize total travel distance.  

- **GenderInfo**:  
  - **student_id**: Unique identifier for a student, linking them to their gender.  
  - **dorm_id**: Unique identifier for a dorm, linking it to its gender constraint.  
  - **gender**: The gender of a student or the gender constraint of a dorm, used to enforce gender matching.  

- **Dorm**:  
  - **dorm_id**: Unique identifier for a dorm, linking it to its capacity and gender constraint.  
  - **student_capacity**: The maximum number of students a dorm can accommodate, used in capacity constraints.  
  - **gender**: The gender constraint for a dorm, used to enforce gender matching.  

- **Assignment**:  
  - **student_id**: Unique identifier for a student, linking them to their assignment.  
  - **dorm_id**: Unique identifier for a dorm, linking it to its assignment.  
  - **assign**: A binary variable indicating whether a student is assigned to a dorm, used as the decision variable in the optimization.  

### Current Stored Values  
```sql
-- Iteration 2 Realistic Data
-- Generated by triple expert (business + data + optimization)
-- Values were determined based on realistic dormitory scenarios, considering typical student populations, dorm capacities, and geographical distances. Gender constraints and assignment logic were respected to ensure feasibility.

-- Realistic data for DistanceMatrix
INSERT INTO DistanceMatrix (student_id, dorm_id, distance) VALUES (1, 1, 12.5);
INSERT INTO DistanceMatrix (student_id, dorm_id, distance) VALUES (1, 2, 18.3);
INSERT INTO DistanceMatrix (student_id, dorm_id, distance) VALUES (2, 1, 15.0);
INSERT INTO DistanceMatrix (student_id, dorm_id, distance) VALUES (2, 2, 10.2);
INSERT INTO DistanceMatrix (student_id, dorm_id, distance) VALUES (3, 1, 20.1);
INSERT INTO DistanceMatrix (student_id, dorm_id, distance) VALUES (3, 2, 14.7);

-- Realistic data for GenderInfo
INSERT INTO GenderInfo (student_id, dorm_id, gender) VALUES (1, 1, 'Male');
INSERT INTO GenderInfo (student_id, dorm_id, gender) VALUES (2, 2, 'Female');
INSERT INTO GenderInfo (student_id, dorm_id, gender) VALUES (3, 1, 'Male');

-- Realistic data for Dorm
INSERT INTO Dorm (dorm_id, student_capacity, gender) VALUES (1, 100, 'Male');
INSERT INTO Dorm (dorm_id, student_capacity, gender) VALUES (2, 150, 'Female');

-- Realistic data for Assignment
INSERT INTO Assignment (student_id, dorm_id, assign) VALUES (1, 1, True);
INSERT INTO Assignment (student_id, dorm_id, assign) VALUES (2, 2, True);
INSERT INTO Assignment (student_id, dorm_id, assign) VALUES (3, 1, True);
```

## 4. Mathematical Optimization Formulation

#### Decision Variables
- \( x_{s,d} \): Binary decision variable indicating whether student \( s \) is assigned to dorm \( d \).  
  \( x_{s,d} \in \{0, 1\} \) for all \( s \in \text{Students}, d \in \text{Dorms} \).

#### Objective Function
Minimize the total distance traveled by all students to their assigned dorms:  
\[
\text{Minimize } Z = \sum_{s \in \text{Students}} \sum_{d \in \text{Dorms}} \text{DistanceMatrix.distance}_{s,d} \times x_{s,d}
\]

#### Constraints
1. **Single Assignment**: Each student must be assigned to exactly one dorm:  
\[
\sum_{d \in \text{Dorms}} x_{s,d} = 1 \quad \forall s \in \text{Students}
\]

2. **Dorm Capacity**: The number of students assigned to a dorm cannot exceed its capacity:  
\[
\sum_{s \in \text{Students}} x_{s,d} \leq \text{Dorm.student_capacity}_d \quad \forall d \in \text{Dorms}
\]

3. **Gender Matching**: A student can only be assigned to a dorm if the dorm's gender matches the student's gender:  
\[
x_{s,d} = 0 \quad \forall (s, d) \in \text{GenderInfo} \text{ where } \text{GenderInfo.gender}_{s,d} \neq \text{Dorm.gender}_d
\]

#### Data Source Verification
- **Objective Function Coefficients**:  
  \(\text{DistanceMatrix.distance}_{s,d}\) from the `DistanceMatrix` table.
  
- **Single Assignment Constraint**:  
  Ensures each student is assigned to exactly one dorm. No specific coefficients; uses binary variables \( x_{s,d} \).

- **Dorm Capacity Constraint**:  
  \(\text{Dorm.student_capacity}_d\) from the `Dorm` table.

- **Gender Matching Constraint**:  
  \(\text{GenderInfo.gender}_{s,d}\) from the `GenderInfo` table and \(\text{Dorm.gender}_d\) from the `Dorm` table.

This formulation is a complete, immediately solvable LINEAR mathematical model with all numerical coefficients derived from the provided data.

## 5. Gurobipy Implementation

```python
#!/usr/bin/env python3
"""
Gurobipy 12.0.2 Implementation for Dormitory Assignment Problem
"""

import gurobipy as gp
from gurobipy import GRB

def dorm_assignment_optimization():
    """Optimize dormitory assignment to minimize total distance traveled by students."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("dorm_assignment")
    
    # Example data (replace with actual database queries)
    students = [1, 2, 3]
    dorms = [1, 2]
    
    # DistanceMatrix data
    distance_matrix = {
        (1, 1): 12.5,
        (1, 2): 18.3,
        (2, 1): 15.0,
        (2, 2): 10.2,
        (3, 1): 20.1,
        (3, 2): 14.7
    }
    
    # GenderInfo data
    gender_info = {
        (1, 1): 'Male',
        (2, 2): 'Female',
        (3, 1): 'Male'
    }
    
    # Dorm data
    dorm_capacity = {
        1: 100,
        2: 150
    }
    
    dorm_gender = {
        1: 'Male',
        2: 'Female'
    }
    
    # CRITICAL: Validate array lengths before loops
    assert len(students) > 0, "No students provided"
    assert len(dorms) > 0, "No dorms provided"
    
    # 2. VARIABLES
    # Binary decision variables: x[s, d] = 1 if student s is assigned to dorm d
    x = model.addVars(students, dorms, vtype=GRB.BINARY, name="x")
    
    # 3. OBJECTIVE FUNCTION
    # Minimize total distance traveled by all students
    model.setObjective(gp.quicksum(distance_matrix[s, d] * x[s, d] for s in students for d in dorms), GRB.MINIMIZE)
    
    # 4. CONSTRAINTS
    
    # Single Assignment: Each student must be assigned to exactly one dorm
    for s in students:
        model.addConstr(gp.quicksum(x[s, d] for d in dorms) == 1, name=f"single_assignment_{s}")
    
    # Dorm Capacity: Number of students assigned to a dorm cannot exceed its capacity
    for d in dorms:
        model.addConstr(gp.quicksum(x[s, d] for s in students) <= dorm_capacity[d], name=f"capacity_{d}")
    
    # Gender Matching: A student can only be assigned to a dorm if the dorm's gender matches the student's gender
    for s in students:
        for d in dorms:
            if (s, d) in gender_info and gender_info[s, d] != dorm_gender[d]:
                model.addConstr(x[s, d] == 0, name=f"gender_matching_{s}_{d}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for s in students:
            for d in dorms:
                if x[s, d].x > 0.5:
                    print(f"Student {s} assigned to Dorm {d}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
if __name__ == "__main__":
    dorm_assignment_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 37.4
**Execution Time**: 0.18 seconds
**Reliability**: high
**Analysis**: Gurobipy found an optimal solution with the lowest execution time, indicating high efficiency and reliability.

## 6. DOCplex Implementation

```python
#!/usr/bin/env python3
"""
DOCPLEX implementation for dormitory assignment problem
"""

from docplex.mp.model import Model

def dorm_assignment_optimization():
    """Optimize dormitory assignments to minimize total distance traveled by students."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="dorm_assignment")
    
    # Sample data from the problem description
    students = [1, 2, 3]
    dorms = [1, 2]
    
    # DistanceMatrix data
    distance_matrix = {
        (1, 1): 12.5,
        (1, 2): 18.3,
        (2, 1): 15.0,
        (2, 2): 10.2,
        (3, 1): 20.1,
        (3, 2): 14.7
    }
    
    # GenderInfo data
    gender_info = {
        (1, 1): 'Male',
        (2, 2): 'Female',
        (3, 1): 'Male'
    }
    
    # Dorm data
    dorm_capacity = {
        1: 100,
        2: 150
    }
    
    dorm_gender = {
        1: 'Male',
        2: 'Female'
    }
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(students) == 3, "Students array length mismatch"
    assert len(dorms) == 2, "Dorms array length mismatch"
    
    # 2. VARIABLES
    # Binary decision variables: x[s, d] = 1 if student s is assigned to dorm d
    x = {(s, d): mdl.binary_var(name=f"x_{s}_{d}") for s in students for d in dorms}
    
    # 3. OBJECTIVE FUNCTION
    # Minimize total distance traveled by all students
    objective = mdl.sum(distance_matrix[(s, d)] * x[(s, d)] for s in students for d in dorms)
    mdl.minimize(objective)
    
    # 4. CONSTRAINTS
    
    # Single Assignment: Each student must be assigned to exactly one dorm
    for s in students:
        mdl.add_constraint(mdl.sum(x[(s, d)] for d in dorms) == 1, ctname=f"single_assignment_{s}")
    
    # Dorm Capacity: The number of students assigned to a dorm cannot exceed its capacity
    for d in dorms:
        mdl.add_constraint(mdl.sum(x[(s, d)] for s in students) <= dorm_capacity[d], ctname=f"capacity_{d}")
    
    # Gender Matching: A student can only be assigned to a dorm if the dorm's gender matches the student's gender
    for s in students:
        for d in dorms:
            if (s, d) in gender_info and gender_info[(s, d)] != dorm_gender[d]:
                mdl.add_constraint(x[(s, d)] == 0, ctname=f"gender_matching_{s}_{d}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for s in students:
            for d in dorms:
                if solution.get_value(x[(s, d)]) > 0.5:
                    print(f"Student {s} assigned to Dorm {d}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

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

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 37.4
**Execution Time**: 1.13 seconds
**Reliability**: medium
**Analysis**: DOCplex also found an optimal solution but took significantly longer than Gurobipy, suggesting lower efficiency.

## 7. Pyomo Implementation

```python
# Complete PYOMO implementation

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

def dorm_assignment_optimization():
    """Optimize dorm assignment to minimize total distance traveled by students."""
    
    # 1. MODEL CREATION
    model = pyo.ConcreteModel()
    
    # 2. DATA SETUP
    # Example data from the provided SQL inserts
    students = [1, 2, 3]
    dorms = [1, 2]
    
    distance_matrix = {
        (1, 1): 12.5,
        (1, 2): 18.3,
        (2, 1): 15.0,
        (2, 2): 10.2,
        (3, 1): 20.1,
        (3, 2): 14.7
    }
    
    gender_info = {
        (1, 1): 'Male',
        (2, 2): 'Female',
        (3, 1): 'Male'
    }
    
    dorm_capacity = {
        1: 100,
        2: 150
    }
    
    dorm_gender = {
        1: 'Male',
        2: 'Female'
    }
    
    # CRITICAL: Validate array lengths before indexing
    assert len(students) == 3, "Student array length mismatch"
    assert len(dorms) == 2, "Dorm array length mismatch"
    
    # 3. SETS (Pyomo way to define indices)
    model.Students = pyo.Set(initialize=students)
    model.Dorms = pyo.Set(initialize=dorms)
    
    # 4. PARAMETERS (data containers)
    model.DistanceMatrix = pyo.Param(model.Students, model.Dorms, initialize=distance_matrix)
    model.GenderInfo = pyo.Param(model.Students, model.Dorms, initialize=gender_info)
    model.DormCapacity = pyo.Param(model.Dorms, initialize=dorm_capacity)
    model.DormGender = pyo.Param(model.Dorms, initialize=dorm_gender)
    
    # 5. VARIABLES
    model.Assign = pyo.Var(model.Students, model.Dorms, within=pyo.Binary)
    
    # 6. OBJECTIVE FUNCTION
    def obj_rule(model):
        return sum(model.DistanceMatrix[s, d] * model.Assign[s, d] for s in model.Students for d in model.Dorms)
    model.objective = pyo.Objective(rule=obj_rule, sense=pyo.minimize)
    
    # 7. CONSTRAINTS - CORRECT SYNTAX PATTERNS
    
    # Single Assignment Constraint
    def single_assignment_rule(model, s):
        return sum(model.Assign[s, d] for d in model.Dorms) == 1
    model.single_assignment = pyo.Constraint(model.Students, rule=single_assignment_rule)
    
    # Dorm Capacity Constraint
    def dorm_capacity_rule(model, d):
        return sum(model.Assign[s, d] for s in model.Students) <= model.DormCapacity[d]
    model.dorm_capacity = pyo.Constraint(model.Dorms, rule=dorm_capacity_rule)
    
    # Gender Matching Constraint
    def gender_matching_rule(model, s, d):
        if (s, d) in model.GenderInfo and model.GenderInfo[s, d] != model.DormGender[d]:
            return model.Assign[s, d] == 0
        else:
            return pyo.Constraint.Skip
    model.gender_matching = pyo.Constraint(model.Students, model.Dorms, rule=gender_matching_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("\nAssignment values:")
        for s in model.Students:
            for d in model.Dorms:
                if pyo.value(model.Assign[s, d]) > 0.5:  # Only print assignments
                    print(f"Student {s} assigned to Dorm {d}")
        
    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__":
    dorm_assignment_optimization()
```

### Execution Results
**Status**: OPTIMAL
**Optimal Value**: 37.4
**Execution Time**: 1.17 seconds
**Reliability**: medium
**Analysis**: Pyomo found an optimal solution but had the longest execution time, indicating lower efficiency compared to Gurobipy.

## 8. Cross-Solver Analysis and Final Recommendation

### Solver Results Comparison

| Solver | Status | Optimal Value | Execution Time | Decision Variables | Retry Attempt |
|--------|--------|---------------|----------------|-------------------|---------------|
| Gurobipy | OPTIMAL | 37.40 | 0.18s | N/A | N/A |
| Docplex | OPTIMAL | 37.40 | 1.13s | N/A | N/A |
| Pyomo | OPTIMAL | 37.40 | 1.17s | N/A | N/A |

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

### Final Recommendation
**Recommended Optimal Value**: 37.4
**Confidence Level**: HIGH
**Preferred Solver(s)**: gurobipy
**Reasoning**: Gurobipy is recommended due to its high reliability and significantly faster execution time compared to DOCplex and Pyomo.

### Business Interpretation
**Overall Strategy**: The optimal solution minimizes the total distance traveled by all students to their assigned dorms, ensuring efficient resource allocation and student satisfaction.
**Objective Value Meaning**: The optimal objective value of 37.4 represents the minimized total distance traveled by all students to their assigned dorms.
**Resource Allocation Summary**: Students should be assigned to dorms in a way that minimizes total travel distance while respecting dorm capacities and gender matching constraints.
**Implementation Recommendations**: Implement the assignment plan derived from the optimal solution, ensuring all constraints are met and students are informed of their dorm assignments promptly.