garizz commited on
Commit
8e7d8ae
·
1 Parent(s): 1987ae5

Upload 31 files

Browse files
__pycache__/ConsoleApp.cpython-39.pyc ADDED
Binary file (978 Bytes). View file
 
__pycache__/HtmlOutput.cpython-39.pyc ADDED
Binary file (5.03 kB). View file
 
algorithm/GeneticAlgorithm.py ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from model.Schedule import Schedule
2
+ import random
3
+ from random import randrange
4
+ from time import time
5
+
6
+
7
+ # Lakshmi, R. et al. “A New Biological Operator in Genetic Algorithm for Class Scheduling Problem.”
8
+ # International Journal of Computer Applications 60 (2012): 6-11.
9
+
10
+
11
+ # Genetic algorithm
12
+ class GeneticAlgorithm:
13
+ def initAlgorithm(self, prototype, numberOfChromosomes=100, replaceByGeneration=8, trackBest=5):
14
+ # Number of best chromosomes currently saved in best chromosome group
15
+ self._currentBestSize = 0
16
+ # Prototype of chromosomes in population
17
+ self._prototype = prototype
18
+
19
+ # there should be at least 2 chromosomes in population
20
+ if numberOfChromosomes < 2:
21
+ numberOfChromosomes = 2
22
+
23
+ # and algorithm should track at least on of best chromosomes
24
+ if trackBest < 1:
25
+ trackBest = 1
26
+
27
+ # Population of chromosomes
28
+ self._chromosomes = numberOfChromosomes * [None]
29
+ # Inidicates whether chromosome belongs to best chromosome group
30
+ self._bestFlags = numberOfChromosomes * [False]
31
+
32
+ # Indices of best chromosomes
33
+ self._bestChromosomes = trackBest * [0]
34
+ # Number of chromosomes which are replaced in each generation by offspring
35
+ self.set_replace_by_generation(replaceByGeneration)
36
+
37
+ # Initializes genetic algorithm
38
+ def __init__(self, configuration, numberOfCrossoverPoints=2, mutationSize=2, crossoverProbability=80,
39
+ mutationProbability=3):
40
+ self.initAlgorithm(Schedule(configuration))
41
+ self._mutationSize = mutationSize
42
+ self._numberOfCrossoverPoints = numberOfCrossoverPoints
43
+ self._crossoverProbability = crossoverProbability
44
+ self._mutationProbability = mutationProbability
45
+
46
+ @property
47
+ # Returns pointer to best chromosomes in population
48
+ def result(self):
49
+ return self._chromosomes[self._bestChromosomes[0]]
50
+
51
+ def set_replace_by_generation(self, value):
52
+ numberOfChromosomes = len(self._chromosomes)
53
+ trackBest = len(self._bestChromosomes)
54
+ if (value > numberOfChromosomes - trackBest):
55
+ value = numberOfChromosomes - trackBest
56
+ self._replaceByGeneration = value
57
+
58
+ # Tries to add chromosomes in best chromosome group
59
+ def addToBest(self, chromosomeIndex):
60
+ bestChromosomes = self._bestChromosomes
61
+ length_best = len(bestChromosomes)
62
+ bestFlags = self._bestFlags
63
+ chromosomes = self._chromosomes
64
+
65
+ # don't add if new chromosome hasn't fitness big enough for best chromosome group
66
+ # or it is already in the group?
67
+ if (self._currentBestSize == length_best and chromosomes[bestChromosomes[self._currentBestSize - 1]].fitness >=
68
+ chromosomes[chromosomeIndex].fitness) or bestFlags[chromosomeIndex]:
69
+ return
70
+
71
+ # find place for new chromosome
72
+ j = self._currentBestSize
73
+ for i in range(j, -1, -1):
74
+ j = i
75
+ pos = bestChromosomes[i - 1]
76
+ # group is not full?
77
+ if i < length_best:
78
+ # position of new chromosomes is found?
79
+ if chromosomes[pos].fitness > chromosomes[chromosomeIndex].fitness:
80
+ break
81
+
82
+ # move chromosomes to make room for new
83
+ bestChromosomes[i] = pos
84
+ else:
85
+ # group is full remove worst chromosomes in the group
86
+ bestFlags[pos] = False
87
+
88
+ # store chromosome in best chromosome group
89
+ bestChromosomes[j] = chromosomeIndex
90
+ bestFlags[chromosomeIndex] = True
91
+
92
+ # increase current size if it has not reached the limit yet
93
+ if self._currentBestSize < length_best:
94
+ self._currentBestSize += 1
95
+
96
+ # Returns TRUE if chromosome belongs to best chromosome group
97
+ def isInBest(self, chromosomeIndex) -> bool:
98
+ return self._bestFlags[chromosomeIndex]
99
+
100
+ # Clears best chromosome group
101
+ def clearBest(self):
102
+ self._bestFlags = len(self._bestFlags) * [False]
103
+ self._currentBestSize = 0
104
+
105
+ # initialize new population with chromosomes randomly built using prototype
106
+ def initialize(self, population):
107
+ # addToBest = self.addToBest
108
+ prototype = self._prototype
109
+ length_chromosomes = len(population)
110
+
111
+ for i in range(0, length_chromosomes):
112
+ # add new chromosome to population
113
+ population[i] = prototype.makeNewFromPrototype()
114
+ # addToBest(i)
115
+
116
+ def selection(self, population):
117
+ length_chromosomes = len(population)
118
+ return (population[randrange(32768) % length_chromosomes], population[randrange(32768) % length_chromosomes])
119
+
120
+ def replacement(self, population, replaceByGeneration) -> []:
121
+ mutationSize = self._mutationSize
122
+ numberOfCrossoverPoints = self._numberOfCrossoverPoints
123
+ crossoverProbability = self._crossoverProbability
124
+ mutationProbability = self._mutationProbability
125
+ selection = self.selection
126
+ isInBest = self.isInBest
127
+ length_chromosomes = len(population)
128
+ # produce offspring
129
+ offspring = replaceByGeneration * [None]
130
+ for j in range(replaceByGeneration):
131
+ # selects parent randomly
132
+ parent = selection(population)
133
+
134
+ offspring[j] = parent[0].crossover(parent[1], numberOfCrossoverPoints, crossoverProbability)
135
+ offspring[j].mutation(mutationSize, mutationProbability)
136
+
137
+ # replace chromosomes of current operation with offspring
138
+ # select chromosome for replacement randomly
139
+ ci = randrange(32768) % length_chromosomes
140
+ while isInBest(ci):
141
+ ci = randrange(32768) % length_chromosomes
142
+
143
+ # replace chromosomes
144
+ population[ci] = offspring[j]
145
+
146
+ # try to add new chromosomes in best chromosome group
147
+ self.addToBest(ci)
148
+ return offspring
149
+
150
+ # Starts and executes algorithm
151
+ def run(self, maxRepeat=9999, minFitness=0.999):
152
+ # clear best chromosome group from previous execution
153
+ self.clearBest()
154
+ length_chromosomes = len(self._chromosomes)
155
+
156
+ self.initialize(self._chromosomes)
157
+ random.seed(round(time() * 1000))
158
+
159
+ # Current generation
160
+ currentGeneration = 0
161
+
162
+ repeat = 0
163
+ lastBestFit = 0.0
164
+
165
+ while 1:
166
+ best = self.result
167
+ print("Fitness:", "{:f}\t".format(best.fitness), "Generation:", currentGeneration, end="\r")
168
+
169
+ # algorithm has reached criteria?
170
+ if best.fitness > minFitness:
171
+ break
172
+
173
+ difference = abs(best.fitness - lastBestFit)
174
+ if difference <= 0.0000001:
175
+ repeat += 1
176
+ else:
177
+ repeat = 0
178
+
179
+ if repeat > (maxRepeat / 100):
180
+ random.seed(round(time() * 1000))
181
+ self.set_replace_by_generation(self._replaceByGeneration * 3)
182
+ self._crossoverProbability += 1
183
+
184
+ self.replacement(self._chromosomes, self._replaceByGeneration)
185
+
186
+ lastBestFit = best.fitness
187
+ currentGeneration += 1
188
+
189
+ def __str__(self):
190
+ return "Genetic Algorithm"
algorithm/NsgaII.py ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from model.Schedule import Schedule
2
+ import numpy as np
3
+ import random
4
+ import sys
5
+ from time import time
6
+
7
+
8
+ # K.Deb, A.Pratap, S.Agrawal, T.Meyarivan, A fast and elitist multiobjective genetic algorithm:
9
+ # NSGA-II, IEEE Transactions on Evolutionary Computation 6 (2002) 182–197.
10
+
11
+
12
+ # NSGA II
13
+ class NsgaII:
14
+ def initAlgorithm(self, prototype, numberOfChromosomes=100):
15
+ # Prototype of chromosomes in population
16
+ self._prototype = prototype
17
+
18
+ # there should be at least 2 chromosomes in population
19
+ if numberOfChromosomes < 2:
20
+ numberOfChromosomes = 2
21
+
22
+ # Population of chromosomes
23
+ self._chromosomes = []
24
+ self._populationSize = numberOfChromosomes
25
+ self._repeatRatio = .0
26
+
27
+ # Initializes genetic algorithm
28
+ def __init__(self, configuration, numberOfCrossoverPoints=2, mutationSize=2, crossoverProbability=80,
29
+ mutationProbability=3):
30
+ self.initAlgorithm(Schedule(configuration))
31
+ self._mutationSize = mutationSize
32
+ self._numberOfCrossoverPoints = numberOfCrossoverPoints
33
+ self._crossoverProbability = crossoverProbability
34
+ self._mutationProbability = mutationProbability
35
+
36
+ @property
37
+ # Returns pointer to best chromosomes in population
38
+ def result(self):
39
+ return self._chromosomes[0]
40
+
41
+ # non-dominated sorting function
42
+ def nonDominatedSorting(self, totalChromosome):
43
+ doublePopulationSize = self._populationSize * 2
44
+ s = doublePopulationSize * [ set() ]
45
+ n = np.zeros(doublePopulationSize, dtype=int)
46
+ front = [ set() ]
47
+
48
+ for p in range(doublePopulationSize):
49
+ for q in range(doublePopulationSize):
50
+ if totalChromosome[p].fitness > totalChromosome[q].fitness:
51
+ s[p].add(q)
52
+ elif totalChromosome[p].fitness < totalChromosome[q].fitness:
53
+ n[p] += 1
54
+
55
+ if n[p] == 0:
56
+ front[0].add(p)
57
+
58
+ i = 0
59
+ while front[i]:
60
+ Q = set()
61
+ for p in front[i]:
62
+ for q in s[p]:
63
+ n[q] -= 1
64
+ if n[q] == 0:
65
+ Q.add(q)
66
+ i += 1
67
+ front.append(Q)
68
+
69
+ front.pop()
70
+ return front
71
+
72
+ # calculate crowding distance function
73
+ def calculateCrowdingDistance(self, front, totalChromosome):
74
+ distance, obj = {}, {}
75
+ for key in front:
76
+ distance[key] = 0
77
+ fitness = totalChromosome[key].fitness
78
+ if fitness not in obj.values():
79
+ obj[key] = fitness
80
+
81
+ sorted_keys = sorted(obj, key=obj.get)
82
+ size = len(obj)
83
+ distance[sorted_keys[0]] = distance[sorted_keys[-1]] = sys.float_info.max
84
+
85
+ if size > 1:
86
+ diff2 = totalChromosome[sorted_keys[-1]].getDifference(totalChromosome[sorted_keys[0]])
87
+
88
+ for i in range(1, size - 1):
89
+ diff = totalChromosome[sorted_keys[i + 1]].getDifference(totalChromosome[sorted_keys[i - 1]]) / diff2
90
+ distance[sorted_keys[i]] += diff
91
+
92
+ return distance
93
+
94
+ def selection(self, front, totalChromosome):
95
+ populationSize = self._populationSize
96
+ calculateCrowdingDistance = self.calculateCrowdingDistance
97
+ N = 0
98
+ newPop = []
99
+ while N < populationSize:
100
+ for row in front:
101
+ N += len(row)
102
+ if N > populationSize:
103
+ distance = calculateCrowdingDistance(row, totalChromosome)
104
+ sortedCdf = sorted(distance, key=distance.get, reverse=True)
105
+ for j in sortedCdf:
106
+ if len(newPop) >= populationSize:
107
+ break
108
+ newPop.append(j)
109
+ break
110
+ newPop.extend(row)
111
+
112
+ return [totalChromosome[n] for n in newPop]
113
+
114
+ def replacement(self, population):
115
+ populationSize = self._populationSize
116
+ numberOfCrossoverPoints = self._numberOfCrossoverPoints
117
+ crossoverProbability = self._crossoverProbability
118
+ offspring = []
119
+ # generate a random sequence to select the parent chromosome to crossover
120
+ S = np.arange(populationSize)
121
+ np.random.shuffle(S)
122
+
123
+ halfPopulationSize = populationSize // 2
124
+ for m in range(halfPopulationSize):
125
+ parent0 = population[S[2 * m]]
126
+ parent1 = population[S[2 * m + 1]]
127
+ child0 = parent0.crossover(parent1, numberOfCrossoverPoints, crossoverProbability)
128
+ child1 = parent1.crossover(parent0, numberOfCrossoverPoints, crossoverProbability)
129
+
130
+ # append child chromosome to offspring list
131
+ offspring.extend((child0, child1))
132
+
133
+ return offspring
134
+
135
+ # initialize new population with chromosomes randomly built using prototype
136
+ def initialize(self, population):
137
+ prototype = self._prototype
138
+
139
+ for i in range(len(population)):
140
+ # add new chromosome to population
141
+ population[i] = prototype.makeNewFromPrototype()
142
+
143
+ def reform(self):
144
+ random.seed(round(time() * 1000))
145
+ np.random.seed(int(time()))
146
+ if self._crossoverProbability < 95:
147
+ self._crossoverProbability += 1.0
148
+ elif self._mutationProbability < 30:
149
+ self._mutationProbability += 1.0
150
+
151
+ # Starts and executes algorithm
152
+ def run(self, maxRepeat=9999, minFitness=0.999):
153
+ mutationSize = self._mutationSize
154
+ mutationProbability = self._mutationProbability
155
+ nonDominatedSorting = self.nonDominatedSorting
156
+ selection = self.selection
157
+ populationSize = self._populationSize
158
+ population = populationSize * [None]
159
+
160
+ self.initialize(population)
161
+ random.seed(round(time() * 1000))
162
+ np.random.seed(int(time()))
163
+
164
+ # Current generation
165
+ currentGeneration = 0
166
+
167
+ repeat = 0
168
+ lastBestFit = 0.0
169
+
170
+ while 1:
171
+ if currentGeneration > 0:
172
+ best = self.result
173
+ print("Fitness:", "{:f}\t".format(best.fitness), "Generation:", currentGeneration, end="\r")
174
+
175
+ # algorithm has reached criteria?
176
+ if best.fitness > minFitness:
177
+ break
178
+
179
+ difference = abs(best.fitness - lastBestFit)
180
+ if difference <= 0.0000001:
181
+ repeat += 1
182
+ else:
183
+ repeat = 0
184
+
185
+ self._repeatRatio = repeat * 100 / maxRepeat
186
+ if repeat > (maxRepeat / 100):
187
+ self.reform()
188
+
189
+ # crossover
190
+ offspring = self.replacement(population)
191
+
192
+ # mutation
193
+ for child in offspring:
194
+ child.mutation(mutationSize, mutationProbability)
195
+
196
+ totalChromosome = population + offspring
197
+
198
+ # non-dominated sorting
199
+ front = nonDominatedSorting(totalChromosome)
200
+ if len(front) == 0:
201
+ break
202
+
203
+ # selection
204
+ population = selection(front, totalChromosome)
205
+ self._populationSize = populationSize = len(population)
206
+
207
+ # comparison
208
+ if currentGeneration == 0:
209
+ self._chromosomes = population
210
+ else:
211
+ totalChromosome = population + self._chromosomes
212
+ newBestFront = nonDominatedSorting(totalChromosome)
213
+ if len(newBestFront) == 0:
214
+ break
215
+ self._chromosomes = selection(newBestFront, totalChromosome)
216
+ lastBestFit = best.fitness
217
+
218
+ currentGeneration += 1
219
+
220
+ def __str__(self):
221
+ return "NSGA II"
algorithm/__pycache__/APNsgaIII.cpython-39.pyc ADDED
Binary file (3.25 kB). View file
 
algorithm/__pycache__/GeneticAlgorithm.cpython-39.pyc ADDED
Binary file (4.34 kB). View file
 
algorithm/__pycache__/NsgaII.cpython-39.pyc ADDED
Binary file (5.06 kB). View file
 
algorithm/__pycache__/NsgaIII.cpython-39.pyc ADDED
Binary file (11.7 kB). View file
 
model/Configuration.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import codecs
2
+ import json
3
+
4
+ from .Professor import Professor
5
+ from .StudentsGroup import StudentsGroup
6
+ from .Course import Course
7
+ from .Room import Room
8
+ from .CourseClass import CourseClass
9
+
10
+
11
+ # Reads configuration file and stores parsed objects
12
+ class Configuration:
13
+
14
+ # Initialize data
15
+ def __init__(self):
16
+ # Indicate that configuration is not parsed yet
17
+ self._isEmpty = True
18
+ # parsed professors
19
+ self._professors = {}
20
+ # parsed student groups
21
+ self._studentGroups = {}
22
+ # parsed courses
23
+ self._courses = {}
24
+ # parsed rooms
25
+ self._rooms = {}
26
+ # parsed classes
27
+ self._courseClasses = []
28
+
29
+ # Returns professor with specified ID
30
+ # If there is no professor with such ID method returns NULL
31
+ def getProfessorById(self, id) -> Professor:
32
+ if id in self._professors:
33
+ return self._professors[id]
34
+ return None
35
+
36
+ @property
37
+ # Returns number of parsed professors
38
+ def numberOfProfessors(self) -> int:
39
+ return len(self._professors)
40
+
41
+ # Returns student group with specified ID
42
+ # If there is no student group with such ID method returns NULL
43
+ def getStudentsGroupById(self, id) -> StudentsGroup:
44
+ if id in self._studentGroups:
45
+ return self._studentGroups[id]
46
+ return None
47
+
48
+ @property
49
+ # Returns number of parsed student groups
50
+ def numberOfStudentGroups(self) -> int:
51
+ return len(self._studentGroups)
52
+
53
+ # Returns course with specified ID
54
+ # If there is no course with such ID method returns NULL
55
+ def getCourseById(self, id) -> Course:
56
+ if id in self._courses:
57
+ return self._courses[id]
58
+ return None
59
+
60
+ @property
61
+ def numberOfCourses(self) -> int:
62
+ return len(self._courses)
63
+
64
+ # Returns room with specified ID
65
+ # If there is no room with such ID method returns NULL
66
+ def getRoomById(self, id) -> Room:
67
+ if id in self._rooms:
68
+ return self._rooms[id]
69
+ return None
70
+
71
+ @property
72
+ # Returns number of parsed rooms
73
+ def numberOfRooms(self) -> int:
74
+ return len(self._rooms)
75
+
76
+ @property
77
+ # Returns reference to list of parsed classes
78
+ def courseClasses(self) -> []:
79
+ return self._courseClasses
80
+
81
+ @property
82
+ # Returns number of parsed classes
83
+ def numberOfCourseClasses(self) -> int:
84
+ return len(self._courseClasses)
85
+
86
+ @property
87
+ # Returns TRUE if configuration is not parsed yet
88
+ def isEmpty(self) -> bool:
89
+ return self._isEmpty
90
+
91
+ # Reads professor's data from config file, makes object and returns
92
+ # Returns NULL if method cannot parse configuration data
93
+ @staticmethod
94
+ def __parseProfessor(dictConfig):
95
+ id = 0
96
+ name = ''
97
+
98
+ for key in dictConfig:
99
+ if key == 'id':
100
+ id = dictConfig[key]
101
+ elif key == 'name':
102
+ name = dictConfig[key]
103
+
104
+ if id == 0 or name == '':
105
+ return None
106
+ return Professor(id, name)
107
+
108
+ # Reads StudentsGroup's data from config file, makes object and returns
109
+ # Returns None if method cannot parse configuration data
110
+ @staticmethod
111
+ def __parseStudentsGroup(dictConfig):
112
+ id = 0
113
+ # name = ''
114
+ size = 0
115
+
116
+ for key in dictConfig:
117
+ if key == 'id':
118
+ id = dictConfig[key]
119
+ # elif key == 'name':
120
+ # name = dictConfig[key]
121
+ elif key == 'size':
122
+ size = dictConfig[key]
123
+
124
+ if id == 0:
125
+ return None
126
+ return StudentsGroup(id, size)
127
+
128
+ # Reads course's data from config file, makes object and returns
129
+ # Returns None if method dictConfig parse configuration data
130
+ @staticmethod
131
+ def __parseCourse(dictConfig):
132
+ id = 0
133
+ name = ''
134
+
135
+ for key in dictConfig:
136
+ if key == 'id':
137
+ id = dictConfig[key]
138
+ elif key == 'name':
139
+ name = dictConfig[key]
140
+
141
+ if id == 0:
142
+ return None
143
+ return Course(id, name)
144
+
145
+ # Reads rooms's data from config file, makes object and returns
146
+ # Returns None if method cannot parse configuration data
147
+ @staticmethod
148
+ def __parseRoom(dictConfig):
149
+ lab = False
150
+ name = ''
151
+ size = 0
152
+
153
+ for key in dictConfig:
154
+ if key == 'lab':
155
+ lab = dictConfig[key]
156
+ elif key == 'name':
157
+ name = dictConfig[key]
158
+ elif key == 'size':
159
+ size = dictConfig[key]
160
+
161
+ if size == 0 or name == '':
162
+ return None
163
+ return Room(name, lab, size)
164
+
165
+ # Reads class' data from config file, makes object and returns pointer
166
+ # Returns None if method cannot parse configuration data
167
+ def __parseCourseClass(self, dictConfig):
168
+ pid = 0
169
+ cid = 0
170
+ dur = 1
171
+ lab = False
172
+ group_list = []
173
+
174
+ for key in dictConfig:
175
+ if key == 'professor':
176
+ pid = dictConfig[key]
177
+ elif key == 'course':
178
+ cid = dictConfig[key]
179
+ elif key == 'lab':
180
+ lab = dictConfig[key]
181
+ elif key == 'duration':
182
+ dur = dictConfig[key]
183
+ elif key == 'group' or key == 'groups':
184
+ groups = dictConfig[key]
185
+ if isinstance(groups, list):
186
+ for grp in groups:
187
+ g = self.getStudentsGroupById(grp)
188
+ if g:
189
+ group_list.append(g)
190
+ else:
191
+ g = self.getStudentsGroupById(groups)
192
+ if g:
193
+ group_list.append(g)
194
+
195
+ # get professor who teaches class and course to which this class belongs
196
+ p = self.getProfessorById(pid)
197
+ c = self.getCourseById(cid)
198
+
199
+ # does professor and class exists
200
+ if not c or not p:
201
+ return None
202
+
203
+ # make object and return
204
+ return CourseClass(p, c, lab, dur, group_list)
205
+
206
+ # parse file and store parsed object
207
+ def parseFile(self, fileName):
208
+ # clear previously parsed objects
209
+ self._professors = {}
210
+ self._studentGroups = {}
211
+ self._courses = {}
212
+ self._rooms = {}
213
+ self._courseClasses = []
214
+ Room.restartIDs()
215
+ CourseClass.restartIDs()
216
+ with codecs.open(fileName, "r", "utf-8") as f:
217
+ # read file into a string and deserialize JSON to a type
218
+ data = json.load(f)
219
+ for dictConfig in data:
220
+ for key in dictConfig:
221
+ if key == 'prof':
222
+ prof = self.__parseProfessor(dictConfig[key])
223
+ self._professors[prof.Id] = prof
224
+ elif key == 'course':
225
+ course = self.__parseCourse(dictConfig[key])
226
+ self._courses[course.Id] = course
227
+ elif key == 'room':
228
+ room = self.__parseRoom(dictConfig[key])
229
+ self._rooms[room.Id] = room
230
+ elif key == 'group':
231
+ group = self.__parseStudentsGroup(dictConfig[key])
232
+ self._studentGroups[group.Id] = group
233
+ elif key == 'class':
234
+ courseClass = self.__parseCourseClass(dictConfig[key])
235
+ self._courseClasses.append(courseClass)
236
+ self._isEmpty = False
model/Constant.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ class Constant:
2
+ # Number of days in week
3
+ DAYS_NUM = 6
4
+ # Number of working hours per day
5
+ DAY_HOURS = 11
model/Course.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Stores data about course
2
+ class Course:
3
+ # Initializes course
4
+ def __init__(self, id, name):
5
+ # Returns course ID
6
+ self.Id = id
7
+ # Returns course name
8
+ self.Name = name
9
+
10
+
11
+
model/CourseClass.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CourseClass:
2
+ # ID counter used to assign IDs automatically
3
+ _next_class_id = 0
4
+
5
+ # Initializes class object
6
+ def __init__(self, professor, course, requires_lab, duration, groups):
7
+ self.Id = CourseClass._next_class_id
8
+ CourseClass._next_class_id += 1
9
+ # Return pointer to professor who teaches
10
+ self.Professor = professor
11
+ # Return pointer to course to which class belongs
12
+ self.Course = course
13
+ # Returns number of seats (students) required in room
14
+ self.NumberOfSeats = 0
15
+ # Returns TRUE if class requires computers in room.
16
+ self.LabRequired = requires_lab
17
+ # Returns duration of class in hours
18
+ self.Duration = duration
19
+ # Returns reference to list of student groups who attend class
20
+ self.Groups = set(groups)
21
+ # bind professor to class
22
+ self.Professor.addCourseClass(self)
23
+
24
+ # bind student groups to class
25
+ for grp in self.Groups: # self.groups:
26
+ grp.addClass(self)
27
+ self.NumberOfSeats += grp.NumberOfStudents
28
+
29
+ # Returns TRUE if another class has one or overlapping student groups.
30
+ def groupsOverlap(self, c):
31
+ return len(self.Groups & c.Groups) > 0
32
+
33
+ # Returns TRUE if another class has same professor.
34
+ def professorOverlaps(self, c):
35
+ return self.Professor == c.Professor
36
+
37
+ def __hash__(self):
38
+ return hash(self.Id)
39
+
40
+ def __eq__(self, other):
41
+ if not isinstance(other, self.__class__):
42
+ return False
43
+ return hash(self) == hash(other)
44
+
45
+ def __ne__(self, other):
46
+ # Not strictly necessary, but to avoid having both x==y and x!=y
47
+ # True at the same time
48
+ return not (self == other)
49
+
50
+ # Restarts ID assigments
51
+ @staticmethod
52
+ def restartIDs() -> None:
53
+ CourseClass._next_class_id = 0
model/Criteria.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .Constant import Constant
2
+
3
+
4
+ # Reads configuration file and stores parsed objects
5
+ class Criteria:
6
+ weights = [0, 0.5, 0.5, 0, 0]
7
+
8
+ # check for room overlapping of classes
9
+ @staticmethod
10
+ def isRoomOverlapped(slots, reservation, dur):
11
+ reservation_index = hash(reservation)
12
+ cls = slots[reservation_index: reservation_index + dur]
13
+ return any(True for slot in cls if len(slot) > 1)
14
+
15
+ # does current room have enough seats
16
+ @staticmethod
17
+ def isSeatEnough(r, cc):
18
+ return r.NumberOfSeats >= cc.NumberOfSeats
19
+
20
+ # does current room have computers if they are required
21
+ @staticmethod
22
+ def isComputerEnough(r, cc):
23
+ # return (not cc.LabRequired) or (cc.LabRequired and r.Lab)
24
+ return cc.LabRequired == r.Lab
25
+
26
+ # check overlapping of classes for professors and student groups (size of course)
27
+ @staticmethod
28
+ def isOverlappedProfStudentGrp(slots, cc, numberOfRooms, timeId):
29
+ po = go = False
30
+
31
+ dur = cc.Duration
32
+ for i in range(numberOfRooms, 0, -1):
33
+ # for each hour of class
34
+ for j in range(timeId, timeId + dur):
35
+ cl = slots[j]
36
+ for cc1 in cl:
37
+ if cc != cc1:
38
+ # professor overlaps?
39
+ if not po and cc.professorOverlaps(cc1):
40
+ po = True
41
+ # student group enough?
42
+ if not go and cc.groupsOverlap(cc1):
43
+ go = True
44
+ # both type of overlapping? no need to check more
45
+ if po and go:
46
+ return po, go
47
+
48
+ timeId += Constant.DAY_HOURS
49
+ return po, go
model/Professor.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Stores data about professor
2
+ class Professor:
3
+ # Initializes professor data
4
+ def __init__(self, id, name):
5
+ self.Id = id
6
+ self.Name = name
7
+ self.CourseClasses = []
8
+
9
+ # Bind professor to course
10
+ def addCourseClass(self, courseClass):
11
+ self.CourseClasses.append(courseClass)
12
+
13
+ def __hash__(self):
14
+ return hash(self.Id)
15
+
16
+ # Compares ID's of two objects which represent professors
17
+ def __eq__(self, other):
18
+ if not isinstance(other, self.__class__):
19
+ return False
20
+ return hash(self) == hash(other)
21
+
22
+ def __ne__(self, other):
23
+ # Not strictly necessary, but to avoid having both x==y and x!=y
24
+ # True at the same time
25
+ return not (self == other)
model/Reservation.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .Constant import Constant
2
+
3
+
4
+ class Reservation:
5
+ NR = -1
6
+ _reservationPool = {}
7
+
8
+
9
+ def __init__(self, day: int, time: int, room: int):
10
+ self.Day = day
11
+ self.Time = time
12
+ self.Room = room
13
+
14
+ @staticmethod
15
+ def parse(hashCode):
16
+ reservation = Reservation._reservationPool.get(hashCode)
17
+ if reservation is None:
18
+ day = hashCode // (Constant.DAY_HOURS * Reservation.NR)
19
+ hashCode2 = hashCode - (day * Constant.DAY_HOURS * Reservation.NR)
20
+ room = hashCode2 // Constant.DAY_HOURS
21
+ time = hashCode2 % Constant.DAY_HOURS
22
+ reservation = Reservation(day, time, room)
23
+ Reservation._reservationPool[hashCode] = reservation
24
+ return reservation
25
+
26
+ @staticmethod
27
+ def getHashCode(day: int, time: int, room: int) -> int:
28
+ return day * Reservation.NR * Constant.DAY_HOURS + room * Constant.DAY_HOURS + time
29
+
30
+ @staticmethod
31
+ def getReservation(nr: int, day: int, time: int, room: int):
32
+ if nr != Reservation.NR and nr > 0:
33
+ Reservation.NR = nr
34
+ Reservation._reservationPool.clear()
35
+
36
+ hashCode = Reservation.getHashCode(day, time, room)
37
+ reservation = Reservation.parse(hashCode)
38
+
39
+ if reservation is None:
40
+ reservation = Reservation(day, time, room)
41
+ Reservation._reservationPool[hashCode] = reservation
42
+ return reservation
43
+
44
+ def __hash__(self) -> int:
45
+ return Reservation.getHashCode(self.Day, self.Time, self.Room)
46
+
47
+
48
+ def __eq__(self, other):
49
+ if not isinstance(other, self.__class__):
50
+ return False
51
+ return hash(self) == hash(other)
52
+
53
+ def __ne__(self, other):
54
+ return not self.__eq__(other)
55
+
56
+ def __str__(self):
57
+ return "Day: " + str(self.Day) + ", " + "Room: " + str(self.Room) + ", Time: " + str(self.Time)
model/Room.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Stores data about classroom
2
+ class Room:
3
+ # ID counter used to assign IDs automatically
4
+ _next_room_id = 0
5
+
6
+ # Initializes room data and assign ID to room
7
+ def __init__(self, name, lab, number_of_seats):
8
+ # Returns room ID - automatically assigned
9
+ self.Id = Room._next_room_id
10
+ Room._next_room_id += 1
11
+ # Returns name
12
+ self.Name = name
13
+ # Returns TRUE if room has computers otherwise it returns FALSE
14
+ self.Lab = lab
15
+ # Returns number of seats in room
16
+ self.NumberOfSeats = number_of_seats
17
+
18
+ def __hash__(self):
19
+ return hash(self.Id)
20
+
21
+ # Compares ID's of two objects which represent rooms
22
+ def __eq__(self, other):
23
+ if not isinstance(other, self.__class__):
24
+ return False
25
+ return hash(self) == hash(other)
26
+
27
+ def __ne__(self, other):
28
+ # Not strictly necessary, but to avoid having both x==y and x!=y
29
+ # True at the same time
30
+ return not (self == other)
31
+
32
+ # Restarts ID assigments
33
+ @staticmethod
34
+ def restartIDs() -> None:
35
+ Room._next_room_id = 0
model/Schedule.py ADDED
@@ -0,0 +1,438 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .Constant import Constant
2
+ from .CourseClass import CourseClass
3
+ from .Reservation import Reservation
4
+ from .Criteria import Criteria
5
+ from collections import deque
6
+ from random import randrange
7
+
8
+ import numpy as np
9
+
10
+ # Schedule chromosome
11
+ class Schedule:
12
+ # Initializes chromosomes with configuration block (setup of chromosome)
13
+ def __init__(self, configuration):
14
+ self._configuration = configuration
15
+ # Fitness value of chromosome
16
+ self._fitness = 0
17
+
18
+ # Time-space slots, one entry represent one hour in one classroom
19
+ slots_length = Constant.DAYS_NUM * Constant.DAY_HOURS * self._configuration.numberOfRooms
20
+ self._slots = [[] for _ in range(slots_length)]
21
+
22
+ # Class table for chromosome
23
+ # Used to determine first time-space slot used by class
24
+ self._classes = {}
25
+
26
+ # Flags of class requirements satisfaction
27
+ self._criteria = np.zeros(self._configuration.numberOfCourseClasses * len(Criteria.weights), dtype=bool)
28
+
29
+ self._diversity = 0.0
30
+ self._rank = 0
31
+
32
+ self._convertedObjectives = []
33
+ self._objectives = []
34
+
35
+ def copy(self, c, setup_only):
36
+ if not setup_only:
37
+ self._configuration = c.configuration
38
+ # copy code
39
+ self._slots, self._classes = [row[:] for row in c.slots], {key: value for key, value in c.classes.items()}
40
+
41
+ # copy flags of class requirements
42
+ self._criteria = c.criteria[:]
43
+
44
+ # copy fitness
45
+ self._fitness = c.fitness
46
+ return self
47
+
48
+ return Schedule(c.configuration)
49
+
50
+ # Makes new chromosome with same setup but with randomly chosen code
51
+ def makeNewFromPrototype(self, positions = None):
52
+ # make new chromosome, copy chromosome setup
53
+ new_chromosome = self.copy(self, True)
54
+ new_chromosome_slots, new_chromosome_classes = new_chromosome._slots, new_chromosome._classes
55
+
56
+ # place classes at random position
57
+ classes = self._configuration.courseClasses
58
+ nr = self._configuration.numberOfRooms
59
+ DAYS_NUM, DAY_HOURS = Constant.DAYS_NUM, Constant.DAY_HOURS
60
+ for c in classes:
61
+ # determine random position of class
62
+ dur = c.Duration
63
+
64
+ day = randrange(DAYS_NUM)
65
+ room = randrange(nr)
66
+ time = randrange(DAY_HOURS - dur)
67
+ reservation = Reservation.getReservation(nr, day, time, room)
68
+
69
+ if positions is not None:
70
+ positions.append(day)
71
+ positions.append(room)
72
+ positions.append(time)
73
+ reservation_index = hash(reservation)
74
+
75
+ # fill time-space slots, for each hour of class
76
+ for i in range(dur - 1, -1, -1):
77
+ new_chromosome_slots[reservation_index + i].append(c)
78
+
79
+ # insert in class table of chromosome
80
+ new_chromosome_classes[c] = reservation_index
81
+
82
+ new_chromosome.calculateFitness()
83
+ return new_chromosome
84
+
85
+ # Performs crossover operation using to chromosomes and returns pointer to offspring
86
+ def crossover(self, parent, numberOfCrossoverPoints, crossoverProbability):
87
+ # check probability of crossover operation
88
+ if randrange(100) > crossoverProbability:
89
+ # no crossover, just copy first parent
90
+ return self.copy(self, False)
91
+
92
+ # new chromosome object, copy chromosome setup
93
+ n = self.copy(self, True)
94
+ n_classes, n_slots = n._classes, n._slots
95
+
96
+ classes = self._classes
97
+ course_classes = tuple(classes.keys())
98
+ parent_classes = parent.classes
99
+ parent_course_classes = tuple(parent.classes.keys())
100
+
101
+ # number of classes
102
+ size = len(classes)
103
+
104
+ cp = size * [False]
105
+
106
+ # determine crossover point (randomly)
107
+ for i in range(numberOfCrossoverPoints, 0, -1):
108
+ check_point = False
109
+ while not check_point:
110
+ p = randrange(size)
111
+ if not cp[p]:
112
+ cp[p] = check_point = True
113
+
114
+ # make new code by combining parent codes
115
+ first = randrange(2) == 0
116
+
117
+ for i in range(size):
118
+ if first:
119
+ course_class = course_classes[i]
120
+ dur = course_class.Duration
121
+ reservation_index = classes[course_class]
122
+ # insert class from first parent into new chromosome's class table
123
+ n_classes[course_class] = reservation_index
124
+ # all time-space slots of class are copied
125
+ for j in range(dur - 1, -1, -1):
126
+ n_slots[reservation_index + j].append(course_class)
127
+ else:
128
+ course_class = parent_course_classes[i]
129
+ dur = course_class.Duration
130
+ reservation_index = parent_classes[course_class]
131
+ # insert class from second parent into new chromosome's class table
132
+ n_classes[course_class] = reservation_index
133
+ # all time-space slots of class are copied
134
+ for j in range(dur - 1, -1, -1):
135
+ n_slots[reservation_index + j].append(course_class)
136
+
137
+ # crossover point
138
+ if cp[i]:
139
+ # change source chromosome
140
+ first = not first
141
+
142
+ n.calculateFitness()
143
+
144
+ # return smart pointer to offspring
145
+ return n
146
+
147
+ # Performs crossover operation using to chromosomes and returns pointer to offspring
148
+ def crossovers(self, parent, r1, r2, r3, etaCross, crossoverProbability):
149
+ # number of classes
150
+ size = len(self._classes)
151
+ jrand = randrange(size)
152
+
153
+ nr = self._configuration.numberOfRooms
154
+ DAY_HOURS, DAYS_NUM = Constant.DAY_HOURS, Constant.DAYS_NUM
155
+
156
+ # make new chromosome, copy chromosome setup
157
+ new_chromosome = self.copy(self, True)
158
+ new_chromosome_slots, new_chromosome_classes = new_chromosome._slots, new_chromosome._classes
159
+ classes = self._classes
160
+ course_classes = tuple(classes.keys())
161
+ parent_classes = parent.classes
162
+ parent_course_classes = tuple(parent.classes.keys())
163
+ for i in range(size):
164
+ if randrange(100) > crossoverProbability or i == jrand:
165
+ course_class = course_classes[i]
166
+ reservation1, reservation2 = Reservation.parse(r1.classes[course_class]), Reservation.parse(r2.classes[course_class])
167
+ reservation3 = Reservation.parse(r3.classes[course_class])
168
+
169
+ dur = course_class.Duration
170
+ day = int(reservation3.Day + etaCross * (reservation1.Day - reservation2.Day))
171
+ if day < 0:
172
+ day = 0
173
+ elif day >= DAYS_NUM:
174
+ day = DAYS_NUM - 1
175
+
176
+ room = int(reservation3.Room + etaCross * (reservation1.Room - reservation2.Room))
177
+ if room < 0:
178
+ room = 0
179
+ elif room >= nr:
180
+ room = nr - 1
181
+
182
+ time = int(reservation3.Time + etaCross * (reservation1.Time - reservation2.Time))
183
+ if time < 0:
184
+ time = 0
185
+ elif time >= (DAY_HOURS - dur):
186
+ time = DAY_HOURS - 1 - dur
187
+
188
+ reservation = Reservation.getReservation(nr, day, time, room)
189
+ reservation_index = hash(reservation)
190
+
191
+ # fill time-space slots, for each hour of class
192
+ for j in range(dur - 1, -1, -1):
193
+ new_chromosome_slots[reservation_index + j].append(course_class)
194
+
195
+ # insert in class table of chromosome
196
+ new_chromosome_classes[course_class] = reservation_index
197
+ else:
198
+ course_class = parent_course_classes[i]
199
+ dur = course_class.Duration
200
+ reservation = parent_classes[course_class]
201
+ reservation_index = hash(reservation)
202
+
203
+ # all time-space slots of class are copied
204
+ for j in range(dur - 1, -1, -1):
205
+ new_chromosome_slots[reservation_index + j].append(course_class)
206
+
207
+ # insert class from second parent into new chromosome's class table
208
+ new_chromosome_classes[course_class] = reservation_index
209
+
210
+ new_chromosome.calculateFitness()
211
+
212
+ # return smart pointer to offspring
213
+ return new_chromosome
214
+
215
+ def repair(self, cc1: CourseClass, reservation1_index: int, reservation2: Reservation):
216
+ nr = self._configuration.numberOfRooms
217
+ DAY_HOURS, DAYS_NUM = Constant.DAY_HOURS, Constant.DAYS_NUM
218
+ slots = self._slots
219
+ dur = cc1.Duration
220
+
221
+ for j in range(dur):
222
+ # remove class hour from current time-space slot
223
+ cl = slots[reservation1_index + j]
224
+ while cc1 in cl:
225
+ cl.remove(cc1)
226
+
227
+ # determine position of class randomly
228
+ if reservation2 is None:
229
+ day = randrange(DAYS_NUM)
230
+ room = randrange(nr)
231
+ time = randrange(DAY_HOURS - dur)
232
+ reservation2 = Reservation.getReservation(nr, day, time, room)
233
+
234
+ reservation2_index = hash(reservation2)
235
+ for j in range(dur):
236
+ # move class hour to new time-space slot
237
+ slots[reservation2_index + j].append(cc1)
238
+
239
+ # change entry of class table to point to new time-space slots
240
+ self._classes[cc1] = reservation2_index
241
+
242
+ # Performs mutation on chromosome
243
+ def mutation(self, mutationSize, mutationProbability):
244
+ # check probability of mutation operation
245
+ if randrange(100) > mutationProbability:
246
+ return
247
+
248
+ classes = self._classes
249
+ # number of classes
250
+ numberOfClasses = len(classes)
251
+ course_classes = tuple(classes.keys())
252
+ configuration = self._configuration
253
+ nr = configuration.numberOfRooms
254
+
255
+ # move selected number of classes at random position
256
+ for i in range(mutationSize, 0, -1):
257
+ # select ranom chromosome for movement
258
+ mpos = randrange(numberOfClasses)
259
+
260
+ # current time-space slot used by class
261
+ cc1 = course_classes[mpos]
262
+ reservation1_index = classes[cc1]
263
+
264
+ self.repair(cc1, reservation1_index, None)
265
+
266
+ self.calculateFitness()
267
+
268
+ # Calculates fitness value of chromosome
269
+ def calculateFitness(self):
270
+
271
+ # increment value when criteria violation occurs
272
+ self._objectives = np.zeros(len(Criteria.weights))
273
+
274
+ # chromosome's score
275
+ score = 0
276
+
277
+ criteria, configuration = self._criteria, self._configuration
278
+ items, slots = self._classes.items(), self._slots
279
+ numberOfRooms = configuration.numberOfRooms
280
+ DAY_HOURS, DAYS_NUM = Constant.DAY_HOURS, Constant.DAYS_NUM
281
+ daySize = DAY_HOURS * numberOfRooms
282
+
283
+ ci = 0
284
+ getRoomById = configuration.getRoomById
285
+
286
+ # check criteria and calculate scores for each class in schedule
287
+ for cc, reservation_index in items:
288
+ reservation = Reservation.parse(reservation_index)
289
+
290
+ # coordinate of time-space slot
291
+ day, time, room = reservation.Day, reservation.Time, reservation.Room
292
+
293
+ dur = cc.Duration
294
+
295
+ ro = Criteria.isRoomOverlapped(slots, reservation, dur)
296
+
297
+ # on room overlapping
298
+ criteria[ci + 0] = not ro
299
+
300
+ r = getRoomById(room)
301
+
302
+ # does current room have enough seats
303
+ criteria[ci + 1] = Criteria.isSeatEnough(r, cc)
304
+
305
+ # does current room have computers if they are required
306
+ criteria[ci + 2] = Criteria.isComputerEnough(r, cc)
307
+
308
+ # check overlapping of classes for professors
309
+ timeId = day * daySize + time
310
+ po, go = Criteria.isOverlappedProfStudentGrp(slots, cc, numberOfRooms, timeId)
311
+
312
+ # professors have no overlapping classes?
313
+ criteria[ci + 3] = not po
314
+
315
+ # student groups has no overlapping classes?
316
+ criteria[ci + 4] = not go
317
+
318
+ for i in range(len(self._objectives)):
319
+ if criteria[ci + i]:
320
+ score += 1
321
+ else:
322
+ score += Criteria.weights[i]
323
+ self._objectives[i] += 1 if Criteria.weights[i] > 0 else 2
324
+
325
+ ci += len(Criteria.weights)
326
+
327
+ # calculate fitness value based on score
328
+ self._fitness = score / len(criteria)
329
+
330
+ def getDifference(self, other):
331
+ return (self._criteria ^ other.criteria).sum()
332
+
333
+
334
+ def extractPositions(self, positions):
335
+ i = 0
336
+ items = self._classes.items()
337
+ for cc, reservation_index in items:
338
+ reservation = Reservation.parse(reservation_index)
339
+
340
+ positions[i] = reservation.Day
341
+ i += 1
342
+ positions[i] = reservation.Room
343
+ i += 1
344
+ positions[i] = reservation.Time
345
+ i += 1
346
+
347
+
348
+ def updatePositions(self, positions):
349
+ DAYS_NUM, DAY_HOURS = Constant.DAYS_NUM, Constant.DAY_HOURS
350
+ nr = self._configuration.numberOfRooms
351
+ i = 0
352
+ items = self._classes.items()
353
+ for cc, reservation1_index in items:
354
+ dur = cc.Duration
355
+ day = abs(int(positions[i]) % DAYS_NUM)
356
+ room = abs(int(positions[i + 1]) % nr)
357
+ time = abs(int(positions[i + 2]) % (DAY_HOURS - dur))
358
+
359
+ reservation2 = Reservation.getReservation(nr, day, time, room)
360
+ self.repair(cc, reservation1_index, reservation2)
361
+
362
+ positions[i] = reservation2.Day
363
+ i += 1
364
+
365
+ positions[i] = reservation2.Room
366
+ i += 1
367
+
368
+ positions[i] = reservation2.Time
369
+ i += 1
370
+
371
+
372
+ self.calculateFitness()
373
+
374
+
375
+ # Returns fitness value of chromosome
376
+ @property
377
+ def fitness(self):
378
+ return self._fitness
379
+
380
+ @property
381
+ def configuration(self):
382
+ return self._configuration
383
+
384
+ @property
385
+ # Returns reference to table of classes
386
+ def classes(self):
387
+ return self._classes
388
+
389
+ @property
390
+ # Returns array of flags of class requirements satisfaction
391
+ def criteria(self):
392
+ return self._criteria
393
+
394
+ @property
395
+ # Return reference to array of time-space slots
396
+ def slots(self):
397
+ return self._slots
398
+
399
+ @property
400
+ def diversity(self):
401
+ return self._diversity
402
+
403
+ @diversity.setter
404
+ def diversity(self, new_diversity):
405
+ self._diversity = new_diversity
406
+
407
+ @property
408
+ def rank(self):
409
+ return self._rank
410
+
411
+ @rank.setter
412
+ def rank(self, new_rank):
413
+ self._rank = new_rank
414
+
415
+ @property
416
+ def convertedObjectives(self):
417
+ return self._convertedObjectives
418
+
419
+ @property
420
+ def objectives(self):
421
+ return self._objectives
422
+
423
+ def resizeConvertedObjectives(self, numObj):
424
+ self._convertedObjectives = numObj * [0]
425
+
426
+ def clone(self):
427
+ return self.copy(self, False)
428
+
429
+ def dominates(self, other):
430
+ better = False
431
+ for f, obj in enumerate(self.objectives):
432
+ if obj > other.objectives[f]:
433
+ return False
434
+
435
+ if obj < other.objectives[f]:
436
+ better = True
437
+
438
+ return better
model/StudentsGroup.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Stores data about student group
2
+ class StudentsGroup:
3
+ # Initializes student group data
4
+ def __init__(self, id, numberOfStudents):
5
+ self.Id = id
6
+ # self.Name = name
7
+ self.NumberOfStudents = numberOfStudents
8
+ self.CourseClasses = []
9
+
10
+ # Bind group to class
11
+ def addClass(self, course_class):
12
+ self.CourseClasses.append(course_class)
13
+
14
+ def __hash__(self):
15
+ return hash(self.Id)
16
+
17
+ # Compares ID's of two objects which represent student groups
18
+ def __eq__(self, other):
19
+ if not isinstance(other, self.__class__):
20
+ return False
21
+ return hash(self) == hash(other)
22
+
23
+ def __ne__(self, other):
24
+ # Not strictly necessary, but to avoid having both x==y and x!=y
25
+ # True at the same time
26
+ return not (self == other)
model/__pycache__/Configuration.cpython-39.pyc ADDED
Binary file (5.18 kB). View file
 
model/__pycache__/Constant.cpython-39.pyc ADDED
Binary file (373 Bytes). View file
 
model/__pycache__/Course.cpython-39.pyc ADDED
Binary file (475 Bytes). View file
 
model/__pycache__/CourseClass.cpython-39.pyc ADDED
Binary file (1.74 kB). View file
 
model/__pycache__/Criteria.cpython-39.pyc ADDED
Binary file (1.63 kB). View file
 
model/__pycache__/Professor.cpython-39.pyc ADDED
Binary file (1.12 kB). View file
 
model/__pycache__/Reservation.cpython-39.pyc ADDED
Binary file (2.19 kB). View file
 
model/__pycache__/Room.cpython-39.pyc ADDED
Binary file (1.18 kB). View file
 
model/__pycache__/Schedule.cpython-39.pyc ADDED
Binary file (9.32 kB). View file
 
model/__pycache__/StudentsGroup.cpython-39.pyc ADDED
Binary file (1.16 kB). View file
 
processing data/GaSchedule3.json ADDED
@@ -0,0 +1 @@
 
 
1
+ [{"prof": {"id": 174, "name": "Dao Tran Hoang Chau"}}, {"course": {"id": 1, "name": "Functional Programming"}}, {"group": {"id": 1, "size": 10}}, {"class": {"professor": 174, "course": 1, "duration": 3, "group": 1, "lab": false}}, {"prof": {"id": 119, "name": "Tran Manh Ha"}}, {"course": {"id": 2, "name": "Operating Systems"}}, {"group": {"id": 2, "size": 90}}, {"class": {"professor": 119, "course": 2, "duration": 3, "group": 2, "lab": false}}, {"group": {"id": 3, "size": 30}}, {"class": {"professor": 119, "course": 2, "duration": 4, "group": 3, "lab": true}}, {"prof": {"id": 213, "name": "Nguyen Tien Dung"}}, {"group": {"id": 4, "size": 30}}, {"class": {"professor": 213, "course": 2, "duration": 4, "group": 4, "lab": true}}, {"group": {"id": 5, "size": 30}}, {"class": {"professor": 213, "course": 2, "duration": 4, "group": 5, "lab": true}}, {"prof": {"id": 74, "name": "Nguyen Van Sinh"}}, {"course": {"id": 3, "name": "IT Project Management"}}, {"group": {"id": 6, "size": 35}}, {"class": {"professor": 74, "course": 3, "duration": 3, "group": 6, "lab": false}}, {"group": {"id": 7, "size": 35}}, {"class": {"professor": 74, "course": 3, "duration": 4, "group": 7, "lab": true}}, {"prof": {"id": 84, "name": "Le Hai Duong"}}, {"course": {"id": 4, "name": "Introduction to Computing"}}, {"group": {"id": 8, "size": 35}}, {"class": {"professor": 84, "course": 4, "duration": 3, "group": 8, "lab": false}}, {"prof": {"id": 19, "name": "Huynh Kha Tu"}}, {"course": {"id": 5, "name": "Digital Logic Design"}}, {"group": {"id": 9, "size": 90}}, {"class": {"professor": 19, "course": 5, "duration": 3, "group": 9, "lab": false}}, {"prof": {"id": 182, "name": "Tran Thanh Tung"}}, {"course": {"id": 6, "name": "Object-Oriented Programming"}}, {"group": {"id": 10, "size": 90}}, {"class": {"professor": 182, "course": 6, "duration": 3, "group": 10, "lab": false}}, {"group": {"id": 11, "size": 30}}, {"class": {"professor": 213, "course": 6, "duration": 4, "group": 11, "lab": true}}, {"group": {"id": 12, "size": 30}}, {"class": {"professor": 213, "course": 6, "duration": 4, "group": 12, "lab": true}}, {"group": {"id": 13, "size": 30}}, {"class": {"professor": 213, "course": 6, "duration": 4, "group": 13, "lab": true}}, {"prof": {"id": 349, "name": "Nguyen Thi Thanh Sang"}}, {"course": {"id": 7, "name": "Software Engineering"}}, {"group": {"id": 14, "size": 70}}, {"class": {"professor": 349, "course": 7, "duration": 3, "group": 14, "lab": false}}, {"group": {"id": 15, "size": 35}}, {"class": {"professor": 349, "course": 7, "duration": 4, "group": 15, "lab": true}}, {"group": {"id": 16, "size": 35}}, {"class": {"professor": 349, "course": 7, "duration": 4, "group": 16, "lab": true}}, {"prof": {"id": 62, "name": "Vo Thi Luu Phuong"}}, {"course": {"id": 8, "name": "Computer Networks"}}, {"group": {"id": 17, "size": 70}}, {"class": {"professor": 62, "course": 8, "duration": 3, "group": 17, "lab": false}}, {"group": {"id": 18, "size": 35}}, {"class": {"professor": 62, "course": 8, "duration": 4, "group": 18, "lab": true}}, {"group": {"id": 19, "size": 35}}, {"class": {"professor": 62, "course": 8, "duration": 4, "group": 19, "lab": true}}, {"prof": {"id": 60, "name": "Ly Tu Nga"}}, {"group": {"id": 20, "size": 20}}, {"class": {"professor": 60, "course": 8, "duration": 4, "group": 20, "lab": true}}, {"course": {"id": 9, "name": "Web Application Development"}}, {"group": {"id": 21, "size": 15}}, {"class": {"professor": 74, "course": 9, "duration": 3, "group": 21, "lab": false}}, {"group": {"id": 22, "size": 15}}, {"class": {"professor": 74, "course": 9, "duration": 4, "group": 22, "lab": true}}, {"group": {"id": 23, "size": 20}}, {"class": {"professor": 213, "course": 9, "duration": 4, "group": 23, "lab": true}}, {"prof": {"id": 36, "name": "Le Thanh Son"}}, {"course": {"id": 10, "name": "Net-Centric Programming"}}, {"group": {"id": 24, "size": 17}}, {"class": {"professor": 36, "course": 10, "duration": 3, "group": 24, "lab": false}}, {"group": {"id": 25, "size": 17}}, {"class": {"professor": 36, "course": 10, "duration": 4, "group": 25, "lab": true}}, {"course": {"id": 11, "name": "Digital Logic Design Laboratory"}}, {"group": {"id": 26, "size": 15}}, {"class": {"professor": 60, "course": 11, "duration": 4, "group": 26, "lab": false}}, {"group": {"id": 27, "size": 15}}, {"class": {"professor": 60, "course": 11, "duration": 4, "group": 27, "lab": false}}, {"group": {"id": 28, "size": 15}}, {"class": {"professor": 60, "course": 11, "duration": 4, "group": 28, "lab": false}}, {"group": {"id": 29, "size": 15}}, {"class": {"professor": 60, "course": 11, "duration": 4, "group": 29, "lab": false}}, {"group": {"id": 30, "size": 15}}, {"class": {"professor": 60, "course": 11, "duration": 4, "group": 30, "lab": false}}, {"course": {"id": 12, "name": "Entrepreneurship"}}, {"group": {"id": 31, "size": 80}}, {"class": {"professor": 174, "course": 12, "duration": 3, "group": 31, "lab": false}}, {"course": {"id": 13, "name": "System & Network Administration"}}, {"group": {"id": 32, "size": 35}}, {"class": {"professor": 36, "course": 13, "duration": 3, "group": 32, "lab": false}}, {"group": {"id": 33, "size": 35}}, {"class": {"professor": 36, "course": 13, "duration": 4, "group": 33, "lab": true}}, {"prof": {"id": 184, "name": "Ha Viet Uyen Synh"}}, {"course": {"id": 14, "name": "Theoretical Models in Computing"}}, {"group": {"id": 34, "size": 80}}, {"class": {"professor": 184, "course": 14, "duration": 3, "group": 34, "lab": false}}, {"group": {"id": 35, "size": 26}}, {"class": {"professor": 184, "course": 14, "duration": 4, "group": 35, "lab": true}}, {"group": {"id": 36, "size": 28}}, {"class": {"professor": 184, "course": 14, "duration": 4, "group": 36, "lab": true}}, {"course": {"id": 15, "name": "Discrete Mathematics"}}, {"group": {"id": 37, "size": 80}}, {"class": {"professor": 74, "course": 15, "duration": 3, "group": 37, "lab": false}}, {"room": {"name": "A1.309", "lab": false, "size": 90}}, {"room": {"name": "L107", "lab": false, "size": 40}}, {"room": {"name": "LA1.605", "lab": true, "size": 35}}, {"room": {"name": "LA1.607", "lab": true, "size": 35}}]
processing data/data.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {'class': {'course': 15, 'duration': 3, 'professor': 1}}{'room': {'lab': False, 'name': 'A1', 'size': 60}}{'prof': {'id': 1, 'name': 'Tran Tien Khoa'}}{'course': {'id': 26, 'name': 'Financial Accounting (2)'}}{'course': {'id': 15, 'name': 'Principles of Marketing (1)'}}{'class': {'course': 15, 'duration': 4, 'professor': 1}}{'class': {'course': 26, 'duration': 4, 'professor': 2}}{'class': {'course': 26, 'duration': 3, 'professor': 2}}{'room': {'lab': True, 'name': 'A2', 'size': 24}}{'prof': {'id': 2, 'name': 'Le Ngoc Anh Khoa'}}
processing data/reprocessing.ipynb ADDED
@@ -0,0 +1,589 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "3745035b",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "data": {
11
+ "text/html": [
12
+ "<div>\n",
13
+ "<style scoped>\n",
14
+ " .dataframe tbody tr th:only-of-type {\n",
15
+ " vertical-align: middle;\n",
16
+ " }\n",
17
+ "\n",
18
+ " .dataframe tbody tr th {\n",
19
+ " vertical-align: top;\n",
20
+ " }\n",
21
+ "\n",
22
+ " .dataframe thead th {\n",
23
+ " text-align: right;\n",
24
+ " }\n",
25
+ "</style>\n",
26
+ "<table border=\"1\" class=\"dataframe\">\n",
27
+ " <thead>\n",
28
+ " <tr style=\"text-align: right;\">\n",
29
+ " <th></th>\n",
30
+ " <th>MaMH</th>\n",
31
+ " <th>TenMH</th>\n",
32
+ " <th>NhomTo</th>\n",
33
+ " <th>ToTH</th>\n",
34
+ " <th>TenLop</th>\n",
35
+ " <th>TongSoSV</th>\n",
36
+ " <th>ThuKieuSo</th>\n",
37
+ " <th>TietBD</th>\n",
38
+ " <th>SoTiet</th>\n",
39
+ " <th>MaPH</th>\n",
40
+ " <th>DSTuanHoc</th>\n",
41
+ " <th>MaNV</th>\n",
42
+ " <th>TenDayDuNV</th>\n",
43
+ " <th>IsTKBDaXep</th>\n",
44
+ " <th>MaDV</th>\n",
45
+ " <th>TenDV</th>\n",
46
+ " <th>TenDVEg</th>\n",
47
+ " <th>NgayBD</th>\n",
48
+ " <th>NgayKT</th>\n",
49
+ " </tr>\n",
50
+ " </thead>\n",
51
+ " <tbody>\n",
52
+ " <tr>\n",
53
+ " <th>0</th>\n",
54
+ " <td>1</td>\n",
55
+ " <td>Functional Programming</td>\n",
56
+ " <td>1</td>\n",
57
+ " <td>NaN</td>\n",
58
+ " <td>ITIT16UN11, ITIT16UN21</td>\n",
59
+ " <td>10</td>\n",
60
+ " <td>2</td>\n",
61
+ " <td>1</td>\n",
62
+ " <td>3</td>\n",
63
+ " <td>LA1.605</td>\n",
64
+ " <td>-2345678901234567---</td>\n",
65
+ " <td>174</td>\n",
66
+ " <td>Dao Tran Hoang Chau</td>\n",
67
+ " <td>0</td>\n",
68
+ " <td>IT IT</td>\n",
69
+ " <td>Computer Science &amp; Engineering</td>\n",
70
+ " <td>Computer Science &amp; Engineering</td>\n",
71
+ " <td>42989</td>\n",
72
+ " <td>43094</td>\n",
73
+ " </tr>\n",
74
+ " <tr>\n",
75
+ " <th>1</th>\n",
76
+ " <td>2</td>\n",
77
+ " <td>Operating Systems</td>\n",
78
+ " <td>1</td>\n",
79
+ " <td>NaN</td>\n",
80
+ " <td>ITIT15CS1, ITIT15IU11, ITIT15IU21, ITIT15IU31</td>\n",
81
+ " <td>90</td>\n",
82
+ " <td>6</td>\n",
83
+ " <td>6</td>\n",
84
+ " <td>3</td>\n",
85
+ " <td>A1.309</td>\n",
86
+ " <td>-2345678901234567---</td>\n",
87
+ " <td>119</td>\n",
88
+ " <td>Tran Manh Ha</td>\n",
89
+ " <td>0</td>\n",
90
+ " <td>IT IT</td>\n",
91
+ " <td>Computer Science &amp; Engineering</td>\n",
92
+ " <td>Computer Science &amp; Engineering</td>\n",
93
+ " <td>42993</td>\n",
94
+ " <td>43098</td>\n",
95
+ " </tr>\n",
96
+ " <tr>\n",
97
+ " <th>2</th>\n",
98
+ " <td>2</td>\n",
99
+ " <td>Operating Systems</td>\n",
100
+ " <td>1</td>\n",
101
+ " <td>1.0</td>\n",
102
+ " <td>ITIT15CS1, ITIT15IU11, ITIT15IU21, ITIT15IU31</td>\n",
103
+ " <td>30</td>\n",
104
+ " <td>2</td>\n",
105
+ " <td>6</td>\n",
106
+ " <td>4</td>\n",
107
+ " <td>LA1.605</td>\n",
108
+ " <td>-----678901234------</td>\n",
109
+ " <td>119</td>\n",
110
+ " <td>Tran Manh Ha</td>\n",
111
+ " <td>0</td>\n",
112
+ " <td>IT IT</td>\n",
113
+ " <td>Computer Science &amp; Engineering</td>\n",
114
+ " <td>Computer Science &amp; Engineering</td>\n",
115
+ " <td>43017</td>\n",
116
+ " <td>43073</td>\n",
117
+ " </tr>\n",
118
+ " <tr>\n",
119
+ " <th>3</th>\n",
120
+ " <td>2</td>\n",
121
+ " <td>Operating Systems</td>\n",
122
+ " <td>1</td>\n",
123
+ " <td>2.0</td>\n",
124
+ " <td>ITIT15CS1, ITIT15IU11, ITIT15IU21, ITIT15IU31</td>\n",
125
+ " <td>30</td>\n",
126
+ " <td>2</td>\n",
127
+ " <td>1</td>\n",
128
+ " <td>4</td>\n",
129
+ " <td>LA1.608</td>\n",
130
+ " <td>-----678901234------</td>\n",
131
+ " <td>213</td>\n",
132
+ " <td>Nguyen Tien Dung</td>\n",
133
+ " <td>0</td>\n",
134
+ " <td>IT IT</td>\n",
135
+ " <td>Computer Science &amp; Engineering</td>\n",
136
+ " <td>Computer Science &amp; Engineering</td>\n",
137
+ " <td>43017</td>\n",
138
+ " <td>43073</td>\n",
139
+ " </tr>\n",
140
+ " <tr>\n",
141
+ " <th>4</th>\n",
142
+ " <td>2</td>\n",
143
+ " <td>Operating Systems</td>\n",
144
+ " <td>1</td>\n",
145
+ " <td>3.0</td>\n",
146
+ " <td>ITIT15CS1, ITIT15IU11, ITIT15IU21, ITIT15IU31</td>\n",
147
+ " <td>30</td>\n",
148
+ " <td>2</td>\n",
149
+ " <td>6</td>\n",
150
+ " <td>4</td>\n",
151
+ " <td>LA1.607</td>\n",
152
+ " <td>-----678901234------</td>\n",
153
+ " <td>213</td>\n",
154
+ " <td>Nguyen Tien Dung</td>\n",
155
+ " <td>0</td>\n",
156
+ " <td>IT IT</td>\n",
157
+ " <td>Computer Science &amp; Engineering</td>\n",
158
+ " <td>Computer Science &amp; Engineering</td>\n",
159
+ " <td>43017</td>\n",
160
+ " <td>43073</td>\n",
161
+ " </tr>\n",
162
+ " </tbody>\n",
163
+ "</table>\n",
164
+ "</div>"
165
+ ],
166
+ "text/plain": [
167
+ " MaMH TenMH NhomTo ToTH \\\n",
168
+ "0 1 Functional Programming 1 NaN \n",
169
+ "1 2 Operating Systems 1 NaN \n",
170
+ "2 2 Operating Systems 1 1.0 \n",
171
+ "3 2 Operating Systems 1 2.0 \n",
172
+ "4 2 Operating Systems 1 3.0 \n",
173
+ "\n",
174
+ " TenLop TongSoSV ThuKieuSo TietBD \\\n",
175
+ "0 ITIT16UN11, ITIT16UN21 10 2 1 \n",
176
+ "1 ITIT15CS1, ITIT15IU11, ITIT15IU21, ITIT15IU31 90 6 6 \n",
177
+ "2 ITIT15CS1, ITIT15IU11, ITIT15IU21, ITIT15IU31 30 2 6 \n",
178
+ "3 ITIT15CS1, ITIT15IU11, ITIT15IU21, ITIT15IU31 30 2 1 \n",
179
+ "4 ITIT15CS1, ITIT15IU11, ITIT15IU21, ITIT15IU31 30 2 6 \n",
180
+ "\n",
181
+ " SoTiet MaPH DSTuanHoc MaNV TenDayDuNV \\\n",
182
+ "0 3 LA1.605 -2345678901234567--- 174 Dao Tran Hoang Chau \n",
183
+ "1 3 A1.309 -2345678901234567--- 119 Tran Manh Ha \n",
184
+ "2 4 LA1.605 -----678901234------ 119 Tran Manh Ha \n",
185
+ "3 4 LA1.608 -----678901234------ 213 Nguyen Tien Dung \n",
186
+ "4 4 LA1.607 -----678901234------ 213 Nguyen Tien Dung \n",
187
+ "\n",
188
+ " IsTKBDaXep MaDV TenDV \\\n",
189
+ "0 0 IT IT Computer Science & Engineering \n",
190
+ "1 0 IT IT Computer Science & Engineering \n",
191
+ "2 0 IT IT Computer Science & Engineering \n",
192
+ "3 0 IT IT Computer Science & Engineering \n",
193
+ "4 0 IT IT Computer Science & Engineering \n",
194
+ "\n",
195
+ " TenDVEg NgayBD NgayKT \n",
196
+ "0 Computer Science & Engineering 42989 43094 \n",
197
+ "1 Computer Science & Engineering 42993 43098 \n",
198
+ "2 Computer Science & Engineering 43017 43073 \n",
199
+ "3 Computer Science & Engineering 43017 43073 \n",
200
+ "4 Computer Science & Engineering 43017 43073 "
201
+ ]
202
+ },
203
+ "execution_count": 1,
204
+ "metadata": {},
205
+ "output_type": "execute_result"
206
+ }
207
+ ],
208
+ "source": [
209
+ "import pandas as pd\n",
210
+ "import numpy as np\n",
211
+ "df = pd.read_csv(\"TKB HKI 2017-2018.csv\")\n",
212
+ "df.head()"
213
+ ]
214
+ },
215
+ {
216
+ "cell_type": "code",
217
+ "execution_count": 2,
218
+ "id": "a605911f",
219
+ "metadata": {},
220
+ "outputs": [
221
+ {
222
+ "data": {
223
+ "text/html": [
224
+ "<div>\n",
225
+ "<style scoped>\n",
226
+ " .dataframe tbody tr th:only-of-type {\n",
227
+ " vertical-align: middle;\n",
228
+ " }\n",
229
+ "\n",
230
+ " .dataframe tbody tr th {\n",
231
+ " vertical-align: top;\n",
232
+ " }\n",
233
+ "\n",
234
+ " .dataframe thead th {\n",
235
+ " text-align: right;\n",
236
+ " }\n",
237
+ "</style>\n",
238
+ "<table border=\"1\" class=\"dataframe\">\n",
239
+ " <thead>\n",
240
+ " <tr style=\"text-align: right;\">\n",
241
+ " <th></th>\n",
242
+ " <th>group_id</th>\n",
243
+ " <th>course_id</th>\n",
244
+ " <th>course_name</th>\n",
245
+ " <th>Lab</th>\n",
246
+ " <th>size</th>\n",
247
+ " <th>duration</th>\n",
248
+ " <th>room</th>\n",
249
+ " <th>prof_id</th>\n",
250
+ " <th>prof_name</th>\n",
251
+ " </tr>\n",
252
+ " </thead>\n",
253
+ " <tbody>\n",
254
+ " <tr>\n",
255
+ " <th>0</th>\n",
256
+ " <td>1</td>\n",
257
+ " <td>1</td>\n",
258
+ " <td>Functional Programming</td>\n",
259
+ " <td>False</td>\n",
260
+ " <td>10</td>\n",
261
+ " <td>3</td>\n",
262
+ " <td>LA1.605</td>\n",
263
+ " <td>174</td>\n",
264
+ " <td>Dao Tran Hoang Chau</td>\n",
265
+ " </tr>\n",
266
+ " <tr>\n",
267
+ " <th>1</th>\n",
268
+ " <td>2</td>\n",
269
+ " <td>2</td>\n",
270
+ " <td>Operating Systems</td>\n",
271
+ " <td>False</td>\n",
272
+ " <td>90</td>\n",
273
+ " <td>3</td>\n",
274
+ " <td>A1.309</td>\n",
275
+ " <td>119</td>\n",
276
+ " <td>Tran Manh Ha</td>\n",
277
+ " </tr>\n",
278
+ " <tr>\n",
279
+ " <th>2</th>\n",
280
+ " <td>3</td>\n",
281
+ " <td>2</td>\n",
282
+ " <td>Operating Systems</td>\n",
283
+ " <td>True</td>\n",
284
+ " <td>30</td>\n",
285
+ " <td>4</td>\n",
286
+ " <td>LA1.605</td>\n",
287
+ " <td>119</td>\n",
288
+ " <td>Tran Manh Ha</td>\n",
289
+ " </tr>\n",
290
+ " <tr>\n",
291
+ " <th>3</th>\n",
292
+ " <td>4</td>\n",
293
+ " <td>2</td>\n",
294
+ " <td>Operating Systems</td>\n",
295
+ " <td>True</td>\n",
296
+ " <td>30</td>\n",
297
+ " <td>4</td>\n",
298
+ " <td>LA1.608</td>\n",
299
+ " <td>213</td>\n",
300
+ " <td>Nguyen Tien Dung</td>\n",
301
+ " </tr>\n",
302
+ " <tr>\n",
303
+ " <th>4</th>\n",
304
+ " <td>5</td>\n",
305
+ " <td>2</td>\n",
306
+ " <td>Operating Systems</td>\n",
307
+ " <td>True</td>\n",
308
+ " <td>30</td>\n",
309
+ " <td>4</td>\n",
310
+ " <td>LA1.607</td>\n",
311
+ " <td>213</td>\n",
312
+ " <td>Nguyen Tien Dung</td>\n",
313
+ " </tr>\n",
314
+ " </tbody>\n",
315
+ "</table>\n",
316
+ "</div>"
317
+ ],
318
+ "text/plain": [
319
+ " group_id course_id course_name Lab size duration \\\n",
320
+ "0 1 1 Functional Programming False 10 3 \n",
321
+ "1 2 2 Operating Systems False 90 3 \n",
322
+ "2 3 2 Operating Systems True 30 4 \n",
323
+ "3 4 2 Operating Systems True 30 4 \n",
324
+ "4 5 2 Operating Systems True 30 4 \n",
325
+ "\n",
326
+ " room prof_id prof_name \n",
327
+ "0 LA1.605 174 Dao Tran Hoang Chau \n",
328
+ "1 A1.309 119 Tran Manh Ha \n",
329
+ "2 LA1.605 119 Tran Manh Ha \n",
330
+ "3 LA1.608 213 Nguyen Tien Dung \n",
331
+ "4 LA1.607 213 Nguyen Tien Dung "
332
+ ]
333
+ },
334
+ "execution_count": 2,
335
+ "metadata": {},
336
+ "output_type": "execute_result"
337
+ }
338
+ ],
339
+ "source": [
340
+ "df = pd.DataFrame(df)\n",
341
+ "df1 = df[['MaMH', 'TenMH', 'ToTH', 'TongSoSV', 'SoTiet', 'MaPH','MaNV', 'TenDayDuNV']]\n",
342
+ "df1 = df1.rename(columns={'MaMH': 'course_id', 'TenMH': 'course_name','ToTH': 'Lab', 'TongSoSV': 'size', 'SoTiet': 'duration', 'MaPH': 'room', 'MaNV': 'prof_id', 'TenDayDuNV': 'prof_name' })\n",
343
+ "df1['Lab'] = df1['Lab'].fillna(0)\n",
344
+ "df1['Lab'] = df1['Lab'].astype(str)\n",
345
+ "df1['prof_id'] = df1['prof_id'].astype(int)\n",
346
+ "df1['course_id'] = df1['course_id'].astype(int)\n",
347
+ "\n",
348
+ "for index, row in df1.iterrows():\n",
349
+ " if row['Lab'] == '1.0' or row['Lab'] == '2.0' or row['Lab'] == '3.0' or row['Lab'] == '4.0':\n",
350
+ " df1.at[index, 'Lab'] = 'True'\n",
351
+ " else:\n",
352
+ " df1.at[index, 'Lab'] = ''\n",
353
+ " \n",
354
+ "df1['Lab'] = df1['Lab'].astype(bool)\n",
355
+ "df1.reset_index(inplace=True)\n",
356
+ "df1 = df1.rename(columns={'index': 'group_id'})\n",
357
+ "df1['group_id'] = np.arange(1, len(df) + 1)\n",
358
+ "df1.head()"
359
+ ]
360
+ },
361
+ {
362
+ "cell_type": "code",
363
+ "execution_count": 3,
364
+ "id": "80f6ef63",
365
+ "metadata": {},
366
+ "outputs": [
367
+ {
368
+ "data": {
369
+ "text/html": [
370
+ "<div>\n",
371
+ "<style scoped>\n",
372
+ " .dataframe tbody tr th:only-of-type {\n",
373
+ " vertical-align: middle;\n",
374
+ " }\n",
375
+ "\n",
376
+ " .dataframe tbody tr th {\n",
377
+ " vertical-align: top;\n",
378
+ " }\n",
379
+ "\n",
380
+ " .dataframe thead th {\n",
381
+ " text-align: right;\n",
382
+ " }\n",
383
+ "</style>\n",
384
+ "<table border=\"1\" class=\"dataframe\">\n",
385
+ " <thead>\n",
386
+ " <tr style=\"text-align: right;\">\n",
387
+ " <th></th>\n",
388
+ " <th>room</th>\n",
389
+ " <th>size</th>\n",
390
+ " <th>Lab</th>\n",
391
+ " </tr>\n",
392
+ " </thead>\n",
393
+ " <tbody>\n",
394
+ " <tr>\n",
395
+ " <th>0</th>\n",
396
+ " <td>A1.309</td>\n",
397
+ " <td>90</td>\n",
398
+ " <td>False</td>\n",
399
+ " </tr>\n",
400
+ " <tr>\n",
401
+ " <th>1</th>\n",
402
+ " <td>L107</td>\n",
403
+ " <td>40</td>\n",
404
+ " <td>False</td>\n",
405
+ " </tr>\n",
406
+ " <tr>\n",
407
+ " <th>2</th>\n",
408
+ " <td>LA1.605</td>\n",
409
+ " <td>35</td>\n",
410
+ " <td>True</td>\n",
411
+ " </tr>\n",
412
+ " <tr>\n",
413
+ " <th>3</th>\n",
414
+ " <td>LA1.607</td>\n",
415
+ " <td>35</td>\n",
416
+ " <td>True</td>\n",
417
+ " </tr>\n",
418
+ " </tbody>\n",
419
+ "</table>\n",
420
+ "</div>"
421
+ ],
422
+ "text/plain": [
423
+ " room size Lab\n",
424
+ "0 A1.309 90 False\n",
425
+ "1 L107 40 False\n",
426
+ "2 LA1.605 35 True\n",
427
+ "3 LA1.607 35 True"
428
+ ]
429
+ },
430
+ "execution_count": 3,
431
+ "metadata": {},
432
+ "output_type": "execute_result"
433
+ }
434
+ ],
435
+ "source": [
436
+ "room_default = [['A1.309', 90, 0],\n",
437
+ " ['L107', 40, 0],\n",
438
+ " ['LA1.605', 35, 1],\n",
439
+ " ['LA1.607', 35, 1],\n",
440
+ "]\n",
441
+ "room_columns = ['room', 'size', 'Lab']\n",
442
+ "df_room = pd.DataFrame(room_default, columns=room_columns)\n",
443
+ "df_room['Lab'] = df_room['Lab'].astype(str)\n",
444
+ "for index, row in df_room.iterrows():\n",
445
+ " if row['Lab'] == '1':\n",
446
+ " df_room.at[index, 'Lab'] = 'True'\n",
447
+ " else:\n",
448
+ " df_room.at[index, 'Lab'] = ''\n",
449
+ "df_room['Lab'] = df_room['Lab'].astype(bool)\n",
450
+ "df_room"
451
+ ]
452
+ },
453
+ {
454
+ "cell_type": "code",
455
+ "execution_count": 4,
456
+ "id": "d6b5b6a2",
457
+ "metadata": {},
458
+ "outputs": [],
459
+ "source": [
460
+ "import json\n",
461
+ "\n",
462
+ "# create list of dictionaries representing each object in the JSON file\n",
463
+ "objects = []\n",
464
+ "\n",
465
+ "for index, row in df1.iterrows():\n",
466
+ " if row['prof_id'] != '':\n",
467
+ " # create professor object\n",
468
+ " prof = {\n",
469
+ " \"prof\": {\n",
470
+ " \"id\": row['prof_id'],\n",
471
+ " \"name\": row['prof_name']\n",
472
+ " }\n",
473
+ " }\n",
474
+ " if prof not in objects:\n",
475
+ " objects.append(prof)\n",
476
+ "\n",
477
+ " if row['course_id'] != '':\n",
478
+ " # create course object\n",
479
+ " course = {\n",
480
+ " \"course\": {\n",
481
+ " \"id\": row['course_id'],\n",
482
+ " \"name\": row['course_name']\n",
483
+ " }\n",
484
+ " }\n",
485
+ " if course not in objects:\n",
486
+ " objects.append(course)\n",
487
+ "\n",
488
+ " if row['group_id'] != '':\n",
489
+ " # create room object\n",
490
+ " group = {\n",
491
+ " \"group\": {\n",
492
+ " \"id\": row['group_id'],\n",
493
+ " \"size\": row['size']\n",
494
+ " }\n",
495
+ " }\n",
496
+ " if group not in objects:\n",
497
+ " objects.append(group)\n",
498
+ " \n",
499
+ " if row['prof_id'] != '' and row['course_id'] != '':\n",
500
+ " # create class object\n",
501
+ " class_ = {\n",
502
+ " \"class\": {\n",
503
+ " \"professor\": row['prof_id'],\n",
504
+ " \"course\": row['course_id'],\n",
505
+ " \"duration\": row['duration'],\n",
506
+ " \"group\": row['group_id'],\n",
507
+ " \"lab\": row['Lab']\n",
508
+ " }\n",
509
+ " }\n",
510
+ " if class_ not in objects:\n",
511
+ " objects.append(class_)\n",
512
+ " \n",
513
+ "for index, row in df_room.iterrows():\n",
514
+ " if row['room'] != '':\n",
515
+ " # create room object\n",
516
+ " room = {\n",
517
+ " \"room\": {\n",
518
+ " \"name\": row['room'],\n",
519
+ " \"lab\": row['Lab'],\n",
520
+ " \"size\": row['size']\n",
521
+ " }\n",
522
+ " }\n",
523
+ " objects.append(room) \n",
524
+ " \n",
525
+ "# create JSON object with list of objects\n",
526
+ "json_data = json.dumps(objects, sort_keys=False)\n",
527
+ "\n",
528
+ "# write JSON object to file\n",
529
+ "with open('GaSchedule3.json', 'w') as f:\n",
530
+ " f.write(json_data)"
531
+ ]
532
+ },
533
+ {
534
+ "cell_type": "code",
535
+ "execution_count": 5,
536
+ "id": "f7a33b15",
537
+ "metadata": {},
538
+ "outputs": [
539
+ {
540
+ "data": {
541
+ "text/plain": [
542
+ "'[{\"prof\": {\"id\": 174, \"name\": \"Dao Tran Hoang Chau\"}}, {\"course\": {\"id\": 1, \"name\": \"Functional Programming\"}}, {\"group\": {\"id\": 1, \"size\": 10}}, {\"class\": {\"professor\": 174, \"course\": 1, \"duration\": 3, \"group\": 1, \"lab\": false}}, {\"prof\": {\"id\": 119, \"name\": \"Tran Manh Ha\"}}, {\"course\": {\"id\": 2, \"name\": \"Operating Systems\"}}, {\"group\": {\"id\": 2, \"size\": 90}}, {\"class\": {\"professor\": 119, \"course\": 2, \"duration\": 3, \"group\": 2, \"lab\": false}}, {\"group\": {\"id\": 3, \"size\": 30}}, {\"class\": {\"professor\": 119, \"course\": 2, \"duration\": 4, \"group\": 3, \"lab\": true}}, {\"prof\": {\"id\": 213, \"name\": \"Nguyen Tien Dung\"}}, {\"group\": {\"id\": 4, \"size\": 30}}, {\"class\": {\"professor\": 213, \"course\": 2, \"duration\": 4, \"group\": 4, \"lab\": true}}, {\"group\": {\"id\": 5, \"size\": 30}}, {\"class\": {\"professor\": 213, \"course\": 2, \"duration\": 4, \"group\": 5, \"lab\": true}}, {\"prof\": {\"id\": 74, \"name\": \"Nguyen Van Sinh\"}}, {\"course\": {\"id\": 3, \"name\": \"IT Project Management\"}}, {\"group\": {\"id\": 6, \"size\": 35}}, {\"class\": {\"professor\": 74, \"course\": 3, \"duration\": 3, \"group\": 6, \"lab\": false}}, {\"group\": {\"id\": 7, \"size\": 35}}, {\"class\": {\"professor\": 74, \"course\": 3, \"duration\": 4, \"group\": 7, \"lab\": true}}, {\"prof\": {\"id\": 84, \"name\": \"Le Hai Duong\"}}, {\"course\": {\"id\": 4, \"name\": \"Introduction to Computing\"}}, {\"group\": {\"id\": 8, \"size\": 35}}, {\"class\": {\"professor\": 84, \"course\": 4, \"duration\": 3, \"group\": 8, \"lab\": false}}, {\"prof\": {\"id\": 19, \"name\": \"Huynh Kha Tu\"}}, {\"course\": {\"id\": 5, \"name\": \"Digital Logic Design\"}}, {\"group\": {\"id\": 9, \"size\": 90}}, {\"class\": {\"professor\": 19, \"course\": 5, \"duration\": 3, \"group\": 9, \"lab\": false}}, {\"prof\": {\"id\": 182, \"name\": \"Tran Thanh Tung\"}}, {\"course\": {\"id\": 6, \"name\": \"Object-Oriented Programming\"}}, {\"group\": {\"id\": 10, \"size\": 90}}, {\"class\": {\"professor\": 182, \"course\": 6, \"duration\": 3, \"group\": 10, \"lab\": false}}, {\"group\": {\"id\": 11, \"size\": 30}}, {\"class\": {\"professor\": 213, \"course\": 6, \"duration\": 4, \"group\": 11, \"lab\": true}}, {\"group\": {\"id\": 12, \"size\": 30}}, {\"class\": {\"professor\": 213, \"course\": 6, \"duration\": 4, \"group\": 12, \"lab\": true}}, {\"group\": {\"id\": 13, \"size\": 30}}, {\"class\": {\"professor\": 213, \"course\": 6, \"duration\": 4, \"group\": 13, \"lab\": true}}, {\"prof\": {\"id\": 349, \"name\": \"Nguyen Thi Thanh Sang\"}}, {\"course\": {\"id\": 7, \"name\": \"Software Engineering\"}}, {\"group\": {\"id\": 14, \"size\": 70}}, {\"class\": {\"professor\": 349, \"course\": 7, \"duration\": 3, \"group\": 14, \"lab\": false}}, {\"group\": {\"id\": 15, \"size\": 35}}, {\"class\": {\"professor\": 349, \"course\": 7, \"duration\": 4, \"group\": 15, \"lab\": true}}, {\"group\": {\"id\": 16, \"size\": 35}}, {\"class\": {\"professor\": 349, \"course\": 7, \"duration\": 4, \"group\": 16, \"lab\": true}}, {\"prof\": {\"id\": 62, \"name\": \"Vo Thi Luu Phuong\"}}, {\"course\": {\"id\": 8, \"name\": \"Computer Networks\"}}, {\"group\": {\"id\": 17, \"size\": 70}}, {\"class\": {\"professor\": 62, \"course\": 8, \"duration\": 3, \"group\": 17, \"lab\": false}}, {\"group\": {\"id\": 18, \"size\": 35}}, {\"class\": {\"professor\": 62, \"course\": 8, \"duration\": 4, \"group\": 18, \"lab\": true}}, {\"group\": {\"id\": 19, \"size\": 35}}, {\"class\": {\"professor\": 62, \"course\": 8, \"duration\": 4, \"group\": 19, \"lab\": true}}, {\"prof\": {\"id\": 60, \"name\": \"Ly Tu Nga\"}}, {\"group\": {\"id\": 20, \"size\": 20}}, {\"class\": {\"professor\": 60, \"course\": 8, \"duration\": 4, \"group\": 20, \"lab\": true}}, {\"course\": {\"id\": 9, \"name\": \"Web Application Development\"}}, {\"group\": {\"id\": 21, \"size\": 15}}, {\"class\": {\"professor\": 74, \"course\": 9, \"duration\": 3, \"group\": 21, \"lab\": false}}, {\"group\": {\"id\": 22, \"size\": 15}}, {\"class\": {\"professor\": 74, \"course\": 9, \"duration\": 4, \"group\": 22, \"lab\": true}}, {\"group\": {\"id\": 23, \"size\": 20}}, {\"class\": {\"professor\": 213, \"course\": 9, \"duration\": 4, \"group\": 23, \"lab\": true}}, {\"prof\": {\"id\": 36, \"name\": \"Le Thanh Son\"}}, {\"course\": {\"id\": 10, \"name\": \"Net-Centric Programming\"}}, {\"group\": {\"id\": 24, \"size\": 17}}, {\"class\": {\"professor\": 36, \"course\": 10, \"duration\": 3, \"group\": 24, \"lab\": false}}, {\"group\": {\"id\": 25, \"size\": 17}}, {\"class\": {\"professor\": 36, \"course\": 10, \"duration\": 4, \"group\": 25, \"lab\": true}}, {\"course\": {\"id\": 11, \"name\": \"Digital Logic Design Laboratory\"}}, {\"group\": {\"id\": 26, \"size\": 15}}, {\"class\": {\"professor\": 60, \"course\": 11, \"duration\": 4, \"group\": 26, \"lab\": false}}, {\"group\": {\"id\": 27, \"size\": 15}}, {\"class\": {\"professor\": 60, \"course\": 11, \"duration\": 4, \"group\": 27, \"lab\": false}}, {\"group\": {\"id\": 28, \"size\": 15}}, {\"class\": {\"professor\": 60, \"course\": 11, \"duration\": 4, \"group\": 28, \"lab\": false}}, {\"group\": {\"id\": 29, \"size\": 15}}, {\"class\": {\"professor\": 60, \"course\": 11, \"duration\": 4, \"group\": 29, \"lab\": false}}, {\"group\": {\"id\": 30, \"size\": 15}}, {\"class\": {\"professor\": 60, \"course\": 11, \"duration\": 4, \"group\": 30, \"lab\": false}}, {\"course\": {\"id\": 12, \"name\": \"Entrepreneurship\"}}, {\"group\": {\"id\": 31, \"size\": 80}}, {\"class\": {\"professor\": 174, \"course\": 12, \"duration\": 3, \"group\": 31, \"lab\": false}}, {\"course\": {\"id\": 13, \"name\": \"System & Network Administration\"}}, {\"group\": {\"id\": 32, \"size\": 35}}, {\"class\": {\"professor\": 36, \"course\": 13, \"duration\": 3, \"group\": 32, \"lab\": false}}, {\"group\": {\"id\": 33, \"size\": 35}}, {\"class\": {\"professor\": 36, \"course\": 13, \"duration\": 4, \"group\": 33, \"lab\": true}}, {\"prof\": {\"id\": 184, \"name\": \"Ha Viet Uyen Synh\"}}, {\"course\": {\"id\": 14, \"name\": \"Theoretical Models in Computing\"}}, {\"group\": {\"id\": 34, \"size\": 80}}, {\"class\": {\"professor\": 184, \"course\": 14, \"duration\": 3, \"group\": 34, \"lab\": false}}, {\"group\": {\"id\": 35, \"size\": 26}}, {\"class\": {\"professor\": 184, \"course\": 14, \"duration\": 4, \"group\": 35, \"lab\": true}}, {\"group\": {\"id\": 36, \"size\": 28}}, {\"class\": {\"professor\": 184, \"course\": 14, \"duration\": 4, \"group\": 36, \"lab\": true}}, {\"course\": {\"id\": 15, \"name\": \"Discrete Mathematics\"}}, {\"group\": {\"id\": 37, \"size\": 80}}, {\"class\": {\"professor\": 74, \"course\": 15, \"duration\": 3, \"group\": 37, \"lab\": false}}, {\"room\": {\"name\": \"A1.309\", \"lab\": false, \"size\": 90}}, {\"room\": {\"name\": \"L107\", \"lab\": false, \"size\": 40}}, {\"room\": {\"name\": \"LA1.605\", \"lab\": true, \"size\": 35}}, {\"room\": {\"name\": \"LA1.607\", \"lab\": true, \"size\": 35}}]'"
543
+ ]
544
+ },
545
+ "execution_count": 5,
546
+ "metadata": {},
547
+ "output_type": "execute_result"
548
+ }
549
+ ],
550
+ "source": [
551
+ "json_data"
552
+ ]
553
+ },
554
+ {
555
+ "cell_type": "code",
556
+ "execution_count": null,
557
+ "id": "ac354530",
558
+ "metadata": {},
559
+ "outputs": [],
560
+ "source": []
561
+ }
562
+ ],
563
+ "metadata": {
564
+ "kernelspec": {
565
+ "display_name": "Python 3",
566
+ "language": "python",
567
+ "name": "python3"
568
+ },
569
+ "language_info": {
570
+ "codemirror_mode": {
571
+ "name": "ipython",
572
+ "version": 3
573
+ },
574
+ "file_extension": ".py",
575
+ "mimetype": "text/x-python",
576
+ "name": "python",
577
+ "nbconvert_exporter": "python",
578
+ "pygments_lexer": "ipython3",
579
+ "version": "3.9.7"
580
+ },
581
+ "vscode": {
582
+ "interpreter": {
583
+ "hash": "9510137371fb582fb03f4a48cfea1312dabd94192ffed7cc50b24473a7d892dd"
584
+ }
585
+ }
586
+ },
587
+ "nbformat": 4,
588
+ "nbformat_minor": 5
589
+ }