# Complete DOCPLEX implementation - Retry Attempt 4

from docplex.mp.model import Model

def optimize_research_allocation():
    # 1. MODEL & DATA SETUP
    mdl = Model(name="research_allocation")
    
    # Data from Authorship table
    authorship_data = [
        (1, 101, 201, 1),
        (2, 102, 202, 2),
        (3, 103, 203, 3)
    ]
    
    # Extract unique sets
    A = list(set(authID for authID, _, _, _ in authorship_data))  # Researchers
    I = list(set(instID for _, instID, _, _ in authorship_data))  # Institutions
    P = list(set(paperID for _, _, paperID, _ in authorship_data))  # Papers
    
    # Weights based on authOrder
    weights = {(authID, paperID): 1.0 / authOrder for authID, _, paperID, authOrder in authorship_data}
    
    # Business configuration
    MaxResearchersPerInstitution = 2
    MaxPapersPerResearcher = 2
    
    # 2. VARIABLES
    x = mdl.binary_var_dict((a, i, p) for a in A for i in I for p in P, name="x")
    
    # 3. OBJECTIVE FUNCTION
    objective = mdl.sum(weights[a, p] * x[a, i, p] for a in A for i in I for p in P)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    
    # Maximum Researchers per Institution
    for i in I:
        mdl.add_constraint(mdl.sum(x[a, i, p] for a in A for p in P) <= MaxResearchersPerInstitution, ctname=f"max_researchers_{i}")
    
    # Maximum Papers per Researcher
    for a in A:
        mdl.add_constraint(mdl.sum(x[a, i, p] for i in I for p in P) <= MaxPapersPerResearcher, ctname=f"max_papers_{a}")
    
    # Single Assignment per Paper
    for p in P:
        mdl.add_constraint(mdl.sum(x[a, i, p] for a in A for i in I) == 1, ctname=f"single_assignment_{p}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for a in A:
            for i in I:
                for p in P:
                    if solution.get_value(x[a, i, p]) > 0.5:
                        print(f"Researcher {a} assigned to Institution {i} for Paper {p}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")

# Execute the optimization
optimize_research_allocation()