【问题标题】:How to set up a linear programming model (transportation problem) using python/PuLp如何使用python/PuLp建立线性规划模型(运输问题)
【发布时间】:2022-11-13 03:20:19
【问题描述】:

我正在研究一种运输/补货模型,我需要在其中以最低成本解决问题。变量是:

  • 仓库 - 几个可能的发货起点。
  • Items - 在这个例子中我只使用了两个项目。每个 Item-Store 组合都有一个独特的需求值。
  • 库存 - 每个“仓库”中每个“项目”的可用库存
  • Stores - 每批货物的目的地。在这个例子中,我只使用了两个 Store。
  • 成本 - 每个仓库-物品-商店组合的唯一成本,用于解决最低成本。
  • 需求 - 每个 'Store' 想要接收的每个 'Item' 的数量;除非没有库存,否则该模型应实现 100%。

我对 Python 不是很有经验。似乎我有点接近,但是,我有一个问题我还没有解决:如果库存太低而无法满足所有需求,模型将中断并返回“不可行”的结果。取而代之的是,我希望模型满足需求,直到库存达到零,然后返回到该点的优化结果。我知道我现在得到的结果是因为我在我的一个约束中将已完成的数量设置为等于需求,但我不确定如何修改/修复它。

这是到目前为止的代码 - 这是大量谷歌搜索的结果,并且像弗兰肯斯坦博士一样将零碎的代码组合在一起 - 如果这里有任何东西看起来很愚蠢,请告诉我。使用当前输入,这将不起作用,因为 Inventory 不能满足 Demand,但如果 Inventory 更高,它似乎可以工作(例如,将 Store1-SKU_B 需求从 250 更改为 50)

from pulp import *
import pandas as pd

# Creates a list of all the supply nodes 
warehouses = ["WHS_1","WHS_2","WHS_3"]

# Creates a dictionary for Inventory by Node-SKU
inventory = {"WHS_1": {"SKU_A":50,"SKU_B":100},
             "WHS_2": {"SKU_A":50,"SKU_B":75} , 
             "WHS_3": {"SKU_A":150,"SKU_B":25} ,
            }

# Store list
stores = ["Store1","Store2"]

# SKU list
items = ["SKU_A","SKU_B"]

# Creates a dictionary for the number of units of demand for each Store-SKU
demand = {
    "Store1": {"SKU_A":100,"SKU_B":250},
    "Store2": {"SKU_A":100,"SKU_B":50},
    }

# Creates a dictionary for the lane cost for each Node-Store-SKU
costs =  {
          "WHS_1": {"Store1": {"SKU_A":10.50,"SKU_B":3.75},
                 "Store2": {"SKU_A":15.01,"SKU_B":5.15}},
          "WHS_2": {"Store1": {"SKU_A":9.69,"SKU_B":3.45},
                 "Store2": {"SKU_A":17.50,"SKU_B":6.06}},
          "WHS_3": {"Store1": {"SKU_A":12.12,"SKU_B":5.15},
                 "Store2": {"SKU_A":16.16,"SKU_B":7.07}},
            }

# Creates the 'prob' variable to contain the problem data 
prob = LpProblem("StoreAllocation", LpMinimize)

# Creates a list of tuples containing all the possible routes for transport 
routes = [(w, s, i) for w in warehouses for s in stores for i in items]
 
# A dictionary called 'Vars' is created to contain the referenced variables(the routes) 
vars = LpVariable.dicts("Route", (warehouses, stores, items), 0, None, LpInteger) 
 
# The objective function is added to 'prob' first 
prob += (
    lpSum([vars[w][s][i] * costs[w][s][i] for (w, s, i) in routes]),
    "Sum_of_Transporting_Costs",
)

# Supply constraint, must not exceed Node Inventory
for w in warehouses:
    for i in items:
        prob += (
            lpSum([vars[w][s][i] for s in stores]) <= inventory[w][i],
            f"Sum_of_Products_out_of_Warehouse_{w}{i}",
        )

# Supply constraint, supply to equal demand
for s in stores:
    for i in items:
        prob += (
            lpSum([vars[w][s][i] for w in warehouses]) == demand[s][i],
            f"Sum_of_Products_into_Store{s}{i}",
        ) 

        
# The problem data is written to an .lp file
prob.writeLP("TestProblem.lp")

prob.solve()
# The status of the solution is printed to the screen 
print("Status:", LpStatus[prob.status])
# Each of the variables is printed with it's resolved optimum value 
for v in prob.variables():
    print(v.name, "=", v.varValue)
# The optimised objective function value is printed to the screen 
print("Total Cost of Fulfillment = ", value(prob.objective))  
 

【问题讨论】:

    标签: python optimization linear-programming pulp


    【解决方案1】:

    这很好。你的模型设置得很好。再说说供应...

    所以这是一个常见的转运模式,你想把成本降到最低,但默认的答案是零成本什么都不发货,这是不好的。如您所知,您需要对交付施加上行压力以满足需求,或者至少在需求 > 库存的情况下尽可能利用手头的库存。

    第一件“便宜又容易”的事情是将每种产品的总交付量减少到可用的……所有商店。在您当前的代码中,您试图强制交付 == 需求,这可能是不可能的。因此,您可以退后一步,只说“提供总需求,或至少提供所有库存”。在伪代码中类似于:

    total_delivery[sku] = min(all inventory, demand)
    

    您可以对其他 SKU 执行相同的操作,然后按 SKU 计算所有仓库和目的地的所有交付量并强制计算:

    for SKU in SKUs:
      sum(deliver[w, s, sku] for w in warehouses for s in stores) >= total_delivery[sku]
    

    意识到范围total_delivery 不是变量,在做任何事情之前可以从数据中辨别出来。

    以上将使模型运行,但存在问题。该模型可能会“超额投放”到某些网站,因为我们正在汇总需求。因此,如果您有 100 个东西,并且将 50/50 的需求分成 2 个站点,它将向最便宜的站点提供 100 个……不好。因此,您需要添加一个约束来限制对每个站点的交付需求,而不管来源如何。就像是:

    for s in stores:
      for sku in skus:
        sum(deliver[w, s, sku] for w in warehouses) <= demand[s, sku]
    

    添加这些应该使您的模型运行。结果(如果库存不足)将不成比例地交付给廉价网站。也许这没关系。平衡它有点复杂。

    ...

    关于您的模型,您将变量构造为嵌套列表...这就是为什么您需要将其索引为vars[w][s][i]。这很好,但我发现对变量进行元组索引要容易得多,而且你已经有了基础集routes 可以使用。所以我会:

    deliver = LpVariable.dicts("deliver", routes, 0, None, LpInteger)
    

    然后你可以像我在上面的例子中那样索引它......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-11
      • 2013-09-18
      • 2023-02-22
      • 2021-12-01
      • 1970-01-01
      • 2021-02-23
      • 1970-01-01
      相关资源
      最近更新 更多