繁体   English   中英

如何使用纸浆解决具有多个最优解的线性规划问题

[英]How to solve Linear Programming Problem with more than one optimal solution using pulp

我想解决一个具有多个最优解决方案的 LPP。 我怎样才能做到这一点? 例如:最大化 2000x1 + 3000x2

受制于

6x1 + 9x2 ≤ 100 2x1 + x2 ≤ 20

x1, x2 ≥ 0

在这个 LPP 问题中,存在不止一种最优解,即 (0,100/9) 和 (20/3,20/3)。 当我使用纸浆库解决这个问题时,它只给了我一个 (0,100/9) 的解决方案。 我想要所有可能的解决方案。

这里有一个很好的讨论。

这里有两个问题:(i)如何找到 LP 的多个最优解,以及(ii)为什么要这样做。

首先回答 (ii) - 通常您可能想要询问所有最佳解决方案,因为在它们之间选择一些次要或较低重要性的目标(例如,希望最小化当前设置的变化,或以某种方式最小化风险)。 如果是这种情况,我个人的建议是找到一种将较低顺序偏好纳入您的目标 function 的方法(例如通过添加一个低权重的术语)。

回答 (i) 我发现以图形方式查看 LP 会有所帮助 - 您给出的示例对此非常有效(两个变量意味着您可以使用 plot - 请参阅wolfram 上的 plot )。 您的每个约束都在此不等式 plot 上放置一条线,并且只能在该线的一侧选择解决方案。 Wolfram 的不等式图

你的目标 function 就像在这个可行区域有一个恒定的梯度,你正试图找到最高点。 您可以通过将其设置为特定值并绘制该线来绘制目标 function 的轮廓。 如果你这样做,你会发现你的目标 function 轮廓平行于顶部约束线(你的第一个约束)。

您可以直接从等式中看到这一点:6x1 + 9x2 <= 100 划分为 2x1 + 3x2 <= 100/3,并且您的目标划分为具有相同的梯度。 这意味着您可以沿着顶部约束从一个角移动到另一个角,而无需更改目标 function 的值。

有无穷多个解方程的最优解:

2x1 + 3x2 == 100/3,在 x1==0 和 x1==20/3 之间。 您已经确定了两个角落的解决方案。

如果你想找到所有同样最优的节点——对于大问题可能会有很多——那么下面的代码给出了这里讨论的方法的基本实现。 当您第一次运行它时,它会给您一个角落解决方案 - 然后您需要将此节点(变量集和零松弛集)添加到 A,并迭代直到目标降级。 你可以把它放在一个循环中。 请注意,正如当前实现的那样,这仅适用于下限为 0 且上无界的变量的问题。

import pulp as pulp

# Accounting:
# n structural varuables (n = 2)
# m constraints (m = 2)
# => No. of basics = 2 (no. of constraints)
# => No. of non-basics = 2 (no. of variables)

nb = 2
M = 100   # large M value - upper bound for x1, x2 * the slacks

model = pulp.LpProblem('get all basis', pulp.LpMaximize)

# Variables
x = pulp.LpVariable.dicts('x', range(2), lowBound=0, upBound=None, cat='Continuous')

# Non-negative Slack Variables - one for each constraint
s = pulp.LpVariable.dicts('s', range(2), lowBound=0, upBound=None, cat='Continuous')

# Basis variables (binary)
# one for each variable & one for each constraint (& so slack)
B_x = pulp.LpVariable.dicts('b_x', range(len(x)), cat='Binary')
B_s = pulp.LpVariable.dicts('b_s', range(len(s)), cat='Binary')

# Objective
model += 2000*x[0] + 3000*x[1]

# Constraints - with explicit slacks
model += 6*x[0] + 9*x[1] + s[0] == 100
model += 2*x[0] + x[1] + s[1] == 20

# No. of basics is correct:
model += pulp.lpSum(B_x) + pulp.lpSum(B_s) == nb


# Enforce basic and non-basic behaviour
for i in range(len(x)):
    model += x[i] <= M*B_x[i]

for i in range(len(x)):
    model += s[i] <= M*B_s[i]


# Cuts - already discovered solutions
A = []
# A = [[1, 1, 0, 0]]
# A = [[1, 1, 0, 0], [0, 1, 0, 1]]

for a in A:
    model += (B_x[0]*a[0] + B_x[1]*a[1] +
              B_s[0]*a[2] + B_s[1]*a[3]) <= nb - 1 

model.solve()

print('Status:', pulp.LpStatus[model.status])
print('Objective:', pulp.value(model.objective))

for v in model.variables():
    print (v.name, "=", v.varValue)

暂无
暂无

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

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