diff --git a/Corvee assignments b/Corvee assignments deleted file mode 100644 index 059d0d3..0000000 --- a/Corvee assignments +++ /dev/null @@ -1,210 +0,0 @@ -/* Number of people */ -param P_count, integer, > 0; - -/* Number of jobs */ -param J_count, integer, > 0; - -/* Number of days */ -param D_count, integer, > 0; - -param WL, integer, > 0; -param WH, integer, > 0; - -set P := 1..P_count; -set J := 1..J_count; -set D := 1..D_count; - -/* Person p likes to solve jobs j */ -param L{p in P, j in J} default 0, binary; - -/* Person p hates to solve jobs j */ -param H{p in P, j in J} default 0, binary; - -/* Person p is capable to perform job j */ -param C{p in P, j in J} default 1, binary; - -/* How many jobs need to be done on what day */ -param R{d in D, j in J}, integer, >= 0; - -/* hardcoded */ -param Q{p in P, j in J, d in D}, default 0, binary; - -/* workload */ -param Wl{j in J}, integer, >= 0; - -param max_load{p in P, d in D}, default 1, integer; - -/* Person p is allocated to do job j on day d */ -var A{p in P, j in J, d in D}, binary; - -var error{p in P}, integer, >= 0; - -s.t. hardcode{p in P, j in J, d in D}: A[p,j,d] >= Q[p,j,d]; - -/* A person only has one task per day, at most */ -s.t. max_load_person{p in P, d in D}: sum{j in J} A[p,j,d] <= max_load[p,d]; - -/* A person has at least D-1 tasks */ -#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; - -/* 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]; - -/* 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]); - -/* Maximize enjoyment */ -# minimize error_diff: sum{p in P} error[p]; -maximize enjoyment: (sum{p in P, d in D, j in J} A[p,j,d] * (L[p, j] * WL - H[p, j] * WH)) - sum{p in P} error[p]; -solve; - -printf "Sum %d\n", (sum{p in P, d in D, j in J} A[p,j,d] * (L[p, j] * WL - H[p, j] * WH)); -printf "p d j W l\n"; -printf ">>>>\n"; -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,d] * (L[p, j] * WL - H[p, j] * WH), Wl[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; - -data; - -/* Test example */ - -param P_count := 44; -param J_count := 11; -param D_count := 3; -param WL := 1; -param WH := 3; -param Wl := 1 4, 2 4, 3 2, 4 2, 5 4, 6 3, 7 2, 8 1, 9 1, 10 2, 11 2; -# de pol-parameter -param max_load := 25,1,2; # 12,1,0 12,2,0 12,3,0; -param R : 1 2 3 4 5 6 7 8 9 10 11 := - 1 1 3 0 0 1 3 4 6 2 5 0 - 2 1 0 6 4 1 3 4 6 2 5 5 - 3 1 0 0 0 1 3 4 6 2 5 5; -/* AUTOGEN STARTS HERE */ -param L : 5 6 7 8 9 10 := - 1 0 1 0 1 0 0 - 2 0 0 1 1 0 1 - 3 0 0 1 0 0 1 - 6 0 1 0 0 0 1 - 7 0 0 0 1 0 1 - 8 0 1 0 0 1 0 - 9 0 1 1 0 0 1 - 11 1 0 0 1 0 0 - 13 0 1 0 0 1 0 - 14 0 1 0 0 0 1 - 16 0 1 0 0 0 0 - 18 1 0 0 0 0 0 - 19 0 0 1 0 1 1 - 20 0 0 0 0 0 1 - 21 0 0 0 1 1 0 - 22 0 1 1 0 0 1 - 23 0 1 0 1 0 0 - 24 0 0 0 0 1 0 - 25 1 0 0 0 0 0 - 26 0 1 1 0 0 1 - 27 0 1 0 0 0 1 - 28 0 1 0 1 0 0 - 29 0 0 1 1 0 0 - 30 0 1 1 0 0 0 - 31 0 1 0 0 0 0 - 32 0 0 1 0 1 1 - 34 0 0 0 0 1 1 - 35 0 1 0 1 1 0 - 36 0 1 0 0 0 1 - 38 0 0 1 0 1 1 - 39 0 0 1 0 0 1 - 40 0 1 0 0 0 1 - 41 0 1 1 0 0 1 - 43 0 1 0 0 0 0 - 44 0 0 0 1 0 0; -param H : 6 7 8 9 10 := - 1 0 0 0 0 1 - 2 1 0 0 1 0 - 6 0 1 0 0 0 - 7 0 1 0 0 0 - 8 0 1 1 0 0 - 9 0 0 1 0 0 - 11 0 1 0 1 0 - 13 0 1 1 0 0 - 14 0 0 1 1 0 - 16 0 0 0 0 1 - 18 0 1 0 0 1 - 19 1 0 1 0 0 - 21 1 1 0 0 0 - 22 0 0 1 1 0 - 23 0 1 0 0 0 - 24 0 0 1 0 0 - 25 0 1 0 0 0 - 26 0 0 1 0 0 - 27 0 0 1 0 0 - 28 0 1 0 1 0 - 29 0 0 0 0 1 - 30 0 0 0 1 0 - 31 0 0 0 1 0 - 32 1 0 1 0 0 - 34 0 0 1 0 0 - 35 0 1 0 0 1 - 36 0 1 0 1 0 - 38 1 0 1 0 0 - 39 1 0 1 0 0 - 40 0 0 0 1 0 - 41 0 0 1 1 0; -param C : 1 2 3 5 6 9 := - 1 0 0 0 0 1 0 - 2 0 1 0 0 0 0 - 3 0 0 0 0 0 0 - 4 1 0 0 0 0 0 - 5 1 0 1 0 0 0 - 6 0 1 0 0 1 0 - 7 0 0 0 0 0 0 - 8 0 0 0 0 1 1 - 9 1 0 0 0 1 0 - 10 0 0 0 0 0 0 - 11 0 0 0 1 0 0 - 12 1 0 0 0 0 0 - 13 1 0 0 0 1 1 - 14 0 0 0 0 1 0 - 15 0 0 0 0 0 0 - 16 0 0 0 0 1 0 - 17 0 0 0 0 0 0 - 18 0 0 0 1 0 0 - 19 0 0 0 0 0 1 - 20 0 0 0 0 0 0 - 21 0 0 1 0 0 1 - 22 0 0 0 0 1 0 - 23 0 0 0 0 1 0 - 24 0 0 1 0 0 1 - 25 0 1 0 1 0 0 - 26 0 0 0 0 1 0 - 27 0 0 0 0 1 0 - 28 0 0 0 0 1 0 - 29 0 0 0 0 0 0 - 30 0 0 0 0 1 0 - 31 0 0 1 0 1 0 - 32 0 0 0 0 0 1 - 33 0 0 0 0 0 0 - 34 0 0 0 0 0 1 - 35 0 0 0 0 1 1 - 36 0 0 0 0 1 0 - 37 0 0 0 0 0 0 - 38 0 0 0 0 0 1 - 39 0 0 0 0 0 0 - 40 0 0 0 0 1 0 - 41 0 0 0 0 1 0 - 42 0 0 0 0 0 0 - 43 0 0 1 0 1 0 - 44 0 0 1 0 0 0; -param Q := 5,1,1,1 25,5,1,1 18,5,2,1 11,5,3,1; - - -end; \ No newline at end of file diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..ad31804 --- /dev/null +++ b/config.yaml @@ -0,0 +1,112 @@ +config: + days: 3 + weights: + likes: 1 + hates: 3 + # TODO: load_dev + ignore: ["(vega)"] + task_re: "[ ,/]+" +tasks: + hotemetoten: + personen: [Linda, Yorick, avel] + workload: 4 + req: [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 + superkok: + req: [1, 1, 1] + personen: [macgyver, bas, lucus] + workload: 4 + hardcode: + - macgyver # dag 1 + - bas # dag 2 + - lucus # dag 3 + lookup: [superkok] + koken: + req: [3, 3, 3] + workload: 3 + personen: liefhebbers + lookup: [koken, kookhulp] + schoonmaken: + req: [4, 4, 4] + workload: 2 + personen: iedereen + lookup: [schoonmaken] + snackdealen: + req: [6, 6, 6] + workload: 1 + personen: iedereen + lookup: [hapjes] + fotograferen: + req: [2, 2, 2] + workload: 1 + personen: liefhebbers + lookup: [fotograferen, fototroep] + afwassen: + req: [5, 5, 5] + workload: 2 + personen: iedereen + lookup: [afwassen] + snijpieten: + req: [0, 5, 5] + workload: 2 + personen: iedereen + +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 +- Wassasin +- Abel +- ElizaAntoine +- carrot +- eric s +- Mike Koeman +- Joshua +- Tessa \ No newline at end of file diff --git a/glpm.py b/glpm.py new file mode 100644 index 0000000..5c8e875 --- /dev/null +++ b/glpm.py @@ -0,0 +1,22 @@ +def col_all_zeros(ls, i, al=0): + return all(x[i] == al for x in ls) +def row_all_zeros(ls, i, al=0): + return all(x == al for x in ls[i]) +def matrix(name, ls, default=0): + nonzero_cols = [i+1 for i in range(len(ls[0])) if not col_all_zeros(ls, i, default)] + nonzero_rows = [i+1 for i in range(len(ls)) if not row_all_zeros(ls, i, default)] + res = "" + for r in nonzero_rows: + res += "\n{:2d}".format(r) + for c in nonzero_cols: + res += " {:2d}".format(ls[r-1][c-1]) + return param(name, res, " : " + " ".join("{:2d}".format(x) for x in nonzero_cols)) + +def dict(name, thing, default=None): + fmt_key = lambda k: " ".join((str(x+1) for x in k)) if type(k) == tuple else k+1 + return param(name, ", ".join(["{} {}".format(fmt_key(k), v) for k,v in thing.items() if v != default])) +def param(name, val, middle=""): + val = str(val) + if "\n" in val: + val = val.replace("\n", "\n" + " " * (len(name) + 6)) + return "param {}{} := {};".format(name, middle, val) diff --git a/magisch_corvee_script.py b/magisch_corvee_script.py new file mode 100755 index 0000000..e45f623 --- /dev/null +++ b/magisch_corvee_script.py @@ -0,0 +1,155 @@ +#! /usr/bin/env nix-shell +#!nix-shell -i python3 -p python python3Packages.pyyaml glpk +import sys +import yaml +import re +import subprocess +from collections import OrderedDict +import glpm +class Person(object): + def __init__(self, conf={}): + self.can = set() + self.loves = set() + self.hates = set() + self.does = set() # hardcoded + self.has_prefs = False + self.conf = conf + def vrolijkheid(self): + res = config['days'] - len(self.does) + for (d,t) in self.does: + if t in self.loves: + res += config['weights']['likes'] + if t in self.hates: + res -= config['weights']['hates'] + 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 read_people(conf_ppl): + def isdict(x): + return type(x) == dict + people = OrderedDict() + for x in conf_ppl: + val = {} + if type(x) == dict: + x,val = x.popitem() + people[x.lower()] = Person(val) + return people +# deal with loves/hates +def make_task_lut(tasks): + task_lut = {} + for t, taskconf in tasks.items(): + if 'lookup' in taskconf: + for lookup in taskconf['lookup']: + task_lut[lookup] = t + task_re = re.compile(config['task_re']) + def lookup_tasks(tasks): + return (task_lut[x] for x in task_re.split(tasks) if not x in config['ignore']) + return lookup_tasks +def read_prefs(pref_file, tasks, people): + lookup_tasks = make_task_lut(tasks) + # read the wiki corvee table + for [name, loves, hates] in ((q.strip().lower() for q in x.split('\t')) for x in pref_file): + p = people[name] + p.has_prefs = True + p.loves |= set(lookup_tasks(loves)) + p.hates |= set(lookup_tasks(hates)) + for name, p in people.items(): + if not p.has_prefs: + print("warning: no preferences for", name, file=sys.stderr) +# deal with capability and hardcode +def set_capabilities(tasks, people): + for ti,(task,conf) in enumerate(tasks.items()): + if conf['personen'] == 'iedereen': + for p in people.values(): + p.can.add(task) + elif conf['personen'] == 'liefhebbers': + for p in people.values(): + if task in p.loves: + p.can.add(task) + else: + for p in conf['personen']: + people[p.lower()].can.add(task) + if 'hardcode' in conf: + for day, pers in enumerate(conf['hardcode']): + people[pers.lower()].does.add((day, task)) +# format as matrices +def matrices(people, tasks): + mat = lambda a,b: [[0 for j in b] for i in a] + loves = mat(people, tasks) + hates = mat(people, tasks) + capab = mat(people, tasks) + tsk_idx = index(tasks) + hardcode = {} + max_loads = {} + 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 + for t in p.can: capab[i][tsk_idx[t]] = 1 + for (d,t) in p.does: hardcode[(i,tsk_idx[t],d)] = 1 + 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 + 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] +def read_assignment(file, people, tasks): + def between_the_lines(f, a=">>>>\n", b="<<<<\n"): + for l in f: + if l == a: break + for l in f: + if l == b: break + yield map(int, l.strip().split()) + + for p in people.values(): + p.does = set() + person_vl = list(people.values()) + task_nm = list(tasks.keys()) + 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) + print(glpm.matrix("L", loves), file=file) + print(glpm.matrix("H", hates), file=file) + print(glpm.matrix("C", capab, 1), file=file) + print(glpm.matrix("R", req, None), file=file) + 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.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) + print(glpm.param("WL", config['weights']['likes']), file=file) + print(glpm.param("WH", config['weights']['hates']), file=file) +def write_tasks(people, tasks, file=sys.stdout): + for name, p in people.items(): + 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("|-") +people = read_people(conf['people']) +with open('prefs_table', 'r') as pref_file: + read_prefs(pref_file, tasks, people) +set_capabilities(tasks, people) +if len(sys.argv)>1 and sys.argv[1] == 'in': + write_data(people, tasks) +elif len(sys.argv)>1 and sys.argv[1] == 'out': + with open('output', 'r') as out_file: + read_assignment(out_file, people, tasks) + write_tasks(people, tasks) +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) + with open('output', 'r') as file: + read_assignment(file, people, tasks) + write_tasks(people, tasks) diff --git a/model.glpm b/model.glpm new file mode 100644 index 0000000..0fdd593 --- /dev/null +++ b/model.glpm @@ -0,0 +1,78 @@ +/* Number of people */ +param P_count, integer, > 0; + +/* Number of jobs */ +param J_count, integer, > 0; + +/* Number of days */ +param D_count, integer, > 0; + +param WL, integer, > 0; +param WH, integer, > 0; + +set P := 1..P_count; +set J := 1..J_count; +set D := 1..D_count; + +/* Person p likes to solve jobs j */ +param L{p in P, j in J} default 0, binary; + +/* Person p hates to solve jobs j */ +param H{p in P, j in J} default 0, binary; + +/* Person p is capable to perform job j */ +param C{p in P, j in J} default 1, binary; + +/* How many jobs need to be done on what day */ +param R{d in D, j in J}, integer, >= 0; + +/* hardcoded */ +param Q{p in P, j in J, d in D}, default 0, binary; + +/* workload */ +param Wl{j in J}, integer, >= 0; + +param max_load{p in P, d in D}, default 1, integer; + +/* Person p is allocated to do job j on day d */ +var A{p in P, j in J, d in D}, binary; + +var error{p in P}, integer, >= 0; + +s.t. hardcode{p in P, j in J, d in D}: A[p,j,d] >= Q[p,j,d]; + +/* A person only has one task per day, at most */ +s.t. max_load_person{p in P, d in D}: sum{j in J} A[p,j,d] <= max_load[p,d]; + +/* A person has at least D-1 tasks */ +#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; + +/* 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]; + +/* 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]); + +/* Maximize enjoyment */ +# minimize error_diff: sum{p in P} error[p]; +maximize enjoyment: (sum{p in P, d in D, j in J} A[p,j,d] * (L[p, j] * WL - H[p, j] * WH)) - sum{p in P} error[p]; +solve; + +printf "Sum %d\n", (sum{p in P, d in D, j in J} A[p,j,d] * (L[p, j] * WL - H[p, j] * WH)); +printf "p d j W l\n"; +printf ">>>>\n"; +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,d] * (L[p, j] * WL - H[p, j] * WH), Wl[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; + + +end; \ No newline at end of file diff --git a/prefs_table b/prefs_table new file mode 100644 index 0000000..cbb0e46 --- /dev/null +++ b/prefs_table @@ -0,0 +1,35 @@ +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 diff --git a/process.py b/process.py deleted file mode 100644 index a593797..0000000 --- a/process.py +++ /dev/null @@ -1,112 +0,0 @@ - -lovehate = dict((x.split('\t')[0].lower(), [q.strip() for q in x.split('\t')[1:]]) for x in open('table')) -people = list(x.strip().lower() for x in open('people')) -used = 0 -for person in people: - try: - assert(len(lovehate[person]) == 2) - used += 1 - except KeyError: - print("unable to match up", person) - except AssertionError: - print("wrong lovehate", person, lovehate[person]) - raise -assert(used == len(lovehate.keys())) -import yaml -conf = yaml.load(open('tasks', 'r')) -config = conf['config'] -tasks_dict = conf['tasks'] -# print(tasks_dict) -tasks = list(tasks_dict.keys()) -tasksi = dict(((v,k) for k,v in enumerate(tasks))) -peoplei = dict(((v,k) for k,v in enumerate(people))) -tasksdesc = { - "schoonmaken": ['schoonmaken'], - "afwassen": ['afwassen'], - "koken": ['koken', 'kookhulp'], - "snackdealen": ['hapjes'], - "ignore": ['(vega)', '(liever niet dezelfde maaltijd als het kan)', ''], - "superkok": ['superkok'], - "fotograferen": ['fotograferen', 'fototroep'] -} -tasksdesci = {} -import re -for t,a in tasksdesc.items(): - for q in a: tasksdesci[q] = t -loves_matrix = [[0] * len(tasks) for person in people] -hates_matrix = [[0] * len(tasks) for person in people] -capab_matrix = [[0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1] for person in people] -def set_capab(person, task): - capab_matrix[peoplei[person]][tasksi[task]] = 1 -cake_penalty = ["linda", "nanette", "alphacentauri", "obfusk (felix)", "tessa", "joshua"] -for person,(loves, hates) in lovehate.items(): - loves = [tasksdesci[x] for x in re.split('[ ,/]+', loves) if tasksdesci[x] != 'ignore'] - hates = [tasksdesci[x] for x in re.split('[ ,/]+', hates) if tasksdesci[x] != 'ignore'] - for l in loves: - loves_matrix[peoplei[person]][tasksi[l]] = 1 - set_capab(person, l) - for h in hates: hates_matrix[peoplei[person]][tasksi[h]] = 1 -for person in cake_penalty: - set_capab(person, "baktaarten") -for person in ["macgyver", "colin", "petervdv"]: - set_capab(person, "halen") -set_capab("weasel", "hotemetoten") -set_capab("yorick", "hotemetoten") -set_capab("linda", "hotemetoten") -#capab_matrix[peoplei["avel"]] = [0]*len(tasks) -def col_all_zeros(ls, i, al=0): - return all(x[i] == al for x in ls) -def row_all_zeros(ls, i, al=0): - return all(x == al for x in ls[i]) -def format_matrix(name, ls, default=0): - nonzero_cols = [i+1 for i in range(len(ls[0])) if not col_all_zeros(ls, i, default)] - nonzero_rows = [i+1 for i in range(len(ls)) if not row_all_zeros(ls, i, default)] - print("param", name, ":", " ".join("{:2d}".format(x) for x in nonzero_cols), ":=") - for r in nonzero_rows: - print("{:9d}".format(r), end='') - for c in nonzero_cols: - print(" {:2d}".format(ls[r-1][c-1]), end='') - print(';' if r == nonzero_rows[-1] else '') -def format_dict(name, thing, default=None): - print("param {} := {};".format(name, ", ".join(["{} {}".format(k, v) for k,v in thing.items() if v != default]))) -def format_param(name, val): - print("param {} := {};".format(name, val)) -req_matrix = [[tasks_dict[t]['req'][d] for t in tasks] for d in range(config['days'])] -from collections import defaultdict -import sys -if sys.argv[1] == 'in': - format_matrix("L", loves_matrix) - format_matrix("H", hates_matrix) - format_matrix("C", capab_matrix, 1) - format_matrix("R", req_matrix, None) - # hardcode: superkoks, linda hotemetoot - print("param Q := 5,1,1,1 25,5,1,1 18,5,2,1 11,5,3,1;") - format_dict("Wl", {tasksi[t]+1: tasks_dict[t]['workload'] for t in tasks}) - format_param("D_count", config['days']) - format_param("P_count", len(people)) - format_param("J_count", len(tasks)) - format_param("WL", config['weights']['likes']) - format_param("WH", config['weights']['hates']) -elif sys.argv[1] == 'out': - flag=False - ln = [] - for l in open('output'): - if l == "<<<<\n": - flag = False - if flag: - ln.append(map(int, l.strip().split())) - if l == ">>>>\n": - flag=True - - assigned = defaultdict(lambda: [[], [], []]) # lambda: [("", 1, 0), ("", 1, 0), ("", 1, 0)]) - - for [p, d, j, W, l] in ln: - assigned[people[p-1]][d-1].append((tasks[j-1], W, l)) - for p, (a, b, c) in assigned.items(): - q = lambda w: ",".join([x[0] + " <3" if x[1] else x[0] for x in w]) - v = lambda w: sum([x[1] for x in w]) if len(w) else 1 - l = lambda w: sum([x[2] for x in w]) - print("| {} || {} || {} || {} || {}||{}".format(p, q(a), q(b), q(c), v(a)+v(b)+v(c), l(a)+l(b)+l(c))) - print("|-") -else: - print(sys.argv[0], "in|out")