# Complete GUROBIPY implementation - Retry Attempt 4

import gurobipy as gp
from gurobipy import GRB

def music_festival_optimization():
    # 1. MODEL & DATA SETUP
    model = gp.Model("music_festival_optimization")
    
    # Sample data
    songs = [0, 1, 2, 3, 4]  # Song indices
    weeks_on_top = [5, 10, 15, 3, 8]  # Weeks on top for each song
    artists = ['A', 'B', 'C', 'D', 'E']  # Artist for each song
    max_songs = 50
    max_songs_per_artist = 3
    min_artists = 10
    
    # CRITICAL: Validate array lengths before loops
    assert len(songs) == len(weeks_on_top) == len(artists), "Array length mismatch"
    
    # 2. VARIABLES
    x = {i: model.addVar(vtype=GRB.BINARY, name=f"x_{i}") for i in songs}
    y = {j: model.addVar(vtype=GRB.BINARY, name=f"y_{j}") for j in set(artists)}
    
    # 3. OBJECTIVE FUNCTION
    model.setObjective(gp.quicksum(weeks_on_top[i] * x[i] for i in songs), GRB.MAXIMIZE)
    
    # 4. CONSTRAINTS
    # Total Song Capacity
    model.addConstr(gp.quicksum(x[i] for i in songs) <= max_songs, name="total_song_capacity")
    
    # Maximum Songs Per Artist
    for j in set(artists):
        artist_songs = [i for i, a in zip(songs, artists) if a == j]
        model.addConstr(gp.quicksum(x[i] for i in artist_songs) <= max_songs_per_artist, name=f"max_songs_per_artist_{j}")
    
    # Minimum Number of Artists
    model.addConstr(gp.quicksum(y[j] for j in set(artists)) >= min_artists, name="min_artists")
    
    # Linking constraints for y_j
    for j in set(artists):
        artist_songs = [i for i, a in zip(songs, artists) if a == j]
        model.addConstr(y[j] <= gp.quicksum(x[i] for i in artist_songs), name=f"link_y_{j}_sum")
        for i in artist_songs:
            model.addConstr(y[j] >= x[i], name=f"link_y_{j}_song_{i}")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in songs:
            if x[i].x > 1e-6:
                print(f"Song {i} selected: {x[i].x}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Execute the optimization
music_festival_optimization()