Manpower Planning (mpex05)
/***************************************************************/
/* */
/* S A S S A M P L E L I B R A R Y */
/* */
/* NAME: mpex05 */
/* TITLE: Manpower Planning (mpex05) */
/* PRODUCT: OR */
/* SYSTEM: ALL */
/* PROCS: OPTMODEL */
/* DATA: */
/* */
/* SUPPORT: UPDATE: */
/* REF: */
/* MISC: Example 05 from the Mathematical Programming */
/* Examples book. */
/* */
/***************************************************************/
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;
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;