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;