行業背景
物流運輸是供應鏈管理的關鍵,往往涉及到運輸、倉儲、裝卸、配送等。如何合理的安排運輸方案以提高貨物運輸的效率和可靠性,降低物流成本。這個優化問題也可以運用數學規劃的方法來建模和求解。
例如:某企業需要將工廠生產的產品,運送至配送中心,再發往各個倉庫,每個產品送往不同倉庫所需的費用也不同,并且每條運輸線路均有運送上限,如何安排運輸,使運配送成本最低。
業務調研、數據量化、數學建模
在使用優化技術的時候,需要更詳細的調研業務的需求,整理相關的業務邏輯和數據,并量化表示它。然后采用數學規劃的方法進行數學建模。
此部分細節較多,可在案例物流運輸中查閱細節,此處我們僅列出數學公式如下,參數部分請點擊案例鏈接查看:
其中s代表每個地址能提供的商品,d代表每個地點需要的商品,i和j代表一段通道的起點和終點,k代表中間站點。
以上公式對應的約束有:
每個地點提供的商品數量加上運入該點的商品之和等于該地其商品需求加上該地運出的商品數量之和
每條運輸路線均有運送上限
源代碼
MindOpt支持多種編程語言或者建模語言來調用。此處僅列出一種供參考:
MindOpt APL建模語言調用
MindOpt APL建模語言的源代碼(可在物流運輸上試運行):
##====MindOpt APL 建模語言版本代碼====
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];
結果和結果用法
不同代碼日志打印不一樣。部分結果日志打印如下所示:
...
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]
...
Simplex method terminated. Time : 0.008s
OPTIMAL; objective 2123.00
...
-----------------結果---------------
經過優化后,最低運輸成本=2123
目標的最優解是:2123。更多解的細節,如決策變量的取值、驗證約束是否正確,可以通過print命令打印來顯示,變量的取值也可以從程序運行寫的.sol文件里面獲取,還可以調用display
獲取所有變量的取值。
如運行如下指令,驗證“每個地點提供的商品數量加上運入該點的商品之和等于該地其商品需求加上該地運出的商品數量之和”這個約束:
forall {<k> in CITIES }
print '{}站點提供的商品數量與運入該站點的商品數量之和為{}'%k ,
supply[k] + sum {<i, k> in LINKS} Ship[i, k];
print "-------------------";
forall {<k> in CITIES }
print '{}站點需要的商品數量與運出該站點的商品數量之和為{}'%k ,
demand[k] + sum {<k, j> in LINKS} Ship[k,j];
結果如下:
HN站點提供的商品數量與運入該站點的商品數量之和為450
NE站點提供的商品數量與運入該站點的商品數量之和為250
SE站點提供的商品數量與運入該站點的商品數量之和為200
LN站點提供的商品數量與運入該站點的商品數量之和為120
JL站點提供的商品數量與運入該站點的商品數量之和為120
HLJ站點提供的商品數量與運入該站點的商品數量之和為50
JS站點提供的商品數量與運入該站點的商品數量之和為90
ZJ站點提供的商品數量與運入該站點的商品數量之和為70
-------------------
HN站點需要的商品數量與運出該站點的商品數量之和為450
NE站點需要的商品數量與運出該站點的商品數量之和為250
SE站點需要的商品數量與運出該站點的商品數量之和為200
LN站點需要的商品數量與運出該站點的商品數量之和為120
JL站點需要的商品數量與運出該站點的商品數量之和為120
HLJ站點需要的商品數量與運出該站點的商品數量之和為50
JS站點需要的商品數量與運出該站點的商品數量之和為90
ZJ站點需要的商品數量與運出該站點的商品數量之和為70
運行如下代碼,將輸出打印為csv格式,作為物流運輸問題的解決方案:
print "{},{},{} "% "起點","途徑點","商品數量" : "Results.csv";
close "Results.csv";
forall {<i, j> in LINKS}
print "{},{},{}" % i,j,Ship[i,j] >> "Results.csv";
close "Results.csv";
結果如下:
即,從工廠運輸商品到各個倉庫的最低運輸成本為2123。運輸方案如下:
從HN工廠運輸到NE配送中心的商品數量為250,到SE配送中心是200;
從NE配送中心運輸到LN倉庫的商品數量為100,到JL倉庫為100,到HLJ倉庫為50
從SE配送中心運輸到LN倉庫的商品數量為20,到JL倉庫是20,到JS倉庫為90,到ZJ倉庫為70
LN倉庫匯總了120的商品,JL匯總120,HLJ匯總50,JS匯總90,ZJ匯總70
最后計算兩個配送中心發往各個倉庫的運輸成本,即2123。