def show_statistics(matrix, data, subjects_order, groups_empty_space, teachers_empty_space): """ Prints statistics. """ cost_hard = check_hard_constraints(matrix, data) if cost_hard == 0: print('Hard constraints satisfied: 100.00 %') else: print('Hard constraints NOT satisfied, cost: {}'.format(cost_hard)) print('Soft constraints satisfied: {:.02f} %\n'.format( subjects_order_cost(subjects_order))) empty_groups, max_empty_group, average_empty_groups = empty_space_groups_cost( groups_empty_space) print('TOTAL empty space for all GROUPS and all days: ', empty_groups) print('MAX empty space for GROUP in day: ', max_empty_group) print('AVERAGE empty space for GROUPS per week: {:.02f}\n'.format( average_empty_groups)) empty_teachers, max_empty_teacher, average_empty_teachers = empty_space_teachers_cost( teachers_empty_space) print('TOTAL empty space for all TEACHERS and all days: ', empty_teachers) print('MAX empty space for TEACHER in day: ', max_empty_teacher) print('AVERAGE empty space for TEACHERS per week: {:.02f}\n'.format( average_empty_teachers))
def write_solution_to_file(matrix, data, filled, filepath, groups_empty_space, teachers_empty_space, subjects_order): """ Writes statistics and schedule to file. """ f = open('solution_files/sol_' + filepath, 'w') f.write( '-------------------------- STATISTICS --------------------------\n') cost_hard = check_hard_constraints(matrix, data) if cost_hard == 0: f.write('\nHard constraints satisfied: 100.00 %\n') else: f.write('Hard constraints NOT satisfied, cost: {}\n'.format(cost_hard)) f.write('Soft constraints satisfied: {:.02f} %\n\n'.format( subjects_order_cost(subjects_order))) empty_groups, max_empty_group, average_empty_groups = empty_space_groups_cost( groups_empty_space) f.write('TOTAL empty space for all GROUPS and all days: {}\n'.format( empty_groups)) f.write('MAX empty space for GROUP in day: {}\n'.format(max_empty_group)) f.write('AVERAGE empty space for GROUPS per week: {:.02f}\n\n'.format( average_empty_groups)) empty_teachers, max_empty_teacher, average_empty_teachers = empty_space_teachers_cost( teachers_empty_space) f.write('TOTAL empty space for all TEACHERS and all days: {}\n'.format( empty_teachers)) f.write( 'MAX empty space for TEACHER in day: {}\n'.format(max_empty_teacher)) f.write('AVERAGE empty space for TEACHERS per week: {:.02f}\n\n'.format( average_empty_teachers)) # f_hour = free_hour(matrix) # if f_hour != -1: # f.write('Free term -> {}\n'.format(f_hour)) # else: # f.write('NO hours without classes.\n') groups_dict = {} for group_name, group_index in data.groups.items(): if group_index not in groups_dict: groups_dict[group_index] = group_name days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'] hours = [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] f.write( '\n--------------------------- SCHEDULE ---------------------------') for class_index, times in filled.items(): c = data.classes[class_index] groups = ' ' for g in c.groups: groups += groups_dict[g] + ', ' f.write('\n\nClass {}\n'.format(class_index)) f.write( 'Teacher: {} \nSubject: {} \nGroups:{} \nType: {} \nDuration: {} hour(s)' .format(c.teacher, c.subject, groups[:len(groups) - 2], c.type, c.duration)) room = str(data.classrooms[times[0][1]]) f.write('\nClassroom: {:2s}\nTime: {}'.format(room[:room.rfind('-')], days[times[0][0] // 12])) for time in times: f.write(' {}'.format(hours[time[0] % 12])) f.close()
def evolutionary_algorithm(matrix, data, free, filled, groups_empty_space, teachers_empty_space, subjects_order): """ Evolutionary algorithm that tires to find schedule such that hard constraints are satisfied. It uses (1+1) evolutionary strategy with Stifel's notation. """ n = 3 sigma = 2 run_times = 5 max_stagnation = 200 for run in range(run_times): print('Run {} | sigma = {}'.format(run + 1, sigma)) t = 0 stagnation = 0 cost_stats = 0 while stagnation < max_stagnation: # check if optimal solution is found loss_before, cost_classes, cost_teachers, cost_classrooms, cost_groups = hard_constraints_cost( matrix, data) if loss_before == 0 and check_hard_constraints(matrix, data) == 0: print('Found optimal solution: \n') show_timetable(matrix) break # sort classes by their loss, [(loss, class index)] costs_list = sorted(cost_classes.items(), key=itemgetter(1), reverse=True) # 10*n for i in range(len(costs_list) // 4): # mutate one to its ideal spot if random.uniform(0, 1) < sigma and costs_list[i][1] != 0: mutate_ideal_spot(matrix, data, costs_list[i][0], free, filled, groups_empty_space, teachers_empty_space, subjects_order) # else: # # exchange two who have the same duration # r = random.randrange(len(costs_list)) # c1 = data.classes[costs_list[i][0]] # c2 = data.classes[costs_list[r][0]] # if r != i and costs_list[r][1] != 0 and costs_list[i][1] != 0 and c1.duration == c2.duration: # exchange_two(matrix, filled, costs_list[i][0], costs_list[r][0]) loss_after, _, _, _, _ = hard_constraints_cost(matrix, data) if loss_after < loss_before: stagnation = 0 cost_stats += 1 else: stagnation += 1 t += 1 # Stifel for (1+1)-ES if t >= 10 * n and t % n == 0: s = cost_stats if s < 2 * n: sigma *= 0.85 else: sigma /= 0.85 cost_stats = 0 print( 'Number of iterations: {} \nCost: {} \nTeachers cost: {} | Groups cost: {} | Classrooms cost:' ' {}'.format(t, loss_after, cost_teachers, cost_groups, cost_classrooms))