0

Background: I am trying to allocate students to teams where each student will have a series of preferences to other students being in their teams. I have an objective function which I want to minimise along with 3 constraints for the function (written in the image below). In my DB I have a set of students along with their preferences (such as student i rating student j as their 3rd choice).

If student A rates student B as their 1st choice, that preference will have a weighting of 1 which is why the objective function is set to minimise.

Mathematical Formula:

enter image description here

Question: I am unsure whether I have written the constraints and variables correctly in PuLP, and I can't find any close resources that do team allocation with preferences. I'm very new to PuLP and am struggling to figure out if what I've written is correct syntatically, thanks for any help!

Here is the code that I have written in my file:

from pulp import *

model = LpProblem("Team Allocation Problem", LpMinimize)

############ VARIABLES ############

students = [1,...,20]
n = 20
# this will be imported from the database
r = [[...],...,[...]]
team_sizes = [5,5,5,5] 
num_teams = len(z)

# x(ik) = 1 if student i in team k
x_vars = [[LpVariable("x%d%d" % (i,k), cat='Binary') 
        for k in range(num_teams)] 
        for i in range(num_students)]
# y(ijk) = 1 if student i and j are in team k
y_vars = [[[LpVariable("y%d%d%d" % (i,j,k), cat='Binary') 
        for k in range(num_teams)] 
        for j in range(num_students)] 
        for i in range(num_students)]


############ OBJECTIVE FUNCTION ############

for i in range(num_students):
    for j in range(num_students):
        if i!=j:
            for k in range(num_teams):
                model += r[i][j] * y_vars[i][j][k], "Minimize the sum of rank points in the team"

############ CONSTRAINTS ############

# C1: Every student is on exactly one team
for i in range(num_students):
    for k in range(num_teams):
        model += lpSum(x_vars[i][k]) == 1


# C2: Every team has the right size
for k in range(num_teams):
    for i in range(num_students):
        model += lpSum(x_vars[i][k]) == team_sizes[k]

# C3: 
for i in range(num_students):
  for j in range(num_students):
      if i != j:
          for k in range(num_teams):
              model += 1 + y_vars[i][j][k] >= x_vars[i][k] + x_vars[j][k]

# Solve and Print
model.solve()
print("Status:", model.status)
  • 1
    Welcome to stack overflow! Right now we can't run your code because it doesn't include any sample data. Please update this to a toy example (hopefully with just a few students and a few teams) so that others on this site can play with your code. Thanks! – josliber Jan 12 '20 at 18:58
  • Just to add to @josliber's comment - if you can provide a [mcve] that makes answering it much more fun - and so more likely you will get good answers. Best of luck! – kabdulla Jan 12 '20 at 21:08

1 Answers1

1

(1) Make sure the sense of the objective is correct. The way I read your problem, you should maximize.

(2) The proper linearization of

  y(i,j,k) = x(i,k)*x(j,k)

is

  y(i,j,k) <= x(i,k)
  y(i,j,k) <= x(j,k)
  y(i,j,k) >= x(i,k)+x(j,k)-1

Sometimes we can drop some of these constraints because of how the objective works. Make sure you have verified, you indeed can drop y(i,j,k) <= x(i,k) and y(i,j,k) <= x(j,k).

(3) This is (almost) the same question as Algorithms for optimal student seating arrangements.

(4) I want to minimise the objective in this case, if someone rates someone as their first choice they'll essentially be given 1 point, 2 points for second, 3 points for third etc. You cannot have 0=no points 1=best 2=second best,... in your formulation. I suggest to recode your points: 0=no points, 1=ok, 2=better, 3=best. (Just preprocessing of the data). Then maximize instead of minimize. You can add -1,-2,... for dislike if you want.

Erwin Kalvelagen
  • 15,677
  • 2
  • 14
  • 39
  • I want to minimise the objective in this case, if someone rates someone as their first choice they'll essentially be given 1 point, 2 points for second, 3 points for third etc. Should have included this in the original question. – css-flexbox Jan 13 '20 at 10:55
  • The model would think that 0 points is even better. The scale must be linear. – Erwin Kalvelagen Jan 13 '20 at 12:22
  • To elaborate on this: you cannot have `0=no points 1=best 2=second best,...` in your formulation. I suggest to recode your points: `0=no points, 1=ok, 2=better, 3=best`. (Just preprocessing of the data). Then maximize instead of minimize. You can add `-1,-2` for dislike if you want. – Erwin Kalvelagen Jan 13 '20 at 16:47