Facility Location (optmie03)
/***************************************************************/
/* */
/* S A S S A M P L E L I B R A R Y */
/* */
/* NAME: optmie03 */
/* TITLE: Facility Location (optmie03) */
/* PRODUCT: OR */
/* SYSTEM: ALL */
/* KEYS: OR */
/* PROCS: OPTMILP, SQL, GPLOT */
/* DATA: */
/* */
/* SUPPORT: UPDATE: */
/* REF: */
/* MISC: Example 3 from the OPTMILP chapter of Mathematical */
/* Programming. */
/* */
/***************************************************************/
%let NumCustomers = 50;
%let NumSites = 10;
%let SiteCapacity = 35;
%let MaxDemand = 10;
%let xmax = 200;
%let ymax = 100;
%let seed = 938;
/* generate random customer locations */
data cdata(drop=i);
length name $8;
do i = 1 to &NumCustomers;
name = compress('C'||put(i,best.));
x = ranuni(&seed) * &xmax;
y = ranuni(&seed) * &ymax;
demand = ranuni(&seed) * &MaxDemand;
output;
end;
run;
/* generate random site locations and fixed charge */
data sdata(drop=i);
length name $8;
do i = 1 to &NumSites;
name = compress('SITE'||put(i,best.));
x = ranuni(&seed) * &xmax;
y = ranuni(&seed) * &ymax;
fixed_charge = 30 * (abs(&xmax/2-x) + abs(&ymax/2-y));
output;
end;
run;
proc optmodel;
set <str> CUSTOMERS;
set <str> SITES init {};
/* x and y coordinates of CUSTOMERS and SITES */
num x {CUSTOMERS union SITES};
num y {CUSTOMERS union SITES};
num demand {CUSTOMERS};
num fixed_charge {SITES};
/* distance from customer i to site j */
num dist {i in CUSTOMERS, j in SITES}
= sqrt((x[i] - x[j])^2 + (y[i] - y[j])^2);
read data cdata into CUSTOMERS=[name] x y demand;
read data sdata into SITES=[name] x y fixed_charge;
var Assign {CUSTOMERS, SITES} binary;
var Build {SITES} binary;
/* each customer assigned to exactly one site */
con assign_def {i in CUSTOMERS}:
sum {j in SITES} Assign[i,j] = 1;
/* if customer i assigned to site j, then facility must be */
/* built at j */
con link {i in CUSTOMERS, j in SITES}:
Assign[i,j] <= Build[j];
/* each site can handle at most &SiteCapacity demand */
con capacity {j in SITES}:
sum {i in CUSTOMERS} demand[i] * Assign[i,j]
<= &SiteCapacity * Build[j];
min CostNoFixedCharge
= sum {i in CUSTOMERS, j in SITES} dist[i,j] * Assign[i,j];
save mps nofcdata;
min CostFixedCharge
= CostNoFixedCharge
+ sum {j in SITES} fixed_charge[j] * Build[j];
save mps fcdata;
quit;
proc optmilp data=fcdata primalout=fcout;
run;
proc optmilp data=nofcdata primalout=nofcout;
run;
proc sql noprint;
select put(sum(_objcoef_ * _value_),6.1) into :varcostNo
from nofcout;
quit;
proc sql;
create table CostNoFixedCharge_Data as
select
scan(p._var_,2,'[],') as customer,
scan(p._var_,3,'[],') as site,
c.x as xi, c.y as yi, s.x as xj, s.y as yj
from
cdata as c,
sdata as s,
nofcout(where=(substr(_var_,1,6)='Assign' and
round(_value_) = 1)) as p
where calculated customer = c.name and calculated site = s.name;
quit;
proc optmilp data=fcdata primalin=nofcout primalout=fcout;
run;
proc sql noprint;
select put(sum(_objcoef_ * _value_), 6.1) into :varcost
from fcout(where=(substr(_var_,1,6)='Assign'));
select put(sum(_objcoef_ * _value_), 5.1) into :fixcost
from fcout(where=(substr(_var_,1,5)='Build'));
select put(sum(_objcoef_ * _value_), 6.1) into :totalcost
from fcout;
quit;
proc sql;
create table CostFixedCharge_Data as
select
scan(p._var_,2,'[],') as customer,
scan(p._var_,3,'[],') as site,
c.x as xi, c.y as yi, s.x as xj, s.y as yj
from
cdata as c,
sdata as s,
fcout(where=(substr(_var_,1,6)='Assign' and
round(_value_) = 1)) as p
where calculated customer = c.name and calculated site = s.name;
quit;
title1 "Facility Location Problem";
title2 "TotalCost = &varcostNo (Variable = &varcostNo, Fixed = 0)";
data csdata;
set cdata(rename=(y=cy)) sdata(rename=(y=sy));
run;
/* create Annotate data set to draw line between customer and */
/* assigned site */
%annomac;
data anno(drop=xi yi xj yj);
%SYSTEM(2, 2, 2);
set CostNoFixedCharge_Data(keep=xi yi xj yj);
%LINE(xi, yi, xj, yj, *, 1, 1);
run;
proc gplot data=csdata anno=anno;
axis1 label=none order=(0 to &xmax by 10);
axis2 label=none order=(0 to &ymax by 10);
symbol1 value=dot interpol=none
pointlabel=("#name" nodropcollisions height=0.7) cv=black;
symbol2 value=diamond interpol=none
pointlabel=("#name" nodropcollisions color=blue height=0.7) cv=blue;
plot cy*x sy*x / overlay haxis=axis1 vaxis=axis2;
run;
quit;
title1 "Facility Location Problem";
title2 "TotalCost = &totalcost (Variable = &varcost, Fixed = &fixcost)";
/* create Annotate data set to draw line between customer and */
/* assigned site */
data anno(drop=xi yi xj yj);
%SYSTEM(2, 2, 2);
set CostFixedCharge_Data(keep=xi yi xj yj);
%LINE(xi, yi, xj, yj, *, 1, 1);
run;
proc gplot data=csdata anno=anno;
axis1 label=none order=(0 to &xmax by 10);
axis2 label=none order=(0 to &ymax by 10);
symbol1 value=dot interpol=none
pointlabel=("#name" nodropcollisions height=0.7) cv=black;
symbol2 value=diamond interpol=none
pointlabel=("#name" nodropcollisions color=blue height=0.7) cv=blue;
plot cy*x sy*x / overlay haxis=axis1 vaxis=axis2;
run;
quit;