1function model = gallery_lukumar_reentrant(schedStrategy)
2% GALLERY_LUKUMAR_REENTRANT Lu-Kumar unstable re-entrant line example
4% This example implements the classic Lu-Kumar re-entrant line network,
5% which demonstrates that queueing networks can be unstable even when
6% the utilization at each station
is strictly less than 1.
9% - 2 stations (servers)
10% - 4 job
classes forming a re-entrant line
11% - Station 1 serves
classes 1 and 4
12% - Station 2 serves
classes 2 and 3
13% - Job path: Source -> Class1 -> Class2 -> Class3 -> Class4 -> Sink
15% Under FCFS scheduling: The network
is stable when all station
16% utilizations are < 1.
18% Under certain priority policies (e.g., HOL with
class 4 >
class 1 at
19% station 1, and
class 2 >
class 3 at station 2): The network can become
20% unstable due to the
"virtual bottleneck" phenomenon, even with
21% utilization < 1 at each station.
24% Lu, S.H. and Kumar,
P.R. (1991),
"Distributed Scheduling Based on Due
25% Dates and Buffer Priorities", IEEE Transactions on Automatic Control,
26% Vol. 36, No. 12, pp. 1406-1416.
29% model = gallery_lukumar_reentrant(); % FCFS scheduling (stable)
30% model = gallery_lukumar_reentrant(
'FCFS'); % FCFS scheduling (stable)
31% model = gallery_lukumar_reentrant(
'HOL'); % HOL priority scheduling
32% model = gallery_lukumar_reentrant(
'PS'); % Processor sharing
34% Copyright (c) 2012-2026, Imperial College London
38 schedStrategy =
'FCFS';
41% Convert
string to scheduling strategy
42switch upper(schedStrategy)
44 sched1 = SchedStrategy.FCFS;
45 sched2 = SchedStrategy.FCFS;
47 sched1 = SchedStrategy.HOL;
48 sched2 = SchedStrategy.HOL;
50 sched1 = SchedStrategy.PS;
51 sched2 = SchedStrategy.PS;
53 sched1 = SchedStrategy.FCFS;
54 sched2 = SchedStrategy.FCFS;
57model = Network(
'Lu-Kumar-Reentrant');
60source = Source(model,
'Source');
61station1 = Queue(model,
'Station1', sched1);
62station2 = Queue(model,
'Station2', sched2);
63sink = Sink(model,
'Sink');
65%% Block 2: Job Classes
66% For HOL scheduling, priority
is specified as the third parameter
67% Higher value = higher priority
69%
"Bad" priority policy
for instability demonstration:
70% Station 1: Class 4 (priority 1) > Class 1 (priority 0)
71% Station 2: Class 2 (priority 1) > Class 3 (priority 0)
73% Under
this policy, jobs in Class 4 are served before Class 1 at Station 1,
74% and jobs in Class 2 are served before Class 3 at Station 2.
76class1 = OpenClass(model,
'Class1', 0); % Lower priority at Station 1
77class2 = OpenClass(model,
'Class2', 1); % Higher priority at Station 2
78class3 = OpenClass(model,
'Class3', 0); % Lower priority at Station 2
79class4 = OpenClass(model,
'Class4', 1); % Higher priority at Station 1
81%% Block 3: Arrival Process
82% External arrivals only to Class 1
83arrivalRate = 0.45; % arrival rate lambda
84source.setArrival(class1, Exp(arrivalRate));
85source.setArrival(class2, Disabled());
86source.setArrival(class3, Disabled());
87source.setArrival(class4, Disabled());
89%% Block 4: Service Times
90% Service rates chosen so that utilization at each station < 1
91% Station 1 serves Class 1 and Class 4
92% Station 2 serves Class 2 and Class 3
95% m1 = 1.0 (Class 1 at Station 1)
96% m2 = 1.0 (Class 2 at Station 2)
97% m3 = 1.0 (Class 3 at Station 2)
98% m4 = 1.0 (Class 4 at Station 1)
100% Station utilizations:
101% rho1 = lambda * (m1 + m4) = 0.45 * (1 + 1) = 0.90 < 1
102% rho2 = lambda * (m2 + m3) = 0.45 * (1 + 1) = 0.90 < 1
104m1 = 1.0; % Mean service time
for Class 1 at Station 1
105m2 = 1.0; % Mean service time
for Class 2 at Station 2
106m3 = 1.0; % Mean service time
for Class 3 at Station 2
107m4 = 1.0; % Mean service time
for Class 4 at Station 1
109% Station 1 services (Class 1 and Class 4)
110station1.setService(class1, Exp(1/m1));
111station1.setService(class2, Disabled());
112station1.setService(class3, Disabled());
113station1.setService(class4, Exp(1/m4));
115% Station 2 services (Class 2 and Class 3)
116station2.setService(class1, Disabled());
117station2.setService(class2, Exp(1/m2));
118station2.setService(class3, Exp(1/m3));
119station2.setService(class4, Disabled());
121%% Block 5: Routing (Re-entrant Line Topology)
122% Job path: Source -> Class1@Station1 -> Class2@Station2 ->
123% Class3@Station2 -> Class4@Station1 -> Sink
125% The re-entrant structure means jobs visit Station 1 twice (as Class 1
126% first, then as Class 4) and Station 2 twice (as Class 2 first, then
129P = model.initRoutingMatrix();
131% Source -> Class1 at Station1
132P{class1, class1}(source, station1) = 1;
134% Class1 at Station1 -> Class2 at Station2 (
class switch)
135P{class1, class2}(station1, station2) = 1;
137% Class2 at Station2 -> Class3 at Station2 (
class switch, same station)
138P{class2, class3}(station2, station2) = 1;
140% Class3 at Station2 -> Class4 at Station1 (
class switch)
141P{class3, class4}(station2, station1) = 1;
143% Class4 at Station1 -> Sink
144P{class4, class4}(station1, sink) = 1;