![](/img/trans.png)
[英]Python PuLP Warning "Overwriting previously set objective" When Adding Constraints to Problem
[英]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.