# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_architect_assignments():
    """Optimize architect assignments to maximize bridge lengths and mill designs."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("architect_assignment")
    
    # Data from the problem context
    bridge_lengths = [150.0, 250.0, 180.0]  # Lengths of bridges
    mill_designed = [1, 1, 0]  # Binary indicators for mills designed
    max_projects_per_architect = 2  # Example capacity constraint for each architect
    
    n_bridges = len(bridge_lengths)
    n_mills = len(mill_designed)
    n_architects = 3  # Assuming 3 architects based on data
    
    # CRITICAL: Validate array lengths before loops
    assert len(bridge_lengths) == n_bridges, "Bridge lengths array length mismatch"
    assert len(mill_designed) == n_mills, "Mill designed array length mismatch"
    
    # 2. VARIABLES
    # Decision variables for bridge assignments
    x = model.addVars(n_architects, n_bridges, vtype=GRB.BINARY, name="x")
    
    # Decision variables for mill assignments
    y = model.addVars(n_architects, n_mills, vtype=GRB.BINARY, name="y")
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total output: sum of bridge lengths and number of mills designed
    model.setObjective(
        gp.quicksum(bridge_lengths[j] * x[i, j] for i in range(n_architects) for j in range(n_bridges)) +
        gp.quicksum(mill_designed[k] * y[i, k] for i in range(n_architects) for k in range(n_mills)),
        GRB.MAXIMIZE
    )
    
    # 4. CONSTRAINTS
    
    # Architect capacity constraint
    model.addConstrs(
        (gp.quicksum(x[i, j] for j in range(n_bridges)) + gp.quicksum(y[i, k] for k in range(n_mills)) <= max_projects_per_architect
         for i in range(n_architects)), name="architect_capacity"
    )
    
    # Bridge assignment constraint
    model.addConstrs(
        (gp.quicksum(x[i, j] for i in range(n_architects)) == 1 for j in range(n_bridges)), name="bridge_assignment"
    )
    
    # Mill assignment constraint
    model.addConstrs(
        (gp.quicksum(y[i, k] for i in range(n_architects)) == 1 for k in range(n_mills)), name="mill_assignment"
    )
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in range(n_architects):
            for j in range(n_bridges):
                if x[i, j].x > 1e-6:
                    print(f"x[{i},{j}] = {x[i, j].x:.3f}")
            for k in range(n_mills):
                if y[i, k].x > 1e-6:
                    print(f"y[{i},{k}] = {y[i, k].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_architect_assignments()