第 16 章:優化研究

此章節主要介紹 SAS 平台如何進行優化研究的應用

基本介紹

首先優化是作業研究,工業工程與管理所組成的科學,其是選擇產生最佳效果的可用操作之過程結果。而數學優化主要有三個階段,分別為:

  1. 描述分析 (Descriptive):發生了什麼?

  2. 預測分析 (Predictive):將會發生什麼?

  3. 指示分析 (Prescriptive):應該怎麼做?

接著優化的業務案例,主要有:

  1. 計劃生產:確定應生產幾種可能的產品組合中的哪一種實現最高利潤。

  2. 設施位置:找到與該位置相關的最佳站點,像是新工廠,材料供應商和配送中心。

  3. 投資組合選擇:最大化投資回報率,同時平衡回報與風險。

  4. 人員分配:使人員符合工作要求,以便滿足當前需求和預期的變化,取決於預算和人力資源要求。

  5. 供應鏈計劃:找到將產品從工廠轉移到配送中心的最低成本方式到商店,併計劃可能的中斷或擴展。

  6. 促銷營銷:確定促銷優惠,投放渠道的最佳組合,和客戶最大化營銷投資的整體回報。

  7. 供應商選擇和評估:選擇要處理的供應商滿意要求和最大化槓桿,使用各種標準對供應商進行評級。

  8. 庫存補貨:重新訂購級別和最大庫存水平,以滿足要求客戶服務目標和最小化成本。

  9. 定價決策:根據成本和區域需求建立並維持最佳日常價格模式和有競爭力的價格資訊。

再來從 SAS 資料集中讀取集合和參數值,並將模型輸出寫入 SAS 資料集是 OPTMODEL 程序應用優化分析的重要部分,其中 SOLVE 語句導致數學優化模型從宣告建立陳述並解決,其產生包含最佳目標值的解決方案摘要和解決時間。

最後優化建模處理流程主要為定義業務問題代表著做出必要的假設和近似將其表示為理想地在合理的時間內解決之優化模型,若無法在業務問題的上下文中解釋優化問題的最佳解決方案,模型就有可能必須進行修改,所以我們針對商業問題會透過公式產生優化模型,產生解決方案以利解釋商業問題,同時再度修改優化模型。

整合應用

首先我們能夠透過 SAS Viya 平台解決優化問題,並且基於分散式處理架構能夠讓使用者在記憶體內快速運算數學優化問題,同時透過持續儲存資料在記憶體中消除在迭代分析期間多次載入資料的操作,以及 PROC OPTMODEL 是一種成熟的互動式線性代數建模語言,其主要分別為三大部份,分別為:

  1. PROC 敘述:主要設定初始選項。

  2. 宣告敘述:主要優化模型元件。

  3. 程式敘述:主要讀取和寫入資料,並且使用求解器,以及輸出結果。

而我們主要透過 PROC OPTMODEL 解決數學優化問題,像是最大化多維多項式的問題,並且提供建立,解決和維護的建模環境,透過輸入資料優化模型,並且儲存優化模型和相關解決方案的資料

接著 SAS Optimization 主要是基於雲端分析服務的環境為不同的問題提供線性程式 (LP)、混合整數線性程式 (MILP)、二次項程式 (QP)、非線性程式 (NLP)、條件約束程式 (CLP) 、網路演算法 (Network) 和局部搜尋優化 (LSO) 優化求解器,並且能夠透過 PROC OPTMODEL 建立優化模型。

問題類型

求解器

線性程式

LP

混合整數線性程式

MILP

二次項程式

QP

非線性程式

NLP

條件約束程式

CLP

網路演算法

Network

局部搜尋優化

LSO

其中分解演算法可以透過 LP 和 MILP 求解器進行求解,至於網路求解器主要包括解決優化問題的演算法,像是最短路徑和最小網路流量成本,並且還提供分析網路結構的演算法,其中包括連接元件和循環檢測。

再來當我們在 SAS Viya 平台中建立優化模型程序時,其分散式運算將能夠大量且獨立執行的重要子程序,同時求解器可以在分散式運算環境中執行運算節點,以利提供優化解決方案。其中 PROC OPTMODEL 將會自動使用多執行緒執行,以及透過 COFOR 敘述允許多個求解器進行平行處理。此外若我們需要在 SAS 中建立在 SAS Viya 平台中執行求解器,也能夠使用 PROC OPTLP、PROC OPTMILP、PROC OPTQP、PROC OPTNET 和 PROC CLP,並且指定問題的輸入 CAS 資料表就能夠在 SAS Viya 平台中執行求解器。

最後企業客戶更能夠透過 sasoptpy 套件直接以 Python 程式語言撰寫解決線性,混合整數線性和非線性優化問題的程式,同時透過 Python 中的結構、字典、元組和列表用於定義優化問題,並且透過 SAS Viya 平台解決企業客戶所面臨的優化問題。

開始使用

  • 在畫面下方按下【Jupyter】鈕。

  • 登入【Jupyter】,輸入【SAS Profile 電子郵件】和【SAS Profile 密碼】,按下【Sign In】鈕。

  • 按下【New】鈕,點選【SAS】。

  • 輸入【SAS 程式碼】,建立人力規劃之優化研究的輸入資料。

data demand_data;
input period unskilled semiskilled skilled;
datalines;
0 2000 1500 1000
1 1000 1400 1000
2 500 2000 1500
3 0 2500 2000
;
data worker_data;
input worker $12. waste_new waste_old recruit_ub redundancy_cost
overmanning_cost shorttime_ub shorttime_cost;
datalines;
unskilled 0.25 0.10 500 200 1500 50 500
semiskilled 0.20 0.05 800 500 2000 50 400
skilled 0.10 0.05 500 500 3000 50 400
;
data retrain_data;
input worker1 $12. worker2 $12. retrain_ub retrain_cost;
datalines;
unskilled semiskilled 200 400
semiskilled skilled . 500
;
data downgrade_data;
input worker1 $12. worker2 $12.;
datalines;
semiskilled unskilled
skilled semiskilled
skilled unskilled
;
%let semiskill_retrain_frac_ub = 0.25;
%let downgrade_leave_frac = 0.5;
%let overmanning_ub = 150;
%let shorttime_frac = 0.5;
  • 按下【Shift + Enter】執行【SAS 程式碼】。

  • 查看 SAS 程式碼執行結果。

  • 輸入【SAS 程式碼】,建立人力規劃之優化研究的模型。

proc optmodel;
set <str> WORKERS;
num waste_new {WORKERS};
num waste_old {WORKERS};
num recruit_ub {WORKERS};
num redundancy_cost {WORKERS};
num overmanning_cost {WORKERS};
num shorttime_ub {WORKERS};
num shorttime_cost {WORKERS};
read data worker_data into WORKERS=[worker]
waste_new waste_old recruit_ub redundancy_cost overmanning_cost
shorttime_ub shorttime_cost;
set PERIODS0;
num demand {WORKERS, PERIODS0};
read data demand_data into PERIODS0=[period]
{worker in WORKERS} <demand[worker,period]=col(worker)>;
var NumWorkers {WORKERS, PERIODS0} >= 0;
for {worker in WORKERS} fix NumWorkers[worker,0] = demand[worker,0];
set PERIODS = PERIODS0 diff {0};
var NumRecruits {worker in WORKERS, PERIODS} >= 0 <= recruit_ub[worker];
var NumRedundant {WORKERS, PERIODS} >= 0;
var NumShortTime {worker in WORKERS, PERIODS} >= 0 <= shorttime_ub[worker];
var NumExcess {WORKERS, PERIODS} >= 0;
set <str,str> RETRAIN_PAIRS;
num retrain_ub {RETRAIN_PAIRS};
num retrain_cost {RETRAIN_PAIRS};
read data retrain_data into RETRAIN_PAIRS=[worker1 worker2]
retrain_ub retrain_cost;
var NumRetrain {RETRAIN_PAIRS, PERIODS} >= 0;
for {<i,j> in RETRAIN_PAIRS: retrain_ub[i,j] ne .}
for {period in PERIODS} NumRetrain[i,j,period].ub = retrain_ub[i,j];
set <str,str> DOWNGRADE_PAIRS;
read data downgrade_data into DOWNGRADE_PAIRS=[worker1 worker2];
var NumDowngrade {DOWNGRADE_PAIRS, PERIODS} >= 0;
con Demand_con {worker in WORKERS, period in PERIODS}:
NumWorkers[worker,period]
- (1 - &shorttime_frac) * NumShortTime[worker,period]
- NumExcess[worker,period]
= demand[worker,period];
con Flow_balance_con {worker in WORKERS, period in PERIODS}:
NumWorkers[worker,period]
= (1 - waste_old[worker]) * NumWorkers[worker,period-1]
+ (1 - waste_new[worker]) * NumRecruits[worker,period]
+ (1 - waste_old[worker]) *
sum {<i,(worker)> in RETRAIN_PAIRS} NumRetrain[i,worker,period]
+ (1 - &downgrade_leave_frac) *
sum {<i,(worker)> in DOWNGRADE_PAIRS} NumDowngrade[i,worker,period]
- sum {<(worker),j> in RETRAIN_PAIRS} NumRetrain[worker,j,period]
- sum {<(worker),j> in DOWNGRADE_PAIRS} NumDowngrade[worker,j,period]
- NumRedundant[worker,period];
con Semiskill_retrain_con {period in PERIODS}:
NumRetrain['semiskilled','skilled',period]
<= &semiskill_retrain_frac_ub * NumWorkers['skilled',period];
con Overmanning_con {period in PERIODS}:
sum {worker in WORKERS} NumExcess[worker,period] <= &overmanning_ub;
min Redundancy =
sum {worker in WORKERS, period in PERIODS} NumRedundant[worker,period];
min Cost =
sum {worker in WORKERS, period in PERIODS} (
redundancy_cost[worker] * NumRedundant[worker,period]
+ shorttime_cost[worker] * NumShorttime[worker,period]
+ overmanning_cost[worker] * NumExcess[worker,period])
+ sum {<i,j> in RETRAIN_PAIRS, period in PERIODS}
retrain_cost[i,j] * NumRetrain[i,j,period];
solve obj Redundancy;
print Redundancy Cost;
print NumWorkers NumRecruits NumRedundant NumShortTime NumExcess;
print NumRetrain;
print NumDowngrade;
create data sol_data1 from [worker period]
NumWorkers NumRecruits NumRedundant NumShortTime NumExcess;
create data sol_data2 from [worker1 worker2 period] NumRetrain NumDowngrade;
solve obj Cost;
print Redundancy Cost;
print NumWorkers NumRecruits NumRedundant NumShortTime NumExcess;
print NumRetrain;
print NumDowngrade;
create data sol_data3 from [worker period]
NumWorkers NumRecruits NumRedundant NumShortTime NumExcess;
create data sol_data4 from [worker1 worker2 period] NumRetrain NumDowngrade;
quit;
  • 按下【Shift + Enter】執行【SAS 程式碼】。

  • 查看 SAS 程式碼執行結果。

  • 點選【Untitled】。

  • 輸入【人力規劃優化研究】為檔案名稱。

  • 按下【Save and Checkpoint】鈕。