【问题标题】:Vehicle Routing Problem: "Solution Infeasible" with PuLP when linking the variable "path (X)" and the variable "Delivered_Quantity"车辆路线问题:链接变量“path (X)”和变量“Delivered_Quantity”时,PuLP 的“解决方案不可行”
【发布时间】:2020-02-25 04:28:06
【问题描述】:

试图最小化总行驶距离(使用纸浆),我得到了一个不可行的解决方案,而它显然是可行的。

当我链接变量“path (X)”和变量“Delivered_Quantity”时,解决方案变得不可行。在代码中,链接是在“卡车 t 交付的总数量不能超过卡车 t 的总吨位能力”的约束下完成的。

from pulp import *

# Sets
Client = [0, 1, 2, 3]  # List of clients
Client_without_warehouse = [1, 2]  # List of clients without warehouse
T = [0, 1, 2]  # List of trucks
P = [0, 1, 2, 3]  # List of product types
Routes = [(i, j) for i in Client for j in Client if i != j]

# Parameters
Dist = {0: {0: 0.0, 1: 50.45, 2: 100.96, 3: 0.0}, 1: {0: 50.96, 1: 0.0, 2: 50.56, 3: 50.14},
        2: {0: 100.23, 1: 50.57, 2: 0.0, 3: 100.21}, 3: {0: 0.0, 1: 50.00, 2: 100.63, 3: 0.0}}  # Matrix Distance
Demand = {0: {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0}, 1: {0: 9.0, 1: 1.0, 2: 2.0, 3: 0.0},
          2: {0: 1.0, 1: 5.0, 2: 0.0, 3: 1.5}, 3: {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0}}  # Demand of client i in product p
TData = {"Truck Capacity": {0: 11.0, 1: 7.0, 2: 10.0}}  # Capacity of the different trucks
Speed = 50.0  # Average speed
TMW = {"Earliest Time": {0: 0.0, 1: 8.0, 2: 9.0, 3: 0.0}, "Latest time": {0: 24.0, 1: 17.0, 2: 16.0, 3: 24.0},
       "Service Time": {0: 0.0, 1: 0.5, 2: 0.5, 3: 0.0}}  # Earliest time, latest time and service time at client i

# Variables
# X = 1, if truck t travels directly from client i to client j ; 0, otherwise
X = LpVariable.dicts("X", (T, Client, Client), lowBound=0, upBound=1, cat="Binary")
# Amount of demand of client i in product p delivered by truck t
Delivered_Quantity = LpVariable.dicts("Delivered_Quantity", (T, Client_without_warehouse, P), lowBound=0, cat="Continuous")
# Starting time of service at client i by truck t
Starting_Time = LpVariable.dicts("Starting_Time", (T, Client), lowBound=0, cat='Continuous')

# Objection Function : Minimize total travel distance
Objective = LpProblem("VRP", LpMinimize)
Objective += lpSum(Dist[i][j]*X[t][i][j] for t in T for (i, j) in Routes)

# Different Constraints
for i in Client_without_warehouse:
    for p in P:
        # Total demand should be fulfilled.
        Objective += lpSum(Delivered_Quantity[t][i][p] for t in T) == Demand[i][p]
for t in T:
    # Warehouse is the starting point.
    Objective += lpSum(X[t][i][0] for i in Client) - lpSum(X[t][0][j] for j in Client) == -1
    # Warehouse is the final point.
    Objective += lpSum(X[t][i][len(Client) - 1] for i in Client) - lpSum(X[t][len(Client) - 1][j] for j in Client) == 1
    for k in Client_without_warehouse:
        # If truck goes to one customer, it has to leave it afterwards.
        Objective += lpSum(X[t][i][k] for i in Client) - lpSum(X[t][k][j] for j in Client) == 0  # (2.1.1)
        for (i, j) in Routes:
            # Total quantity delivered by truck t cannot exceed total tonnage capacity of truck t.
            Objective += lpSum(Delivered_Quantity[t][k][p] for k in Client_without_warehouse for p in P) <= X[t][k][j] * TData["Truck Capacity"][t]
            # Feasibility of time schedule + No sub-tour.
            Objective += Starting_Time[t][i] + (Dist[i][j] / Speed) + TMW["Service Time"][i] - (
                         TMW["Latest time"][i] + (Dist[i][j] / Speed) - TMW["Earliest Time"][i]) * (1 - X[t][i][j]) <= Starting_Time[t][j]

# Print Solution
status = Objective.solve()
if status == LpStatusOptimal:
    print("Solution: ", LpStatus[Objective.status])
    print("Total travel distance: ", pulp.value(Objective.objective))
else:
    print("Solution: ", LpStatus[Objective.status])

你知道哪里出了问题吗?

【问题讨论】:

  • 您在 Client_without_warehouse:` 和 Objective += lpSum(Delivered_Quantity[t][k][p] for k in Client_without_warehouse for p in P) &lt;= X[t][k][j] * TData["Truck Capacity"][t] 中为 k 定义了两次 k,我认为您可能对 for (i,j) in Routes 也有类似的问题
  • @StuartMitchell,我已经尝试过了,但它也不起作用:for t in T: Total_Quantity_Delivered = lpSum(Delivered_Quantity[t][k][p] for k in Client_without_warehouse for p in P) for k in Client_without_warehouse: Objective += Total_Quantity_Delivered &lt;= X[t][k][j] * TData["Truck Capacity"][t] 你对我如何重新表述它以不定义两次 k 有其他想法吗?
  • @StuartMitchell,我还发现如果我删除:(Dist[i][j] / Speed) + TMW["Service Time"][i] ,求解器会找到一个解决方案——虽然不是我想要的……但这可能意味着这部分还有一个如你所说的问题。我不明白我在哪里定义了两次 (i, j)。可以给我解释一下吗?
  • 对不起,我读到你的代码有点错误,i 的缩进没有重新定义

标签: python-3.x mathematical-optimization pulp vehicle-routing


【解决方案1】:

我希望这对您进行模型调试有所帮助。无论如何,它提供了一种相当简单的方法来调试我经常使用的复杂数学模型。

  1. 我创建了一个新的松弛变量:
ip = [(i, p) for i in Client_without_warehouse for p in  P]
Demand_slack = LpVariable.dicts("Demand_slack", ip, lowBound=0, cat='Continuous')
tkr = [(t, k, i, j) for t in T for k in Client_without_warehouse for (i, j) in Routes]
slack_tkr = LpVariable.dicts("slack_tkr", tkr, lowBound=0, cat='Continuous')

  1. 我将它们添加到您之前的目标函数中,权重很大:
BIG_WEIGHT = 99999
Objective += lpSum(Dist[i][j]*X[t][i][j] for t in T for (i, j) in Routes) + \
             BIG_WEIGHT * lpSum(slack_tkr.values()) + \
             10000 * BIG_WEIGHT * lpSum(Demand_slack.values())
  1. 我将它们添加到您的约束中:
# Different Constraints
for i in Client_without_warehouse:
    for p in P:
        # Total demand should be fulfilled.
        Objective += lpSum(Delivered_Quantity[t][i][p] for t in T) + Demand_slack[i][p] >= Demand[i][p]

和其他:

#(...)
            Objective += Starting_Time[t][i] + (Dist[i][j] / Speed) + TMW["Service Time"][i] - (
                         TMW["Latest time"][i] + (Dist[i][j] / Speed) - TMW["Earliest Time"][i]) * (1 - X[t][i][j]) <=\
                         Starting_Time[t][j] + slack_tkr[t, k, i, j]
  1. 求解并获得最优解后,我打印了非零松弛变量的组合:
[tup for tup, _var in Demand_slack.items() if _var.value()]
[tup for tup in tkr if slack_tkr[tup].value()]

表明以下客户和产品组合存在满足需求的问题:

[(1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 3)]

如果您更改 slack 变量中的权重,您会在以下路由约束(一半路由)中遇到问题:

[(0, 1, 0, 2), (0, 1, 1, 0), (0, 1, 1, 2), (0, 1, 1, 3), (0, 1, 2, 0), (0, 1, 2, 1), (0, 1, 3, 1), (0, 1, 3, 2), (0, 2, 0, 2), (0, 2, 1, 0), (0, 2, 1, 2), (0, 2, 1, 3), (0, 2, 2, 0), (0, 2, 2, 1), (0, 2, 3, 1), (0, 2, 3, 2), (2, 1, 0, 2), (2, 1, 1, 0), (2, 1, 1, 2), (2, 1, 1, 3), (2, 1, 2, 0), (2, 1, 2, 1), (2, 1, 3, 1), (2, 1, 3, 2), (2, 2, 0, 2), (2, 2, 1, 0), (2, 2, 1, 2), (2, 2, 1, 3), (2, 2, 2, 0), (2, 2, 2, 1), (2, 2, 3, 1), (2, 2, 3, 2)]

祝你好运!

【讨论】:

    猜你喜欢
    • 2019-08-01
    • 2020-12-02
    • 2021-05-15
    • 2022-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-21
    相关资源
    最近更新 更多