LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
me_oqn.m
1function [L, W, Ca, Cd, lambda, rho, iter] = me_oqn(M, R, lambda0, Ca0, mu, Cs, P, c, insens, options)
2%ME_OQN Maximum Entropy algorithm for Open Queueing Networks
3%
4% Implements the ME algorithm from Kouvatsos (1994) "Entropy Maximisation
5% and Queueing Network Models", Section 3.2, with the GE/GE/c building
6% block of Section 3.4 (eq. 3.9) and the GE/GE/inf building block.
7%
8% INPUTS:
9% M - Number of queues (stations)
10% R - Number of job classes
11% lambda0 - External arrival rates [M x R matrix], lambda0(i,r) = lambda_oi,r
12% Ca0 - External arrival scv [M x R matrix], Ca0(i,r) = Caoi,r
13% mu - Service rates [M x R matrix], mu(i,r) = mu_i,r
14% Cs - Service scv [M x R matrix], Cs(i,r) = Cs_i,r
15% P - Routing probability matrix [M x M x R], P(j,i,r) = p_ji,r
16% (probability class r goes from queue j to queue i)
17% c - (optional) Servers per queue [M x 1 vector]; Inf marks an
18% infinite-server (IS) queue (default: ones(M,1))
19% insens - (optional) Logical vector [M x 1]; true marks a station with
20% an insensitive scheduling discipline (PS, LCFS-PR), solved
21% with the product-form mean queue length L_r = rho_r/(1-rho)
22% instead of the FCFS GE formula (default: false(M,1))
23% options - (optional) struct with fields:
24% .tol - convergence tolerance (default: 1e-6)
25% .maxiter - maximum iterations (default: 1000)
26% .verbose - print iteration info (default: false)
27%
28% OUTPUTS:
29% L - Mean queue lengths [M x R matrix]
30% W - Mean response times [M x R matrix], W = L ./ lambda
31% Ca - Arrival scv at each queue [M x R matrix]
32% Cd - Departure scv at each queue [M x R matrix]
33% lambda - Total arrival rates [M x R matrix], inclusive of self-loop
34% revisits (visit-based throughput)
35% rho - Utilizations [M x R matrix]: per-server utilization for finite
36% c, mean number of busy servers for IS queues
37% iter - Number of iterations until convergence
38%
39% Reference:
40% D.D. Kouvatsos, "Entropy Maximisation and Queueing Network Models",
41% Annals of Operations Research, 48:63-126, 1994. Equations (3.3), (3.6),
42% (3.7), (3.9) and the multiclass GE/GE/1/FCFS mql of Section 3.1.1.
43
44% Handle optional arguments
45if nargin < 8 || isempty(c)
46 c = ones(M, 1);
47end
48if nargin < 9 || isempty(insens)
49 insens = false(M, 1);
50end
51if nargin < 10
52 options = struct();
53end
54insens = logical(insens(:));
55if ~isfield(options, 'tol')
56 options.tol = 1e-6;
57end
58if ~isfield(options, 'maxiter')
59 options.maxiter = 1000;
60end
61if ~isfield(options, 'verbose')
62 options.verbose = false;
63end
64c = c(:);
65
66% Step 1: Feedback correction. A job that returns immediately to queue i
67% with probability pii receives a geometric number of service passes, so
68% the composite service time has rate mu*(1-pii) and scv pii+(1-pii)*Cs.
69% The self-loop is removed and the residual routing renormalized.
70P_eff = P;
71mu_eff = mu;
72Cs_eff = Cs;
73for i = 1:M
74 for r = 1:R
75 pii = P(i, i, r);
76 if pii > 0
77 mu_eff(i, r) = mu(i, r) * (1 - pii);
78 Cs_eff(i, r) = pii + (1 - pii) * Cs(i, r);
79 P_eff(i, :, r) = P(i, :, r) / (1 - pii);
80 P_eff(i, i, r) = 0;
81 end
82 end
83end
84
85% Step 3: Solve the job flow balance equations lambda = lambda0 + P'*lambda
86% on the original routing; lambda counts self-loop revisits (visit-based
87% throughput), while lambda_eff excludes them and is the arrival rate seen
88% by the feedback-corrected queue.
89lambda = zeros(M, R);
90lambda_eff = zeros(M, R);
91for r = 1:R
92 Pr = P(:, :, r);
93 A = eye(M) - Pr';
94 lambda(:, r) = A \ lambda0(:, r);
95 lambda_eff(:, r) = lambda(:, r) .* (1 - diag(Pr));
96end
97
98% Utilizations: per-server utilization for finite-server queues (invariant
99% to the feedback correction since lambda_eff/mu_eff = lambda/mu); mean
100% number of busy servers for IS queues.
101rho = zeros(M, R);
102for i = 1:M
103 for r = 1:R
104 if mu(i, r) > 0
105 if isinf(c(i))
106 rho(i, r) = lambda_eff(i, r) / mu_eff(i, r);
107 else
108 rho(i, r) = lambda(i, r) / (c(i) * mu(i, r));
109 end
110 end
111 end
112end
113
114% Stability check (finite-server queues only)
115unstable = false(M, 1);
116for i = 1:M
117 if ~isinf(c(i)) && sum(rho(i, :)) >= 1
118 unstable(i) = true;
119 end
120end
121if any(unstable)
122 warning('me_oqn:unstable', 'Network is unstable (utilization >= 1 at some queues)');
123end
124
125% Step 2: Initialize arrival scvs
126Ca = ones(M, R);
127Cd = ones(M, R);
128L = zeros(M, R);
129
130% Steps 4-5: fixed-point iteration on the arrival scvs
131delta = Inf;
132iter = 0;
133for iter = 1:options.maxiter
134 Ca_old = Ca;
135
136 % Step 4: GE-type mean queue length formulae
137 for i = 1:M
138 rho_i = sum(rho(i, :));
139 if isinf(c(i))
140 % GE/GE/inf queue: L = lambda/mu
141 for r = 1:R
142 if lambda_eff(i, r) > 0 && mu_eff(i, r) > 0
143 L(i, r) = lambda_eff(i, r) / mu_eff(i, r);
144 end
145 end
146 elseif unstable(i)
147 for r = 1:R
148 if lambda_eff(i, r) > 0
149 L(i, r) = Inf;
150 end
151 end
152 elseif c(i) == 1
153 if insens(i)
154 % Insensitive disciplines (PS, LCFS-PR): product-form mql,
155 % exact irrespective of the service distribution
156 for r = 1:R
157 if lambda_eff(i, r) > 0 && mu_eff(i, r) > 0
158 L(i, r) = rho(i, r) / (1 - rho_i);
159 end
160 end
161 else
162 % Multiclass GE/GE/1/FCFS mql (Section 3.1.1):
163 % L_r = rho_r*(Ca_r+1)/2
164 % + lambda_r*sum_u lambda_u*(Cs_u+Ca_u)/mu_u^2/(2*(1-rho))
165 resid = 0;
166 for u = 1:R
167 if lambda_eff(i, u) > 0 && mu_eff(i, u) > 0
168 resid = resid + lambda_eff(i, u) * (Cs_eff(i, u) + Ca(i, u)) / mu_eff(i, u)^2;
169 end
170 end
171 for r = 1:R
172 if lambda_eff(i, r) > 0 && mu_eff(i, r) > 0
173 L(i, r) = rho(i, r) * (Ca(i, r) + 1) / 2 + lambda_eff(i, r) * resid / (2 * (1 - rho_i));
174 end
175 end
176 end
177 else
178 % GE/GE/c/FCFS (eq. 3.9) on the class-aggregated stream; the
179 % per-class disaggregation assigns each class its mean number
180 % in service plus a share of the common FCFS waiting line
181 % proportional to its arrival rate.
182 lam_a = 0;
183 for u = 1:R
184 if lambda_eff(i, u) > 0 && mu_eff(i, u) > 0
185 lam_a = lam_a + lambda_eff(i, u);
186 end
187 end
188 if lam_a > 0
189 inv_a = 0;
190 ES = 0;
191 ES2 = 0;
192 for u = 1:R
193 if lambda_eff(i, u) > 0 && mu_eff(i, u) > 0
194 wu = lambda_eff(i, u) / lam_a;
195 inv_a = inv_a + wu / (Ca(i, u) + 1);
196 ES = ES + wu / mu_eff(i, u);
197 ES2 = ES2 + wu * (Cs_eff(i, u) + 1) / mu_eff(i, u)^2;
198 end
199 end
200 Ca_a = -1 + 1 / inv_a;
201 Cs_a = ES2 / ES^2 - 1;
202 L_a = ge_gec_mql(lam_a, Ca_a, 1 / ES, Cs_a, c(i));
203 Lq_a = L_a - lam_a * ES; % mean waiting-line length
204 for r = 1:R
205 if lambda_eff(i, r) > 0 && mu_eff(i, r) > 0
206 L(i, r) = c(i) * rho(i, r) + (lambda_eff(i, r) / lam_a) * Lq_a;
207 end
208 end
209 end
210 end
211 end
212
213 % Step 5a: departure scvs
214 for j = 1:M
215 rho_j = sum(rho(j, :));
216 for r = 1:R
217 if lambda_eff(j, r) > 0
218 if isinf(c(j))
219 % GE/GE/inf queue: interdeparture scv = interarrival scv
220 Cd(j, r) = Ca(j, r);
221 elseif unstable(j)
222 % Saturated server: departures follow the service process
223 Cd(j, r) = Cs_eff(j, r);
224 elseif c(j) == 1
225 % Eq. (3.6) on the class-r virtual queue, with the
226 % marginal utilization rhohat_r of eq. (3.3)
227 rhohat = rho(j, r) * L(j, r) / (L(j, r) + rho_j - rho(j, r));
228 Cd(j, r) = 2 * L(j, r) * (1 - rhohat) + Ca(j, r) * (1 - 2 * rhohat);
229 else
230 % GE/GE/c interdeparture scv (Section 4.2)
231 Cd(j, r) = rho_j * (1 - rho_j) + (1 - rho_j) * Ca(j, r) + rho_j^2 * Cs_eff(j, r);
232 end
233 end
234 end
235 end
236
237 % Step 5b: arrival scvs by GE-type merging, eq. (3.7), with the
238 % splitting (thinning) formula Cdji = 1 + pji*(Cd - 1) applied to the
239 % feedback-corrected flows
240 for i = 1:M
241 for r = 1:R
242 if lambda_eff(i, r) > 0
243 sum_inv = 0;
244 for j = 1:M
245 pji = P_eff(j, i, r);
246 if pji > 0 && lambda_eff(j, r) > 0
247 Cdji = 1 + pji * (Cd(j, r) - 1);
248 sum_inv = sum_inv + (lambda_eff(j, r) * pji / lambda_eff(i, r)) / (Cdji + 1);
249 end
250 end
251 if lambda0(i, r) > 0
252 sum_inv = sum_inv + (lambda0(i, r) / lambda_eff(i, r)) / (Ca0(i, r) + 1);
253 end
254 if sum_inv > 0
255 Ca(i, r) = -1 + 1 / sum_inv;
256 end
257 end
258 end
259 end
260
261 % Check convergence
262 delta = max(abs(Ca(:) - Ca_old(:)));
263 if options.verbose
264 fprintf('Iteration %d: max delta = %e\n', int32(iter), delta);
265 end
266 if delta < options.tol
267 if options.verbose
268 fprintf('Converged after %d iterations\n', int32(iter));
269 end
270 break;
271 end
272end
273
274if iter == options.maxiter && delta >= options.tol
275 warning('me_oqn:noconverge', 'Did not converge within %d iterations (delta=%e)', int32(options.maxiter), delta);
276end
277
278% Step 6: response times by Little's law on the reported arrival rates
279W = zeros(M, R);
280for i = 1:M
281 for r = 1:R
282 if lambda(i, r) > 0
283 W(i, r) = L(i, r) / lambda(i, r);
284 end
285 end
286end
287
288end
289
290function L = ge_gec_mql(lambda, Ca, mu, Cs, c)
291% Mean queue length of a stable GE/GE/c/FCFS queue via the exact ME
292% solution of Kouvatsos (1994), eq. (3.9).
293alpha2 = 2 / (Cs + 1);
294alpha1 = 1 - alpha2;
295beta2 = 2 / (Ca + 1);
296beta1 = 1 - beta2;
297lambda2 = beta2 * lambda;
298mu2 = alpha2 * mu;
299g = zeros(c, 1);
300for j = 1:(c - 1)
301 g(j) = (lambda2 + (j - 1) * mu2 * beta1) * alpha2 / (j * mu2 * (1 - alpha1 * beta1));
302end
303g(c) = (lambda2 + (c - 1) * mu2 * beta1) * alpha2 / (lambda2 * alpha1 + c * mu2);
304x = (lambda2 + c * mu2 * beta1) / (lambda2 * alpha1 + c * mu2);
305Gn = cumprod(g);
306Z = 1 + sum(Gn(1:c-1)) + Gn(c) / (1 - x);
307S1 = 0;
308for n = 1:(c - 1)
309 S1 = S1 + n * Gn(n);
310end
311S2 = Gn(c) * (c / (1 - x) + x / (1 - x)^2);
312L = (S1 + S2) / Z;
313end
Definition Station.m:245