half-hardcoded work

This commit is contained in:
Yorick van Pelt 2018-02-14 13:55:06 +01:00
parent 54120ceade
commit f58ba0f37d
2 changed files with 269 additions and 28 deletions

View File

@ -24,58 +24,187 @@ param H{p in P, j in J} default 0, binary;
param C{p in P, j in J} default 1, binary; param C{p in P, j in J} default 1, binary;
/* How many jobs need to be done on what day */ /* How many jobs need to be done on what day */
param R{j in J, d in D}, integer, >= 0; 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 */ /* Person p is allocated to do job j on day d */
var A{p in P, j in J, d in D}, binary; 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 */ /* 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] <= 1; 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 */ /* 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] >= D_count-1; #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[j, d]; 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];
/* Maximize enjoyment */ s.t. error_lt{p in P}: error[p] >= ((sum{j in J, d in D} A[p,j,d] * Wl[j]) - 4);
maximize enjoyment: sum{p in P, d in D, j in J} A[p,j,d] * (L[p, j] * WL - H[p, j] * WH); 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; solve;
printf "Sum %d\n", enjoyment; 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 in P, d in D, j in J : A[p,j,d] > 0} "%d %d %d %d\n", p, d, 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; data;
/* Test example */ /* Test example */
param P_count := 3; param P_count := 44;
param J_count := 2; param J_count := 11;
param D_count := 2; param D_count := 3;
param WL := 3; param WL := 1;
param WH := 9; 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;
param L : 1 2 :=
1 0 1
2 1 0
3 0 0;
param H : 1 2 :=
1 1 0
2 0 1
3 0 1;
param R : 1 2 :=
1 1 2
2 2 1;
param C[3,2] := 0;
end; end;

112
process.py Normal file
View File

@ -0,0 +1,112 @@
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")