weekend xii

This commit is contained in:
Yorick van Pelt 2019-02-18 11:36:35 +01:00
parent 842c773be0
commit 6b72a56fc6
No known key found for this signature in database
GPG Key ID: D8D3CC6D951384DE
4 changed files with 137 additions and 130 deletions

View File

@ -1,112 +1,106 @@
config: config:
days: 3 days: 4
weights: weights:
likes: 1 likes: 1
hates: 3 hates: 3
# TODO: load_dev # TODO: load_dev
ignore: ["(vega)"] ignore: []
task_re: "[ ,/]+" task_re: "[ ,/]+"
tasks: tasks:
hotemetoten: hotemetoten:
personen: [Linda, Yorick, avel] personen: [Lucus, Yorick, Sjors, MacGyver, Linda, Wassasin]
workload: 4 workload: 4
req: [1, 1, 1] req: [1, 1, 1, 1]
hardcode: hardcode:
- Linda # dag 1 - Wassasin
halen: - lucus
req: [3, 0, 0] - Yorick
personen: [Colin, Petervdv, MacGyver] - Sjors
workload: 4 lookup: [hotemetoten]
baktaarten:
req: [0, 6, 0]
personen: [Linda, joshua, obfusk (felix), alphacentauri, tessa, nanette]
workload: 2
taartpiet:
req: [0, 4, 0]
personen: iedereen
workload: 2
superkok: superkok:
req: [1, 1, 1] req: [1, 1, 1, 1]
personen: [macgyver, bas, lucus] personen: [linda, pepper, bwesterb, tommeh]
workload: 4 workload: 4
hardcode:
- macgyver # dag 1
- bas # dag 2
- lucus # dag 3
lookup: [superkok] lookup: [superkok]
hardcode:
- Linda
- Pepper
- bwesterb
- tommeh
drankmanagen:
req: [1, 1, 1, 1]
personen: [MacGyver]
workload: 1
lookup: [drankmanagen]
koken: koken:
req: [3, 3, 3] req: [4, 2, 2, 2]
workload: 3 workload: 3
personen: liefhebbers personen: liefhebbers
lookup: [koken, kookhulp] lookup: [koken, kookhulp, hulpkoken]
schoonmaken: schoonmaken:
req: [4, 4, 4] req: [3, 4, 4, 4]
workload: 2 workload: 2
personen: iedereen personen: iedereen
lookup: [schoonmaken] lookup: [schoonmaken]
snackdealen: snackdealen:
req: [6, 6, 6] req: [4, 5, 5, 5]
workload: 1 workload: 1
personen: iedereen personen: iedereen
lookup: [hapjes] lookup: [hapjes, snackdealen]
fotograferen: fotograferen:
req: [2, 2, 2] req: [2, 2, 2, 2]
workload: 1 workload: 1
personen: liefhebbers personen: liefhebbers
lookup: [fotograferen, fototroep] lookup: [fotograferen]
afwassen: afwassen:
req: [5, 5, 5] req: [4, 4, 4, 4]
workload: 2 workload: 2
personen: iedereen personen: iedereen
lookup: [afwassen] lookup: [afwassen]
snijpieten: snijpieten:
req: [0, 5, 5] req: [5, 4, 4, 4]
workload: 2 workload: 2
personen: iedereen personen: iedereen
lookup: [snijden]
people: people:
- Loeka
- Petervdv
- Margot
- Yorick
- linda
- Colin
- Sjors
- Erik
- weasel
- Minnozz
- Lucus - Lucus
- avel - Yorick
- Daan - Sjors
- Felix - MacGyver
- Maurice - Linda
- Marlon
- Hannah
- bas
- Ed
- Ilona
- AlphaCentauri
- Joost
- Blondie
- Nanette
- MacGyver:
max_load: [2, 0, 0]
- Pepper
- MrNGm
- quis
- Nick
- roflincopter
- obfusk (Felix)
- SyntaxTerror
- Tom de Ruijter
- annelies
- roy
- PaxSum
- Wassasin - Wassasin
- Abel - Daan
- MrNGm
- Petervdv
- Minnozz
- Nova
- Joost
- Obfusk:
dagen: []
- Marlon
- Pepper
- PaxSum: # vrijdag
dagen: [1,2,3]
- M-ou-se
- Annelies
- Weasel
- Carrot
- Roflincopter
- Bwesterb
- Tommeh: # vrijdag
dagen: [1,2,3]
- NickNick
- Quis
- SyntaxTerror
- ElizaAntoine - ElizaAntoine
- carrot - Abel
- eric s - Carlien
- Mike Koeman - Blondie
- Joshua - Avel: # vrijdag
- Tessa dagen: [1,2,3]
- Thundur: # vrijdag
dagen: [1,2,3]
- Ayke
- Hannah
- Cocidius:
dagen: [1,2,3]

View File

@ -6,14 +6,23 @@ import re
import subprocess import subprocess
from collections import OrderedDict from collections import OrderedDict
import glpm import glpm
conf = yaml.load(open('config.yaml', 'r'))
config = conf['config']
config['ignore'].append('')
tasks = OrderedDict(conf['tasks'])
index = lambda x: {v:k for k,v in enumerate(x)}
daily_workloads = \
[sum(task['workload'] * task['req'][d] for task in tasks.values()) for d in range(config['days'])]
ALL_DAYS = set(range(config['days']))
class Person(object): class Person(object):
def __init__(self, conf={}): def __init__(self, conf={"dagen":ALL_DAYS}):
self.can = set() self.can = set()
self.loves = set() self.loves = set()
self.hates = set() self.hates = set()
self.does = set() # hardcoded self.does = set() # hardcoded
self.has_prefs = False self.has_prefs = False
self.conf = conf self.conf = conf
self.conf['dagen'] = set(conf['dagen'])
def vrolijkheid(self): def vrolijkheid(self):
res = config['days'] - len(self.does) res = config['days'] - len(self.does)
for (d,t) in self.does: for (d,t) in self.does:
@ -24,17 +33,15 @@ class Person(object):
return res return res
def workload(self, tasks): def workload(self, tasks):
return sum(tasks[t]['workload'] for (d,t) in self.does) return sum(tasks[t]['workload'] for (d,t) in self.does)
conf = yaml.load(open('config.yaml', 'r')) def cost(self, num_people):
config = conf['config'] return round(sum((daily_workloads[d] for d in self.conf['dagen'])) / num_people)
config['ignore'].append('') # probabilistic round: int(math.floor(x + random.random()))
tasks = OrderedDict(conf['tasks'])
index = lambda x: {v:k for k,v in enumerate(x)}
def read_people(conf_ppl): def read_people(conf_ppl):
def isdict(x): def isdict(x):
return type(x) == dict return type(x) == dict
people = OrderedDict() people = OrderedDict()
for x in conf_ppl: for x in conf_ppl:
val = {} val = {"dagen": ALL_DAYS}
if type(x) == dict: if type(x) == dict:
x,val = x.popitem() x,val = x.popitem()
people[x.lower()] = Person(val) people[x.lower()] = Person(val)
@ -86,6 +93,7 @@ def matrices(people, tasks):
tsk_idx = index(tasks) tsk_idx = index(tasks)
hardcode = {} hardcode = {}
max_loads = {} max_loads = {}
costs = {}
for i,(person, p) in enumerate(people.items()): for i,(person, p) in enumerate(people.items()):
for t in p.loves: loves[i][tsk_idx[t]] = 1 for t in p.loves: loves[i][tsk_idx[t]] = 1
for t in p.hates: hates[i][tsk_idx[t]] = 1 for t in p.hates: hates[i][tsk_idx[t]] = 1
@ -94,12 +102,16 @@ def matrices(people, tasks):
if 'max_load' in p.conf: # max_load override for Pol if 'max_load' in p.conf: # max_load override for Pol
for d,l in enumerate(p.conf['max_load']): for d,l in enumerate(p.conf['max_load']):
max_loads[(i,d)] = l max_loads[(i,d)] = l
# filter days that the person does not exist
for d in ALL_DAYS - p.conf['dagen']:
max_loads[(i,d)] = 0
costs[i] = p.cost(len(people))
req = mat(range(config['days']), tasks) req = mat(range(config['days']), tasks)
for di in range(config['days']): for di in range(config['days']):
for ti,t in enumerate(tasks.values()): for ti,t in enumerate(tasks.values()):
req[di][ti] = t['req'][di] req[di][ti] = t['req'][di]
workload = {tsk_idx[t]: tasks[t]['workload'] for t in tasks} workload = {tsk_idx[t]: tasks[t]['workload'] for t in tasks}
return [loves, hates, capab, hardcode, max_loads, req, workload] return [loves, hates, capab, hardcode, max_loads, req, workload, costs]
def read_assignment(file, people, tasks): def read_assignment(file, people, tasks):
def between_the_lines(f, a=">>>>\n", b="<<<<\n"): def between_the_lines(f, a=">>>>\n", b="<<<<\n"):
for l in f: for l in f:
@ -115,7 +127,7 @@ def read_assignment(file, people, tasks):
for [p,d,j,W,l] in between_the_lines(file): for [p,d,j,W,l] in between_the_lines(file):
person_vl[p-1].does.add((d-1, task_nm[j-1])) person_vl[p-1].does.add((d-1, task_nm[j-1]))
def write_data(people, tasks, file=sys.stdout): def write_data(people, tasks, file=sys.stdout):
[loves, hates, capab, hardcode, max_loads, req, workload] = matrices(people, tasks) [loves, hates, capab, hardcode, max_loads, req, workload, costs] = matrices(people, tasks)
print(glpm.matrix("L", loves), file=file) print(glpm.matrix("L", loves), file=file)
print(glpm.matrix("H", hates), file=file) print(glpm.matrix("H", hates), file=file)
print(glpm.matrix("C", capab, 1), file=file) print(glpm.matrix("C", capab, 1), file=file)
@ -123,6 +135,7 @@ def write_data(people, tasks, file=sys.stdout):
print(glpm.dict("Q", hardcode), file=file) print(glpm.dict("Q", hardcode), file=file)
print(glpm.dict("Wl", workload), file=file) print(glpm.dict("Wl", workload), file=file)
print(glpm.dict("max_load", max_loads), file=file) print(glpm.dict("max_load", max_loads), file=file)
print(glpm.dict("Costs", costs), file=file)
print(glpm.param("D_count", config['days']), file=file) print(glpm.param("D_count", config['days']), file=file)
print(glpm.param("P_count", len(people)), file=file) print(glpm.param("P_count", len(people)), file=file)
print(glpm.param("J_count", len(tasks)), file=file) print(glpm.param("J_count", len(tasks)), file=file)
@ -130,12 +143,12 @@ def write_data(people, tasks, file=sys.stdout):
print(glpm.param("WH", config['weights']['hates']), file=file) print(glpm.param("WH", config['weights']['hates']), file=file)
def write_tasks(people, tasks, file=sys.stdout): def write_tasks(people, tasks, file=sys.stdout):
for name, p in people.items(): for name, p in people.items():
days = [[],[],[]] days = [[] for i in range(config['days'])]
for (d,t) in p.does: for (d,t) in p.does:
days[d].append((t, t in p.loves)) days[d].append((t, t in p.loves, t in p.hates))
q = lambda w: ",".join([x[0] + " <3" if x[1] else x[0] for x in w]) q = lambda w: ",".join([t + (" <3" if l else "") + (" :(" if h else "") for (t,l,h) in w])
print("| {} || {} || {} || {} || {} || {}".format(name, *map(q, days), p.vrolijkheid(), p.workload(tasks)), file=file) print("| {} || {} || {} || {} || {} || {} || {}".format(name, *map(q, days), p.vrolijkheid(), p.workload(tasks)), file=file)
# print("|-") print("|-")
people = read_people(conf['people']) people = read_people(conf['people'])
with open('prefs_table', 'r') as pref_file: with open('prefs_table', 'r') as pref_file:
read_prefs(pref_file, tasks, people) read_prefs(pref_file, tasks, people)
@ -149,7 +162,7 @@ elif len(sys.argv)>1 and sys.argv[1] == 'out':
else: else:
with open('data', 'w') as out: with open('data', 'w') as out:
write_data(people, tasks, file=out) write_data(people, tasks, file=out)
subprocess.call(["glpsol", "--model", "model.glpm", "-d", "data", "--tmlim", "30", "--log", "output"], stdout=sys.stderr, stderr=sys.stdout) subprocess.call(["glpsol", "--model", "model.glpm", "-d", "data", "--tmlim", "15", "--log", "output"], stdout=sys.stderr, stderr=sys.stdout)
with open('output', 'r') as file: with open('output', 'r') as file:
read_assignment(file, people, tasks) read_assignment(file, people, tasks)
write_tasks(people, tasks) write_tasks(people, tasks)

View File

@ -14,6 +14,10 @@ set P := 1..P_count;
set J := 1..J_count; set J := 1..J_count;
set D := 1..D_count; set D := 1..D_count;
/* aanwezigheid x workload for that day */
param Costs{p in P}, integer, >= 0;
/* Person p likes to solve jobs j */ /* Person p likes to solve jobs j */
param L{p in P, j in J} default 0, binary; param L{p in P, j in J} default 0, binary;
@ -48,7 +52,7 @@ s.t. max_load_person{p in P, d in D}: sum{j in J} A[p,j,d] <= max_load[p,d];
#s.t. min_load_person{p in P}: sum{j in J, d in D} A[p,j,d] >= min_load[p]; #s.t. min_load_person{p in P}: sum{j in J, d in D} A[p,j,d] >= min_load[p];
/* A person does not perform the same job on all days */ /* A person does not perform the same job on all days */
s.t. duplicate_jobs{p in P, j in J}: sum{d in D} A[p,j,d] <= D_count-1; /*s.t. duplicate_jobs{p in P, j in J}: sum{d in D} A[p,j,d] <= D_count-1;*/
/* Each task is allocated */ /* Each task is allocated */
s.t. all_allocated{j in J, d in D}: sum{p in P} A[p,j,d] == R[d, j]; s.t. all_allocated{j in J, d in D}: sum{p in P} A[p,j,d] == R[d, j];
@ -56,8 +60,8 @@ s.t. all_allocated{j in J, d in D}: sum{p in P} A[p,j,d] == R[d, j];
/* A person only performs what (s)he is capable of */ /* A person only performs what (s)he is capable of */
s.t. capability_person{p in P, j in J, d in D}: A[p,j,d] <= C[p,j]; s.t. capability_person{p in P, j in J, d in D}: A[p,j,d] <= C[p,j];
s.t. error_lt{p in P}: error[p] >= ((sum{j in J, d in D} A[p,j,d] * Wl[j]) - 4); s.t. error_lt{p in P}: error[p] >= ((sum{j in J, d in D} A[p,j,d] * Wl[j]) - Costs[p]);
s.t. error_gt{p in P}: error[p] >= 4 - (sum{j in J, d in D} A[p,j,d] * Wl[j]); s.t. error_gt{p in P}: error[p] >= Costs[p] - (sum{j in J, d in D} A[p,j,d] * Wl[j]);
/* Maximize enjoyment */ /* Maximize enjoyment */
# minimize error_diff: sum{p in P} error[p]; # minimize error_diff: sum{p in P} error[p];
@ -71,8 +75,8 @@ printf{p in P, d in D, j in J : A[p,j,d] > 0} "%d %d %d %d %d\n", p, d, j, A[p,j
printf "<<<<\n"; printf "<<<<\n";
printf "workloads\n"; printf "workloads\n";
printf "p l\n"; printf "p l\n";
printf{p in P} "%d %d\n", p, abs((sum{j in J, d in D : A[p,j,d] > 0} Wl[j]) - ((sum{d in D, j in J} Wl[j] * R[d,j]) / P_count)); printf{p in P} "%d %d\n", p, abs((sum{j in J, d in D : A[p,j,d] > 0} Wl[j]) - Costs[p]);
printf "workload_dev: %d\n", sum{p in P} abs((sum{j in J, d in D : A[p,j,d] > 0} Wl[j]) - ((sum{d in D, j in J} Wl[j] * R[d,j]) / P_count))^2; printf "workload_dev: %d\n", sum{p in P} abs((sum{j in J, d in D : A[p,j,d] > 0} Wl[j]) - Costs[p])^2;
end; end;

View File

@ -1,35 +1,31 @@
Weasel schoonmaken/afwassen/kookhulp hapjes Lucus koken schoonmaken, fotograferen
Petervdv schoonmaken, afwassen, hapjes koken, fotograferen Wassasin koken fotograferen
Daan fotograferen, kookhulp hapjes, schoonmaken linda superkok, snackdealen koken, snijden, afwassen, schoonmaken, fotograferen
Bas superkok afwassen, schoonmaken Nova koken, afwassen fotograferen, snackdealen
Lucus superkok, hapjes fotograferen, schoonmaken Obfusk koken, afwassen fotograferen, snackdealen, schoonmaken
mrngm kookhulp, afwassen hapjes Daan fotograferen, koken schoonmaken
Nick hapjes, schoonmaken afwassen Pepper superkok
obfusk (Felix) koken (vega) fotograferen Roflincopter snijden, afwassen, schoonmaken snackdealen, fotograferen, koken
PaxSum kookhulp, afwassen fotograferen, schoonmaken SyntaxTerror fotograferen, snijden, afwassen koken
ElizaAntoine afwassen, schoonmaken hapjes, koken Annelies fotograferen, afwassen, koken snackdealen
SyntaxTerror fotograferen, afwassen, schoonmaken hapjes, koken Joost snijden, koken, afwassen fotograferen, snackdealen
Abel fotograferen, afwassen, schoonmaken hapjes, koken MrNGm koken, snijden, schoonmaken, fotograferen
Annelies fotograferen, afwassen hapjes PaxSum koken, snijden, afwassen Fotograferen, snackdealen
Roflincopter schoonmaken, kookhulp fotograferen Weasel hulpkoken, snijden, fotograferen snackdealen, schoonmaken
carrot kookhulp, afwassen fotograferen NickNick snackdealen, snijden, koken schoonmaken, afwassen
MacGyver superkok schoonmaken carrot snijden, koken, afwassen schoonmaken, snackdealen
Felix afwassen, kookhulp fotograferen, hapjes bwesterb superkok, snijden schoonmaken, snackdealen, afwassen
Eric S kookhulp, afwassen, schoonmaken hapjes, fotograferen Minnozz koken schoonmaken
Sjors afwassen, hapjes schoonmaken ElizaAntoine snijden, schoonmaken, afwassen snackdealen, koken
AlphaCentauri fotograferen, hapjes schoonmaken, koken Ayke koken, snijden, afwassen
Blondie koken, hapjes schoonmaken Cocidius koken, snijden, afwassen schoonmaken
Nanette fotograferen hapjes Blondie fotograferen, koken schoonmaken, snackdealen
Loeka kookhulp, hapjes afwassen Thundur snijden, koken, afwassen snackdealen, fotograferen
Marlon koken afwassen Tommeh superkok
Joost kookhulp, afwassen, schoonmaken hapjes, fotograferen Petervdv snackdealen fotograferen, koken, afwassen
Erik koken, fotograferen schoonmaken, hapjes Abel fotograferen, afwassen
Roy koken, hapjes, fotograferen afwassen, schoonmaken Avel fotograferen, schoonmaken, snackdealen snijden, afwassen
Joshua koken Sjors snackdealen, schoonmaken koken
Tessa hapjes Carlien snackdealen, schoonmaken koken
Ed fotograferen, afwassen, schoonmaken hapjes, koken Quis snackdealen, snijden, koken schoonmaken, fotograferen
Margot afwassen, schoonmaken MacGyver drankmanagen
Colin afwassen, koken schoonmaken
Pepper kookhulp, afwassen, schoonmaken hapjes
Ilona afwassen
Quis koken, hapjes schoonmaken, fototroep