# Complete DOCPLEX implementation - Retry Attempt 4

from docplex.mp.model import Model

def restaurant_optimization():
    """Optimize student visits to restaurants for maximum satisfaction."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="restaurant_optimization")
    
    # Data from the problem statement
    restaurants = [1, 2, 3]
    students = [101, 102, 103]
    
    ratings = {1: 4.5, 2: 3.8, 3: 5.0}
    budgets = {101: 120, 102: 180, 103: 150}
    costs = {(101, 1): 12.0, (102, 2): 15.0, (103, 3): 20.0}
    
    # Validate data consistency
    assert len(ratings) == len(restaurants), "Ratings length mismatch"
    assert len(budgets) == len(students), "Budgets length mismatch"
    assert len(costs) == len(students) * len(restaurants), "Costs length mismatch"
    
    # Safe range for indexing
    safe_students = range(len(students))
    safe_restaurants = range(len(restaurants))
    
    # 2. VARIABLES
    # Decision variables: number of visits each student makes to each restaurant
    visits = {(i, j): mdl.integer_var(name=f"x_{i}_{j}", lb=0) for i in students for j in restaurants}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize total satisfaction score
    objective = mdl.sum(ratings[j] * visits[i, j] for i in students for j in restaurants)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    # Budget constraints for each student
    for i in students:
        mdl.add_constraint(mdl.sum(costs[i, j] * visits[i, j] for j in restaurants) <= budgets[i], ctname=f"budget_{i}")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for i in students:
            for j in restaurants:
                value = solution.get_value(visits[i, j])
                if value > 0:
                    print(f"Student {i} visits Restaurant {j}: {value} times")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")

# Run the optimization
restaurant_optimization()