-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathorar.py
757 lines (595 loc) · 30.6 KB
/
orar.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
import itertools
import sys
from copy import deepcopy, copy
import re
from itertools import product
import utils
#import Problem
import random
import itertools
import yaml
import collections
import check_constraints
# filename = f'inputs/orar_mic_exact.yaml'
# timetable_specs = utils.read_yaml_file(filename)
# ------------- Room, Teacher, Class, SchedulerTimeTable
class Room:
def __init__(self, name):
self.name = name
self.capacity = self.get_capacity()
self.classes = self.get_classes()
def get_capacity(self):
if self.name in timetable_specs['Sali']:
return timetable_specs['Sali'][self.name]['Capacitate']
def get_classes(self):
if self.name in timetable_specs['Sali']:
return timetable_specs['Sali'][self.name]['Materii']
class Class:
def __init__(self, name):
self.name = name
self.nr_students = self.get_nr_students()
self.class_teachers = self.get_teachers_for_class()
self.class_rooms = self.get_class_rooms()
def get_nr_students(self):
nr = timetable_specs['Materii'].get(self.name)
return nr
def get_teachers_for_class(self):
teachers = []
for teacher, details in timetable_specs['Profesori'].items():
if self.name in details['Materii']:
teachers.append(teacher)
result = []
for elem in teachers:
teacher_class = Teacher(elem)
result.append(teacher_class)
return result
def get_class_rooms(self):
class_rooms = []
for class_room, details in timetable_specs['Sali'].items():
if self.name in details['Materii']:
class_rooms.append(class_room)
result = []
for elem in class_rooms:
res = Room(elem)
result.append(res)
return result
class Teacher:
def __init__(self, name):
self.name = name
self.classes = self.get_classes_of_teacher()
self.constraints_list = self.constraints()
def get_classes_of_teacher(self):
classes = []
for teacher, details in timetable_specs['Profesori'].items():
if self.name == teacher:
classes = details['Materii']
break
return classes
def constraints(self):
soft_constraints = []
if self.name in timetable_specs['Profesori']:
soft_constraints = timetable_specs['Profesori'][self.name]['Constrangeri']
return soft_constraints
class SchedulerTimeTable:
def __init__(self):
self.days = timetable_specs['Zile']
self.hours = timetable_specs['Intervale']
self.pairs_intervals = self.get_intervals()
def get_intervals(self):
intervals_list = [(day, interval) for day in self.days for interval in self.hours]
return intervals_list
# ----------------------- Class Schedule
class ClassSchedule:
def __init__(self):
self.classes = self.get_classes()
self.all_Constraints = self.get_list_constraints_correct_form(self.get_list_constraints())
self.timetable = SchedulerTimeTable()
self.teachers_freq = self.get_teachers_freq_simple()
def get_classes(self):
result = []
for class_name in timetable_specs['Materii'].items():
elem = Class(class_name[0])
result.append(elem)
return result
def build_teacher_schedule_map(self, schedule):
teacher_schedule_map = {}
for entry in schedule:
key = (entry['teacher'], entry['day'])
if key not in teacher_schedule_map:
teacher_schedule_map[key] = []
teacher_schedule_map[key].append(entry['time'])
return teacher_schedule_map
def get_teachers_freq(self):
teachers_freq = {}
for class_obj in self.classes:
for teacher in class_obj.class_teachers:
teachers_freq[teacher.name] = 7
return teachers_freq
def get_teachers_freq_simple(self):
teachers_freq = {}
for class_obj in self.classes:
for teacher in class_obj.class_teachers:
teachers_freq[teacher.name] = 0
return teachers_freq
def get_list_constraints(self):
soft_constraints = {}
for class_obj in self.classes:
for teacher in class_obj.class_teachers:
aux = teacher.constraints_list
soft_constraints[teacher.name] = {'negative': [], 'positive': []}
for elem in aux:
if '-' in elem:
if elem.startswith('!'):
start, end = map(int, elem[1:].split('-'))
soft_constraints[teacher.name]['negative'].append(f'({start}, {end})')
else:
start, end = map(int, elem.split('-'))
soft_constraints[teacher.name]['positive'].append(f'({start}, {end})')
else:
if elem.startswith('!'):
soft_constraints[teacher.name]['negative'].append(elem[1:])
else:
soft_constraints[teacher.name]['positive'].append(elem)
return soft_constraints
def get_list_constraints_correct_form(self, soft_constraints):
# (8, 14) => (8, 10), (10, 12), (12, 14)
for teacher, constraints in soft_constraints.items():
for constraint_type, intervals in constraints.items():
for interval in intervals[:]:
if interval.startswith('(') and interval.endswith(')'):
start, end = map(int, interval[1:-1].split(','))
if end - start > 2:
new_intervals = [(x, x + 2) for x in range(start, end, 2)]
intervals.remove(interval)
intervals.extend([f'({interv[0]}, {interv[1]})' for interv in new_intervals])
return soft_constraints
def helper_time_slots(self):
available_time_slots = {}
for class_obj in self.classes:
for day, hour in itertools.product(self.timetable.days, self.timetable.hours):
if (day, hour) not in available_time_slots:
available_time_slots[(day, hour)] = {'classrooms': set(), 'teachers': set(), 'subjects': set()}
room_names = [room.name for room in class_obj.class_rooms]
teacher_names = [teacher.name for teacher in class_obj.class_teachers]
available_time_slots[(day, hour)]['classrooms'].update(room_names)
available_time_slots[(day, hour)]['teachers'].update(teacher_names)
available_time_slots[(day, hour)]['subjects'].add(class_obj.name)
return available_time_slots
def get_teachers_names_for_a_class(self, class_obj):
teacher_names_for_class = {teacher.name for teacher in class_obj.class_teachers if
class_obj.name in teacher.classes}
return teacher_names_for_class
def hard_schedule_hc(self):
# la fel precum hard_schedule doar ca intoarce si copy_available_slots (pt hill climbing clasic)
schedule = []
self.classes = self.get_classes()
self.teachers_freq = self.get_teachers_freq_simple()
self.available_time_slots = self.helper_time_slots()
sorted_classes = sorted(self.classes, key=lambda x: len(x.class_rooms))
for class_obj in sorted_classes:
nr_all_students = class_obj.nr_students
num_intervals_needed = -(-nr_all_students // min(room.capacity for room in class_obj.class_rooms))
intervals_counter = 0
room_classes_for_class = {room.name for room in class_obj.class_rooms if
class_obj.name in room.get_classes()}
teacher_names_for_class = {teacher.name for teacher in class_obj.class_teachers if
class_obj.name in teacher.classes}
while intervals_counter < num_intervals_needed:
# slot timp disponibil
if nr_all_students <= 0:
intervals_counter = num_intervals_needed
continue
day, interval = random.choice(list(self.available_time_slots.keys()))
infos = self.available_time_slots[(day, interval)]
if class_obj.name not in infos['subjects']:
continue
chosen_room_name = random.choice(list(room_classes_for_class))
if chosen_room_name not in infos['classrooms']:
continue
for room in class_obj.class_rooms:
if room.name == chosen_room_name:
chosen_room_capacity = room.capacity
break
if chosen_room_capacity is None:
break
# profesori disponibili
chosen_teacher = random.choice(list(teacher_names_for_class))
if chosen_teacher not in infos['teachers']:
continue
if self.teachers_freq[chosen_teacher] >= 7:
continue
schedule.append(
{'day': day, 'time': interval, 'room': chosen_room_name, 'teacher': chosen_teacher,
'class': class_obj.name})
nr_all_students -= chosen_room_capacity
self.teachers_freq[chosen_teacher] += 1
infos['teachers'].remove(chosen_teacher)
infos['classrooms'].remove(chosen_room_name)
intervals_counter += 1
copy_available_slots = deepcopy(self.available_time_slots)
return schedule, copy_available_slots
def hard_schedule(self):
schedule = []
self.classes = self.get_classes()
self.teachers_freq = self.get_teachers_freq_simple()
self.available_time_slots = self.helper_time_slots()
sorted_classes = sorted(self.classes, key=lambda x: len(x.class_rooms))
for class_obj in sorted_classes:
nr_all_students = class_obj.nr_students
num_intervals_needed = -(-nr_all_students // min(room.capacity for room in class_obj.class_rooms))
intervals_counter = 0
room_classes_for_class = {room.name for room in class_obj.class_rooms if
class_obj.name in room.get_classes()}
teacher_names_for_class = {teacher.name for teacher in class_obj.class_teachers if
class_obj.name in teacher.classes}
while intervals_counter < num_intervals_needed:
# slot timp disponibil
if nr_all_students <= 0:
intervals_counter = num_intervals_needed
continue
day, interval = random.choice(list(self.available_time_slots.keys()))
infos = self.available_time_slots[(day, interval)]
if class_obj.name not in infos['subjects']:
continue
chosen_room_name = random.choice(list(room_classes_for_class))
if chosen_room_name not in infos['classrooms']:
continue
for room in class_obj.class_rooms:
if room.name == chosen_room_name:
chosen_room_capacity = room.capacity
break
if chosen_room_capacity is None:
break
# profesori disponibili
chosen_teacher = random.choice(list(teacher_names_for_class))
if chosen_teacher not in infos['teachers']:
continue
if self.teachers_freq[chosen_teacher] >= 7:
continue
schedule.append(
{'day': day, 'time': interval, 'room': chosen_room_name, 'teacher': chosen_teacher,
'class': class_obj.name})
nr_all_students -= chosen_room_capacity
self.teachers_freq[chosen_teacher] += 1
infos['teachers'].remove(chosen_teacher)
infos['classrooms'].remove(chosen_room_name)
intervals_counter += 1
return schedule
def format_for_pretty_print(self, schedule_list):
schedule_dict = {}
all_rooms = set()
for appointment in schedule_list:
try:
all_rooms.add(appointment['room'])
except TypeError:
print('\n exceptia: ')
print(appointment)
print(appointment['room'])
for day in self.timetable.days:
schedule_dict[day] = {}
for time in self.timetable.hours:
time_tuple = tuple(map(int, time.strip("()").split(",")))
schedule_dict[day][time_tuple] = {}
for room in all_rooms:
schedule_dict[day][time_tuple][room] = None
for appointment in schedule_list:
day = appointment['day']
time = appointment['time']
#time = tuple(map(int, time.strip().strip("()").split(",")))
time = tuple(map(int, time.strip("()").split(",")))
room = appointment['room']
teacher, subject = appointment['teacher'], appointment['class']
if teacher and subject:
schedule_dict[day][time][room] = (teacher, subject)
return schedule_dict
def crossed_neg_constraints(self, constraints_dict):
transformed_dict = {}
for name, info in constraints_dict.items():
data = info[0]
zi = [data[0]] if data[0] is not None else []
ora = [data[1]] if data[1] is not None else []
transformed_dict[(name, info[1])] = {'zi': zi, 'ora': ora}
return transformed_dict
def get_entry(self, data, day, time_interval, teacher_name):
for entry in data:
if entry['day'] == day and entry['time'] == time_interval and entry['teacher'] == teacher_name:
return entry
return None
def good_combos(self, alternative_bune):
zile_bune = []
ore_bune = []
for element in alternative_bune:
if re.match(r'^[a-zA-Z]+$', element):
zile_bune.append(element)
elif re.match(r'^\(\d+,\s*\d+\)$', element):
ore_bune.append(element)
combinate = [(zi, ora) for zi, ora in product(zile_bune, ore_bune)]
return combinate
# ------------------- my min conflicts => ia o stare => o rezolva (solve_constraint)
def check_teacher_in_schedule(self, schedule, teacher_name, interval_ora, ziua):
teacher_schedule_map = self.build_teacher_schedule_map(schedule)
# for entry in schedule:
# if entry['teacher'] == teacher_name and entry['time'] == interval_ora and entry['day'] == ziua:
# return True
# return False
key = (teacher_name, ziua)
if key in teacher_schedule_map:
return interval_ora in teacher_schedule_map[key]
return False
def search_available_slots(self, combinate, current_entry, new_prof, hard_schedule,flag = 0):
while(len(combinate) != 0 and flag == 0):
for combinatie_buna in combinate:
time_slot = self.available_time_slots.get(combinatie_buna)
if time_slot is None:
combinate.remove(combinatie_buna)
continue
classrooms = time_slot['classrooms']
if len(classrooms) == 0:
combinate.remove(combinatie_buna)
continue
rooms = list(classrooms)
curr_room = current_entry['room']
if curr_room is None:
continue
if new_prof is None:
curr_teacher = current_entry['teacher']
update_freq = 0
else:
curr_teacher = new_prof
update_freq = 1
if curr_room in rooms and curr_teacher in time_slot['teachers']:
if self.check_teacher_in_schedule(hard_schedule, curr_teacher, combinatie_buna[1], combinatie_buna[0]) is False:
current_entry['day'] = combinatie_buna[0]
current_entry['time'] = combinatie_buna[1]
current_entry['teacher'] = curr_teacher
info = self.available_time_slots[combinatie_buna]
info['classrooms'].remove(curr_room)
info['teachers'].remove(curr_teacher)
combinate.remove(combinatie_buna)
flag = 1
if update_freq == 1:
self.teachers_freq[curr_teacher] += 1
else:
combinate.remove(combinatie_buna)
continue
return flag
def solve_constraint(self, hard_schedule, soft_constraint):
soft_schedule = deepcopy(hard_schedule)
flag = 0 # nu am rezolvat constrangerea
teacher = soft_constraint
teacher_nume = teacher[0][0]
teacher_interval_curent = teacher[0][1]
teacher_zi = teacher_interval_curent[0]
teacher_ora = teacher_interval_curent[1]
current_entry = self.get_entry(soft_schedule, teacher_zi, teacher_ora, teacher_nume)
if current_entry is None:
return None
materia = current_entry['class']
class_ob = Class(materia)
alternative_bune = self.all_Constraints[teacher_nume]['positive']
combinate = self.good_combos(alternative_bune)
if self.search_available_slots(combinate, current_entry, None, hard_schedule, flag) == 1:
return soft_schedule
if len(combinate) == 0 and flag == 0:
# incerc switch cu un prof random
# tin cont de teacher_freq
profi_freqs = self.teachers_freq
profesori_ord = sorted(profi_freqs, key=lambda x: profi_freqs[x])
for new_prof in profesori_ord:
if new_prof == teacher_nume:
continue
profesori_care_predau_materia = self.get_teachers_names_for_a_class(class_ob)
if new_prof not in profesori_care_predau_materia or self.teachers_freq[new_prof] >= 7:
continue
new_prof_constraints = self.all_Constraints[new_prof]
positive_constraints = new_prof_constraints['positive']
if teacher_zi in positive_constraints and teacher_ora in positive_constraints:
# am gasit un inlocuitor
info = self.available_time_slots[teacher_interval_curent]
# adaug new_prof in sala, dar verific suplimentar din nou sa nu aiba deja ora in acel interval
if self.check_teacher_in_schedule(hard_schedule, new_prof, teacher_ora, teacher_zi) is False:
if new_prof in info['teachers']:
info['teachers'].remove(new_prof) # ???
self.teachers_freq[new_prof] += 1
current_entry['teacher'] = new_prof
info['teachers'].add(teacher_nume)
self.teachers_freq[teacher_nume] -= 1
return soft_schedule
else:
continue
# am SALA, PROF --> caut un slot liber care sa fie in preferintele lui
else:
combos = self.good_combos(positive_constraints)
if self.search_available_slots(combos, current_entry, new_prof, hard_schedule, flag) == 1:
return soft_schedule
return soft_schedule
def next_state_csp(self, current_state):
current_pretty = classSchedule.format_for_pretty_print(current_state)
current_constraints_nr, current_dict = check_constraints.my_optional_constraints_checker(
current_pretty,
timetable_specs)
hards, _ = check_constraints.my_check_mandatory_constraints(current_pretty, timetable_specs)
if hards != 0:
# print(str(i) + " " + str(j))
#print("constrangere hard incalcata la hard_schedule!!!!!!!")
return None, None, None, None, None, None
current_constraints = classSchedule.crossed_neg_constraints(current_dict)
current_constraints_list = list(current_constraints.items())
random_constraint = random.choice(current_constraints_list)
new_succ = self.solve_constraint(current_state, random_constraint)
new_succ_pretty = classSchedule.format_for_pretty_print(new_succ)
succ_nr_constraints, constraints_dict = check_constraints.my_optional_constraints_checker(
new_succ_pretty, timetable_specs)
succ_mandatory_cons, _ = check_constraints.my_check_mandatory_constraints(new_succ_pretty,
timetable_specs)
if succ_mandatory_cons != 0:
return None, None, None, None, None, None
return succ_nr_constraints, current_constraints_nr, succ_mandatory_cons, new_succ, new_succ_pretty, current_constraints_list
def my_csp(self, max_iters = 50, min_iters = 25):
new_schedule = None
best_options = list()
for i in range(max_iters):
current_state = self.hard_schedule()
for j in range(max_iters):
# ----------------- next_states:
succ_nr_constraints, current_constraints_nr, succ_mandatory_cons, new_succ, new_succ_pretty, current_constraints_list = self.next_state_csp(current_state)
# ----------------- next_states
if succ_nr_constraints is None:
break
if succ_nr_constraints <= current_constraints_nr:
current_state = new_succ
if succ_nr_constraints == 0 and succ_mandatory_cons == 0:
#print('BINGO')
new_schedule = new_succ_pretty
return new_schedule, 0
if succ_nr_constraints <= 5 and succ_mandatory_cons == 0:
best_options.append((new_succ, current_constraints_list, succ_nr_constraints))
sorted_best_options = sorted(best_options, key=lambda x: x[2])
if len(sorted_best_options) > 0:
min = sorted_best_options[0][2]
min_constraint_options = [option for option in sorted_best_options if option[2] == min]
hards = 0
if len(sorted_best_options) > 0:
# am orare cu mai putin de 5 constrangeri
for elem in min_constraint_options:
if hards == 0:
new_current_best = elem
best_optionals = elem[2]
#print("Nr cel mai mic de constrangeri: " + str(elem[2]))
for k in range(min_iters):
constrangere_lista = new_current_best[1]
if len(constrangere_lista) == 0:
break
constraint = random.choice(constrangere_lista)
pretty_elem = classSchedule.format_for_pretty_print(new_current_best[0])
elem_opts, init_dict = check_constraints.my_optional_constraints_checker(pretty_elem,
timetable_specs)
new_succc = self.solve_constraint(new_current_best[0], constraint)
if new_succc is None:
hards = 0
break
new_succ_pretty = classSchedule.format_for_pretty_print(new_succc)
optionals, opt_dct = check_constraints.my_optional_constraints_checker(new_succ_pretty,
timetable_specs)
hards, _ = check_constraints.my_check_mandatory_constraints(new_succ_pretty, timetable_specs)
if hards != 0:
break
if hards == 0 and optionals == 0:
new_schedule = new_succ_pretty
return new_schedule, 0
if hards == 0 and optionals < elem_opts and best_optionals > optionals:
constrangere_lista.remove(constraint)
new_current_best = (new_succc, constrangere_lista, optionals)
if len(best_options) > 0:
new_schedule = classSchedule.format_for_pretty_print(min_constraint_options[0][0])
optionals = min_constraint_options[0][2]
return new_schedule, optionals
# ------------------- classic hill climbing ()
def generate_succesors_hc(self, hard_schedule, main_entry, current_slots):
current_materie = main_entry['class']
current_day = main_entry['day']
current_time = main_entry['time']
current_room = main_entry['room']
teacher_nume = main_entry['teacher']
class_ob = Class(current_materie)
materie_classrooms_objs = class_ob.class_rooms
materie_classrooms_names = list()
for classroom in materie_classrooms_objs:
materie_classrooms_names.append(classroom.name)
all_moves = list()
available_time_slots = deepcopy(current_slots)
for day, interval in available_time_slots:
info = available_time_slots[(day, interval)]
if teacher_nume in info['teachers']:
for classroom_name in materie_classrooms_names:
if classroom_name in info['classrooms']:
new_schedule = deepcopy(hard_schedule)
new_schedule_entry = self.get_entry(new_schedule, current_day, current_time, teacher_nume)
new_schedule_entry['day'] = day
new_schedule_entry['time'] = interval
pretty_elem = classSchedule.format_for_pretty_print(new_schedule)
obligatoriu, _ = check_constraints.my_check_mandatory_constraints(pretty_elem, timetable_specs)
if obligatoriu != 0:
continue
optional, _ = check_constraints.my_optional_constraints_checker(pretty_elem, timetable_specs)
copy_time_slots = deepcopy(available_time_slots)
info_copy = copy_time_slots[(day, interval)]
info_copy['classrooms'].remove(classroom_name)
info_copy['teachers'].remove(teacher_nume)
all_moves.append((new_schedule, optional, copy_time_slots))
return all_moves
def get_next_states_hc(self, current_state, current_pretty, current_slots):
hards, _ = check_constraints.my_check_mandatory_constraints(current_pretty, timetable_specs)
if hards != 0:
print("constrangere hard incalcata la hard_schedule!!!!!!!")
return None
all_succesors = list()
for schedule_entry in current_state:
elem_succesors = self.generate_succesors_hc(current_state, schedule_entry, current_slots)
all_succesors.extend(elem_succesors)
all_succesors_sorted = sorted(all_succesors, key=lambda x: x[1])
return all_succesors_sorted
def my_hill_climbing(self, max_iters = 10):
hard_schedule, available_slots = self.hard_schedule_hc()
best_choice = (float('inf'), hard_schedule, available_slots)
for i in range(max_iters):
if i == 0:
current_state = best_choice[1]
current_slots = best_choice[2]
else:
current_state, current_slots = self.hard_schedule_hc()
#print('-----restart----- ' + str(i))
for j in range(max_iters):
current_pretty = classSchedule.format_for_pretty_print(current_state)
current_constraints_nr, current_dict = check_constraints.my_optional_constraints_checker(current_pretty, timetable_specs)
next_states = self.get_next_states_hc(current_state, current_pretty, current_slots)
if next_states is None:
break
found_better = False
for state, state_constraints_nr, time_slots in next_states:
if state_constraints_nr >= current_constraints_nr:
break
if state_constraints_nr < current_constraints_nr:
found_better = True
current_constraints_nr = state_constraints_nr
if current_constraints_nr < best_choice[0]:
best_choice = (current_constraints_nr, state, time_slots)
current_state = state
#print('current_constraints_nr: ' + str(current_constraints_nr))
current_slots = time_slots
if not found_better:
break
return best_choice[1], best_choice[0]
if __name__ == '__main__':
nr_args = len(sys.argv)
if nr_args != 3:
# sys.argv[0] este numele fisierului
print('Numar invalid de args')
else:
algoritm = sys.argv[1]
fisier = sys.argv[2]
filename = f'fisier'
timetable_specs_input = utils.read_yaml_file(fisier)
if algoritm == 'csp':
timetable_specs = timetable_specs_input
classSchedule = ClassSchedule()
_state, constraints = classSchedule.my_csp()
print(utils.pretty_print_timetable_aux_zile(_state, fisier))
if algoritm == 'hc':
timetable_specs = timetable_specs_input
classSchedule = ClassSchedule()
state, my_hc_constraints = classSchedule.my_hill_climbing()
pretty_elem = classSchedule.format_for_pretty_print(state)
print(utils.pretty_print_timetable_aux_zile(pretty_elem, fisier))
# ------------------ csp
# classSchedule = ClassSchedule()
# min_state, nr_options = classSchedule.my_csp()
# print('min-conflicts alg: ' + str(nr_options))
# print(utils.pretty_print_timetable_aux_zile(min_state, filename))
#------------------ clasic hill climbing
# classSchedule = ClassSchedule()
# my_hc_state, my_hc_constraints = classSchedule.my_hill_climbing()
# pretty_elem = classSchedule.format_for_pretty_print(my_hc_state)
# print(utils.pretty_print_timetable_aux_zile(pretty_elem, filename))
# print('-----------------------------------------------\n')
# print("my_hc_state : " + str(my_hc_constraints))