def __init__(self, type, instance_data):

        self.instance_data = instance_data
        self.type = type

        # Penalty scores
        self.penalties = penalty(type)
Exemple #2
0
    def calculate_room_stability_cost(schedule, instance_data, day, period, c,
                                      room):

        penalty_instance = penalty(configs.cbctt_type)
        scheduled_rooms = []
        cost = 0
        # If some lectures of the course have already been scheduled and none of the
        # rooms where these lectures take place are available in the considered period,
        # the penalty for violating the room stability is added.
        for d in range(instance_data.days):
            for p in range(instance_data.periods_per_day):
                for r in range(instance_data.rooms_count):
                    if schedule[d][p][r] == c and r not in scheduled_rooms:
                        scheduled_rooms.append(r)
                        break

        available_room = False
        # if we want to calculate the cost for a certain room
        if room is not None and room in scheduled_rooms:
            available_room = True
        else:
            # if we want to calculate the cost comparing all rooms
            for r in range(instance_data.rooms_count):
                if r in scheduled_rooms and schedule[day][period][r] == -1:
                    available_room = True
                    break

        if not available_room:
            cost += penalty_instance.get_room_stability_penalty()

        # print("Room Stability Cost for day {}, period {}, course {}: {}".format(day, period, c, cost))
        return cost
Exemple #3
0
    def calculate_spread_days_cost(schedule, instance_data,
                                   period_lecture_assignments, day, course):

        penalty_instance = penalty(configs.cbctt_type)
        spread = 0
        cost = 0

        course_exists_in_day = alns_helpers.course_exists_in_day(
            schedule, instance_data, period_lecture_assignments, day, course)

        if not course_exists_in_day:
            # Whenever the required spread over days of the course is not reached and
            # no other lecture of the same course has been scheduled on the considered day,
            # the respective penalty is subtracted, since the solution will be improved.

            for d in range(instance_data.days):
                if d != day:

                    course_scheduled_in_day = alns_helpers.course_exists_in_day(
                        schedule, instance_data, period_lecture_assignments,
                        day, course)

                    if course_scheduled_in_day:
                        spread += 1

            if instance_data.courses_wdays[course] > spread:
                cost -= penalty_instance.get_min_wdays_penalty()

        # print("Minimum Spread Days Cost for day {}, course {}: {}".format(day, course , cost))
        return cost
Exemple #4
0
    def calculate_compactness_cost(schedule, instance_data,
                                   period_lecture_assignments, day, period, c):

        penalty_instance = penalty(configs.cbctt_type)
        cost = 0
        # if there is no adjacent slot that has scheduled any course from the same curriculum
        # means that if we place the lecture in the current slot it will be isolated
        # and hence it will increase the cost of curriculum compactness
        #
        # if there is a course from same curriculum in the neighbor period (adjacent slot)
        # means that if we place this current lecture at this slot,
        # and if the course from same curricula in the adjacent slot was isolated before,
        # will no longer be so, and we will reduce the cost of curriculum compactness
        # line below checks if same curriculum course in the adjacent period is isolated or not
        is_lecture_isolated = alns_helpers.is_lecture_isolated(
            schedule, instance_data, period_lecture_assignments, c, day,
            period)
        if is_lecture_isolated:
            cost += penalty_instance.get_isolated_lectures_penalty()
        else:
            if period == 0:
                is_neighbor_isolated = alns_helpers.is_lecture_isolated(
                    schedule, instance_data, period_lecture_assignments, c,
                    day, period + 1)
                if is_neighbor_isolated:
                    cost -= penalty_instance.get_isolated_lectures_penalty()

            elif period == instance_data.periods_per_day - 1:
                is_neighbor_isolated = alns_helpers.is_lecture_isolated(
                    schedule, instance_data, period_lecture_assignments, c,
                    day, period - 1)
                if is_neighbor_isolated:
                    cost -= penalty_instance.get_isolated_lectures_penalty()

            else:
                if alns_helpers.has_curriculum_neighbor(
                        schedule, instance_data, period_lecture_assignments, c,
                        day, period - 1):
                    is_left_neighbor_isolated = alns_helpers.is_lecture_isolated(
                        schedule, instance_data, period_lecture_assignments, c,
                        day, period - 1)
                    if is_left_neighbor_isolated:
                        cost -= penalty_instance.get_isolated_lectures_penalty(
                        )

                if alns_helpers.has_curriculum_neighbor(
                        schedule, instance_data, period_lecture_assignments, c,
                        day, period + 1):
                    is_right_neighbor_isolated = alns_helpers.is_lecture_isolated(
                        schedule, instance_data, period_lecture_assignments, c,
                        day, period + 1)
                    if is_right_neighbor_isolated:
                        cost -= penalty_instance.get_isolated_lectures_penalty(
                        )

        print("Compactness Cost for day {}, period {}, course{}".format(
            day, period, c))
        return cost
Exemple #5
0
    def calculate_spread_days_cost(schedule, instance_data,
                                   period_lecture_assignments, day, course):

        penalty_instance = penalty(configs.cbctt_type)
        spread = 0
        cost = 0

        # Whenever the required spread over days of the course is not reached and
        # no other lecture of the same course has been scheduled on the considered day,
        # the respective penalty is subtracted, since the solution will be improved.
        course_exists_in_considered_day = False
        for d in range(instance_data.days):
            course_scheduled_in_day = False
            # check if any lecture of this course is already assigned to this day
            # so we count it in the spread days cost
            period_assigned_courses = [
                x.course for x in period_lecture_assignments if x.day == d
            ]
            if course in period_assigned_courses:
                course_scheduled_in_day = True

            # if no lecture of the course is scheduled to this day during the period-lecture assignment stage
            # we check if any lecture of the course is scheduled in this day in the fixed schedule
            if not course_scheduled_in_day:
                for p in range(instance_data.periods_per_day):
                    for r in range(instance_data.rooms_count):
                        if schedule[d][p][r] == course:
                            course_scheduled_in_day = True
                            break

                    if course_scheduled_in_day:
                        break

            if course_scheduled_in_day:
                spread += 1
                if d == day:
                    course_exists_in_considered_day = True

        if instance_data.courses_wdays[
                course] > spread and not course_exists_in_considered_day:
            cost -= penalty_instance.get_min_wdays_penalty()

        print("Minimum Spread Days Cost for day {}, course {}: {}".format(
            day, course, cost))
        return cost
Exemple #6
0
    def calculate_room_capacity_cost(schedule, instance_data,
                                     unscheduled_lectures,
                                     period_lecture_assignments, day, period,
                                     course, lecture_period_heuristic):

        penalty_instance = penalty(configs.cbctt_type)
        cost = 0

        # if 2stage "best" heuristic applies
        # the capacity penalty is roughly estimated by assuming that
        # if the lecture has the xth most students of all courses that are assigned to the period in the part of the schedule that is under construction,
        # it will get the xth largest available room in the second stage.
        # The capacity penalty then corresponds to the excess number of students.

        if lecture_period_heuristic == "best":
            # print("2-stage Best Heuristic")

            courses_to_schedule = [
                x.course for x in period_lecture_assignments
                if x.day == day and x.period == period
            ]
            courses_to_schedule.append(course)
            courses_to_schedule.sort(
                key=lambda x: instance_data.courses_students[x], reverse=True)

            available_rooms = []
            for r in range(instance_data.rooms_count):
                if schedule[day][period][r] == -1:
                    available_rooms.append(instance_data.rooms[r])

            available_rooms.sort(key=lambda x: int(x.size), reverse=True)

            courses_to_schedule_length = len(courses_to_schedule)
            available_rooms_length = len(available_rooms)

            # in cases of backtracking when the period is not available due to the fact that there are no more available rooms
            # we will be evaluating which period results in more conflicts so we decide from which to remove courses
            # namely, when we come at this step we will already be having more courses we want to assign to the period
            # because we havent decided yet from which to remove, and if we want to evaluate this we suppose that we will remove courses
            # from this period, and we calculate the cost only by the difference of the course we want to schedule and the available rooms
            if (courses_to_schedule_length > available_rooms_length):
                cost += max(0, (instance_data.courses_students[course] -
                                int(available_rooms[0].size)))
            else:
                for i in range(courses_to_schedule_length):
                    cost += max(
                        0,
                        (instance_data.courses_students[courses_to_schedule[i]]
                         - int(available_rooms[i].size)))

            cost = cost * penalty_instance.get_room_capacity_penalty()

        # if 2stage "mean" heuristic applies
        # A reference utilization of the room capacities u is computed by dividing the sum of the number of students
        # of all lectures that have to be scheduled Σl by the sum of the capacities of all available rooms
        # Σr, i.e., u = Σl / Σr . Then a capacity limit is computed for each period individually as η · u ·Σp,
        # where Σp denotes the sum of the capacities of the available rooms in period p and η denotes
        # a parameter that controls the penalty-free number of students. The capacity penalty added to
        # the insertion cost corresponds to the number of students of the assigned lectures exceeding
        # the capacity limit of the considered period.
        elif lecture_period_heuristic == "mean":
            # print("2-stage Mean Heuristic")

            available_capacity = 0
            required_capacity = 0
            period_available_capacity = 0
            period_required_capacity = 0

            for l in unscheduled_lectures:
                required_capacity += instance_data.courses_students[l]

            for d in range(instance_data.days):
                for p in range(instance_data.periods_per_day):
                    for r in range(instance_data.rooms_count):
                        if schedule[d][p][r] == -1:
                            available_capacity += int(
                                instance_data.rooms[r].size)
                            if d == day and p == period:
                                period_available_capacity += int(
                                    instance_data.rooms[r].size)
                        else:
                            if d == day and p == period:
                                period_required_capacity += instance_data.courses_students[
                                    schedule[d][p][r]]

            # an extra of 40% more than average of capacity "utilization";
            # if more students are assigned, there will be penalty
            eta_param = 1.3

            # allowed percentage of covered capacity (without being penalized)
            cap_utilization = float(required_capacity) / available_capacity

            capacity_limit = cap_utilization * eta_param * period_available_capacity

            cost += max(
                float(0),
                min(
                    period_required_capacity +
                    instance_data.courses_students[course] - capacity_limit,
                    float(instance_data.courses_students[course])) *
                penalty_instance.get_room_capacity_penalty())

        # print("Room Capacity Cost for day {}, period {}, course {}: {}".format(day, period, course, cost))
        return cost