I have to create a solution for assigning tasks to users according to some rules and I wanted to give linear programming a try.
I have a list of tasks that require a certain skill and belong to a specific team, and I have a list of available users, their assigned team for the day, and their skill set:
# Creating dummies
task = pd.DataFrame({
'id': [n for n in range(25)],
'skill': [random.randint(0,3) for _ in range(25)]
})
task['team'] = task.apply(lambda row: 'A' for row.skill in (1, 2) else 'B', axis=1)
user_list = pd.DataFrame({
'user': [''.join(random.sample(string.ascii_lowercase, 4)) for _ in range(10)],
'team': [random.choice(['A', 'B']) for _ in range(10)]
})
user_skill = {user_list['user'][k]: random.sample(range(5), 3) for k in range(len(user_list))}
The constraints I have to implement are the following:
- All tasks must be assigned
- A task can only be assigned to one user
- A user can not do a task for which he or she isn't skilled
- A user can not do a task for another team than his or hers
- The amount of tasks per user should be as low as possible inside a team
I struggled a lot to write this in PuLP but thanks to this post I managed to get some results.
# Create the problem
task_assignment = pulp.LpProblem('task_assignment', pulp.LpMaximize)
# Create model vars
pair = pulp.LpVariable.dicts("Pair", (user_list.user, task.id), cat=pulp.LpBinary)
task_covered = pulp.LpVariable.dicts('Covered', task.id, cat=pulp.LpBinary)
# Set objective
task_assignment += pulp.lpSum(task_covered[t] for t in task.id) + \
0.05 * pulp.lpSum(pair[u][t] for u in user_list.user for t in task.id)
# Constraint
# A task can only be done by one user
for t in task.id:
task_assignment+= pulp.lpSum([pair[u][t] for u in user_list.user]) <= 1
# A user must be skilled for the task
for u in user_list.user:
for t in task.id:
if not task[task.id == t].skill.values[0] in user_skill[u]:
task_assignment += pair[u][t] == 0
# A user can not do a task for another team
for u in user_list.user:
for t in task.id:
if not (task[task.id == t].team.values[0] == user_list[user_list.user == u].team.values[0]):
task_assignment+= pair[u][t] == 0
task_assignment.solve()
My problem is that I have absolutely no idea on how to implement the last constraint (i.e. the amount of tasks per user should be as low as possible inside a team)
Does someone have any idea how to do this ?