具有附加约束的运输问题
Transportation problem with additional constraints
我正在尝试使用 PuLP 包解决运输问题。在我的例子中,它略有修改并且有额外的限制。
假设有 7 个供应商 [s1、s2、s3、s4、s5、s6、s7] 和 6 个目的地 [d1、d2、d3、d4、d5、d6]。
每个目的地的需求是 1。每个供应商的供应是 3。
目前执行情况:
capacity=3
suppliers,targets = cost.shape
objective = LpProblem("Optimize_allocation",LpMinimize)
x = LpVariable.dicts("assignment", product(range(suppliers), range(targets)), 0, 1)
objective += lpSum(cost[i, j] * x[i, j] for i in range(suppliers) for j in range(targets))
for j in range(targets):
condition1 = lpSum( x[i, j] for i in range(suppliers)) == 1
objective+= condition1
for i in range(suppliers):
condition2 = lpSum(x[i, j] for j in range(targets)) <= capacity
objective+= condition2
objective.solve(PULP_CBC_CMD(msg=0))
我的其他限制是,目的地 (d3,d4) 将只接受来自一个供应商(可以是其中任何一个)的货物,并且该供应商应该只为他们提供服务,而不应向任何其他目的地提供服务。
如果我将它们与需求 2 组合到一个目的地并平均可行的成本,但我如何确保约束的后半部分?这只是一个示例案例,但在我的实际问题中,可能有多个目的地相互组合并要求相同的约束示例:(d1,d2) 和 (d5,d6,d3)。
编辑:
根据@kabdulla 的回答更新为以下工作代码,但最后一个约束已更改。
suppliers = 10
targets = ['A','B','C','D','E','F','G','H','I']
grps = [['A','B','C'],['D'],['E'],['F','G'],['H','I']] #constraint groups
groups = [[0, 1, 2], [3], [4], [5, 6], [7, 8]] #constraint group ids
capacities = [3, 1, 1, 2, 2]
capacity = 3
cost = np.random.rand(suppliers,len(targets))
objective = LpProblem("Optimize_allocation",LpMinimize)
x = LpVariable.dicts("assignment1", product(range(suppliers), range(len(targets))), 0, 1,'Integer')
y = LpVariable.dicts("assignment2", product(range(suppliers), range(len(groups))), 0, 1,'Integer')
objective += lpSum(cost[i, j] * x[i, j] for i in range(suppliers) for j in range(len(targets)))
for j in range(len(targets)):
objective+= lpSum( x[i, j] for i in range(suppliers)) == 1
for i in range(suppliers):
objective+= lpSum(x[i, j] for j in range(len(targets))) <= capacity
for i in range(suppliers):
for k in range(len(groups)):
objective += lpSum(x[i,j] for j in groups[k]) <= y[i,k]*capacities[k]
for k in range(len(groups)):
objective += lpSum(y[i,k] for i in range(suppliers)) == 1
for i in range(suppliers):
objective+= lpSum(y[i, j] for j in range(len(groups))) <= 1
objective.solve()
首先观察 - 您的 x[i, j]
变量(从供应商 i
到目标 j
的供应数量)是连续的 - 表明可以运送一小部分单位。如果这不是本意,这些 x
需要设为整数(cat='Integer'
调用 LpVariable.dicts()
)。
如果我正确理解了您的附加限制条件,则存在一些目标节点的“独家供应”集 E_k
。在其中一组中:
- 所有供应必须来自单个供应商节点
- 该供应商不得向集外的任何节点提供
要执行这种逻辑,您将需要一些二进制变量(如果您的 x
变量是不连续的并且限制在 [0,1] 范围内(即它们是二进制的),您可能是可以直接使用)。我假设你的 x
是连续的。
解决这个问题的一种方法是引入新的二进制变量y[i, k]
,当且仅当供应商i
是选择的独家供应商来设置k
。
假设您还声明了属于相同排他供应集的目标节点列表列表E
您可以添加所需的约束,如下所示:
for i in suppliers:
for k in range(len(E)):
objective += lpSum(x[i,j] for j in E[k]) <= y[i, k]*M[k]
其中 M[k]
足够大以至于当 y[i,k]
为 1 时它们不会添加额外的约束(例如,这可能只是 k
中节点的需求总和独家供应套装
然后您可以对 y[i,k]
变量强制执行所需的约束 - 即每个集合 k
必须只有一个供应商:
for k in range(len(E)):
objective += lpSum(y[i, k] for i in suppliers) == 1
最后你需要添加一个约束,如果供应商 i
正在服务独占集 k
(即 y[i,k] == 1
),则不允许他们提供任何不在其中的节点那一组:
for i in suppliers:
for k in range(len(E)):
objective += lpSum(x[i, j] for j in targets if j not in E[k]) <= \
(1 - y[i,k])*N[k]
其中 N[k]
足够大以至于当 y[i,j] == 0
时它们不会添加额外的约束(例如可能是不在第 k
个独家供应中的节点的需求总和设置。
我正在尝试使用 PuLP 包解决运输问题。在我的例子中,它略有修改并且有额外的限制。 假设有 7 个供应商 [s1、s2、s3、s4、s5、s6、s7] 和 6 个目的地 [d1、d2、d3、d4、d5、d6]。 每个目的地的需求是 1。每个供应商的供应是 3。
目前执行情况:
capacity=3
suppliers,targets = cost.shape
objective = LpProblem("Optimize_allocation",LpMinimize)
x = LpVariable.dicts("assignment", product(range(suppliers), range(targets)), 0, 1)
objective += lpSum(cost[i, j] * x[i, j] for i in range(suppliers) for j in range(targets))
for j in range(targets):
condition1 = lpSum( x[i, j] for i in range(suppliers)) == 1
objective+= condition1
for i in range(suppliers):
condition2 = lpSum(x[i, j] for j in range(targets)) <= capacity
objective+= condition2
objective.solve(PULP_CBC_CMD(msg=0))
我的其他限制是,目的地 (d3,d4) 将只接受来自一个供应商(可以是其中任何一个)的货物,并且该供应商应该只为他们提供服务,而不应向任何其他目的地提供服务。 如果我将它们与需求 2 组合到一个目的地并平均可行的成本,但我如何确保约束的后半部分?这只是一个示例案例,但在我的实际问题中,可能有多个目的地相互组合并要求相同的约束示例:(d1,d2) 和 (d5,d6,d3)。
编辑: 根据@kabdulla 的回答更新为以下工作代码,但最后一个约束已更改。
suppliers = 10
targets = ['A','B','C','D','E','F','G','H','I']
grps = [['A','B','C'],['D'],['E'],['F','G'],['H','I']] #constraint groups
groups = [[0, 1, 2], [3], [4], [5, 6], [7, 8]] #constraint group ids
capacities = [3, 1, 1, 2, 2]
capacity = 3
cost = np.random.rand(suppliers,len(targets))
objective = LpProblem("Optimize_allocation",LpMinimize)
x = LpVariable.dicts("assignment1", product(range(suppliers), range(len(targets))), 0, 1,'Integer')
y = LpVariable.dicts("assignment2", product(range(suppliers), range(len(groups))), 0, 1,'Integer')
objective += lpSum(cost[i, j] * x[i, j] for i in range(suppliers) for j in range(len(targets)))
for j in range(len(targets)):
objective+= lpSum( x[i, j] for i in range(suppliers)) == 1
for i in range(suppliers):
objective+= lpSum(x[i, j] for j in range(len(targets))) <= capacity
for i in range(suppliers):
for k in range(len(groups)):
objective += lpSum(x[i,j] for j in groups[k]) <= y[i,k]*capacities[k]
for k in range(len(groups)):
objective += lpSum(y[i,k] for i in range(suppliers)) == 1
for i in range(suppliers):
objective+= lpSum(y[i, j] for j in range(len(groups))) <= 1
objective.solve()
首先观察 - 您的 x[i, j]
变量(从供应商 i
到目标 j
的供应数量)是连续的 - 表明可以运送一小部分单位。如果这不是本意,这些 x
需要设为整数(cat='Integer'
调用 LpVariable.dicts()
)。
如果我正确理解了您的附加限制条件,则存在一些目标节点的“独家供应”集 E_k
。在其中一组中:
- 所有供应必须来自单个供应商节点
- 该供应商不得向集外的任何节点提供
要执行这种逻辑,您将需要一些二进制变量(如果您的 x
变量是不连续的并且限制在 [0,1] 范围内(即它们是二进制的),您可能是可以直接使用)。我假设你的 x
是连续的。
解决这个问题的一种方法是引入新的二进制变量y[i, k]
,当且仅当供应商i
是选择的独家供应商来设置k
。
假设您还声明了属于相同排他供应集的目标节点列表列表E
您可以添加所需的约束,如下所示:
for i in suppliers:
for k in range(len(E)):
objective += lpSum(x[i,j] for j in E[k]) <= y[i, k]*M[k]
其中 M[k]
足够大以至于当 y[i,k]
为 1 时它们不会添加额外的约束(例如,这可能只是 k
中节点的需求总和独家供应套装
然后您可以对 y[i,k]
变量强制执行所需的约束 - 即每个集合 k
必须只有一个供应商:
for k in range(len(E)):
objective += lpSum(y[i, k] for i in suppliers) == 1
最后你需要添加一个约束,如果供应商 i
正在服务独占集 k
(即 y[i,k] == 1
),则不允许他们提供任何不在其中的节点那一组:
for i in suppliers:
for k in range(len(E)):
objective += lpSum(x[i, j] for j in targets if j not in E[k]) <= \
(1 - y[i,k])*N[k]
其中 N[k]
足够大以至于当 y[i,j] == 0
时它们不会添加额外的约束(例如可能是不在第 k
个独家供应中的节点的需求总和设置。