# Complete DOCPLEX implementation - Retry Attempt 3

from docplex.mp.model import Model

def optimize_scientist_assignment():
    # 1. MODEL & DATA SETUP
    mdl = Model(name="scientist_assignment")
    
    # Data from the problem
    projects_hours = [120, 150, 100]
    project_max_hours = [200, 250, 180]
    
    # Number of scientists and projects
    n_scientists = 3  # Assuming 3 scientists based on the AssignedTo data
    n_projects = len(projects_hours)
    
    # CRITICAL: Validate array lengths to prevent IndexError
    assert len(projects_hours) == len(project_max_hours) == n_projects, "Array length mismatch"
    
    # Safe indexing range
    safe_range_scientists = range(n_scientists)
    safe_range_projects = range(n_projects)
    
    # 2. VARIABLES
    # Binary decision variables: x[i][j] = 1 if scientist i is assigned to project j, 0 otherwise
    x = {(i, j): mdl.binary_var(name=f"x_{i}_{j}") 
         for i in safe_range_scientists 
         for j in safe_range_projects}
    
    # 3. OBJECTIVE FUNCTION
    # Minimize the total project hours
    objective = mdl.sum(projects_hours[j] * x[(i, j)] 
                        for i in safe_range_scientists 
                        for j in safe_range_projects)
    mdl.minimize(objective)
    
    # 4. CONSTRAINTS
    
    # Scientist Assignment Constraint: Each scientist must be assigned to at least one project
    for i in safe_range_scientists:
        mdl.add_constraint(mdl.sum(x[(i, j)] for j in safe_range_projects) >= 1, 
                           ctname=f"scientist_assignment_{i}")
    
    # Project Hours Constraint: The total hours assigned to a project must not exceed its maximum allowed hours
    for j in safe_range_projects:
        mdl.add_constraint(mdl.sum(projects_hours[j] * x[(i, j)] for i in safe_range_scientists) <= project_max_hours[j], 
                           ctname=f"project_hours_{j}")
    
    # Project Assignment Constraint: Each project must have at least one scientist assigned to it
    for j in safe_range_projects:
        mdl.add_constraint(mdl.sum(x[(i, j)] for i in safe_range_scientists) >= 1, 
                           ctname=f"project_assignment_{j}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in safe_range_scientists:
            for j in safe_range_projects:
                if solution.get_value(x[(i, j)]) > 0:
                    print(f"Scientist {i} is assigned to Project {j}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")
    
    return mdl

# Execute the optimization
optimize_scientist_assignment()