如何根据pulp python中先前变量的值分配后续变量?

问题描述

我正在使用纸浆库解决 Python 中的优化问题。我有一个 5X5 矩阵作为优化问题的决策变量 (x(i,j))。这些决策变量可以采用从 1 到 10 的整数值。我需要帮助编写 2 个无法在纸浆中定义的约束的代码

  1. 如果 x(i,j) 的值为 1,则 x(i,k)=1 for k >j (此约束意味着在任何行中,如果决策变量的值为 1,那么该行所有后续元素的值也是 1)

  2. 如果 x(i,j) 的值不为 1,且 x(i,k) 的值不为 1,则 x(i,j) 不应等于 x(i,k) (此约束意味着在任何行中没有 2 个元素(值不等于 1)可以相等

我还附上了满足这两个约束的样本 x 矩阵的屏幕截图。任何帮助表示赞赏。提前致谢。 enter image description here

解决方法

基于@Erwin Kalvelagen 的评论,如果决策变量被选为二元变量:

y(i,j,k) == 1,如果元素 (i,j) 具有值 k

那么您的第二个约束非常简单(假设 set_Iset_Jset_K 已被声明为适当的列表):

for i in set_I:
    for k in set_K:
        if k==1:
            continue
        model += lpSum([y[i,k] for j in set_J]) <= 1

换句话说,对于每行 i 和所有可能的数字 k1 除外),它们最多可以出现在每行的 1 列中。

第一个约束更有趣,我相信它可以通过很多不同的方式完成。这是一种方法 - 我们要禁止所有左边至少有一个 1 的数字(1 除外)。所以我们可以如下设置约束:

for i in set_I:
    for j in set_J:
        if j == 1:
            continue # no constraint for 1st column
        for k in set_K:
            if k==1:
                continue # no constraint on 1s
            prev_cols = [item for item in set_J if item < j]
            model += y[i,k] <= 1 - 0.25*lpSum([y[i,item,1] for item in prev_cols])

您可能需要将某些 1 更改为 0,具体取决于您设置索引/集的方式。要理解最后一个约束,请考虑两种情况:

i) 前面的列都没有 1。此约束将它们变为 y[i,k] <= 1,因此它没有任何影响(无论如何,y 都是二元变量)。

ii) 任何前面的列都包含 1 - 约束将变为 y[i,k] <= 0.75(或 0.50.250,如果有是前 2、3 或 4 个)。由于 y 是二进制变量,唯一小于 1 的可行值是 0。因此,对于左侧有 1 的列,将禁止所有非 1 值。

,

我的做法略有不同。同样,使用 x(i,k)=1 表示单元格 (i,j) 的值为 k

 sum(k,x(i,k)) = 1        ∀i,j    # each cell contains exactly one value
 x(i,1) >= x(i,j-1,1)      ∀i,j>1  # x(i,j)=1 => x(i,j+1)=1
 sum(j,k)) <= 1       ∀i,k>1  # only one of 2,3,.. in a row
 x(i,k) ∈ {0,1}