简体   繁体   中英

Conditionals on Pulp variables

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:

assign={(prof, subject, group): pulp.LpVariable('prof_%r_subj_%r_grp_%r'%(prof, subj, grp), cat=pulp.LpBinary)
       for prof in professors
       for subj in subjects
       for grp in groups}

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:

assign_subj={(prof, subject): pulp.LpVariable('prof_%r_subj_%r'%(prof, subj), cat=pulp.LpBinary)
           for prof in professors
           for subj in subjects}

And you can then set up constraints which in pseudocode are something like:

for prof in professors:
    for subj in subjects:
        model += pulp.lpSum([assign[(prof, subj, grp)] for grp in groups]) <= assign_subj[(prof, subj)]*max_no_groups

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 particular prof to have any assignments to a particular subj the appropriate assign_subj variable will have to be set to 1. You can then count these or do whatever you want with them in your objective.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM