繁体   English   中英

Pulp Python 在对列中的值求和时设置约束问题

[英]Pulp Python problem setting constraints when summing values in a column

嗨,这是我的第一个问题,所以如果我的格式不正确,go 对我来说很容易。

我正在尝试 model 一个表,其中每个值都是 1 或 0。我想确定一列的总和是否为 0,然后检查有多少列 > 0。我的根本问题是试图解决的是约会安排,其中每一列代表一个约会。 我在这里简化了它,因为我使用 dataframe 来使临床医生的能力与患者需求相匹配(每一行都是患者的需求)。 当我试图确保所有变量只能等于 1 时,如果它们在 2 列之一中,我的问题就开始了,因此我在此处简化代码以尝试找出我出错的地方。

我设置了一个以 ROWS 和 COLS 为键的纸浆变量字典,值 == 0 或 1。

在问题定义中,如果列中行值的总和 >= 1,我试图将值 1 分配给列总和,否则为 0,然后对总和进行求和。 这应该允许我设置总和为 >= 1 的列总数,例如只有 2 列由非零变量表示。

在下面的代码中,我的目标是最小化所有变量的总和,但应该有 2 列包含变量 1,即 2 列总和 >=1。

提前致谢。

import pulp as Pulp
ROWS = range(1, 6)
COLS = range(1,5)

prob = Pulp.LpProblem("Fewestcolumns", Pulp.LpMinimize)
choices = Pulp.LpVariable.dicts("Choice", (ROWS, COLS), cat="Integer", lowBound=0, upBound=1)
prob += Pulp.lpSum([choices[row][col] for row in ROWS for col in COLS])
prob += Pulp.lpSum([1 if Pulp.lpSum([choices[row][col] for row in ROWS]) >= 1 else 0 for col in COLS]) == 2



prob.solve()

print("Status:", Pulp.LpStatus[prob.status])
for v in prob.variables():
    print(v.name, "=", v.varValue)`

我的结果:

C:\Users\xxxComputing\LinearProgramming\Scripts\python.exe C:/Users/xxx/Computing/LinearProgramming/LinearProgTest.py
Welcome to the CBC MILP Solver 
Version: 2.10.3 
Build Date: Dec 15 2019 

command line - C:\Users\xxxx\Computing\LinearProgramming\lib\site-packages\pulp\solverdir\cbc\win\64\cbc.exe C:\Users\simon\AppData\Local\Temp\4f8ff67726844bde8abe98316b6338c4-pulp.mps timeMode elapsed branch printingOptions all solution C:\Users\simon\AppData\Local\Temp\4f8ff67726844bde8abe98316b6338c4-pulp.sol (default strategy 1)
At line 2 NAME          MODEL
At line 3 ROWS
At line 6 COLUMNS
At line 67 RHS
At line 69 BOUNDS
At line 90 ENDATA
Problem MODEL has 1 rows, 20 columns and 0 elements
Coin0008I MODEL read with 0 errors
Option for timeMode changed from cpu to elapsed
Problem is infeasible - 0.00 seconds
Option for printingOptions changed from normal to all
Total time (CPU seconds):       0.01   (Wallclock seconds):       0.01

Status: Infeasible
Choice_1_1 = 0.0
Choice_1_2 = 0.0
Choice_1_3 = 0.0
Choice_1_4 = 0.0
Choice_2_1 = 0.0
Choice_2_2 = 0.0
Choice_2_3 = 0.0
Choice_2_4 = 0.0
Choice_3_1 = 0.0
Choice_3_2 = 0.0
Choice_3_3 = 0.0
Choice_3_4 = 0.0
Choice_4_1 = 0.0
Choice_4_2 = 0.0
Choice_4_3 = 0.0
Choice_4_4 = 0.0
Choice_5_1 = 0.0
Choice_5_2 = 0.0
Choice_5_3 = 0.0
Choice_5_4 = 0.0

Process finished with exit code 0

我期待一个有点像这样的变量列表,以及一个可能的解决方案:

Status: Optimal
Choice_1_1 = 1.0
Choice_1_2 = 1.0
Choice_1_3 = 0.0
Choice_1_4 = 0.0
Choice_2_1 = 0.0
Choice_2_2 = 0.0
Choice_2_3 = 0.0
Choice_2_4 = 0.0
Choice_3_1 = 0.0
Choice_3_2 = 0.0
Choice_3_3 = 0.0
Choice_3_4 = 0.0
Choice_4_1 = 0.0
Choice_4_2 = 0.0
Choice_4_3 = 0.0
Choice_4_4 = 0.0
Choice_5_1 = 0.0
Choice_5_2 = 0.0
Choice_5_3 = 0.0
Choice_5_4 = 0.0

编辑:非常感谢 AirSquid 为我指明了正确的方向。 我仍在为大 M 约束而苦苦挣扎。

我试过这个:

import pulp as Pulp
ROWS = range(1, 6)
COLS = range(1,5)

prob = Pulp.LpProblem("Fewestcolumns", Pulp.LpMaximize)
choices = Pulp.LpVariable.dicts("Choice", (ROWS, COLS), cat="Integer", lowBound=0, upBound=1)
used = Pulp.LpVariable.dicts("used", COLS, cat="Binary")
b = Pulp.LpVariable.dicts("b", COLS, cat="Binary")

prob += Pulp.lpSum([choices[row][col] for row in ROWS for col in COLS])
for rows, items in choices.items():
    prob += Pulp.lpSum(cols for cols in items.values()) == 1

M = 20
for col in COLS:
    prob += b[col] >= (Pulp.lpSum([choices[row][col] for row in ROWS]) - 1) / M
    prob += used[col] >= M * (b[col] - 1)

prob += Pulp.lpSum([used[col] for col in COLS]) == 2
prob.solve()

print("Status:", Pulp.LpStatus[prob.status])
for v in prob.variables():
    print(v.name, "=", v.varValue)

我得到以下结果:

 Result - Optimal solution found

Objective value:                5.00000000
Enumerated nodes:               0
Total iterations:               0
Time (CPU seconds):             0.00
Time (Wallclock seconds):       0.00

Option for printingOptions changed from normal to all
Total time (CPU seconds):       0.01   (Wallclock seconds):       0.02

Status: Optimal
Choice_1_1 = 0.0
Choice_1_2 = 0.0
Choice_1_3 = 0.0
Choice_1_4 = 1.0
Choice_2_1 = 0.0
Choice_2_2 = 0.0
Choice_2_3 = 0.0
Choice_2_4 = 1.0
Choice_3_1 = 0.0
Choice_3_2 = 0.0
Choice_3_3 = 0.0
Choice_3_4 = 1.0
Choice_4_1 = 0.0
Choice_4_2 = 0.0
Choice_4_3 = 0.0
Choice_4_4 = 1.0
Choice_5_1 = 0.0
Choice_5_2 = 0.0
Choice_5_3 = 0.0
Choice_5_4 = 1.0
b_1 = 1.0
b_2 = 1.0
b_3 = 1.0
b_4 = 1.0
used_1 = 1.0
used_2 = 1.0
used_3 = 0.0
used_4 = 0.0

Process finished with exit code 0

不确定我做错了什么 - 我希望在不是第 4 列的列中出现一些 1.0。请提供更多提示?

您的问题很明确,但您的 LP 上的设置并不十分清楚。 我们可以回到那个。

您收到错误是因为您在求和中使用了if语句。 那是不合法的。 pulp在求解数学 model 时,变量的值是未知的,所以我们不能在公式中使用if语句。 听起来您想在这里使用“大 M”约束来查看是否在该列中选择了任何内容。 (谷歌它或在这个网站上看,它是一个基本的 LP 概念,我已经发布了几个答案)。 您将需要引入另一个按列索引的二进制变量,然后将其最小化……在伪代码中:

used[col] a binary variable, indexed by Col
M = some suitably large variable (a max).  In your case the number of rows would be appropriate.

然后:

sum(choices[row, col] for row in rows) <= used[col] * M    

如果需要,您可以将used最小化所用列的变量最小化。

我遇到了>导致错误的麻烦; >=并没有强制used_ variable为 1 或 0。

我最终在公式中添加了一个非常小的数字,以确保如果我的决策变量 b_ == 1 那么我的used_variable肯定是 1:

for col in COLS:
    prob += b[col] >= 0.001 + ((Pulp.lpSum([choices[row][col] for row in ROWS]) - 1) / M)
    prob += used[col] >= (M * (b[col] - 1)) + 0.001
    prob += Pulp.lpSum([used[col] for col in COLS]) == 2

这给出了以下结果:

Status: Optimal
Choice_1_1 = 0.0
Choice_1_2 = 1.0
Choice_1_3 = 0.0
Choice_1_4 = 0.0
Choice_2_1 = 1.0
Choice_2_2 = 0.0
Choice_2_3 = 0.0
Choice_2_4 = 0.0
Choice_3_1 = 0.0
Choice_3_2 = 1.0
Choice_3_3 = 0.0
Choice_3_4 = 0.0
Choice_4_1 = 0.0
Choice_4_2 = 1.0
Choice_4_3 = 0.0
Choice_4_4 = 0.0
Choice_5_1 = 0.0
Choice_5_2 = 1.0
Choice_5_3 = 0.0
Choice_5_4 = 0.0
b_1 = 1.0
b_2 = 1.0
b_3 = 0.0
b_4 = 0.0
used_1 = 1.0
used_2 = 1.0
used_3 = 0.0
used_4 = 0.0

这似乎适用于不同数量的列以提供可接受的答案。

我不确定这个解决方案有多糟糕,所以如果有更优雅的方式,请随时回答!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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