Hello Everyone! I am trying to run my code to solve an MILP with optmodel procedure. I am using SAS enterprise Guide 7.1. I was trying to locate optimal number of Depots for storing supplies from fields. My two location sets for Depot and Field are the same, using the county centroids. When I used one state (North Carolina) which has 100 counties, the code ran fine and gave me results. But just when I increased the number of states, my log showed me the error of "Ran out of memory". I am attaching my code here and also attaching the log. What can I do to resolve this issue? Thank you in advance!
/*creating macro variables*/
%let NumFields = 50;
%let NumDepots = 10;
%let DepotCapacity = 25000;
%let MaxDemand = 1000;
%let xmax = 200;
%let ymax = 100;
%let seed = 423;
data fdata(Rename=(County=name));
set UScounties;
if state in ("North Carolina", "South Carolina", "Virgina") then
do;
x=Long;
demand=rand('UNIFORM') * &MaxDemand;
Y=Lat;
output fdata;
keep county x demand y;
end;
run;
data pdata(Rename=(county=name));
set UScounties;
if state in ("North Carolina", "South Carolina", "Virgina") then
do;
x=Long;
y=Lat;
fixed_cost=275000;
output;
keep county x y fixed_cost;
end;
run;
/*Solving the MILP*/
proc optmodel;
set <str> Fields;
/*declares set of fields*/
set <str> Depots init {};
/*declares set of depots*/
num x{Fields union Depots};
/*creating an array of x cooordinate with all the field and depot location, union combines both field and depot*/
num y{Fields union Depots};
/*creating an array of y cooordinate with all the field and depot location*/
num demand{Fields};
num fixed_cost{Depots};
num distance {i in Fields, j in Depots}=sqrt((x[i] - x[j])^2 + (y[i]
- y[j])^2);
/* linear distance between fields and depots*/
read data fdata into Fields=[name] x y demand;
read data pdata into Depots=[name] x y fixed_cost;
var Assign {Fields, Depots} binary;
/* binary value to assign specific fields to specific depots*/
var Build {Depots} binary;
/*objective function*/
/* binary variable to determine which depots will be established*/
min cost=sum{i in Fields, j in Depots} Distance[i, j]*Assign[i, j] + sum{j in
Depots}Fixed_cost[j]*Build[j];
/*Constraints*/
con Assign_fields{i in Fields}: sum{j in Depots}Assign[i, j]=1;
/*each field assigned to one depot only*/
con Build_depot{i in Fields, j in Depots}: Assign[i, j] <=Build[j];
/* if a field is assigned to a depot, it has to be build*/
con Depot_capacity{j in Depots}: sum {i in Fields}Demand[i]*Assign[i,
j]<=&DepotCapacity*Build[j];
/*ensuring total field supply to a depot is within its capacity*/
solve obj Cost with MILP/Primalin;
num varcost=sum {i in FIELDS, j in DEPOTS} distance[i, j] * Assign[i, j].sol;
num fixcost=sum {j in DEPOTS} fixed_cost[j] * Build[j].sol;
for {s in 1.._NSOL_} do;
/*clean up the solution*/
for {i in FIELDS, j in DEPOTS} Assign[i, j]=round(Assign[i, j].sol[s]);
for {j in DEPOTS} Build[j]=round(Build[j].sol[s]);
call symput('varcost', put(varcost, 6.1));
call symput('fixcost', put(fixcost, 5.1));
call symput('totalcost', put(Cost, 6.1));
/*create a data set for use by PROC SGPLOT*/
create data CostFixedCharge_Data from
[FIELD DEPOT]={i in FIELDS, j in DEPOTS: Assign[i, j]=1}
x1=x[i] y1=y[i] x2=x[j] y2=y[j] function='line' drawspace='datavalue'
linethickness=1 linecolor='black';
submit s;
endsubmit;
end;
quit;
Can you please attach the UScounties data set or provide code to generate it?
Thank you so much for your reply. Although I am using the county names now as [name] but later I will use the unique FIPS code as there are duplicate county names within the US. I am attaching the US Counites dataset here.
One suggestion is to omit the Build_depot constraints, which are not strictly necessary. They tighten the formulation but also make it bigger, requiring more memory. The logical implication "if Assign[i,j] = 1 then Build[j]" is already enforced via the Depot_capacity constraints.
You might also try increasing the MEMSIZE option value, as described here.
Note also that Virgina should instead be Virginia.
Two additional suggestions:
1. Consider heuristically reducing the allowed field-to-depot assignments based on a distance threshold. This documentation example shows how to do that efficiently, by omitting variables from the formulation.
2. Use a Benders decomposition approach, as shown in this SAS Communities thread.
Thank you so much for all your great suggestions!
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
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.