added: leaders, after_time constraint, workgroups of length 2 working
This commit is contained in:
parent
d4da0ee959
commit
ad97a5a376
|
@ -3,27 +3,38 @@ from math import floor
|
|||
import subprocess
|
||||
|
||||
|
||||
data = json.load(open('backup.json'))
|
||||
|
||||
# Maximum time for AK: 2 Timeslots
|
||||
SLOT_LEN = 120
|
||||
|
||||
DAYS = 3
|
||||
START = 800
|
||||
END = 1800
|
||||
DAYS = 1
|
||||
START = 480
|
||||
END = 1080
|
||||
|
||||
|
||||
class WorkGroup:
|
||||
def __init__(self, id, interest, track, projector, reso, length, leaders):
|
||||
self.id = id # must be int
|
||||
def __init__(self, id, interest, track, projector, reso, length, leaders, constraints):
|
||||
self.id = id # must be int
|
||||
self.interest = interest
|
||||
self.track = track if track is not None else 'none' # haben alle aks einen track?
|
||||
self.projector = 'true' if projector else 'false'
|
||||
self.reso = 'true' if reso else 'false'
|
||||
self.length = floor(length/SLOT_LEN) + 1
|
||||
self.leaders = leaders
|
||||
self.after_time = []
|
||||
self.before_time = []
|
||||
for constraint in constraints:
|
||||
if constraint["type"] == 'OnlyAfterTime':
|
||||
if constraint['workGroup'] is None:
|
||||
self.after_time.append({'day': constraint['day'], 'time': constraint['time']})
|
||||
elif constraint["type"] == 'OnlyBeforeTime':
|
||||
self.before_time.append({'day': constraint['day'], 'time': constraint['time']})
|
||||
|
||||
def __str__(self):
|
||||
return f'ak({self.id}, {self.interest}, "{self.track}", {self.projector}, {self.reso}, {self.length}).' # TODO Leader
|
||||
leader_rules = ''
|
||||
for leader in self.leaders:
|
||||
leader_rules += f'leader({self.id}, "{leader}").\n'
|
||||
return f'ak({self.id}, {self.interest}, "{self.track}", {self.projector}, {self.reso}, {self.length}).' + leader_rules
|
||||
|
||||
|
||||
class Room:
|
||||
|
@ -62,23 +73,45 @@ class Schedule:
|
|||
'workGroup': self.workgroup,
|
||||
'room': self.room,
|
||||
'time': self.time,
|
||||
'day': self.day
|
||||
'day': self.day,
|
||||
'lockRoom': False,
|
||||
'lockTime': False,
|
||||
}
|
||||
|
||||
workgroups = []
|
||||
rooms = []
|
||||
id_to_workgroup = {}
|
||||
id_to_room = {}
|
||||
for i, workgroup in enumerate(data['workGroups']):
|
||||
workgroups.append(WorkGroup(workgroup['id'], workgroup['interested'], workgroup['track'], workgroup['projector'],
|
||||
workgroup['resolution'], workgroup['length'], '')) # TODO add leaders
|
||||
id_to_workgroup[workgroup['id']] = i
|
||||
|
||||
for i, room in enumerate(data['rooms']):
|
||||
rooms.append(Room(room['id'], room['places'], room['projector'])) # TODO internet, whiteboard & co.
|
||||
id_to_room[room['id']] = i
|
||||
def parse_workgroups(data):
|
||||
workgroups = []
|
||||
id_to_workgroup = {}
|
||||
for i, workgroup in enumerate(data['workGroups']):
|
||||
workgroups.append(
|
||||
WorkGroup(workgroup['id'], workgroup['interested'], workgroup['track'], workgroup['projector'],
|
||||
workgroup['resolution'], workgroup['length'], workgroup['leader'], workgroup['constraints']))
|
||||
id_to_workgroup[workgroup['id']] = i
|
||||
return workgroups, id_to_workgroup
|
||||
|
||||
def parse_rooms(data):
|
||||
rooms = []
|
||||
id_to_room = {}
|
||||
for i, room in enumerate(data['rooms']):
|
||||
rooms.append(Room(room['id'], room['places'], room['projector'])) # TODO internet, whiteboard & co.
|
||||
id_to_room[room['id']] = i
|
||||
return rooms, id_to_room
|
||||
|
||||
|
||||
#######################
|
||||
# READ BACKUP JSON #
|
||||
#######################
|
||||
|
||||
|
||||
data = json.load(open('backup.json'))
|
||||
|
||||
workgroups, id_to_workgroup = parse_workgroups(data)
|
||||
rooms, id_to_room = parse_rooms(data)
|
||||
|
||||
|
||||
|
||||
rules = """
|
||||
%LENGTH = { schedule(AK,TIMESLOT,ROOM): timeslot(TIMESLOT,_,_,_,_), room(ROOM,_,_) } :- ak(AK,_,_,_,_,LENGTH).
|
||||
LENGTH = { schedule(AK,TIMESLOT,ROOM): timeslot(TIMESLOT,_,_,_,_), room(ROOM,_,_) } :- ak(AK,_,_,_,_,LENGTH).
|
||||
|
||||
% forbid 2AKS in the same room at the same time
|
||||
|
@ -92,6 +125,10 @@ LENGTH = { schedule(AK,TIMESLOT,ROOM): timeslot(TIMESLOT,_,_,_,_), room(ROOM,_,_
|
|||
|
||||
% forbid two AKs with same leader at same timestep
|
||||
:- schedule(AK1,TIMESTEP,_), schedule(AK2,TIMESTEP,_), leader(AK1,LEADER), leader(AK2,LEADER), AK1 != AK2.
|
||||
|
||||
% schedules of longer aks should be in the same room and in consecutive timeslots
|
||||
schedule(AK,TIMESLOT2,ROOM) :- ak(AK,_,_,_,_,2), schedule(AK,TIMESLOT1,ROOM), timeslot(TIMESLOT1,ORDER1,_,_,DAY), timeslot(TIMESLOT2,ORDER2,_,_,DAY), timeslot(TIMESLOT3,ORDER3,_,_,_), ORDER2 != ORDER1+1, ORDER1 = ORDER3+1, not schedule(AK,TIMESLOT3,ROOM) .
|
||||
|
||||
"""
|
||||
|
||||
for workgroup in workgroups:
|
||||
|
@ -101,15 +138,29 @@ for room in rooms:
|
|||
rules += str(room) + '\n'
|
||||
|
||||
|
||||
|
||||
timeslots = [(start, start+200, day) for day in range(DAYS) for start in range(START, END, 200)]
|
||||
timeslots = [(start, start+SLOT_LEN, day) for day in range(DAYS) for start in range(START, END, SLOT_LEN)]
|
||||
|
||||
for order, timeslot in enumerate(timeslots):
|
||||
rules += str(Timeslot(order, timeslot)) + '\n'
|
||||
|
||||
def time_to_id(timeslots, day, time):
|
||||
timeslots = list(filter(lambda ts: time>= ts[1][0] and time <= ts[1][1] and day == ts[1][2], enumerate(timeslots)))
|
||||
return timeslots[0][0]
|
||||
|
||||
for workgroup in filter(lambda wg: wg.after_time, workgroups):
|
||||
for after_time in workgroup.after_time:
|
||||
timeslot_id = time_to_id(timeslots, after_time['day'], after_time['time'])
|
||||
timeslot = timeslots[timeslot_id] # after this slot: ok
|
||||
print(f':- schedule({workgroup.id}, TIMESLOT, _), ak({workgroup.id},_,_,_,_,_), timeslot(TIMESLOT, ORDER, _, _, _), ORDER < {timeslot_id + 1}.')
|
||||
rules += f':- schedule({workgroup.id}, TIMESLOT, _), ak({workgroup.id},_,_,_,_,_), timeslot(TIMESLOT, ORDER, _, _, _), ORDER < {timeslot_id + 1}.\n'
|
||||
|
||||
rules += "#show schedule/3."
|
||||
|
||||
|
||||
#######################
|
||||
# GENERATE SCHEDULE #
|
||||
#######################
|
||||
|
||||
output_file_name = "generated_rules.pl"
|
||||
|
||||
open(output_file_name, 'w').write(rules)
|
||||
|
@ -121,40 +172,61 @@ process = ['clingo', output_file_name]
|
|||
completed_process = subprocess.run(process, universal_newlines = True, stdout = subprocess.PIPE, stderr = subprocess.DEVNULL)
|
||||
output = completed_process.stdout
|
||||
|
||||
#######################
|
||||
# OUTPUT SCHEDULE #
|
||||
#######################
|
||||
|
||||
if 'SATISFIABLE' not in output:
|
||||
if 'UNSATISFIABLE' in output:
|
||||
print('UNSATISFIABLE')
|
||||
print(output)
|
||||
else:
|
||||
|
||||
print('SATISFIABLE, outputting schedule...')
|
||||
import re
|
||||
|
||||
match = re.match('(.|\n)*Answer: (.+)\n(.*)\nSATISFIABLE', output)
|
||||
schedules_string = match.group(3)
|
||||
try:
|
||||
match = re.match('(.|\n)*Answer: (.+)\n(.*)\nSATISFIABLE', output)
|
||||
schedules_string = match.group(3)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(output)
|
||||
schedules = []
|
||||
from collections import defaultdict
|
||||
workgroup_to_schedule = defaultdict(list)
|
||||
for i, schedule in enumerate(schedules_string.split('schedule')[1:]):
|
||||
match = re.match('\((.+),"(.+)#(.+)#.+",(.+)\)', schedule)
|
||||
workgroup_id = id_to_workgroup[int(match.group(1))]
|
||||
room_id = id_to_room[int(match.group(4))]
|
||||
schedules.append(
|
||||
{
|
||||
'id': i,
|
||||
'workGroup': data['workGroups'][workgroup_id],
|
||||
'room': data['rooms'][room_id],
|
||||
'time': match.group(3),
|
||||
'day': match.group(2),
|
||||
'lockRoom': False,
|
||||
'lockTime': False,
|
||||
})
|
||||
s = {
|
||||
'id': i,
|
||||
'workGroup': data['workGroups'][workgroup_id],
|
||||
'room': data['rooms'][room_id],
|
||||
'time': match.group(3),
|
||||
'day': match.group(2),
|
||||
'lockRoom': False,
|
||||
'lockTime': False,
|
||||
}
|
||||
#json.dumps(s)
|
||||
try:
|
||||
workgroup_id = id_to_workgroup[int(match.group(1))]
|
||||
room_id = id_to_room[int(match.group(4))]
|
||||
schedules.append(Schedule(i, data['workGroups'][workgroup_id], match.group(2), match.group(3), data['rooms'][room_id]))
|
||||
# {
|
||||
# 'id': i,
|
||||
# 'workGroup': data['workGroups'][workgroup_id],
|
||||
# 'room': data['rooms'][room_id],
|
||||
# 'time': match.group(3),
|
||||
# 'day': match.group(2),
|
||||
# 'lockRoom': False,
|
||||
# 'lockTime': False,
|
||||
# })
|
||||
workgroup_to_schedule[workgroup_id].append(i)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
schedules_filtered = []
|
||||
|
||||
for workgroup_id in workgroup_to_schedule:
|
||||
schedules_for_workgroup = workgroup_to_schedule[workgroup_id]
|
||||
if len(schedules_for_workgroup) == 1:
|
||||
schedules_filtered.append(schedules[schedules_for_workgroup[0]])
|
||||
else:
|
||||
# more than one schedule contains workgroup, because workgroup is 2 slots long
|
||||
# find out which one is the first one and remove the second workgroup:
|
||||
schedules_for_workgroup_0 = schedules[schedules_for_workgroup[0]]
|
||||
schedules_for_workgroup_1 = schedules[schedules_for_workgroup[1]]
|
||||
if schedules_for_workgroup_0.time < schedules_for_workgroup_1.time:
|
||||
schedules_filtered.append(schedules_for_workgroup_0)
|
||||
else:
|
||||
schedules_filtered.append(schedules_for_workgroup_1)
|
||||
|
||||
|
||||
data = {}
|
||||
data['schedules'] = schedules
|
||||
data['schedules'] = [s.to_dict() for s in schedules_filtered]
|
||||
json.dump(data, open('output.json', 'w'))
|
||||
|
|
Loading…
Reference in a new issue