# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def decoration_competition_optimization():
    """Optimize member participation in decoration competition rounds to maximize rank points."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("decoration_competition")
    
    # Sample data based on the provided schema and realistic data
    rounds = [1, 2, 3]
    members = [101, 102, 103]
    
    # Objective coefficients (rank points) from ObjectiveCoefficients table
    rank_points = {
        (1, 101): 25.0,
        (2, 102): 30.0,
        (3, 103): 0.0,
        (1, 102): 20.0,
        (2, 101): 0.0
    }
    
    # Validate data lengths
    assert all(isinstance(rank_points[key], float) for key in rank_points), "Rank points data type mismatch"
    
    # 2. VARIABLES
    # Binary decision variables for participation
    x = model.addVars(rounds, members, vtype=GRB.BINARY, name="participation")
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total rank points
    model.setObjective(gp.quicksum(rank_points.get((i, j), 0) * x[i, j] for i in rounds for j in members), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    
    # Constraint: Each member can participate in a maximum of three rounds
    model.addConstrs((gp.quicksum(x[i, j] for i in rounds) <= 3 for j in members), name="max_rounds_per_member")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in rounds:
            for j in members:
                if x[i, j].x > 1e-6:
                    print(f"Member {j} participates in round {i}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
decoration_competition_optimization()