仓储物流调度问题也是网络流问题的一种,在上篇我们已经介绍了什么是网络流问题。那么什么是仓储物流调度呢?仓储物流调度是指在物流供应链中,对仓储和运输(运输路线、成本)进行协调和安排的过程。主要包含物流计划、运输调度、运发管理、库存管理等重要环节。随着网络、电商行业的迅速发展,仓储物流调度对于企业来说也非常重要,优秀的调度方案可以帮助降低库存成本、物流配送的效率、成本等等等,从而给企业带来降本增效。
1. 仓储物流调度
考虑如下决策问题。现有一位置在河南(HN)的工厂将生产450个产品,产品需要从工厂运至东北(NE),东南(SE)两个配送中心,再由配送中心发往江苏(JS), 浙江(ZJ), 吉林(JL),辽宁(LN)和黑龙江(HLJ)五个省份的仓库。已知这五个省份的仓库分别需要的产品如下:
仓库需求 | |
---|---|
JS | 90 |
ZJ | 120 |
JL | 120 |
LN | 70 |
HLJ | 50 |
且每个产品送往不同仓库所需的费用也不同,并且每条运输线路均有运送上限, 具体如下表所示:
运输每个产品的价格 | 运送产品的上限 | |
---|---|---|
HN, NE | 3.5元/个 | 250个 |
HN, SE | 2.5元/个 | 250个 |
NE, LN | 1.5元/个 | 100个 |
NE, JL | 1.7元/个 | 100个 |
NE, HLJ | 2.0元/个 | 100个 |
SE, LN | 2.6元/个 | 100个 |
SE, JL | 2.7元/个 | 100个 |
SE, JS | 1.3元/个 | 100个 |
SE, ZJ | 1.5元/个 | 100个 |
请问该公司该如何决策,使得总配送成本最低?
2. 数学规划模型
以上问题的数学模型如下。
集合
- 地点集合 C C C
- 线路集合 L L L
- 混合集合 I I I(由运输一个商品所需成本 c o s t \rm{cost} cost和 运输的商品的数量上限 c a p a c i t y \rm{capacity} capacity组成)
参数
- 地点 c ∈ C c \in C c∈C能够提供的商品 s c s_c sc
- 地点 c ∈ C c \in C c∈C需要的商品 d c d_c dc
- 线路 l ∈ L l \in L l∈L运输一件商品的成本 d c o s t d_{\mathrm{cost}} dcost
- 线路 l ∈ L l \in L l∈L运输的商品的数量上限 d c a p d_{\mathrm{cap}} dcap
变量
线路 l ∈ L l \in L l∈L中地点 i , j ∈ C i,j \in C i,j∈C间运输的商品的数量 0 ≤ s i j ≤ d c a p 0 \leq s_{ij}\leq d_{\mathrm{cap}} 0≤sij≤dcap
目标函数
最小化运输成本 min ∑ l ∈ L d c o s t ⋅ s i j \min \sum_{l \in L}d_{\mathrm{cost}}\cdot s_{ij} min∑l∈Ldcost⋅sij
约束
地点 k ∈ C k \in C k∈C提供的商品数量 s c s_c sc加上运入该点的商品之和 ∑ i ∈ C s i k \sum_{i \in C}s_{ik} ∑i∈Csik等于该地其商品需求 d k d_k dk加上该地运出的商品数量之和 ∑ j ∈ C s k j \sum_{j \in C}s_{kj} ∑j∈Cskj
3. MindOpt APL 建模和求解
MindOpt APL是一款代数建模语言,它可以方便地将数学语言描述成程序,然后调用多种求解器求解。MindOpt Solver对网络流的线性规划求解效率很不错,且能支持大规模的问题。
MindOpt云上建模平台是一款用于优化建模和求解的在线教学和开发调试的工具。它支持Notebook、Python 编程、MindOpt APL优化建模语言和多个优化求解器,并业的教程和多个案例。
改写上面的数据图和数学模型,如下代码,在云上平台Notebook的cell中运行它:
clear model;
# 建模-------
# net2.mapl
# 数据
set CITIES := {"HN", "NE", "SE", "LN", "JL", "HLJ", "JS", "ZJ"} ;
set LINKS := {<"HN", "NE">, <"HN", "SE">, <"NE", "LN">, <"NE","JL">, <"NE","HLJ">, <"SE","LN">, <"SE","JL">, <"SE", "JS">, <"SE", "ZJ">};
param supply[CITIES] := <"HN"> 450 default 0;
param demand[CITIES] := <"JS"> 90, <"ZJ"> 70, <"JL"> 120, <"LN"> 120, <"HLJ"> 50 default 0;
set C := {"cost", "capacity"};
param data[LINKS * C] :=
| "cost", "capacity"|
|"HN", "NE" | 3.5, 250 |
|"HN", "SE" | 2.5, 250 |
|"NE", "LN" | 1.5, 100 |
|"NE", "JL" | 1.7, 100 |
|"NE", "HLJ"| 2.0, 100 |
|"SE", "LN" | 2.6, 100 |
|"SE", "JL" | 2.7, 100 |
|"SE", "JS" | 1.3, 100 |
|"SE", "ZJ" | 1.5, 100 |;
# 检查数据是否填正确
forall {<i> in CITIES } check supply[i] >= 0;
forall {<i> in CITIES } check demand[i] >= 0;
check sum {<i> in CITIES } supply[i] >= sum {<j> in CITIES} demand[j]; #供给大于需求
# 模型
var Ship[<i, j> in LINKS] >= 0 <= data[i, j, "capacity"];
minimize Total_Cost: sum {<i, j> in LINKS } data[i, j, "cost"] * Ship[i, j];
subto Balance:
forall {<k> in CITIES }
supply[k] + sum {<i, k> in LINKS} Ship[i, k] >= demand[k] + sum {<k, j> in LINKS} Ship[k,j]; #每个站点供给都满足了需求
print "-----------------用MindOpt求解---------------";
option solver mindopt; # (可选)指定求解用的求解器,默认是MindOpt
#option mindopt_options 'print=0'; #设置求解器输出级别,减少过程打印
solve; # 求解
print "-----------------Display---------------";
display; # 展示结果
print "经过优化后,最低运输成本=" , sum {<i, j> in LINKS } data[i, j, "cost"] * Ship[i, j];
运行代码结果如下:
-----------------用MindOpt求解---------------
Running mindoptampl
wantsol=1
mip_integer_tolerance=1e-9
MindOpt Version 0.24.1 (Build date: 20230423)
Copyright (c) 2020-2023 Alibaba Cloud.
Start license validation (current time : 29-JUN-2023 21:31:22).
License validation terminated. Time : 0.006s
Only one thread allowed -- optimize with Simplex method.
Model summary.
- Num. variables : 9
- Num. constraints : 5
- Num. nonzeros : 15
- Bound range : [5.0e+01,4.5e+02]
- Objective range : [1.3e+00,3.5e+00]
- Matrix range : [1.0e+00,1.0e+00]
Presolver started.
Presolver terminated. Time : 0.000s
Simplex method started.
Model fingerprint: ==gZ3F2dkdXZ
Iteration Objective Dual Inf. Primal Inf. Time
0 9.30000e+01 0.0000e+00 4.0000e+00 0.01s
1 2.12300e+03 0.0000e+00 0.0000e+00 0.01s
Postsolver started.
Simplex method terminated. Time : 0.002s
OPTIMAL; objective 2123.00
1 simplex iterations
Completed.
-----------------Display---------------
Primal Solution:
Ship@<HN,NE> = 250.000
Ship@<HN,SE> = 200.000
Ship@<NE,LN> = 100.000
Ship@<NE,JL> = 100.000
Ship@<NE,HLJ> = 50.0000
Ship@<SE,LN> = 20.0000
Ship@<SE,JL> = 20.0000
Ship@<SE,JS> = 90.0000
Ship@<SE,ZJ> = 70.0000
经过优化后,最低运输成本=2123
4. 结果
运行上述代码后,得到结果为:
Primal Solution:
Ship@<HN,NE> = 250.000
Ship@<HN,SE> = 200.000
Ship@<NE,LN> = 100.000
Ship@<NE,JL> = 100.000
Ship@<NE,HLJ> = 50.0000
Ship@<SE,LN> = 20.0000
Ship@<SE,JL> = 20.0000
Ship@<SE,JS> = 90.0000
Ship@<SE,ZJ> = 70.0000
经过优化后,最低运输成本=2123
需注意的是,优化问题可能有多个可行解或可行域的情况,更换求解器的时候,解的变量取值可能会不一样,但是最优的目标值是一样的,比如如果我们更换求解器会得到如下结果。
其他求解器的使用方法请浏览:MindOpt平台上各种求解器的用法
Cbc求解器:
Primal Solution:
Ship@<HN,NE> = 200.000
Ship@<HN,SE> = 250.000
Ship@<NE,LN> = 100.000
Ship@<NE,JL> = 50.0000
Ship@<NE,HLJ> = 50.0000
Ship@<SE,LN> = 20.0000
Ship@<SE,JL> = 70.0000
Ship@<SE,JS> = 90.0000
Ship@<SE,ZJ> = 70.0000
经过优化后,最低运输成本=2123
HiGHS求解器:
Primal Solution:
Ship@<HN,NE> = 250.000
Ship@<HN,SE> = 200.000
Ship@<NE,LN> = 100.000
Ship@<NE,JL> = 100.000
Ship@<NE,HLJ> = 50.0000
Ship@<SE,LN> = 20.0000
Ship@<SE,JL> = 20.0000
Ship@<SE,JS> = 90.0000
Ship@<SE,ZJ> = 70.0000
经过优化后,最低运输成本=2123