# Complete DOCPLEX implementation

from docplex.mp.model import Model

def optimize_architect_assignments():
    # 1. MODEL & DATA SETUP
    mdl = Model(name="architect_assignment")
    
    # Data from the problem context
    bridge_lengths = [150.0, 250.0, 180.0]  # Lengths of bridges
    mill_designed = [1, 1, 0]  # Binary indicator if mill is designed
    architect_capacity = [2, 2, 2]  # Maximum projects each architect can handle
    
    n_bridges = len(bridge_lengths)
    n_mills = len(mill_designed)
    n_architects = len(architect_capacity)
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert n_bridges == n_mills == n_architects, "Array length mismatch"
    safe_range = range(min(n_bridges, n_mills, n_architects))  # Safe indexing
    
    # 2. VARIABLES
    x = {(i, j): mdl.binary_var(name=f"x_{i}_{j}") for i in safe_range for j in safe_range}
    y = {(i, k): mdl.binary_var(name=f"y_{i}_{k}") for i in safe_range for k in safe_range}
    
    # 3. OBJECTIVE FUNCTION
    objective = mdl.sum(bridge_lengths[j] * x[i, j] for i in safe_range for j in safe_range) + \
                mdl.sum(mill_designed[k] * y[i, k] for i in safe_range for k in safe_range)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    
    # Architect Capacity Constraint
    for i in safe_range:
        mdl.add_constraint(mdl.sum(x[i, j] for j in safe_range) + mdl.sum(y[i, k] for k in safe_range) <= architect_capacity[i], ctname=f"capacity_{i}")
    
    # Bridge Assignment Constraint
    for j in safe_range:
        mdl.add_constraint(mdl.sum(x[i, j] for i in safe_range) == 1, ctname=f"bridge_assignment_{j}")
    
    # Mill Assignment Constraint
    for k in safe_range:
        mdl.add_constraint(mdl.sum(y[i, k] for i in safe_range) == 1, ctname=f"mill_assignment_{k}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_range:
            for j in safe_range:
                if solution.get_value(x[i, j]) > 1e-6:
                    print(f"x[{i},{j}] = {solution.get_value(x[i, j]):.3f}")
            for k in safe_range:
                if solution.get_value(y[i, k]) > 1e-6:
                    print(f"y[{i},{k}] = {solution.get_value(y[i, k]):.3f}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")

    return mdl

# Run the optimization
optimize_architect_assignments()