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]
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.