I am trying to solve a professor/class asignment problem using Pulp. Below is a simplified example of my code. In the example there are 12 different subjects/year ('Maths_1', stands for Maths 1st year) to be given to 3 different groups (A, B, C). There are a total of 36 classes to be asigned to 9 professors (4 classes each). I want to minimize the number of different subjects a professor has to give. This is: a professor has to be assigned 4 clases, then, for example, Maths_1_A, Maths_1_B, Maths_1_C & Programming_1A involves only two different subjects (Maths_1, and Programming_1) and is a better option than Maths_1_A, Maths_2_A, Physics_1_B, Chemistry_3_A that involves 4 different subjects (Maths_1, Maths_2, Physics_1, Chemistry_3). I try to do this by defining an objective function that is the sum of the number of different subjects a professor is assigned.
from itertools import product
import pulp
subjects=['Maths_1','Maths_2','Maths_3', 'Physics_1','Physics_2','Physics_3',
'Quemistry_1', 'Quemistry_2', 'Quemistry_3',
'Programming_1', 'Programming_2', 'Programming_3']
groups=['A','B','C']
clases=[a[0]+'_'+a[1] for a in product(subjects, groups)]
professors=['professor'+str(i) for i in range(1,10)]
number_of_clases_per_professor=4
model=pulp.LpProblem('Class assignmnet', sense=pulp.LpMaximize)
assign={(prof, clas): pulp.LpVariable('prof_%r_class_%r'%(prof, clas), cat=pulp.LpBinary)
for prof in professors
for clas in clases}
#CONSTRAINTS
# 1. Each "class" has to be assigned exactly once:
for clas in clases:
model.addConstraint(sum(assign[(prof, clas)] for prof in professors)==1)
#2. The number of classes per professor cannot exceed 4
for prof in professors:
model.addConstraint(sum(assign[(prof, clas)] for clas in clases)<=4)
The problem I am having is in defining the objective function. I can only think in terms of conditionals on the pulp variable assign:
obj=0
for prof in professors:
subjects_for_prof=[]
for subject in subjects:
for group in groups:
clas=subject+'_'+group
if assign[(prof, clas)]:
if subject not in subjects_for_prof:
subjects_for_prof.append(subject)
obj+=len(subjects_for_prof)
model+=obj
The question is: how can I make an objective function that counts the different number of subjects a professor is assigned?
I think you will make life easier by keeping a 3-component index for your primary assignment variables:
If you want to count the number of different subjects a professor is assigned to teach then you can introduce a specific set of binary variables:
And you can then set up constraints which in pseudocode are something like:
In this last set of constraints you'd need to set
max_no_groups
to the maximum expected number of groups for any subject. This constraint will mean that for any particularprof
to have any assignments to a particularsubj
the appropriateassign_subj
variable will have to be set to 1. You can then count these or do whatever you want with them in your objective.