Spaces:
Sleeping
Sleeping
Upload 31 files
Browse files- __pycache__/ConsoleApp.cpython-39.pyc +0 -0
- __pycache__/HtmlOutput.cpython-39.pyc +0 -0
- algorithm/GeneticAlgorithm.py +190 -0
- algorithm/NsgaII.py +221 -0
- algorithm/__pycache__/APNsgaIII.cpython-39.pyc +0 -0
- algorithm/__pycache__/GeneticAlgorithm.cpython-39.pyc +0 -0
- algorithm/__pycache__/NsgaII.cpython-39.pyc +0 -0
- algorithm/__pycache__/NsgaIII.cpython-39.pyc +0 -0
- model/Configuration.py +236 -0
- model/Constant.py +5 -0
- model/Course.py +11 -0
- model/CourseClass.py +53 -0
- model/Criteria.py +49 -0
- model/Professor.py +25 -0
- model/Reservation.py +57 -0
- model/Room.py +35 -0
- model/Schedule.py +438 -0
- model/StudentsGroup.py +26 -0
- model/__pycache__/Configuration.cpython-39.pyc +0 -0
- model/__pycache__/Constant.cpython-39.pyc +0 -0
- model/__pycache__/Course.cpython-39.pyc +0 -0
- model/__pycache__/CourseClass.cpython-39.pyc +0 -0
- model/__pycache__/Criteria.cpython-39.pyc +0 -0
- model/__pycache__/Professor.cpython-39.pyc +0 -0
- model/__pycache__/Reservation.cpython-39.pyc +0 -0
- model/__pycache__/Room.cpython-39.pyc +0 -0
- model/__pycache__/Schedule.cpython-39.pyc +0 -0
- model/__pycache__/StudentsGroup.cpython-39.pyc +0 -0
- processing data/GaSchedule3.json +1 -0
- processing data/data.json +1 -0
- processing data/reprocessing.ipynb +589 -0
__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 & Engineering</td>\n",
|
70 |
+
" <td>Computer Science & 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 & Engineering</td>\n",
|
92 |
+
" <td>Computer Science & 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 & Engineering</td>\n",
|
114 |
+
" <td>Computer Science & 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 & Engineering</td>\n",
|
136 |
+
" <td>Computer Science & 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 & Engineering</td>\n",
|
158 |
+
" <td>Computer Science & 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 |
+
}
|