Hello All! I am using SAS Enterprise Guide. I have a optimization code where I have many constraints and decision variables. It is a facility location problem using multimodal (truck and rail) and I have created routes using location j and k. I have two constraints right now where I am putting conditions if j and k does not have rail access, it can not ship using rail. I tried to combine the two constraints (freight_depot and freight_bioref) into one but it only considered the first condition before the constraint and not the one I join using AND. Is there anyway I can use the AND operator to join two conditions before a constraint, so that I can make the two constraints into one. I don't have all my constraints here. Just put some of them.
This is how I want to write them together-
Con freight {<j,k> in ROUTES2: (s[j]=0 and l[k] =0)}:
sum{<f,'1'> in tr} Amount2[j,k,f,'1'] = 0;
Also, my code is very memory intensive as it deals with inputs of 2000 rows and millions of constraints and decision variables. Is there any way I can solve the out of memory issue? Right now, after reaching an error gap of 8%, I am going out of memory.
Thank you so much for all of your help.
@RobPratt, any help from you would be greatly appreciated. Thank you again!
proc optmodel ;
*****DECLARE SETS AND PARAMETERS*******;
set <str> Fields;
set <str> Depots init {};
set <str> Bioref;
set <str> Feedstock;
set <str> Price;
set Mode = {'0', '1'};
set <num> Capacity;
set <str,str,str> TRIPLES;
set DOUBLES = setof {<i,f,p> in TRIPLES} <i,f>;
set <str,str,str> ROUTES;
set <str,str> ROUTES2;
set <str,str> ROUTES3;
set <str,str> tr;
*Parameters for fields;
num sifp{Fields,Feedstock,Price} init 0; *Available biomass in field i of feedstock f at price p;
num maif{Fields,Feedstock} init 0; *binary assignment of type f from field i;
num gp {Price} init 0; *Farmgate price including grower payment and harvest and collection cost;
num fsb {Feedstock}init 0; *field site storage in bales;
num dmloss {Feedstock}init 0; *dry matter loss from bales;
num aifp{i in Fields,f in Feedstock,p in Price} = round(sifp[i,f,p]*(1-dmloss[f])); *available biomass in the fields after considering the dry matter loss;
*Transportation parameters;
num x{Fields union Depots}; *union combines both field and depot;
num y{Fields union Depots};
num s{Depots};
num l{Bioref};
*Calculating distances between fields and depots;
num a{i in Fields, j in Depots}= (sin((y[j]-y[i])*&C/2))**2+cos(y[i]*&C)*cos(y[j]*&C)*(sin((x[j]-x[i])*&C/2))**2;
num sij{i in Fields, j in Depots} = ifn(x[i]=x[j] and y[i]=y[j],0,2*atan2(sqrt(a[i,j]),sqrt(1-a[i,j]))*3957.143);*converted the distance to miles;
num dij{i in Fields, j in Depots} = round(sij[i,j],0.01);
*Calculating distances between depots and biorefineries;
num b{j in Depots, k in Bioref}= (sin((y[k]-y[j])*&C/2))**2+cos(y[j]*&C)*cos(y[k]*&C)*(sin((x[k]-x[j])*&C/2))**2;
num sjk{j in Depots, k in Bioref} = ifn(x[j]=x[k] and y[j]=y[k],0,2*atan2(sqrt(b[j,k]),sqrt(1-b[j,k]))*3957.143);*converted the distance to miles;
num djk{j in Depots, k in Bioref} = round(sjk[j,k],0.01);
*Transportation costs;
num vfb {Feedstock}; *variable cost of transporting bales of feedstock f;
num cfb {Feedstock}; *fixed/constant cost of transporting bales of feedstock f;
num vfp {Feedstock, Mode}; *variable cost of transporting pellets of feedstock f using mode t;
num cfp {Feedstock, Mode}; *fixed/constant cost of transporting pellets of feedstock f using mode t;
num tijf {i in Fields, j in Depots, f in Feedstock}= ifn (dij[i,j] = 0, 0, cfb[f] + vfb[f]*1.2*dij[i,j]); *Transportation cost for bales;
num tjkf_pellets {j in Depots, k in Bioref, f in Feedstock, t in Mode}= ifn (djk[j,k] = 0, 0, cfp[f,t] + vfp[f,t]*1.2*djk[j,k]); *Transportation cost for pellets;
*Parameters for Depots;
num qh{Feedstock}init 0; *Handling and queuing of bales at depot: $1.21 for CS and $1.34 for SW;
num pf{Feedstock}init 0; *preprocessing cost at depot: $22.65-3.18=$19.47 for CS and $22.05-3.18=$18.77 for SW;
num ds{Feedstock}init 0; *depot storage in pellet form;
num U = 0.9; *depot utilization factor;
num max_distance1 = 200;
num max_distance2 = 1300;
num max_distance3 = 400;
num min_distance = 300;
*quality parameters;
num Ash{Feedstock};
num Moisture{Feedstock};
num Carb{Feedstock};
num Ash_dock{Feedstock};
num Moist_dock{Feedstock};
num Ash_diff{f in Feedstock} = ifn(&Max_Ash>=Ash[f],0, Ash[f] - &Max_Ash);
num Moist_diff{f in Feedstock} = ifn(&Min_moisture<=Moisture[f],0, &Min_moisture-Moisture[f]);
read data out.fields_&year into Fields = [fips] x y;
read data out.INLdepots_&year into Depots = [fips] x y s=site;
read data out.INLdepots_&year into Bioref = [fips] x y l=site;
read data out.Price into Price = [name] gp = Pr ; *gp= grower payment;
read data out.feedstockpropertiesbales_MS into Feedstock=[Feed] vfb=TranspCostVar cfb=TranspCostFixed fsb=StorageCost
qh=HandlingQueuingCost dmloss=BiomassLoss;
read data out.feedstockpropertiespellets_MS into Feedstock=[Feed] ds=StorageCost pf=ProcessingCost;
read data out.Supplymod_&year into TRIPLES=[fips Feed Price] sifp=Supply; *same as line commented below;
read data out.Supplymin_&year into [fips Feed] maif=MinAssign; *minimum assignment (binary);
read data out.quality_MS into Feedstock = [feed] Ash Moisture carb Ash_dock Moist_dock;
read data out.transport into tr=[Feed Mode] vfp=TranspCostVar cfp=TranspCostFixed;
ROUTES = {<i,f> in DOUBLES, j in DEPOTS: dij[i,j] < max_distance1};
ROUTES2 = {j in DEPOTS, k in BIOREF: djk[j,k] <max_distance2};
*****DECLARE MODEL ELEMENTS*******;
******DECISION VARIABLES*****;
var Build {DEPOTS} binary; *binary value to build depots with specific capacity;
var CapacityChunks {DEPOTS} >= 0; *integer value to determine depot capacity;
var Build2 {Bioref} binary; *binary value to build biorefineries with fixed capacity of 725000 dry tons;
var CapacityBioRef {Bioref} >= 0; *to determine biorefinery capacity;
var AnyPurchased {TRIPLES} binary;
var AmountPurchased {TRIPLES} >= 0;
var AmountShipped {ROUTES} >= 0;
var Amount2{ROUTES2,tr} >= 0;
impvar BuildingCost {j in DEPOTS} =
132717 * Build[j] + 2.297 * 25000 * CapacityChunks[j];
impvar VariableCost = sum{<i,f,p> in TRIPLES} 0.977*gp[p] * AmountPurchased[i,f,p] +
sum{<i,f,j> in ROUTES} (fsb[f]+ tijf[i,j,f]+ qh[f]+ ds[f]+ pf[f]) * AmountShipped[i,f,j]
+ sum{<j,k> in ROUTES2, <f,t> in tr}
(tjkf_pellets[j,k,f,t]+(Ash_dock[f]*Ash_diff[f])
+ (Moist_dock[f]*Moist_diff[f])) * Amount2[j,k,f,t];
impvar FixedCost = sum {j in Depots} BuildingCost[j];
*****OBJECTIVE FUNCTION******;
max Supply = sum{<j,k> in ROUTES2,<f,t> in tr} Amount2[j,k,f,t];
*****CONSTRAINTS******;
*Flow balance between field-depot and depot-biorefinery;
Con Depot_avail {j in Depots,f in Feedstock}:
sum {<i,(f),(j)> in ROUTES} AmountShipped[i,f,j]
= sum{<(j),k> in ROUTES2, <(f),t> in tr} Amount2[j,k,f,t];
*Depot locations which have do not freight access;
Con freight_depot {j in Depots: s[j]=0}:
sum{<f,'1'> in tr} Amount2[j,k,f,'1'] = 0;
*Biorefinery Locations which have do not freight access;
Con freight_bioref {k in Bioref: l[k]=0}:
sum{<j,(k)> in ROUTES2,<f,'1'> in tr} Amount2[j,k,f,'1'] = 0;
Con rail_minimum {<j,k> in ROUTES2: djk[j,k]<= min_distance}:
sum{<f,'1'> in tr} Amount2[j,k,f,'1'] = 0;
/**/
Con truck_maximum {<j,k> in ROUTES2: djk[j,k] > max_distance3 }:
sum{<f,'0'> in tr} Amount2[j,k,f,'0'] = 0;
*****SOLVE*******;
solve obj Supply with milp / maxtime=&MaxRunTime relobjgap=0.03; * To force the code to stop after maxtime;
run;
The final four constraint declarations have the effect of setting many variables to 0. The presolver will remove these explicit constraints and the corresponding variables, but a much more efficient approach is to modify the index sets to avoid creating the variables in the first place. Please see this documentation example: SAS Help Center: Sparse Modeling
Making similar changes in your code will reduce the memory needed to store the data and generate the problem, thereby freeing up more memory to be used by the solver. Please let me know if this does not resolve your out-of-memory issue.
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.