BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Santha
Pyrite | Level 9

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  

1 ACCEPTED SOLUTION

Accepted Solutions
RobPratt
SAS Super FREQ

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.

View solution in original post

5 REPLIES 5
RobPratt
SAS Super FREQ

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.

Santha
Pyrite | Level 9

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;

Santha
Pyrite | Level 9

Please let me know if my distance calculation is not correct. 

RobPratt
SAS Super FREQ

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.

Santha
Pyrite | Level 9

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: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

Multiple Linear Regression in SAS

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.

Discussion stats
  • 5 replies
  • 960 views
  • 1 like
  • 2 in conversation