【问题标题】:Conditionals on Pulp variables纸浆变量的条件
【发布时间】:2021-02-08 16:06:24
【问题描述】:

我正在尝试使用 Pulp 解决教授/班级分配问题。下面是我的代码的简化示例。在示例中,每年有 12 个不同的科目(“Maths_1”,代表数学第一年)分配给 3 个不同的组(A、B、C)。共有 36 个班级分配给 9 位教授(每个教授 4 个班级)。我想尽量减少教授必须提供的不同科目的数量。这是:必须为教授分配 4 个类,然后,例如, Maths_1_A、Maths_1_B、Maths_1_C 和 Programming_1A 只涉及两个不同的科目(Maths_1 和 Programming_1) 并且是比涉及 4 个不同科目(Maths_1、Maths_2、Physics_1、Chemistry_3)的 Maths_1_A、Maths_2_A、Physics_1_B、Chemistry_3_A 更好的选择。我尝试通过定义一个目标函数来做到这一点,该函数是教授分配的不同学科数量的总和。

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)

我遇到的问题是定义目标函数。我只能考虑纸浆变量分配的条件:

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

问题是:如何创建一个目标函数来计算教授分配的不同科目数量?

【问题讨论】:

    标签: python conditional-statements pulp objective-function


    【解决方案1】:

    我认为通过为您的主要赋值变量保留一个由 3 组成的索引会使生活变得更轻松:

    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}
    

    如果您想计算教授被分配教授的不同科目的数量,那么您可以引入一组特定的二进制变量:

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

    然后您可以设置伪代码中的约束,如下所示:

    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
    

    在最后一组约束中,您需要将max_no_groups 设置为任何主题的最大预期组数。此约束意味着对于任何特定的 prof 对特定的 subj 进行任何分配,必须将相应的 assign_subj 变量设置为 1。然后您可以计算这些或在您的目标中对它们做任何您想做的事情.

    【讨论】:

    • 非常感谢,我正在尝试。我是纸浆新手,让我问你一些别的问题:你建议使用三分量索引而不是二分量索引。这不会增加问题的复杂性并因此增加运行时间吗?
    • 当 prof 没有被分配到该特定主题的任何组时,我们是否应该将 assign_subj[(prof, subject)] 限制为 0?我看不出它隐含在您提出的约束中,或者是吗?我正在为 ILP 的逻辑而苦恼!!
    • 回答第一条评论 - 据我所知,你有 3 个索引还是 2 个索引并不重要 - 重要的是二进制变量的总数。无论是 N_profs x N_subjects x N_groups,还是 N_profs x N_classes,总数都是一样的。
    • 在回答第二条评论时,了解第二组约束如何工作的最佳方法是重新编写约束,假设 assign_subj 为真,然后再次假设它为假。然后查看哪些约束适用于您的主要决策变量的总和。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 2020-09-16
    • 2022-01-10
    • 1970-01-01
    相关资源
    最近更新 更多