update step 6

This commit is contained in:
SowinskiBraeden committed 2022-05-14 12:22:19 -07:00
1 parent 73590ccbf9
commit e582745c07
2 files changed
+150 -49

No files matched your search

+123 -40
View File
@@ -4,6 +4,8 @@ import math
import random import random
from inspect import currentframe from inspect import currentframe
from click import pass_context
# Import from custom utilities # Import from custom utilities
from util.mockStudents import getSampleStudents from util.mockStudents import getSampleStudents
from util.generateCourses import getSampleCourses from util.generateCourses import getSampleCourses
@@ -347,7 +349,7 @@ def generateScheduleV3(
# Step 6 - Evaluate, move students to fix conflicts # Step 6 - Evaluate, move students to fix conflicts
conflictLogs = [] conflictLogs = {}
for student in students: for student in students:
initialBlocks = [student["schedule"][block] for block in student["schedule"]] initialBlocks = [student["schedule"][block] for block in student["schedule"]]
@@ -378,11 +380,18 @@ def generateScheduleV3(
while hasConflicts: while hasConflicts:
# Check if conflicts have been resolved # Check if conflicts have been resolved
blocks = [student["schedule"][block] for block in student["schedule"]] blocks = [student["schedule"][block] for block in student["schedule"]]
# If there is exceptions, make them look normal in blocks
# list to ginore them when looking for clashes, and not to
# accidently overwrite while evaluating other classes
if len(exceptions) > 0:
for i, block in enumerate(blocks):
if i in exceptions: blocks[i] = ['EXPT']
conflicts = sum(1 for b in blocks if len(b)>1) conflicts = sum(1 for b in blocks if len(b)>1)
if conflicts == 0: hasConflicts = False if conflicts == 0: hasConflicts = False
elif conflicts > 0: elif conflicts > 0:
blockLens = [len(block) for block in blocks] blockLens = [len(block) for block in blocks]
freeBlocks = [index for index in range(len(blocks)) if len(blocks[index]) == 0] freeBlocks = [index for index in range(len(blocks)) if len(blocks[index]) == 0]
@@ -422,43 +431,91 @@ def generateScheduleV3(
continue continue
elif found: done = True elif found: done = True
if advancedConflict: if advancedConflict:
classIndex = 0 attemptResolve = True
solved, done = False, False classOutIndex = 0
classOut = blocks[clashIndex][classIndex] while attemptResolve:
while not done: foundSolution = False
newClassOut = blocks[clashIndex][classOutIndex]
for blockIndex in range(len(running)): for blockIndex in range(len(running)):
if solved: break if foundSolution: break
if blockIndex != clashIndex: if blockIndex != clashIndex and blockIndex not in exceptions:
for cname in running[list(running)[blockIndex]]: for cname in running[list(running)[blockIndex]]:
if cname[:-2] == classOut[:-2]: if cname[:-2] == newClassOut[:-2]:
blockIn = f"block{blockIndex+1}" blockIn = f"block{blockIndex+1}"
if blockIndex in freeBlocks: if blockIndex in freeBlocks:
if len(running[blockIn][cname]["students"]) < classCap: if len(running[blockIn][cname]["students"]) < classCap:
# In the rare or impossible case a student was not inserted to a class # In the rare or impossible case a student was not inserted to a class
# And it weren't full, insert them into the class # And it weren't full, insert them into the class
student["schedule"][blockOut].remove(classOut) student["schedule"][blockOut].remove(newClassOut)
student["schedule"][blockIn].append(cname) student["schedule"][blockIn].append(cname)
running[blockOut][classOut]["students"].remove(studentData) running[blockOut][newClassOut]["students"].remove(studentData)
running[blockIn][cname]["students"].append(studentData) running[blockIn][cname]["students"].append(studentData)
foundSolution = True
solved = True
break break
else:
# Resort to remaining alternates
if len(student["remainingAlts"]) > 0:
pass
else:
# Add to exceptions try to continue
print("Create exception and continue")
pass
elif len(blocks[blockIndex]) == 1: elif len(blocks[blockIndex]) == 1:
pass oClassOut = blocks[blockIndex][0]
elif len(blocks[blockIndex]) > 1: found_oBlockSolution = False
print("How to solve") for oBlockIndex in range(len(running)):
if found_oBlockSolution: break
if oBlockIndex != clashIndex and oBlockIndex not in exceptions and oBlockIndex in freeBlocks:
for ocname in running[list(running)[oBlockIndex]]:
if ocname[:-2] == oClassOut[:-2]:
oBlockIn = f"block{oBlockIndex+1}"
if len(running[oBlockIn][ocname]["students"]) < classCap:
student["schedule"][blockOut].remove(newClassOut)
student["schedule"][blockIn].append(cname)
student["schedule"][blockIn].remove(oClassOut)
student["schedule"][oBlockIn].append(ocname)
running[blockOut][newClassOut]["students"].remove(studentData)
running[blockIn][cname]["students"].append(studentData)
running[blockIn][oClassOut]["students"].remove(studentData)
running[oBlockIn][ocname]["students"].append(studentData)
found_oBlockSolution = True
break
if not found_oBlockSolution: exceptions.append(clashIndex)
foundSolution = True
break
if not foundSolution:
if classOutIndex < len(blocks[clashIndex]) - 1: classOutIndex += 1
elif classOutIndex == len(blocks[clashIndex]) - 1:
if len(student["remainingAlts"]) > 0:
exceptions.append(clashIndex)
print("Attempt to use alt")
attemptResolve = False
# Attempt to use alt
elif len(student["remainingAlts"]) == 0:
exceptions.append(clashIndex)
if student["Pupil #"] in conflictLogs:
conflictLogs[student["Pupil #"]].append({
"Pupil #": student["Pupil #"],
"Email": "",
"Type": "Critical",
"Code": "C-CR",
"Conflict": "Couldn't Resolve"
})
else:
conflictLogs[student["Pupil #"]] = [{
"Pupil #": student["Pupil #"],
"Email": "",
"Type": "Critical",
"Code": "C-CR",
"Conflict": "Couldn't Resolve"
}]
attemptResolve = False
else: print("Impossible - Thanos")
elif foundSolution:
attemptResolve = False
else: else:
print(f"Fatal error ({getLineNumber()}): Impossible error") print(f"Fatal error ({getLineNumber()}): Impossible error")
@@ -468,34 +525,60 @@ def generateScheduleV3(
while not metSelfRequirements: while not metSelfRequirements:
if (student["expectedClasses"] - 2) <= student["classes"] < student["expectedClasses"]: if (student["expectedClasses"] - 2) <= student["classes"] < student["expectedClasses"]:
conflictLogs.append({ if student["Pupil #"] in conflictLogs:
"Pupil #": student["Pupil #"], conflictLogs[student["Pupil #"]].append({
"Email": "", "Pupil #": student["Pupil #"],
"Type": "Acceptable", "Email": "",
"Code": "A-MC", "Type": "Acceptable",
"Conflict": "Missing 1-2 classes" "Code": "A-MC",
}) "Conflict": "Missing 1-2 classes"
})
else:
conflictLogs[student["Pupil #"]] = [{
"Pupil #": student["Pupil #"],
"Email": "",
"Type": "Acceptable",
"Code": "A-MC",
"Conflict": "Missing 1-2 classes"
}]
metSelfRequirements = True metSelfRequirements = True
elif student["classes"] < (student["expectedClasses"] - 2): elif student["classes"] < (student["expectedClasses"] - 2):
# Difference between classes inserted to and # Difference between classes inserted to and
# expected classes is too great, attempt to fix # expected classes is too great, attempt to fix
conflictLogs.append({ if student["Pupil #"] in conflictLogs:
"Pupil #": student["Pupil #"], conflictLogs[student["Pupil #"]].append({
"Email": "", "Pupil #": student["Pupil #"],
"Type": "Critical", "Email": "",
"Code": "C-MC", "Type": "Critical",
"Conflict": "Missing too many classes" "Code": "C-MC",
}) "Conflict": "Missing too many classes"
})
else:
conflictLogs[student["Pupil #"]] = [{
"Pupil #": student["Pupil #"],
"Email": "",
"Type": "Critical",
"Code": "C-MC",
"Conflict": "Missing too many classes"
}]
metSelfRequirements = True metSelfRequirements = True
else: else:
print(f"Fatal error ({getLineNumber()}): Impossible error") print(f"Fatal error ({getLineNumber()}): Impossible error")
continue continue
criticals = []
acceptables = []
for student in conflictLogs:
for conflict in conflictLogs[student]:
if conflict["Type"] == "Critical": criticals.append(conflict)
elif conflict["Type"] == "Acceptable": acceptables.append(conflict)
finalConflictLogs = { finalConflictLogs = {
"Critical": [conflict for conflict in conflictLogs if conflict["Type"] == "Critical"], "All": conflictLogs,
"Acceptable": [conflict for conflict in conflictLogs if conflict["Type"] == "Acceptable"] "Critical": criticals,
"Acceptable": acceptables
} }
# Update Student records # Update Student records
+27 -9
View File
@@ -20,15 +20,31 @@ def errorOutput(students) -> Tuple[PrettyTable, dict, dict]:
conflicts = json.load(f) conflicts = json.load(f)
f.close() f.close()
critical, acceptable = 0, 0
for student in conflicts["All"]:
studentHasCritical, studentHasAcceptable = False, False
read = False
for conflict in conflicts["All"][student]:
if read: break
if conflict["Type"] == "Critical":
critical += 1
studentHasCritical = True
if studentHasAcceptable: read = True
elif conflict["Type"] == "Acceptable":
acceptable += 1
studentHasAcceptable = True
if studentHasCritical: read = True
continue
t = PrettyTable(['Type', 'Error %', 'Success %', 'Error Ratio']) t = PrettyTable(['Type', 'Error %', 'Success %', 'Error Ratio'])
errorsC = round(len(conflicts["Critical"]) / len(students) * 100, 2) errorsC = round(critical / len(students) * 100, 2)
successC = round(100 - errorsC, 2) successC = round(100 - errorsC, 2)
errorsA = round(len(conflicts["Acceptable"]) / len(students) * 100, 2) errorsA = round(acceptable / len(students) * 100, 2)
successA = round(100 - errorsA, 2) successA = round(100 - errorsA, 2)
t.add_row(['Critical', f"{errorsC} %", f"{successC} %", f"{len(conflicts['Critical'])}/{len(students)}"]) t.add_row(['Critical', f"{errorsC} %", f"{successC} %", f"{critical}/{len(students)}"])
t.add_row(['Acceptable', f"{errorsA} %", f"{successA} %", f"{len(conflicts['Acceptable'])}/{len(students)}"]) t.add_row(['Acceptable', f"{errorsA} %", f"{successA} %", f"{acceptable}/{len(students)}"])
return t, conflicts["Critical"], conflicts["Acceptable"] return t, conflicts["Critical"], conflicts["Acceptable"]
@@ -69,8 +85,10 @@ if __name__ == '__main__':
print(errors) print(errors)
elif sys.argv[1].upper() == "ERRORS": elif sys.argv[1].upper() == "ERRORS":
sampleStudents = getSampleStudents("./sample_data/course_selection_data.csv", True) f = open('./output/students.json')
errors, critical, acceptable = errorOutput(sampleStudents) studentData = json.load(f)
f.close()
errors, critical, acceptable = errorOutput(studentData)
print() print()
print(errors) print(errors)
@@ -78,11 +96,11 @@ if __name__ == '__main__':
c1, c2, co = 0, 0, 0 c1, c2, co = 0, 0, 0
for error in critical: for error in critical:
if error["Code"] == "C-MC": c1 +=1 if error["Code"] == "C-MC": c1 +=1
elif error["Code"] == "C-CSS": c2 += 1 elif error["Code"] == "C-CR": c2 += 1
else: co += 1 else: co += 1
print(f"x{c1} C-MC Errors: Critical - Missing Classes") print(f"x{c1} C-MC Errors: Critical - Missing too many Classes")
print(f"x{c2} C-CSS Errors: Critical - Couldn't Solve Schedule") print(f"x{c2} C-CR Errors: Critical - Couldn't Resolve")
print(f"x{co} Other/Undefined Critical Errors") print(f"x{co} Other/Undefined Critical Errors")
print(f"\n{len(acceptable)} acceptable errors") print(f"\n{len(acceptable)} acceptable errors")