示例#1
0
def best_teaching_swap(schedule, courses, halls):
    """
    Finds the best possible swap of a pair of teachings (if it exists),
    returning a new schedule with these teachings swapped.
    """
    schedule_flat = functions.flatten_schedule(schedule)
    hall_count = len(halls)

    best_schedule = schedule
    best_score = score(schedule, courses)

    # initialise array for 'equivalent' schedules (having the same score)
    equiv_schedules = []

    # check all possible swaps of teachings
    for i, old_teaching in enumerate(schedule_flat):
        for m, new_teaching in enumerate(schedule_flat[i + 1:]):
            # position of new_teaching in schedule_flat
            j = m + i + 1

            # swap teachings
            if new_teaching:
                first_to_swap = classes.Teaching(new_teaching,
                                                 hall=halls[i % hall_count])
            else:
                first_to_swap = None

            if old_teaching:
                second_to_swap = classes.Teaching(old_teaching,
                                                  hall=halls[j % hall_count])
            else:
                second_to_swap = None

            # create new_schedule from schedule
            new_schedule = [None] * len(schedule)
            for k, row in enumerate(schedule):
                new_schedule[k] = list(row)
            new_schedule[i % hall_count][i // hall_count] = first_to_swap
            new_schedule[j % hall_count][j // hall_count] = second_to_swap

            # compute new score
            new_score = score(new_schedule, courses)
            if new_score > best_score:
                best_schedule, best_score = new_schedule, new_score

                # there are no 'equivalent' schedules anymore
                equiv_schedules = []

            # remember equivalent schedule
            elif new_score == best_score:
                equiv_schedules.append(new_schedule)

    # choose randomly between the equivalent schedules
    if equiv_schedules:
        best_schedule = random.choice(equiv_schedules)

    return best_schedule
def random_fill_teachings(courses):
    """
    Iterate over courses and make a list of teachings such that all seminar
    and practical groups are filled with students randomly.
    Returns a list of teachings.
    """
    teachings = []

    for course in courses:
        for _ in range(course.lectures):
            # assign students to lecture
            teachings.append(
                classes.Teaching("lecture", course, course.students))

        if course.seminars:
            # randomly fill seminars with students
            seminars = functions.fill_teaching_groups(course, "seminar")

            for seminar in seminars:
                teachings.append(seminar)

        if course.practicals:
            # randomly fill seminars with students
            practicals = functions.fill_teaching_groups(course, "practical")

            for practical in practicals:
                teachings.append(practical)

    return teachings
def fill_teaching_groups(course, _type):
    """
    Randomly fills all teachings of a course of a certain type with students,
    returning a list of filled teachings.
    """
    group_count = course.get_group_count(_type)
    students_per_group = [0] * group_count

    if _type == "seminar":
        capacity = course.s_cap
    else:
        capacity = course.p_cap

    # initialise list of teaching groups
    groups = [classes.Teaching(_type, course, [], ALPHABET[i]) \
            for i in range(group_count)]

    # insert each student into a random teaching group
    # provided that the group is not full yet
    for student in course.students:
        rand = random.randint(0, group_count - 1)

        while students_per_group[rand] == capacity:
            rand = random.randint(0, group_count - 1)
        groups[rand].students.append(student)
        students_per_group[rand] += 1

    return groups
def alphabetical(courses, halls):
    """
    Creates a schedule, filling all halls with
    teachings in the alphabetical order given by the file of courses.
    Returns a list of lists containing Teaching objects.
    """
    # create a list of teachings to fill alphabetically
    teachings = []

    for course in courses:
        for _ in range(course.lectures):
            # assign students to lecture
            teachings.append(
                classes.Teaching("lecture", course, course.students))

        if course.seminars:
            # assign students to seminar groups (in alphabetical order)
            for i in range(course.get_group_count("seminar")):
                group = course.students[i * course.s_cap:(i + 1) *
                                        course.s_cap]
                teachings.append(
                    classes.Teaching("seminar", course, group, ALPHABET[i]))

        if course.practicals:
            # assign students to practical groups (in alphabetical order)
            for i in range(course.get_group_count("practical")):
                group = course.students[i * course.p_cap:(i + 1) *
                                        course.p_cap]
                teachings.append(
                    classes.Teaching("practical", course, group, ALPHABET[i]))

    # create an empty schedule of the right dimensions
    schedule = [[None] * TIMESLOTS for _ in range(len(halls))]

    # keep track of how many timeslots have been filled for each hall
    tracker = [0] * len(halls)

    # fill schedule with teachings
    for teaching in teachings:
        greedy_fill(schedule, teaching, halls, tracker)

    return schedule
def random_teaching_swap(schedule, courses, halls):
    """
    Swaps two randomly selected teachings, returning the new schedule.
    """
    schedule_flat = functions.flatten_schedule(schedule)
    hall_count = len(halls)
    teaching_count = len(schedule_flat)

    # select random teachings
    i = random.randrange(teaching_count)
    j = random.randrange(teaching_count)

    # ensure teachings are different
    while i == j:
        j = random.randrange(teaching_count)

    first_teaching = schedule_flat[i]
    second_teaching = schedule_flat[j]

    # swap teachings
    if second_teaching:
        first_to_swap = classes.Teaching(second_teaching,
                                         hall=halls[i % hall_count])
    else:
        first_to_swap = None

    if first_teaching:
        second_to_swap = classes.Teaching(first_teaching,
                                          hall=halls[j % hall_count])
    else:
        second_to_swap = None

    # create new_schedule from schedule
    new_schedule = [None] * len(schedule)
    for k, row in enumerate(schedule):
        new_schedule[k] = list(row)

    # swap teachings
    new_schedule[i % hall_count][i // hall_count] = first_to_swap
    new_schedule[j % hall_count][j // hall_count] = second_to_swap

    return new_schedule
def flatten_schedule(schedule, new_teachings=False):
    """
    Flatten schedule in such a way that the teachings are sorted by timeslot.
    Schedule is a list of lists, where each list contains teachings
    scheduled at a certain hall. Returns flattened schedule.
    """
    schedule_flat = []
    for timeslot in zip(*schedule):
        for teaching in timeslot:

            if new_teachings:
                # create new Teaching object for teaching
                # if there exists a teaching at that timeslot
                if teaching:
                    schedule_flat.append(classes.Teaching(teaching))
                else:
                    schedule_flat.append(None)
            else:
                schedule_flat.append(teaching)

    return schedule_flat