问题描述
我正在使用纸浆库解决 Python 中的优化问题。我有一个 5X5 矩阵作为优化问题的决策变量 (x(i,j))。这些决策变量可以采用从 1 到 10 的整数值。我需要帮助编写 2 个无法在纸浆中定义的约束的代码:
-
如果 x(i,j) 的值为 1,则 x(i,k)=1 for k >j (此约束意味着在任何行中,如果决策变量的值为 1,那么该行所有后续元素的值也是 1)
-
如果 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_I
和 set_J
和 set_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
和所有可能的数字 k
(1
除外),它们最多可以出现在每行的 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.5
、0.25
或 0
,如果有是前 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}