# Complete DOCPLEX implementation

from docplex.mp.model import Model

def optimize_teacher_course_assignment():
    """Optimize teacher assignments to courses to maximize expected grade improvement."""
    
    # 1. MODEL & DATA SETUP
    mdl = Model(name="course_teach")
    
    # Data from the problem statement
    courses = [101, 102, 103]
    teachers = [201, 202, 203]
    
    # Expected improvements from the grade_improvement table
    expected_improvements = {
        (101, 201): 0.8,
        (102, 202): 0.6,
        (103, 203): 0.7,
        (101, 202): 0.5,
        (102, 203): 0.4
    }
    
    # Validate data consistency
    assert all((course, teacher) in expected_improvements for course in courses for teacher in teachers), "Data inconsistency detected"
    
    # 2. VARIABLES
    # Binary decision variables for teacher-course assignments
    x = {(course, teacher): mdl.binary_var(name=f"x_{course}_{teacher}") for course in courses for teacher in teachers}
    
    # 3. OBJECTIVE FUNCTION
    # Maximize the total expected improvement in student grades
    objective = mdl.sum(expected_improvements[(course, teacher)] * x[(course, teacher)] for course in courses for teacher in teachers)
    mdl.maximize(objective)
    
    # 4. CONSTRAINTS
    
    # Each course can have at most one teacher assigned
    for course in courses:
        mdl.add_constraint(mdl.sum(x[(course, teacher)] for teacher in teachers) <= 1, ctname=f"course_{course}_limit")
    
    # Each teacher can only be assigned to one course
    for teacher in teachers:
        mdl.add_constraint(mdl.sum(x[(course, teacher)] for course in courses) <= 1, ctname=f"teacher_{teacher}_limit")
    
    # 5. SOLVING & RESULTS
    solution = mdl.solve()
    
    if solution:
        print(f"Optimal value: {solution.objective_value}")
        for course in courses:
            for teacher in teachers:
                if solution.get_value(x[(course, teacher)]) > 0.5:  # Binary variable threshold
                    print(f"Teacher {teacher} assigned to Course {course}")
    else:
        print("No solution found")
        print(f"Status: {mdl.solve_details.status}")

    return mdl

# Run the optimization
optimize_teacher_course_assignment()