import math, string, glob
from math import ceil
from random import seed, random, choice, randrange
class TimetablingInstance:
"A class storing properties of a (randomly generated) instance of a course timetabling problem"
def __init__(self, events, occupancy):
self.pEvents = events
self.pOccupancy = float(occupancy)/100
self.pDays = 5
self.pPeriodsPerDay = 5
self.pPeriods = self.pDays * self.pPeriodsPerDay
self.pMinEventsPerCourse = 2
self.pMaxEventsPerCourse = 5
self.pCourses = 0 self.pMinDaysFactor = 1.125
self.pMaxRoomCourseRatio = 1
self.pMinRoomCourseRatio = 0.7
self.pTeachers = int(self.pEvents / 6)
self.pMinCoursesPerTeacher = 1
self.pMaxCoursesPerTeacher = 3
self.pCurricula = int(self.pEvents / 10)
self.pMinCoursesPerCurriculum = 2
self.pMaxCoursesPerCurriculum = 6
self.pRooms = max(int(ceil(self.pEvents / self.pPeriods / self.pOccupancy)), 1)
self.pDistinctRoomSizes = max(int(ceil(0.6 * self.pRooms)), 1)
self.pSmallestClassroom = 40
self.pLargestClassroom = 350
self.pConstraints = int(self.pEvents * 1.2)
self.intRoomSizes = []
self.intCourseIds = []
def genRooms(self):
outRooms = "\nROOMS:\n"
distinct = []
for i in range(self.pDistinctRoomSizes):
distinct.append(randrange(self.pSmallestClassroom, self.pLargestClassroom, 5))
complete = distinct[:]
for j in range(self.pRooms - self.pDistinctRoomSizes):
complete.append(choice(distinct))
complete.sort()
intRoomSizes = complete[:]
for room, capacity in zip(range(self.pRooms), complete):
outRooms += "R%02i\t%i\n" % (room + 1, capacity)
return outRooms
def genCourses(self):
outCourses = "\nCOURSES:\n"
eventsCounts = []
minDaysSpecs = []
taughtEvents = 0
while taughtEvents < self.pEvents:
ev = min(randrange(self.pMinEventsPerCourse, self.pMaxEventsPerCourse), self.pEvents - taughtEvents)
eventsCounts.append(ev)
minDaysSpecs.append(int(ev/self.pMinDaysFactor))
taughtEvents += ev
self.pCourses = len(eventsCounts)
taught = self.pMinCoursesPerTeacher * range(self.pTeachers)
teachers = set(range(self.pTeachers))
while len(taught) < self.pCourses:
teacher = teachers.pop()
for i in range(max(self.pMaxCoursesPerTeacher - self.pMinCoursesPerTeacher, len(taught) - self.pCourses)):
taught.append(teacher)
students = [randrange(int(self.pSmallestClassroom/2), self.pLargestClassroom) for j in range(self.pCourses)]
for course, teacher, eventsCount, minDays, capacity in zip(range(self.pCourses), taught, eventsCounts, minDaysSpecs, students):
id = "Course%03i" % (course + 1)
self.intCourseIds.append(id)
outCourses += "%s t%02i %i %i %i\n" % (id, teacher, eventsCount, minDays, capacity)
return outCourses
def genUnavailability(self):
outUnavail = "\nUNAVAILABILITY_CONSTRAINTS:\n"
unavail = []
while len(unavail) < self.pConstraints:
course = choice(self.intCourseIds)
day = randrange(0, self.pDays)
period = randrange(0, self.pPeriodsPerDay)
if random() > 0.5:
for p in range(period, self.pPeriodsPerDay): unavail.append((course, day, p))
else:
for p in range(0, period+1): unavail.append((course, day, p))
unavail = list(set(unavail))
unavail.sort()
for course, day, period in unavail:
outUnavail += "%s %i %i\n" % (course, day, period)
return outUnavail
def genCurricula(self):
outCurr = "\nCURRICULA:\n"
curr = []
for i in range(self.pCurricula):
courses = []
for i in range(self.pMinCoursesPerCurriculum):
courses.append(choice(self.intCourseIds))
if self.pMaxCoursesPerCurriculum - self.pMinCoursesPerCurriculum > 0:
for i in range(randrange(1, self.pMaxCoursesPerCurriculum - self.pMinCoursesPerCurriculum, 1)):
courses.append(choice(self.intCourseIds))
courses = list(set(courses))
courses.sort()
curr.append((i, courses))
for id, courses in curr:
outCurr += "Curr%003i %i %s\n" % (id, len(courses), string.join(courses, " "))
return outCurr
def genHeader(self):
outHeader = "Name: Random_%iEvents_Occupancy%i\n" % (self.pEvents, int(self.pOccupancy * 100))
outHeader += "Courses: %i\n" % self.pCourses
outHeader += "Rooms: %i\n" % self.pRooms
outHeader += "Days: %i\n" % self.pDays
outHeader += "Periods_per_day: %i\n" % self.pPeriodsPerDay
outHeader += "Curricula: %i\n" % self.pCurricula
outHeader += "Constraints: %i\n" % self.pConstraints
return outHeader
def genInstanceDef(self):
seed()
rooms = self.genRooms()
courses = self.genCourses()
curr = self.genCurricula()
unavail = self.genUnavailability()
header = self.genHeader()
return header + courses + rooms + curr + unavail