I would like to conditionally define a part of a constraint for a network model. The goal is to limit an constraint element to a range of feasible time periods (1 to 10 in this example, 0 and negative periods not allowed) using something like:
Con ..: - (If (t-DELTATIME[j,i]) in _Time_ Then .. )
What I have so far is (problematic row is number 3):
Con Balance{<t,i> in _Time_Nodes_}:
Sum{<(t),(i),j> in _Time_Arcs_} Flow[t,i,j]
- (If (t-DELTATIME[j,i]) in _Time_ Then Sum{<(t),j,(i)> in _Time_Arcs_} Flow[t - DELTATIME[j,i],j,i])
- (If (t-1) in _Time_ Then Inventory[t-1,i])
+ Inventory[t,i]
<= SD[t,i] + Rejected_Qty[t,i];
which throws an error because I do not properly define the indices of the constant/number matrix DELTATIME. My question is, is it possible to fix this - (without using macro code). The entire example code is here:
Data Arcs;
Length Tail $20. Head $20.;
Input Tail $ Head $ Cost Upper_Limit Delta_Time;
Datalines;
n1 n2 20 500 0
n2 n3 10 400 1
;
Data Nodes;
Length Node $20.;
Input Node $ Supply_Demand Max_Inventory Storage_Costs;
Datalines;
n1 300 0 100
n2 0 940 1
n3 -300 0 100
;
%Macro CreateTime;
%Do i=1 %To 10;
%If &i=1 %Then %Do;
Data Arcs_Time;
Length Time 8.;
Set Arcs (Drop=Delta_Time);
Time = Input(&i., Best.);
Run;
Data Nodes_Time;
Length Time 8.;
Set Nodes;
Time = Input(&i., Best.);
If Find(Node, "customer") Then Supply_Demand=0;
Run;
%End;
%Else %Do;
Data Arcs_Time_i;
Length Time 8.;
Set Arcs (Drop=Delta_Time);
Time = Input(&i., Best.);
Run;
Proc Append Base=Arcs_Time Data=Arcs_Time_i; Run;
Data Nodes_Time_i;
Length Time 8.;
Set Nodes;
Time = Input(&i., Best.);
Run;
Proc Append Base=Nodes_Time Data=Nodes_Time_i; Run;
%End;
Data Nodes_Time;
Set Nodes_Time;
If Time in (1,2,3) & Node = "n3" Then Supply_Demand = 0;
If Time in (3) & Node = "n1" Then Supply_Demand = 900;
Run;
Data Arcs_Time;
Set Arcs_Time;
If Time in(6) & Tail = "n1" Then Upper_Limit=0;
Run;
Proc Datasets NoList NoWarn;
Delete Nodes_Time_i;
Delete Arcs_Time_i;
Run;
%End;
%Mend;
%CreateTime;
%Macro MacroOpt(Working=);
Proc Optmodel;
Set <Num,Str> _Time_Nodes_;
Num SD{_Time_Nodes_};
Num MaxInv{_Time_Nodes_};
Num InvCost{_Time_Nodes_};
Read Data Nodes_Time Into _Time_Nodes_=[Time Node] SD=Supply_Demand MaxInv=Max_Inventory InvCost=Storage_Costs;
Set <Num,Str,Str> _Time_Arcs_;
Num Upper_Bound{_Time_Arcs_};
Num Cost{_Time_Arcs_};
Read Data Arcs_Time Into _Time_Arcs_=[Time Tail Head] Cost=Cost Upper_Bound=Upper_Limit;
Set _Time_ = SetOf{<t,i,j> in _Time_Arcs_} t,
_Tail_ = SetOf{<t,i,j> in _Time_Arcs_} i,
_Head_ = SetOf{<t,i,j> in _Time_Arcs_} j;
Set _Arcs_ = SetOf{<t,i,j> in _Time_Arcs_} <i,j>;
Num DELTATIME{_Arcs_};
Read Data Arcs Into [Tail Head] DELTATIME=Delta_Time;
Var Flow{<t,i,j> in _Time_Arcs_} >=0 <=Upper_Bound[t,i,j];
Var Rejected_Qty{<t,i> in _Time_Nodes_} >=0;
Var Inventory{<t,i> in _Time_Nodes_} >=0 <=MaxInv[t,i];
Con Inventory1{<t,i> in _Time_Nodes_: t=1}: Inventory[t,i] = 0;
/* interesting part, start ************************************* */
/* PROBLEM: Merge constraints for time = 1 and time >= 2 into one */
%If "&Working."="YES" %Then %Do;
Con Balance_TimeEQ1{<t,i> in _Time_Nodes_: t=1}:
Sum{<(t),(i),j> in _Time_Arcs_} Flow[t,i,j]
- Sum{<(t),j,(i)> in _Time_Arcs_} Flow[t,j,i]
+ Inventory[t,i]
<= SD[t,i] + Rejected_Qty[t,i];
Con Balance_TimeGE2{<t,i> in _Time_Nodes_: 2<=t<=10}:
Sum{<(t),(i),j> in _Time_Arcs_} Flow[t,i,j]
- Sum{<(t),j,(i)> in _Time_Arcs_} Flow[t - DELTATIME[j,i],j,i]
- Inventory[t-1,i]
+ Inventory[t,i]
<= SD[t,i] + Rejected_Qty[t,i];
%End;
%Else %Do;
Con Balance{<t,i> in _Time_Nodes_}:
Sum{<(t),(i),j> in _Time_Arcs_} Flow[t,i,j]
/* Is it possible to create a dynamic expression for flows with (transportation) times directly */
/* linked to the arc like for the inventory constraint with the hard-coded t-1 below? */
- (If (t-DELTATIME[j,i]) in _Time_ Then Sum{<(t),j,(i)> in _Time_Arcs_} Flow[t - DELTATIME[j,i],j,i])
- (If (t-1) in _Time_ Then Inventory[t-1,i])
+ Inventory[t,i]
<= SD[t,i] + Rejected_Qty[t,i];
%End;
/* interesting part, end ******************************************* */
Min Objective=Sum{<t,i,j> in _Time_Arcs_} Flow[t,i,j] * Cost[t,i,j] +
Sum{<t,i> in _Time_Nodes_} Inventory[t,i] * InvCost[t,i] +
Sum{<t,i> in _Time_Nodes_} Rejected_Qty[t,i] * 1e6;
Solve;
*Expand Balance1;
*Expand Balance;
Create Data Result_Flow From [Time From To]={<t,i,j> in _Time_Arcs_} DELTATIME[i,j] Flow Upper_Bound Cost;
Create Data Result_Arcs From [Time Location]={<t,i> in _Time_Nodes_} Inventory MaxInv InvCost Rejected_Qty SD;
Quit;
%Mend;
%MacroOpt(Working=NO) /* this call produces an error */
%MacroOpt(Working=YES) /* this optimization run works syntactically */
Two ways:
- Sum{<(t),j,(i)> in _Time_Arcs_} (If (t-DELTATIME[j,i]) in _Time_ Then Flow[t - DELTATIME[j,i],j,i])
- Sum{<(t),j,(i)> in _Time_Arcs_: t-DELTATIME[j,i] in _Time_} Flow[t - DELTATIME[j,i],j,i]
Two ways:
- Sum{<(t),j,(i)> in _Time_Arcs_} (If (t-DELTATIME[j,i]) in _Time_ Then Flow[t - DELTATIME[j,i],j,i])
- Sum{<(t),j,(i)> in _Time_Arcs_: t-DELTATIME[j,i] in _Time_} Flow[t - DELTATIME[j,i],j,i]
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 25. 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.