From 6b72a56fc6aeb78e21d74858d23f5e0656869df2 Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Mon, 18 Feb 2019 11:36:35 +0100 Subject: [PATCH] weekend xii --- config.yaml | 144 +++++++++++++++++++-------------------- magisch_corvee_script.py | 43 ++++++++---- model.glpm | 14 ++-- prefs_table | 66 +++++++++--------- 4 files changed, 137 insertions(+), 130 deletions(-) diff --git a/config.yaml b/config.yaml index ad31804..2c26feb 100644 --- a/config.yaml +++ b/config.yaml @@ -1,112 +1,106 @@ config: - days: 3 + days: 4 weights: likes: 1 hates: 3 # TODO: load_dev - ignore: ["(vega)"] + ignore: [] task_re: "[ ,/]+" tasks: hotemetoten: - personen: [Linda, Yorick, avel] + personen: [Lucus, Yorick, Sjors, MacGyver, Linda, Wassasin] workload: 4 - req: [1, 1, 1] + req: [1, 1, 1, 1] hardcode: - - Linda # dag 1 - halen: - req: [3, 0, 0] - personen: [Colin, Petervdv, MacGyver] - workload: 4 - baktaarten: - req: [0, 6, 0] - personen: [Linda, joshua, obfusk (felix), alphacentauri, tessa, nanette] - workload: 2 - taartpiet: - req: [0, 4, 0] - personen: iedereen - workload: 2 + - Wassasin + - lucus + - Yorick + - Sjors + lookup: [hotemetoten] superkok: - req: [1, 1, 1] - personen: [macgyver, bas, lucus] + req: [1, 1, 1, 1] + personen: [linda, pepper, bwesterb, tommeh] workload: 4 - hardcode: - - macgyver # dag 1 - - bas # dag 2 - - lucus # dag 3 lookup: [superkok] + hardcode: + - Linda + - Pepper + - bwesterb + - tommeh + drankmanagen: + req: [1, 1, 1, 1] + personen: [MacGyver] + workload: 1 + lookup: [drankmanagen] koken: - req: [3, 3, 3] + req: [4, 2, 2, 2] workload: 3 personen: liefhebbers - lookup: [koken, kookhulp] + lookup: [koken, kookhulp, hulpkoken] schoonmaken: - req: [4, 4, 4] + req: [3, 4, 4, 4] workload: 2 personen: iedereen lookup: [schoonmaken] snackdealen: - req: [6, 6, 6] + req: [4, 5, 5, 5] workload: 1 personen: iedereen - lookup: [hapjes] + lookup: [hapjes, snackdealen] fotograferen: - req: [2, 2, 2] + req: [2, 2, 2, 2] workload: 1 personen: liefhebbers - lookup: [fotograferen, fototroep] + lookup: [fotograferen] afwassen: - req: [5, 5, 5] + req: [4, 4, 4, 4] workload: 2 personen: iedereen lookup: [afwassen] snijpieten: - req: [0, 5, 5] + req: [5, 4, 4, 4] workload: 2 personen: iedereen - + lookup: [snijden] people: -- Loeka -- Petervdv -- Margot -- Yorick -- linda -- Colin -- Sjors -- Erik -- weasel -- Minnozz - Lucus -- avel -- Daan -- Felix -- Maurice -- 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 +- Yorick +- Sjors +- MacGyver +- Linda - 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 -- carrot -- eric s -- Mike Koeman -- Joshua -- Tessa \ No newline at end of file +- Abel +- Carlien +- Blondie +- Avel: # vrijdag + dagen: [1,2,3] +- Thundur: # vrijdag + dagen: [1,2,3] +- Ayke +- Hannah +- Cocidius: + dagen: [1,2,3] diff --git a/magisch_corvee_script.py b/magisch_corvee_script.py index e45f623..dc84d7a 100755 --- a/magisch_corvee_script.py +++ b/magisch_corvee_script.py @@ -6,14 +6,23 @@ import re import subprocess from collections import OrderedDict 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): - def __init__(self, conf={}): + def __init__(self, conf={"dagen":ALL_DAYS}): self.can = set() self.loves = set() self.hates = set() self.does = set() # hardcoded self.has_prefs = False self.conf = conf + self.conf['dagen'] = set(conf['dagen']) def vrolijkheid(self): res = config['days'] - len(self.does) for (d,t) in self.does: @@ -24,17 +33,15 @@ class Person(object): return res def workload(self, tasks): return sum(tasks[t]['workload'] for (d,t) in self.does) -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)} + def cost(self, num_people): + return round(sum((daily_workloads[d] for d in self.conf['dagen'])) / num_people) + # probabilistic round: int(math.floor(x + random.random())) def read_people(conf_ppl): def isdict(x): return type(x) == dict people = OrderedDict() for x in conf_ppl: - val = {} + val = {"dagen": ALL_DAYS} if type(x) == dict: x,val = x.popitem() people[x.lower()] = Person(val) @@ -86,6 +93,7 @@ def matrices(people, tasks): tsk_idx = index(tasks) hardcode = {} max_loads = {} + costs = {} for i,(person, p) in enumerate(people.items()): for t in p.loves: loves[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 for d,l in enumerate(p.conf['max_load']): 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) for di in range(config['days']): for ti,t in enumerate(tasks.values()): req[di][ti] = t['req'][di] 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 between_the_lines(f, a=">>>>\n", b="<<<<\n"): 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): person_vl[p-1].does.add((d-1, task_nm[j-1])) 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("H", hates), 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("Wl", workload), 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("P_count", len(people)), 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) def write_tasks(people, tasks, file=sys.stdout): for name, p in people.items(): - days = [[],[],[]] + days = [[] for i in range(config['days'])] for (d,t) in p.does: - days[d].append((t, t in p.loves)) - q = lambda w: ",".join([x[0] + " <3" if x[1] else x[0] for x in w]) - print("| {} || {} || {} || {} || {} || {}".format(name, *map(q, days), p.vrolijkheid(), p.workload(tasks)), file=file) - # print("|-") + days[d].append((t, t in p.loves, t in p.hates)) + 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("|-") people = read_people(conf['people']) with open('prefs_table', 'r') as pref_file: read_prefs(pref_file, tasks, people) @@ -149,7 +162,7 @@ elif len(sys.argv)>1 and sys.argv[1] == 'out': else: with open('data', 'w') as 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: read_assignment(file, people, tasks) write_tasks(people, tasks) diff --git a/model.glpm b/model.glpm index 0fdd593..11b5a33 100644 --- a/model.glpm +++ b/model.glpm @@ -14,6 +14,10 @@ set P := 1..P_count; set J := 1..J_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 */ 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]; /* 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 */ 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 */ 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_gt{p in P}: error[p] >= 4 - (sum{j in J, d in D} A[p,j,d] * Wl[j]); +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] >= Costs[p] - (sum{j in J, d in D} A[p,j,d] * Wl[j]); /* Maximize enjoyment */ # 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 "workloads\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 "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{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]) - Costs[p])^2; end; \ No newline at end of file diff --git a/prefs_table b/prefs_table index cbb0e46..78178c0 100644 --- a/prefs_table +++ b/prefs_table @@ -1,35 +1,31 @@ -Weasel schoonmaken/afwassen/kookhulp hapjes -Petervdv schoonmaken, afwassen, hapjes koken, fotograferen -Daan fotograferen, kookhulp hapjes, schoonmaken -Bas superkok afwassen, schoonmaken -Lucus superkok, hapjes fotograferen, schoonmaken -mrngm kookhulp, afwassen hapjes -Nick hapjes, schoonmaken afwassen -obfusk (Felix) koken (vega) fotograferen -PaxSum kookhulp, afwassen fotograferen, schoonmaken -ElizaAntoine afwassen, schoonmaken hapjes, koken -SyntaxTerror fotograferen, afwassen, schoonmaken hapjes, koken -Abel fotograferen, afwassen, schoonmaken hapjes, koken -Annelies fotograferen, afwassen hapjes -Roflincopter schoonmaken, kookhulp fotograferen -carrot kookhulp, afwassen fotograferen -MacGyver superkok schoonmaken -Felix afwassen, kookhulp fotograferen, hapjes -Eric S kookhulp, afwassen, schoonmaken hapjes, fotograferen -Sjors afwassen, hapjes schoonmaken -AlphaCentauri fotograferen, hapjes schoonmaken, koken -Blondie koken, hapjes schoonmaken -Nanette fotograferen hapjes -Loeka kookhulp, hapjes afwassen -Marlon koken afwassen -Joost kookhulp, afwassen, schoonmaken hapjes, fotograferen -Erik koken, fotograferen schoonmaken, hapjes -Roy koken, hapjes, fotograferen afwassen, schoonmaken -Joshua koken -Tessa hapjes -Ed fotograferen, afwassen, schoonmaken hapjes, koken -Margot afwassen, schoonmaken -Colin afwassen, koken schoonmaken -Pepper kookhulp, afwassen, schoonmaken hapjes -Ilona afwassen -Quis koken, hapjes schoonmaken, fototroep \ No newline at end of file +Lucus koken schoonmaken, fotograferen +Wassasin koken fotograferen +linda superkok, snackdealen koken, snijden, afwassen, schoonmaken, fotograferen +Nova koken, afwassen fotograferen, snackdealen +Obfusk koken, afwassen fotograferen, snackdealen, schoonmaken +Daan fotograferen, koken schoonmaken +Pepper superkok +Roflincopter snijden, afwassen, schoonmaken snackdealen, fotograferen, koken +SyntaxTerror fotograferen, snijden, afwassen koken +Annelies fotograferen, afwassen, koken snackdealen +Joost snijden, koken, afwassen fotograferen, snackdealen +MrNGm koken, snijden, schoonmaken, fotograferen +PaxSum koken, snijden, afwassen Fotograferen, snackdealen +Weasel hulpkoken, snijden, fotograferen snackdealen, schoonmaken +NickNick snackdealen, snijden, koken schoonmaken, afwassen +carrot snijden, koken, afwassen schoonmaken, snackdealen +bwesterb superkok, snijden schoonmaken, snackdealen, afwassen +Minnozz koken schoonmaken +ElizaAntoine snijden, schoonmaken, afwassen snackdealen, koken +Ayke koken, snijden, afwassen +Cocidius koken, snijden, afwassen schoonmaken +Blondie fotograferen, koken schoonmaken, snackdealen +Thundur snijden, koken, afwassen snackdealen, fotograferen +Tommeh superkok +Petervdv snackdealen fotograferen, koken, afwassen +Abel fotograferen, afwassen +Avel fotograferen, schoonmaken, snackdealen snijden, afwassen +Sjors snackdealen, schoonmaken koken +Carlien snackdealen, schoonmaken koken +Quis snackdealen, snijden, koken schoonmaken, fotograferen +MacGyver drankmanagen \ No newline at end of file