BookmarkSubscribeRSS Feed
thossain
Obsidian | Level 7

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;
5 REPLIES 5
RobPratt
SAS Super FREQ

Can you please attach the UScounties data set or provide code to generate it?

thossain
Obsidian | Level 7

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. 

RobPratt
SAS Super FREQ

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.

RobPratt
SAS Super FREQ

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.

thossain
Obsidian | Level 7

Thank you so much for all your great suggestions! 

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
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
  • 1216 views
  • 0 likes
  • 2 in conversation