Commit 254c0a01 authored by Jack Otto's avatar Jack Otto
Browse files

Merge branch 'master' of https://gitlab.bucknell.edu/tjs030/bucknellscheduler

 Conflicts:
	backend/scheduler/scheduler_class.py
parents 504f2279 2c7e2b54
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
# List of all classes # List of all classes
#Test classes #Test classes
test_inputs = True
classes = [ classes = [
['MECH 202 01', 1, 19, 'Computers', ['We'], '1'], ['MECH 202 01', 1, 19, 'Computers', ['We'], '1'],
['MECH 202 02', 1, 19, 'Computers', ['We'], '1'], ['MECH 202 02', 1, 19, 'Computers', ['We'], '1'],
...@@ -176,4 +178,51 @@ professors = [ ...@@ -176,4 +178,51 @@ professors = [
# ['Madero', 2, ['MECH 312 01', 'MECH 312L 62', 'MECH 312L 63']], # ['Madero', 2, ['MECH 312 01', 'MECH 312L 62', 'MECH 312L 63']],
# ['Siegel', 1.5, ['MECH 402C 10', 'MECH 402C 11', 'MECH 420 01']], # ['Siegel', 1.5, ['MECH 402C 10', 'MECH 402C 11', 'MECH 420 01']],
# ['Wright', 1, ['MECH 473 01']], # ['Wright', 1, ['MECH 473 01']],
# ] # ]
\ No newline at end of file
if test_inputs == True:
classes = [
['MECH 202 01', 1, 19, 'Computers', ['We'], '1'],
['MECH 202 02', 1, 19, 'Computers', ['We'], '1'],
['MECH 202 03', 1, 19, 'Computers', ['We'], '1'],
['MECH 202L 60', 2, 19, 'Computers', ['Th'], '1'],
['MECH 202L 61', 2, 19, 'Computers', ['Th'], '1'],
['MECH 202L 62', 2, 19, 'Computers', ['Th'], '1'],
['MECH 220 01', 1, 27, 'Chairs', ['Mo', 'Tu', 'We', 'Fr'], '1'],
['MECH 220 02', 1, 27, 'Chairs', ['Mo', 'Tu', 'We', 'Fr'], '1'],
['MECH 302 01', 1, 15, 'Computers', ['Mo', 'We', 'Fr'], '3'],
['MECH 302L 60', 2, 15, 'Computers', ['Tu'], '3'],
# ['MECH 312 01', 1, 23, 'Chairs', ['Mo', 'We', 'Fr'], '3'],
# ['MECH 312L 60', 2, 12, 'Computers', ['Th'], '3'],
# ['MECH 312L 61', 2, 12, 'Computers', ['Th'], '3'],
# ['MECH 312 02', 1, 23, 'Chairs', ['Mo', 'We', 'Fr'], '3'],
# ['MECH 312L 62', 2, 12, 'Computers', ['Tu'], '3'],
# ['MECH 312L 63', 2, 12, 'Computers', ['Tu'], '3'],
# ['MECH 353 01', 1, 25, 'Chairs', ['Mo', 'We', 'Fr'], '2'],
# ['MECH 353L 60', 2, 12, 'CC04', ['Tu'], '2'],
# ['MECH 353L 61', 2, 12, 'CC04', ['Th'], '2'],
# ['MECH 353 02', 1, 25, 'Chairs', ['Mo', 'We', 'Fr'], '2'],
# ['MECH 353L 62', 2, 12, 'CC04', ['Tu'], '2'],
# ['MECH 353L 63', 2, 12, 'CC04', ['Th'], '2'],
# ['MECH 392 01', 2, 23, 'Chairs', ['Mo', 'We'], '3'],
# ['MECH 392L 60', 2, 12, 'Computers', ['Th'], '3'],
# ['MECH 392L 61', 2, 12, 'Computers', ['Th'], '3'],
# ['MECH 392 02', 1, 23, 'Chairs', ['Mo', 'We', 'Fr'], '3'],
# ['MECH 392L 62', 2, 12, 'Computers', ['Tu'], '3'],
# ['MECH 392L 63', 2, 12, 'Computers', ['Tu'], '3'],
# ['MECH 402 01', 1, 23, 'Chairs', ['Mo', 'We'], '4'],
# ['MECH 402C 10', 2, 14, 'Chairs', ['Th']],
# ['MECH 402C 11', 2, 14, 'Chairs', ['Th']],
# ['MECH 420 01', 1, 14, 'Computers/Chairs', ['Mo', 'We', 'Fr'], '3'],
# ['MECH 473 01', 2, 12, 'Chairs', ['Mo', 'We', 'Fr'], '4'],
# ['MECH 484 01', 2, 14, 'Computers', ['Tu', 'Th'], '4'],
# ['MECH 495 01', 1, 15, 'Chairs', ['Mo', 'We', 'Fr'], '4'],
# ['ENGR 453 01', 1, 26, 'Chairs', ['Mo', 'We', 'Fr'], '1'],
# ['ENGR 214 01', 1, 30, 'Computational/CoE Priority', ['Mo', 'We', 'Fr'], '1'],
# ['ENGR 214 02', 1, 30, 'Computational/CoE Priority', ['Mo', 'We', 'Fr'], '1'],
# ['ENGR 214L 60', 2, 15, 'Computers/Chairs', ['Tu'], '1'],
# ['ENGR 214L 61', 2, 15, 'Computers/Chairs', ['Tu'], '1'],
# ['ENGR 214L 62', 2, 15, 'Computers/Chairs', ['Th'], '1'],
# ['ENGR 214L 63', 2, 15, 'Computers/Chairs', ['Th'], '1']
]
\ No newline at end of file
from ortools.sat.python import cp_model from ortools.sat.python import cp_model
from ortools.sat.python.cp_model import CpModel from ortools.sat.python.cp_model import CpModel
from ..calendar.cal_setup import get_calendar_service from gcalendar.cal_setup import get_calendar_service
from datetime import datetime, timedelta from datetime import datetime, timedelta
from googleapiclient import errors from googleapiclient import errors
from .schedule_objects import Course, Room, Professor from .schedule_objects import Course, Room, Professor
class Schedule: class Schedule:
def __init__(self, courses, rooms, profs, days, hours): def __init__(self, courses, rooms, profs, days, hours):
self.model = cp_model.CpModel() self.model = cp_model.CpModel()
...@@ -21,13 +20,12 @@ class Schedule: ...@@ -21,13 +20,12 @@ class Schedule:
for n in self.courses: for n in self.courses:
for day in self.days: for day in self.days:
for hour in ['10', '11', '12', '14', '15', '09', '08', '16', for hour in ['10', '11', '12', '14', '15', '09', '08', '16', '13']: ## This is the ideal arrangement of hours
'13']: ## This is the ideal arrangement of hours
for c in self.rooms: for c in self.rooms:
for p in self.profs: for p in self.profs:
self.scheduled_classes[(n, c, p, day, hour)] = self.model.NewBoolVar( self.scheduled_classes[(n, c, p, day, hour)] = self.model.NewBoolVar(
f'{n}_{c}_{p}_{day}_{hour}') f'{n}_{c}_{p}_{day}_{hour}')
self.initialize_constraints() self.initialize_constraints()
def initialize_constraints(self): def initialize_constraints(self):
...@@ -141,45 +139,45 @@ class Schedule: ...@@ -141,45 +139,45 @@ class Schedule:
print("Adding constraint for classes longer than an hour") print("Adding constraint for classes longer than an hour")
# Make sure if a class is longer than an hour that a class can not be taught in the time span of that class --> slow working version # Make sure if a class is longer than an hour that a class can not be taught in the time span of that class --> slow working version
for n in self.courses: # for n in self.courses:
if n.length != 1: # if n.length != 1:
for c in self.rooms: # for c in self.rooms:
for p in self.profs: # for p in self.profs:
for d in n.days: # for d in n.days:
for h in self.hours[0:len(self.hours) - n.length + 1]: # for h in self.hours[0:len(self.hours) - n.length + 1]:
subsequent_hours_of_classes = [] # subsequent_hours_of_classes = []
for delta_t in range(1, n.length): # for delta_t in range(1, n.length):
dh = str(int(h) + delta_t) # dh = str(int(h) + delta_t)
dh = str(((2 - len(dh)) * "0") + dh) # dh = str(((2 - len(dh)) * "0") + dh)
# ALL classes with the prof and room need to be 0 # # ALL classes with the prof and room need to be 0
for other_n in self.courses: # for other_n in self.courses:
for other_p in self.profs: # for other_p in self.profs:
subsequent_hours_of_classes.append( # subsequent_hours_of_classes.append(
self.scheduled_classes[other_n, c, other_p, d, dh]) # self.scheduled_classes[other_n, c, other_p, d, dh])
self.model.Add( # self.model.Add(
self.scheduled_classes[n, c, p, d, h] + sum(subsequent_hours_of_classes) <= 1) # self.scheduled_classes[n, c, p, d, h] + sum(subsequent_hours_of_classes) <= 1)
# # Classes Longer than an hour should block out the following classes --> fast meh version # Classes Longer than an hour should block out the following classes --> fast meh version
# for n in [classes for classes in self.courses if classes.length > 1]: for n in [classes for classes in self.courses if classes.length > 1]:
# for c in [room for room in self.rooms if n.size <= room.capacity or n.room_requirement == room.features]: for c in [room for room in self.rooms if n.size <= room.capacity or n.room_requirement == room.features]:
# for p in [professor for professor in self.profs if n in professor.teachable_classes]: for p in [professor for professor in self.profs if n in professor.teachable_classes]:
# for d in n.days: for d in n.days:
# for h in self.hours[0:len(self.hours) - n.length+1]: for h in self.hours[0:len(self.hours) - n.length+1]:
# subsequent_hours_of_classes=[] subsequent_hours_of_classes=[]
# for delta_t in range(1, n.length): for delta_t in range(1, n.length):
# dh = str(int(h) + delta_t) dh = str(int(h) + delta_t)
# dh = str(((2-len(dh))*"0") + dh) dh = str(((2-len(dh))*"0") + dh)
#
# ## TODO FIX THIS CONSTRAINT ## TODO FIX THIS CONSTRAINT
#
# # ALL classes with the prof and room need to be 0 # ALL classes with the prof and room need to be 0
# for other_n in self.courses: for other_n in self.courses:
# for other_p in self.profs: for other_p in self.profs:
# subsequent_hours_of_classes.append(self.scheduled_classes[other_n, c, other_p, d, dh]) subsequent_hours_of_classes.append(self.scheduled_classes[other_n, c, other_p, d, dh])
#
# self.model.Add(self.scheduled_classes[n, c, p, d, h] + sum(subsequent_hours_of_classes) <= 1) self.model.Add(self.scheduled_classes[n, c, p, d, h] + sum(subsequent_hours_of_classes) <= 1)
print("Adding constraint for senior design common hour to be blocked off") print("Adding constraint for senior design common hour to be blocked off")
for p in self.profs: for p in self.profs:
...@@ -229,19 +227,33 @@ class Schedule: ...@@ -229,19 +227,33 @@ class Schedule:
for p in self.profs: for p in self.profs:
if self.solver.Value(self.scheduled_classes[(n, c, p, d, h)]) == 1: if self.solver.Value(self.scheduled_classes[(n, c, p, d, h)]) == 1:
print(f'{n} is taught with {p} in {c} on {d} at {h}') print(f'{n} is taught with {p} in {c} on {d} at {h}')
self.create_event(n,c,p,d,h) # Create GCAL events
self.create_event(n, c, p, d, h) # Create GCAL events
## TODO Manually add these events ## TODO Manually add these events
# final_schedule.append(ScheduleObject(Course("MECH 402C 10", 20, "", 2, ["Th"], 4), Room("DANA115", 20, "", []), Professor("Senior Design Profs", 0, []), "Th", "13")) #final_schedule.append(ScheduleObject(Course("MECH 402C 10", 20, "", 2, ["Th"], 4), Room("DANA115", 20, "", []), Professor("Senior Design Profs", 0, []), "Th", "13"))
# final_schedule.append(ScheduleObject(Course("MECH 402C 11", 20, "", 2, ["Th"], 4), Room("DANA137", 20, "", []), Professor("Senior Design Profs", 0, []), "Th", "13")) #final_schedule.append(ScheduleObject(Course("MECH 402C 11", 20, "", 2, ["Th"], 4), Room("DANA137", 20, "", []), Professor("Senior Design Profs", 0, []), "Th", "13"))
def print_schedule(self):
status = self.solver.Solve(self.model)
self.solver.Solve(self.model)
print(status)
for d in self.days:
for h in self.hours:
for c in self.rooms:
for p in self.profs:
for n in self.courses:
if self.solver.Value(self.scheduled_classes[(n, c, p, d, h)]) == 1:
print(f'{n} is taught with {p} in {c} on {d} at {h}')
def create_event(self, n, c, p, d, h): def create_event(self, n, c, p, d, h):
# creates an event that lasts the length of the class # creates an event that lasts the length of the class
service = get_calendar_service() service = get_calendar_service()
dt_now = datetime.now().date() dt_now = datetime.now().date()
dayOffset = 0 dayOffset=0
if d == "Mo": if d == "Mo":
dayOffset = 0 dayOffset = 0
elif d == "Tu": elif d == "Tu":
...@@ -254,7 +266,7 @@ class Schedule: ...@@ -254,7 +266,7 @@ class Schedule:
dayOffset = 4 dayOffset = 4
# using 11/1/21 as the date to start the calendar on because 11/1/21 is a monday and thus can use the days the class is taught on to determine the day offset # using 11/1/21 as the date to start the calendar on because 11/1/21 is a monday and thus can use the days the class is taught on to determine the day offset
setTime = datetime(dt_now.year, 11, 1 + dayOffset, int(h)) setTime = datetime(dt_now.year, 11, 1+dayOffset, int(h))
start = setTime.isoformat() start = setTime.isoformat()
end = (setTime + timedelta(hours=n.length)).isoformat() end = (setTime + timedelta(hours=n.length)).isoformat()
...@@ -268,7 +280,7 @@ class Schedule: ...@@ -268,7 +280,7 @@ class Schedule:
} }
).execute() ).execute()
# write the id to a file to save it #write the id to a file to save it
with open("./backend/scheduler/eventID.txt", 'a') as file: with open("./backend/scheduler/eventID.txt", 'a') as file:
file.write(event_result['id']) file.write(event_result['id'])
file.write("\n") file.write("\n")
...@@ -301,7 +313,7 @@ class Schedule: ...@@ -301,7 +313,7 @@ class Schedule:
for n in self.courses: for n in self.courses:
if n.name == name: if n.name == name:
return n return n
for c in self.rooms: for c in self.rooms:
if c.name == name: if c.name == name:
return c return c
...@@ -309,3 +321,10 @@ class Schedule: ...@@ -309,3 +321,10 @@ class Schedule:
for p in self.profs: for p in self.profs:
if p.name == name: if p.name == name:
return p return p
#Test
def test_scheuler_class():
pass
if __name__ == '__main__':
test_scheuler_class()
\ No newline at end of file
from scheduler.scheduler_class import Schedule
from scheduler.scheduler_class import Schedule
from scheduler.schedule_objects import Course, Room, Professor
from inputs.spring_2022_inputs import classes, classrooms, professors
profs = []
courses = []
rooms = []
day_names = ['Mo', 'Tu', 'We', 'Th', 'Fr']
hours = ['08', '09', '10', '11', '12', '13', '14', '15', '16']
for name, length, size, req, days, color in classes:
courses.append(Course(name, size, req, length, days, color))
for room, capacity, feature, unavailable in classrooms:
rooms.append(Room(room, capacity, feature, unavailable))
for name, load, teachable in professors:
profs.append(Professor(name, load, teachable))
scheduler = Schedule(courses, rooms, profs, day_names, hours)
\ No newline at end of file
from flask import Flask, redirect, url_for, request from flask import Flask, redirect, url_for, request
from flask.templating import render_template from flask.templating import render_template
###########################################################################################
############# TODO FIX THIS SECTION SO THAT IT DOES NOT CRASH ##########################
from backend.scheduler.scheduler_class import Schedule from backend.scheduler.scheduler_class import Schedule
from backend.scheduler.schedule_objects import Course, Room, Professor from backend.scheduler.schedule_objects import Course, Room, Professor
from backend.inputs.spring_2022_inputs import classes, classrooms, professors from backend.inputs.spring_2022_inputs import classes, classrooms, professors
...@@ -24,7 +26,8 @@ for name, load, teachable in professors: ...@@ -24,7 +26,8 @@ for name, load, teachable in professors:
scheduler = Schedule(courses, rooms, profs, day_names, hours) scheduler = Schedule(courses, rooms, profs, day_names, hours)
## TODO Only run the scheduler init once!!!! ###########################################################################################
###########################################################################################
running = False running = False
app = Flask(__name__) app = Flask(__name__)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment