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
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.
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)
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
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.
44% Handle optional arguments
45if nargin < 8 || isempty(c)
48if nargin < 9 || isempty(insens)
54insens = logical(insens(:));
55if ~isfield(options,
'tol')
58if ~isfield(options, 'maxiter')
59 options.maxiter = 1000;
61if ~isfield(options, 'verbose')
62 options.verbose = false;
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.
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);
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.
90lambda_eff = zeros(M, R);
94 lambda(:, r) = A \ lambda0(:, r);
95 lambda_eff(:, r) = lambda(:, r) .* (1 - diag(Pr));
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.
106 rho(i, r) = lambda_eff(i, r) / mu_eff(i, r);
108 rho(i, r) = lambda(i, r) / (c(i) * mu(i, r));
114% Stability check (finite-server queues only)
115unstable = false(M, 1);
117 if ~isinf(c(i)) && sum(rho(i, :)) >= 1
122 warning('me_oqn:unstable', 'Network
is unstable (utilization >= 1 at some queues)');
125% Step 2: Initialize arrival scvs
130% Steps 4-5: fixed-point iteration on
the arrival scvs
133for iter = 1:options.maxiter
136 % Step 4: GE-type mean queue length formulae
138 rho_i = sum(rho(i, :));
140 % GE/GE/inf queue: L = lambda/mu
142 if lambda_eff(i, r) > 0 && mu_eff(i, r) > 0
143 L(i, r) = lambda_eff(i, r) / mu_eff(i, r);
148 if lambda_eff(i, r) > 0
154 % Insensitive disciplines (PS, LCFS-PR): product-form mql,
155 % exact irrespective of
the service distribution
157 if lambda_eff(i, r) > 0 && mu_eff(i, r) > 0
158 L(i, r) = rho(i, r) / (1 - rho_i);
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))
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;
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));
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.
184 if lambda_eff(i, u) > 0 && mu_eff(i, u) > 0
185 lam_a = lam_a + lambda_eff(i, u);
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;
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
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;
213 % Step 5a: departure scvs
215 rho_j = sum(rho(j, :));
217 if lambda_eff(j, r) > 0
219 % GE/GE/inf queue: interdeparture scv = interarrival scv
222 % Saturated server: departures follow
the service process
223 Cd(j, r) = Cs_eff(j, r);
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);
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);
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
242 if lambda_eff(i, r) > 0
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);
252 sum_inv = sum_inv + (lambda0(i, r) / lambda_eff(i, r)) / (Ca0(i, r) + 1);
255 Ca(i, r) = -1 + 1 / sum_inv;
262 delta = max(abs(Ca(:) - Ca_old(:)));
264 fprintf('Iteration %d: max delta = %e\n', int32(iter), delta);
266 if delta < options.tol
268 fprintf('Converged after %d iterations\n', int32(iter));
274if iter == options.maxiter && delta >= options.tol
275 warning('me_oqn:noconverge', 'Did not converge within %d iterations (delta=%e)', int32(options.maxiter), delta);
278% Step 6: response times by Little's law on
the reported arrival rates
283 W(i, r) = L(i, r) / lambda(i, r);
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);
297lambda2 = beta2 * lambda;
301 g(j) = (lambda2 + (j - 1) * mu2 * beta1) * alpha2 / (j * mu2 * (1 - alpha1 * beta1));
303g(c) = (lambda2 + (c - 1) * mu2 * beta1) * alpha2 / (lambda2 * alpha1 + c * mu2);
304x = (lambda2 + c * mu2 * beta1) / (lambda2 * alpha1 + c * mu2);
306Z = 1 + sum(Gn(1:c-1)) + Gn(c) / (1 - x);
311S2 = Gn(c) * (c / (1 - x) + x / (1 - x)^2);