Rob:
here is the code that you had. i am having 2 questions (a) in the create data step, i was trying various options to print the distance between the customer and its assigned facility. One of the example, is fro Miami to Newark, where the distance should have been 1,268 (miles) but it gave me 3,493. I used Distance[i,j] to come up with this number. I also tried using GEODIST to calculate the distance between the final X and customers but it did not work either. (b) Is there a way to specify to the model to pick a facility that is no more than 500 miles or any prefixed number. I was thinking to have this constraint like this in NLP :- con radius{i in CUSTOMERS, j in FACILITIES}: Distance[i,j] <= 500;
Will that be ok. I ran the model but it gave me same result as without the constraint "radius"
%let m = 3;
proc optmodel;
set DIMS = 1..2;
set CUSTOMERS;
set FACILITIES = 1..&m;
num a {CUSTOMERS, DIMS};
num demand {CUSTOMERS};
read data cdata into CUSTOMERS=[_N_] {d in DIMS} <a[_N_,d]=col('a'||d)> demand;
num Xlb {d in DIMS} = min {i in CUSTOMERS} a[i,d];
num Xub {d in DIMS} = max {i in CUSTOMERS} a[i,d];
var X {FACILITIES, d in DIMS} >= Xlb[d] <= Xub[d];
var W {CUSTOMERS, FACILITIES} >= 0;
impvar Distance {i in CUSTOMERS, j in FACILITIES} =
sqrt(sum {d in DIMS}(a[i,d]-X[j,d])^2);
min Z = sum {i in CUSTOMERS, j in FACILITIES} W[i,j]*Distance[i,j];
con DemandCon {i in CUSTOMERS}:
sum {j in FACILITIES} W[i,j] = demand[i];
solve with nlp / ms;
print X;
put _OBJ_=;
/* post-processing: assign each customer to closest facility */
set CUSTOMERS_j {FACILITIES} init {};
num minDistance, argminDistance;
for {i in CUSTOMERS} do;
minDistance = constant('BIG');
argminDistance = .;
for {j in FACILITIES} do;
if minDistance > Distance[i,j] then do;
minDistance = Distance[i,j];
argminDistance = j;
end;
end;
for {j in FACILITIES} W[i,j] = 0;
W[i,argminDistance] = demand[i];
CUSTOMERS_j[argminDistance] = CUSTOMERS_j[argminDistance] union {i};
end;
put _OBJ_=;
/* post-processing: solve each facility separately */
min SingleFacilityObjective {j in FACILITIES} =
sum {i in CUSTOMERS_j[j]} demand[i]*Distance[i,j];
problem SingleFacilityProblem {j in FACILITIES} include
{d in DIMS} X[j,d]
SingleFacilityObjective[j];
for {j in FACILITIES} do;
put j=;
use problem SingleFacilityProblem[j];
solve;
end;
put (sum {j in FACILITIES} SingleFacilityObjective[j])=;
print X;
create data Xdata from [j]=FACILITIES {d in DIMS} <col('X'||d)=X[j,d].sol>;
create data assignments from [j i]={j in FACILITIES, i in CUSTOMERS_j[j]} W[i,j]
x1=a[i,1] y1=a[i,2] x2=X[j,1] y2=X[j,2];
quit;
i
You should not sum over DIMS. That was for the Euclidean distance. Also, the default units for GEODIST are kilometers. To get miles instead, use the 'M' option.
Please provide the code you used, especially the declaration of Distance and the CREATE DATA statement.
The radius constraint you suggested looks correct but won't yield the results you want if the Distance calculation is wrong. A more efficient approach is to use sparse modeling.
Rob
Thank you. I will do sparse modeling.
Here is the code:
impvar Distance {i in CUSTOMERS, j in FACILITIES} = sum{d in DIMS} GEODIST(a[i,1],a[i,2],X[j,1],X[j,2]);
min Z = sum {i in CUSTOMERS, j in FACILITIES} W[i,j]*Distance[i,j];
con DemandCon {i in CUSTOMERS}: sum {j in FACILITIES} W[i,j] = demand[i];
con radius{i in CUSTOMERS, j in FACILITIES}: Distance[i,j] <= 500;
solve with nlp / ms=(maxtime=10) timetype=real;
**print X;
put _OBJ_=;
/* post-processing: assign each customer to closest facility */
set CUSTOMERS_j {FACILITIES} init {};
num minDistance, argminDistance;
for {i in CUSTOMERS} do;
minDistance = constant('BIG');
argminDistance = .;
for {j in FACILITIES} do;
if minDistance > Distance[i,j] then do;
minDistance = Distance[i,j];
argminDistance = j;
end;
end;
for {j in FACILITIES} W[i,j] = 0;
W[i,argminDistance] = demand[i];
CUSTOMERS_j[argminDistance] = CUSTOMERS_j[argminDistance] union {i};
end;
put _OBJ_=;
/* post-processing: solve each facility separately */
min SingleFacilityObjective {j in FACILITIES} = sum {i in CUSTOMERS_j[j]} demand[i]*Distance[i,j];
problem SingleFacilityProblem {j in FACILITIES} include
{d in DIMS} X[j,d]
SingleFacilityObjective[j];
for {j in FACILITIES} do;
put j=;
use problem SingleFacilityProblem[j];
solve;
end;
put (sum {j in FACILITIES} SingleFacilityObjective[j])=;
print X;
create data STDOPT.WinnersCOG from [j]=FACILITIES {d in DIMS} <col('X'||d)=X[j,d].sol>;
create data STDOPT.COG_Output from [j i]={j in FACILITIES, i in CUSTOMERS_j[j]} W[i,j]
Cust_Lat=a[i,1] Cust_Lon=a[i,2] Fac_Lat=X[j,1] Fac_Lon=X[j,2] Distance[i,j]
SiteState=SiteState[i] SiteRegion=SiteRegion[i] SiteComment1=SiteComment1[i];
quit;
Please let me know if my distance calculation is not correct.
You should not sum over DIMS. That was for the Euclidean distance. Also, the default units for GEODIST are kilometers. To get miles instead, use the 'M' option.
perfect .it worked. thank you rob.
for the constraint radius, let me do that and get back to you next week about how it went. thank u for everything
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.
Find more tutorials on the SAS Users YouTube channel.