-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprogram.py
459 lines (403 loc) · 15.6 KB
/
program.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
import copy
import math
import os
import random
import pandas as pd
fileDir = './test_dataset/' # Dataset Folder
courses = {} # All Courses
rooms = {} # All Rooms
studentcourse = {} # Students Assigned to courses
indstudentcourses = {} # Courses assigned to students
teachers = [] # All Teachers
studentnames = [] # All Students
days = 14 # Examination Period
coursesstudents = {} # Courses and students
# Coloring Functions
def prRed(skk): print("\033[91m {}\033[00m" .format(skk), end="")
def prGreen(skk): print("\033[92m {}\033[00m" .format(skk), end="")
def prYellow(skk): print("\033[93m {}\033[00m" .format(skk), end="")
def prLightPurple(skk): print("\033[94m {}\033[00m" .format(skk), end="")
def prPurple(skk): print("\033[95m {}\033[00m" .format(skk), end="")
def prCyan(skk): print("\033[96m {}\033[00m" .format(skk), end="")
def prLightGray(skk): print("\033[97m {}\033[00m" .format(skk), end="")
def prBlack(skk): print("\033[98m {}\033[00m" .format(skk), end="")
listOfHardConstraints = [
'1. An exam will be scheduled for each course.',
'2. A student is enrolled in at least 3 courses. A student cannot give more than 1 exam \
at a time.',
'3. Exam will not be held on weekends.',
'4. Each exam must be held between 9 am and 5 pm',
'5. Each exam must be invigilated by a teacher. A teacher cannot invigilate two \
exams at the same time.',
'6. A teacher cannot invigilate two exams in a row.'
]
listOfSoftConstraints = [
'1. All students and teachers shall be given a break on Friday from 1-2.',
'2. A student shall not give more than 1 exam consecutively.',
'3. If a student is enrolled in a MG course and a CS course, it is preferred that \
their MG course exam be held before their CS course exam.',
'4. Two hours of break in the week such that at least half the faculty is free in \
one slot and the rest of the faculty is free in the other slot so the faculty \
meetings shall be held in parts as they are now.'
]
# Class defined containing all information about individual exams
class Exam:
course = ''
room = []
teacher = []
time = ''
date = 0
def clear(): # function to clear screen
if os.name == 'nt':
_ = os.system('cls')
else:
_ = os.system('clear')
def importdata(): # Function to import data from files
global teachers
read_teachers = pd.read_csv(fileDir + 'teachers.csv')
teachers = list(read_teachers.iloc[:, 0])
global studentnames
read_students = pd.read_csv(fileDir + 'studentNames.csv')
studentnames = list(read_students.iloc[:, 0])
read_courses = pd.read_csv(fileDir + 'courses.csv')
course_codes = list(read_courses.iloc[:, 0])
course_names = list(read_courses.iloc[:, 1])
for i in range(len(course_codes)):
courses[course_codes[i]] = course_names[i]
read_rooms = pd.read_csv(fileDir + 'rooms.csv')
room_capacity = list(read_rooms.iloc[:, 1])
for i in range(len(room_capacity)):
rooms[i] = room_capacity[i]
read_studentcourses = pd.read_csv(fileDir + 'studentCourses.csv')
studentname = list(read_studentcourses.iloc[:, 1])
course_code = list(read_studentcourses.iloc[:, 2])
for i in range(len(studentname)):
studentcourse[i] = (studentname[i], course_code[i])
def createtable(sol): # function converts the given schedule dict into a 2d list
table = []
for i in sol.keys():
if len(sol[i].room) > 1:
for j in range(len(sol[i].room)):
ex = [i, sol[i].room[j], sol[i].teacher[j], sol[i].date, sol[i].time]
table.append(ex)
else:
ex = [i, sol[i].room[0], sol[i].teacher[0], sol[i].date, sol[i].time]
table.append(ex)
return table
def assignteacherrooms(exam, roomsno): #function assigns rooms to teachers -> Hard Constraint #6
for i in range(roomsno):
random_room_no = random.randint(1, len(rooms.items()))
flag = True
while flag:
for room in exam.room:
if room == random_room_no:
random_room_no = random.randint(1, len(rooms.items()))
break
flag = False
exam.room.append(random_room_no)
for i in range(roomsno):
random_teacher = random.randint(0, len(teachers) - 1)
flag = True
while flag:
for teacher in exam.teacher:
if teacher == teachers[random_teacher]:
random_teacher = random.randint(0, len(teachers) - 1)
break
flag = False
exam.teacher.append(teachers[random_teacher])
def assigncourses(): # assign courses to students -> Hard Constraint #1
for student in studentnames:
indstudentcourses[student] = []
for item in range(len(studentcourse.items())):
indstudentcourses[studentcourse[item][0]].append(studentcourse[item][1])
for student in studentnames:
if len(indstudentcourses[student]) < 3: # Hard Constraint #2
indstudentcourses.pop(student)
def assignstudentstocourse(): # create lists of students enrolled in each course
global coursesstudents
for course in courses.keys():
coursesstudents[course] = []
for item in range(len(studentcourse.items())):
coursesstudents[studentcourse[item][1]].append(studentcourse[item][0])
def random_solution():
sol = {}
for i in courses.keys():
exam = Exam()
exam.room = []
exam.teacher = []
roomsno = int(len(coursesstudents[i]) / 28) + 1
assignteacherrooms(exam, roomsno)
randtime = random.randint(0, 1)
if randtime == 0:
exam.time = 9
else:
exam.time = 2
exam.date = random.randint(1, days)
sol[i] = exam
return sol
''' Hard Constraints '''
'''
1. An exam will be scheduled for each course.
2. A student is enrolled in at least 3 courses. A student cannot give more than 1 exam
at a time.
3. Exam will not be held on weekends.
4. Each exam must be held between 9 am and 5 pm
5. Each exam must be invigilated by a teacher. A teacher cannot invigilate two exams at the same time.
6. A teacher cannot invigilate two exams in a row.
Constraint 3, 4 are already fulfilled because of the structure of the program
'''
def studentconstraint(sol): # Checks the number of student clashes in a particular solution -> Hard Constraint #2
date_list = []
cost = 0
for student in indstudentcourses.keys():
for course in indstudentcourses[student]:
date_list.append(sol[course].date)
a = set(date_list)
if len(a) != len(date_list):
cost = cost + 1
date_list = []
return cost
def teachersconstraint(sol): # Checks the number of teacher clashes in a particular solution -> Hard Constraint #5
exams = {}
cost = 0
for i in range(1, days + 1):
exams[i] = []
for i in sol.keys():
for j in sol[i].teacher:
exams[sol[i].date].append(j)
for i in exams.keys():
a = set(exams[i])
if len(a) != len(exams[i]):
cost = cost + 1
return cost
def costfunction(sol): # calculates fitness value of a solution
cost = 0
sf2, sf3 = returnSoftConstraintTwoAndThree(sol)
cost = studentconstraint(sol) * 1 + teachersconstraint(sol) * 1 + sf2 * 0.05 + sf3 * 0.05
return cost
def getclashes(sol): # find where clashes occur
date_list = []
for student in indstudentcourses.keys():
for course in indstudentcourses[student]:
date_list.append(sol[course].date)
a = set(date_list)
if len(a) != len(date_list):
return student
date_list = []
return False
def neighboringsolution(solution): # create neighboring solution
student = getclashes(solution)
if not student:
print("Test")
date1 = 0
date2 = 0
while date1 == date2:
index1 = random.randint(0, len(solution.items()) - 1)
index2 = random.randint(0, len(solution.items()) - 1)
if index1 == index2:
continue
date1 = list(solution.values())[index1].date
date2 = list(solution.values())[index2].date
time1 = list(solution.values())[index1].time
time2 = list(solution.values())[index2].time
if date1 == date2:
continue
course1 = list(solution.keys())[index1]
course2 = list(solution.keys())[index2]
solution[course1].date = date2
solution[course2].date = date1
solution[course1].time = time2
solution[course2].time = time1
return solution
while True:
random_numbers = random.sample(range(1, days), len(indstudentcourses[student]))
a = set(random_numbers)
if len(a) != len(random_numbers):
continue
i = 0
for course in indstudentcourses[student]:
solution[course].date = random_numbers[i]
i = i + 1
break
return solution
def setupdata(): # set up all prerequisites of the program
importdata()
assignstudentstocourse()
assigncourses()
def sortsol(solution): # sort solution by date and time
sol2 = copy.deepcopy(solution)
sol = list(sol2.values())
sol3 = list(sol2.keys())
for i in range(len(sol)):
# loop to compare array elements
for j in range(0, len(sol) - i - 1):
# compare two adjacent elements
# change > to < to sort in descending order
if sol[j].date > sol[j + 1].date:
# swapping elements if elements
# are not in the intended order
temp = sol[j]
temp2 = sol3[j]
sol[j] = sol[j + 1]
sol3[j] = sol3[j + 1]
sol[j + 1] = temp
sol3[j + 1] = temp2
if sol[j].time < sol[j + 1].time and sol[j].date == sol[j + 1].date:
temp = sol[j]
temp2 = sol3[j]
sol[j] = sol[j + 1]
sol3[j] = sol3[j + 1]
sol[j + 1] = temp
sol3[j + 1] = temp2
j = 0
xdict = {}
for i in sol3:
xdict[i] = []
for i in xdict.keys():
xdict[i] = sol[j]
j += 1
return xdict
''' Soft Constraints '''
'''
Already Fulfilled soft constraint
Soft Constraint #1: All students and teachers shall be given a break on Friday from 1-2.
Soft Constraint #4: Two hours of break in the week such that at least half the faculty is free in
one slot and the rest of the faculty is free in the other slot so the faculty
meetings shall be held in parts as they are now.
'''
'''
1 Function that returns Soft constraint #2 and Soft Constraint #4
Soft Constraint #2: A student shall not give more than 1 exam consecutively.
Soft Constraint #3: If a student is enrolled in a MG course and a CS course, it is preferred that their MG course
exam be held before their CS course exam
'''
def returnSoftConstraintTwoAndThree(sol):
studentEnrolledCourses = copy.deepcopy(indstudentcourses)
examSchedule = copy.deepcopy(sortsol(sol))
costOfCSCourseOverMGCourse = 0
costOfConsecutiveExams = 0
for student, coursesList in studentEnrolledCourses.items():
examOccured = False
checkCSCourseInFirstSlot = False
for course in coursesList:
for exam in examSchedule.keys():
# print(schedule)
if examSchedule[exam].time == 9: # First check exams of the student in first slot
if course == exam:
examOccured = True
if "CS" in course:
checkCSCourseInFirstSlot = True
else:
if course == exam:
# print(examOccured)
if examOccured: # Then check exams of the student in 2nd slot
costOfConsecutiveExams += 1
if "MG" in course and checkCSCourseInFirstSlot:
costOfCSCourseOverMGCourse += 1
checkCSCourseInFirstSlot = False
examOccured = False
return costOfConsecutiveExams, costOfCSCourseOverMGCourse
def printFulfilledHardConstraints():
prGreen("Fulfilled Hard Constraints: \n")
for constraint in listOfHardConstraints:
prLightGray(constraint + '\n')
def printFulfilledSoftConstraints():
prCyan("\nFulfilled Soft Constraints: \n")
for constraint in listOfSoftConstraints:
prLightGray(constraint + '\n')
print('\n')
def simulatedanealing():
temp = 10000
coolingrate = 1
currentsol = random_solution()
bestsol = random_solution()
currentcost = costfunction(currentsol)
bestcost = currentcost
prRed("Initial Cost: " + str(bestcost) + "\n")
while temp > 1:
load = "*" * (100 - int(temp / 10)) + "_" * int(temp / 10)
prGreen("[" + load + "]\n")
newsol = copy.deepcopy(neighboringsolution(currentsol))
newcost = costfunction(newsol)
prYellow("Current Cost: " + str(newcost) + '\n')
if newcost < currentcost:
currentsol = newsol
currentcost = newcost
bestsol = copy.deepcopy(newsol)
bestcost = newcost
if newcost <= 10:
printFulfilledHardConstraints()
printFulfilledSoftConstraints()
break
else:
costdiff = newcost - bestcost
if random.uniform(0, 1) < math.exp(-costdiff / temp):
currentsol = newsol
currentcost = newcost
temp = temp - coolingrate
clear()
return createtable(bestsol)
def setday(datalist):
day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
dt = copy.deepcopy(datalist)
dy = []
for i in range(len(dt)):
dy.append('')
j = dt[0] - 1
for i in range(len(dt)):
if (j > 4):
j = dt[0] - 1
dy[i] = day[j]
if i != len(dt) - 1 and dt[i + 1] > dt[i]:
j = j + 1
return dy
def settime(timelist):
tl = copy.deepcopy(timelist)
tx = []
dx = []
for i in tl:
if i == 9:
tx.append("9:00 AM - 12:00 AM")
elif i == 2:
tx.append("2:00 PM - 5:00 PM")
return tx
def setdate(daylist, datelist):
dx = []
dl = copy.deepcopy(datelist)
count = 0
for i in range(len(dl)-1):
dx.append(dl[i] + count)
if daylist[i] == 'Friday' and daylist[i+1] != 'Friday':
count += 2
if i == len(dl)-2:
dx.append(dl[i] + count)
return dx
def createdataframe(bestsol): # create Dataframe from table
result = []
for i in bestsol:
result.append([])
for i in range(len(bestsol)):
for j in range(len(bestsol[0])):
result[j].append(bestsol[i][j])
df = pd.DataFrame(bestsol, columns=["Course Code", "Room Number", "Teacher Name", "Date", "Time Slot"])
sdf = df.sort_values(by=['Date', 'Room Number'], ascending=True)
daycol = setday(list(sdf['Date']))
timecol = settime(list(sdf['Time Slot']))
datecol = setdate(daycol, list(sdf['Date']))
sdf.drop(["Date", "Time Slot"], axis=1)
sdf['Time Slot'] = timecol
sdf['Day'] = daycol
sdf['Date'] = datecol
if os.path.exists('Datesheet.csv'):
os.remove('Datesheet.csv')
sdf.to_csv('Datesheet.csv')
return sdf
prPurple("Press 1 for Two week Schedule\n Press 2 for 3 Week Schedule\n")
x = int(input("Enter Option: "))
if x == 1:
days = 10
else:
days = 15
setupdata()
print(createdataframe(simulatedanealing()))
x = input("Press any key to exit")