LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
pfqn_mvacld.m
1%{
2%{
3 % @file pfqn_mvacld.m
4 % @brief MVAC (Mean Value Analysis by Chain) for load-dependent networks.
5%}
6%}
7
8%{
9%{
10 % @brief MVAC (Mean Value Analysis by Chain) for load-dependent networks.
11 % @fn pfqn_mvacld(L, N, Z, mu)
12 % @param L Service demand matrix of the queue-length dependent centers (M x R).
13 % @param N Population vector (1 x R).
14 % @param Z Think time matrix of the infinite-server centers (1 x R or Mz x R).
15 % @param mu Load-dependent rate matrix (M x Nt), mu(j,n) = rate with n jobs.
16 % @return XN Per-class throughput (1 x R).
17 % @return QN Per-class mean queue-length at the centers (M x R).
18 % @return UN Utilization of each center (M x 1), i.e. 1-P_j(0).
19 % @return CN Per-class cycle time exclusive of think time (1 x R).
20 % @return pij Marginal queue-length probabilities (M x (Nt+1)).
21%}
22%}
23function [XN,QN,UN,CN,pij] = pfqn_mvacld(L,N,Z,mu)
24% [XN,QN,UN,CN,PIJ] = PFQN_MVACLD(L,N,Z,MU)
25%
26% Exact mean value analysis by chain (MVAC) of a closed multichain product-form
27% queueing network that may contain queue-length dependent (QLD) service
28% centers. This is the extension of Section V of Conway, de Souza e Silva and
29% Lavenberg, "Mean Value Analysis by Chain of Product Form Queueing Networks",
30% IEEE Trans. Computers 38(3):432-442, 1989; PFQN_MVAC implements Sections II-IV,
31% which cover single-server fixed-rate (SSFR) and infinite-server (IS) centers
32% only.
33%
34% Where PFQN_MVAC propagates the MEAN queue-lengths L^k_j(v) through eq. (7) and
35% closes the recursion with the arrival-theorem identity (10), the QLD extension
36% propagates the MARGINAL queue-length DISTRIBUTIONS P^k_j(n,v) instead. That is
37% forced by load dependence -- the rate seen by a job depends on the whole
38% occupancy, so a mean no longer suffices -- but it also SIMPLIFIES the
39% recursion: eq. (21)-(25) read level k-1 only at the shifted vectors v + 1_i,
40% so the basic step sweeps v in I_k alone, where PFQN_MVAC must sweep the larger
41% I_k u ... u I_K. The extra information comes almost for free, and PIJ is
42% returned as a first-class output.
43%
44% Notation follows PFQN_MVAC: j and i index centers (j = 1,...,J1 are the QLD
45% centers of L, j = J1+1,...,J the IS centers of Z), k and l index the
46% single-customer chains, a_jk = theta_jk T_jk is the demand of chain k at
47% center j, K = sum(N) and I_k = {v : sum_j v_j = K - k} with v_j the number of
48% self-looping single-customer (SCSL) chains pinned at center j. P^k_j(n,v) is
49% the probability of n customers at center j -- EXCLUDING the v_j SCSL customers
50% there -- in the network with normalizing constant G_k(v). Writing tau_k(v,i)
51% for the throughput of an SCSL chain that replaces chain k at center i, the
52% recursion of Section V reads
53% tau_k(v,i) = T_ik^-1 sum_{n=0}^{k-1} P^{k-1}_i(n,v+1_i) mu_i(n+v_i+1)
54% / (n+v_i+1), (21)
55% tau_k(v,i) = T_ik^-1, i IS, (22)
56% L^k_{jk}(v) = theta_jk tau_k(v,j)^-1 / sum_m theta_mk tau_k(v,m)^-1, (23)
57% lambda^k_k(v) = tau_k(v,j(k)) L^k_{j(k)k}(v), (24)
58% P^k_j(n,v) = L^k_{jk}(v) P^{k-1}_j(n-1,v+1_j)
59% + sum_{m ~= j} L^k_{mk}(v) P^{k-1}_j(n,v+1_m), (25)
60% with P^0_j(0,v) = 1 and P^{k-1}_j(n,.) = 0 for n < 0 or n > k-1. Eq. (21) is
61% just "the mean rate at which an SCSL chain is served": given n other customers
62% the processor-sharing rate share is mu_i(n+v_i+1)/(n+v_i+1), averaged over the
63% distribution of those others. The queueing discipline may be assumed PS with
64% no loss of generality, since product-form measures do not depend on it.
65%
66% This implementation writes (23)-(24) in the reference-station-free form
67% c_i(k,v) = sum_{n=0}^{k-1} P^{k-1}_i(n,v+1_i) mu_i(n+v_i+1)/(n+v_i+1),
68% L^k_{jk}(v) = (a_jk/c_j) / sum_m (a_mk/c_m),
69% lambda^k_k(v) = 1 / sum_m (a_mk/c_m),
70% which follows from theta_jk tau_k(v,j)^-1 = a_jk/c_j and theta_{j(k)k} = 1, so
71% only the demands a_jk are needed and the visit ratios never appear separately.
72% For an IS center c_i = 1 identically, which is exactly (22). Eq. (25) is
73% self-normalizing, sum_n P^k_j(n,v) = sum_m L^k_{mk}(v) = 1, so no normalizing
74% constant is formed and the recursion involves only positive quantities: unlike
75% the classic load-dependent MVA of PFQN_MVALD it cannot produce negative
76% probabilities and needs no stabilization.
77%
78% Parts 2 and 3 of the algorithm are unchanged from PFQN_MVAC, since eq. (6)
79% holds verbatim in the presence of QLD centers: part 2 resolves the chains that
80% visit at least one IS center, and the chains that visit no IS center are
81% resolved by re-executing part 1 with their label interchanged with K.
82%
84% L - (M x R) service demand matrix of the QLD centers.
85% N - (1 x R) closed population vector, finite and nonnegative.
86% Z - (1 x R) or (Mz x R) demand matrix of the IS centers, one row per
87% center. Defaults to zeros(1,R).
88% mu - (M x Nt) load-dependent rates, Nt >= sum(N); mu(j,n) is the total
89% service rate of center j with n jobs present. mu(j,:) = 1 is a
90% single-server fixed-rate queue, mu(j,n) = min(n,c) a c-server queue,
91% mu(j,n) = n an infinite server. Defaults to ones(M,sum(N)), i.e. all
92% centers SSFR, in which case the results agree with PFQN_MVAC.
93%
94% Returns:
95% XN - (1 x R) per-class throughput at the reference station.
96% QN - (M x R) per-class mean queue-length at the QLD centers.
97% UN - (M x 1) utilization of each center, 1 - P_j(0). PER-STATION, not
98% per-class, as in PFQN_MVALD and PFQN_DAC: for a load-dependent center
99% the per-class product XN(r)*L(j,r) of PFQN_MVAC is NOT the utilization.
100% CN - (1 x R) per-class cycle time exclusive of think time, N(r)/XN(r)-Z(r),
101% as in PFQN_MVALD and PFQN_DAC. NOT the (M x R) per-station residence
102% time of PFQN_MVAC: the whole LD family reports a cycle time here.
103% pij - (M x (sum(N)+1)) marginal queue-length probabilities,
104% pij(j,n+1) = P(n jobs at center j).
105%
106% See also PFQN_MVAC, PFQN_MVALD, PFQN_DAC, PFQN_GLD.
107%
108% Copyright (c) 2012-2026, Imperial College London
109% All rights reserved.
110
111[M,R] = size(L);
112if nargin < 3 || isempty(Z)
113 Z = zeros(1,R);
114end
115if size(Z,2) ~= R
116 line_error(mfilename,'the think time matrix and the demand matrix have a different number of classes');
117end
118N = round(N(:)');
119if length(N) ~= R
120 line_error(mfilename,'the demand matrix and the population vector have a different number of classes');
121end
122if any(N < 0) || any(isinf(N))
123 line_error(mfilename,'the population vector must be finite and nonnegative');
124end
125K = sum(N); % number of single-customer chains in the original network
126if nargin < 4 || isempty(mu)
127 mu = ones(M,max(K,1));
128end
129if size(mu,1) ~= M
130 line_error(mfilename,'the rate matrix and the demand matrix have a different number of centers');
131end
132if K > 0 && size(mu,2) < K
133 line_error(mfilename,'the rate matrix must supply a rate for every population up to sum(N)');
134end
135
136XN = zeros(1,R);
137QN = zeros(M,R);
138UN = zeros(M,1);
139CN = zeros(1,R);
140pij = zeros(M,K+1);
141pij(:,1) = 1; % an unvisited center holds no jobs
142if K == 0
143 return
144end
145
146% Discard the centers that no chain visits: they carry no customers and would
147% only inflate the multiplicity vector v.
148ldIdx = find(any(L > 0, 2))';
149isIdx = find(any(Z > 0, 2))';
150J1 = length(ldIdx);
151J = J1 + length(isIdx);
152if J == 0
153 line_error(mfilename,'all service demands are zero, the throughput is unbounded');
154end
155% A(j,r) = a_jr, centers ordered QLD first, then IS, as required by (21)-(22)
156A = [L(ldIdx,:); Z(isIdx,:)];
157MU = mu(ldIdx,1:K); % (J1 x K) rates of the QLD centers
158if any(MU(:) <= 0)
159 line_error(mfilename,'the service rates must be strictly positive for every population up to sum(N)');
160end
161
162%% Partition the chains into subsets of identical single-customer chains.
163% Two chains are identical when they have the same demand at every center, so
164% the subsets are the distinct columns of A restricted to the populated classes.
165posr = find(N > 0);
166[Adist,~,grpOfClass] = unique(A(:,posr)','rows','stable');
167Dall = size(Adist,1);
168visitsIS = false(1,Dall);
169for g = 1:Dall
170 visitsIS(g) = any(Adist(g,(J1+1):J) > 0);
171end
172% Chains that visit at least one IS center are labelled K-D+1,...,K-S and are
173% resolved by part 2 (their throughput follows from Little's law at that IS
174% center); the S chains that visit no IS center are labelled K-S+1,...,K and are
175% resolved by re-executions of part 1.
176gorder = [find(visitsIS), find(~visitsIS)];
177D = Dall;
178S = sum(~visitsIS);
179Agrp = Adist(gorder,:)'; % (J x D) demands of the representative of each subset
180mult = zeros(1,D);
181for g = 1:D
182 mult(g) = sum(N(posr(grpOfClass == gorder(g))));
183end
184
185% Chain labels: the D representatives are labelled K-D+1,...,K, the remaining
186% K-D identical chains fill the labels 1,...,K-D in any order.
187chainGroup = zeros(1,K);
188chainGroup((K-D+1):K) = 1:D;
189p = 0;
190for g = 1:D
191 for c = 1:(mult(g)-1)
192 p = p + 1;
193 chainGroup(p) = g;
194 end
195end
196a = Agrp(:,chainGroup); % (J x K) relative utilizations a_jk
197
198%% Enumerate the multiplicity vectors.
199% Unlike PFQN_MVAC, the QLD basic step at level k sweeps I_k ALONE, because
200% (21) and (25) read level k-1 only at v + 1_i. Vectors are enumerated by
201% increasing component sum, so I_k occupies the contiguous block of sum K-k.
202Vlist = [];
203cnt = zeros(1,K+1);
204off = zeros(1,K+1);
205for t = 0:K
206 Vt = multichoose(J,t);
207 off(t+1) = size(Vlist,1);
208 cnt(t+1) = size(Vt,1);
209 Vlist = [Vlist; Vt]; %#ok<AGROW>
210end
211nv = size(Vlist,1);
212% succ(vi,i) is the global index of v + 1_i, or 0 when out of range (sum(v)==K)
213succ = zeros(nv,J);
214for j = 1:J
215 Vplus = Vlist;
216 Vplus(:,j) = Vplus(:,j) + 1;
217 [tf,loc] = ismember(Vplus,Vlist,'rows');
218 succ(:,j) = loc .* tf;
219end
220
221%% MVAC recursion.
222Pall = cell(1,K+1); % Pall{k+1}(j,vloc,n+1) = P^k_j(n,v), v the vloc-th of I_k
223Ljkall = cell(1,K+1); % Ljkall{k+1}(j,vloc) = L^k_{jk}(v)
224lamall = cell(1,K+1); % lamall{k+1}(vloc) = lambda^k_k(v)
225Pall{1} = ones(J1,cnt(K+1),1); % P^0_j(0,v) = 1, I_0 is the block of sum K
226
227lamChain = zeros(1,K); % per-chain throughput, indexed by the ORIGINAL chain label
228Lchain = zeros(J,K); % per-chain mean queue-length, same indexing
229
230% First execution of the basic step, k0 = 1.
231[Pall,Ljkall,lamall] = mvacld_part1(1,K,J,J1,a,MU,Vlist,off,cnt,succ,Pall,Ljkall,lamall);
232lamChain(K) = lamall{K+1}(1);
233Lchain(:,K) = Ljkall{K+1}(:,1);
234% The marginals of the ORIGINAL network are read at k = K and v = 0; the label
235% interchanges below overwrite this level, so capture them now.
236pij(ldIdx,:) = reshape(Pall{K+1}(:,1,:),J1,K+1);
237
238% Part 2: measures of the chains that visit at least one IS center. Eq. (6) is
239% unchanged by load dependence.
240lmaxK = min(K-1,K-S);
241if D >= 2 && lmaxK >= K-D+1
242 L2prev = cell(1,K);
243 for k = (K-D+2):K
244 t = K-k;
245 L2cur = cell(1,K);
246 for l = (K-D+1):min(k-1,K-S)
247 acc = zeros(J,cnt(t+1));
248 for vloc = 1:cnt(t+1)
249 vi = off(t+1) + vloc;
250 for j = 1:J
251 sloc = succ(vi,j) - off(t+2);
252 if l == k-1
253 % base case of (6): L^{k-1}_{i,k-1} comes from (23)
254 prev = Ljkall{k}(:,sloc);
255 else
256 prev = L2prev{l}(:,sloc);
257 end
258 acc(:,vloc) = acc(:,vloc) + Ljkall{k+1}(j,vloc) * prev;
259 end
260 end
261 L2cur{l} = acc;
262 end
263 if k == K
264 for l = (K-D+1):lmaxK
265 Lchain(:,l) = L2cur{l}(:,1);
266 % Little's law at an IS center visited by chain l
267 jIS = find(a((J1+1):J,l) > 0,1) + J1;
268 lamChain(l) = Lchain(jIS,l) / a(jIS,l);
269 end
270 end
271 L2prev = L2cur;
272 end
273end
274
275% Re-executions of part 1: measures of the chains that visit no IS center.
276% Interchanging the labels of chains K-l and K leaves chains 1,...,K-l-1 in
277% place, so the levels up to K-l-1 computed by the first execution stay valid
278% and the basic step can restart at k0 = K-l.
279perm = 1:K; % perm(k) is the original label of the chain now labelled k
280for l = 1:(S-1)
281 perm([K-l,K]) = perm([K,K-l]);
282 a(:,[K-l,K]) = a(:,[K,K-l]);
283 [Pall,Ljkall,lamall] = mvacld_part1(K-l,K,J,J1,a,MU,Vlist,off,cnt,succ,Pall,Ljkall,lamall);
284 lamChain(perm(K)) = lamall{K+1}(1);
285 Lchain(:,perm(K)) = Ljkall{K+1}(:,1);
286end
287
288%% Expand the per-chain measures back to the per-class measures.
289% Every chain of a subset has the same measures, hence a class with N_r chains
290% in that subset carries N_r times the measures of the subset representative.
291for g = 1:D
292 kg = K-D+g; % original label of the representative of subset g
293 for r = posr(grpOfClass == gorder(g))
294 XN(r) = N(r) * lamChain(kg);
295 QN(ldIdx,r) = N(r) * Lchain(1:J1,kg);
296 end
297end
298% Utilization of a load-dependent center is 1-P_j(0), NOT XN(r)*L(j,r).
299UN = 1 - pij(:,1);
300% Cycle time exclusive of think time, as in PFQN_MVALD and PFQN_DAC. An empty
301% class has zero throughput, hence no cycle time.
302CN = zeros(1,R);
303CN(posr) = N(posr) ./ XN(posr) - sum(Z(:,posr),1);
304end
305
306function [Pall,Ljkall,lamall] = mvacld_part1(k0,K,J,J1,a,MU,Vlist,off,cnt,succ,Pall,Ljkall,lamall)
307% Part 1 of the basic step for networks with QLD centers: evaluate (21)-(25) for
308% k = k0,...,K over v in I_k, the block of multiplicity vectors of sum K-k.
309for k = k0:K
310 t = K - k;
311 nvk = cnt(t+1);
312 Pp = Pall{k}; % P^{k-1}, over I_{k-1}, third dimension n = 0,...,k-1
313 Lk = zeros(J,nvk);
314 lam = zeros(1,nvk);
315 Pk = zeros(J1,nvk,k+1);
316 for vloc = 1:nvk
317 vi = off(t+1) + vloc;
318 v = Vlist(vi,:);
319 sloc = succ(vi,:) - off(t+2); % local index of v + 1_i within I_{k-1}
320 % (21): c(i) is the mean rate at which an SCSL chain pinned at center i
321 % is served, i.e. tau_k(v,i)*T_ik. For an IS center (22) gives c(i) = 1,
322 % which the general formula would also return since mu_i(n) = n.
323 c = ones(1,J);
324 for i = 1:J1
325 ci = 0;
326 for n = 0:(k-1)
327 ci = ci + Pp(i,sloc(i),n+1) * MU(i,n+v(i)+1) / (n+v(i)+1);
328 end
329 c(i) = ci;
330 end
331 % (23)-(24) in reference-station-free form: theta_jk/tau_k(v,j) = a_jk/c_j
332 w = zeros(J,1);
333 for j = 1:J
334 if a(j,k) > 0
335 w(j) = a(j,k) / c(j);
336 end
337 end
338 sw = sum(w);
339 lam(vloc) = 1 / sw;
340 Lk(:,vloc) = w / sw;
341 % (25): condition on the center holding the single chain-k customer
342 for j = 1:J1
343 for n = 0:k
344 s = 0;
345 if n >= 1
346 % chain k is at j, so n-1 of the k-1 others are there too
347 s = Lk(j,vloc) * Pp(j,sloc(j),n);
348 end
349 if n <= k-1
350 % chain k is elsewhere, so all n are from the k-1 others
351 for m = 1:J
352 if m ~= j
353 s = s + Lk(m,vloc) * Pp(j,sloc(m),n+1);
354 end
355 end
356 end
357 Pk(j,vloc,n+1) = s;
358 end
359 end
360 end
361 Pall{k+1} = Pk;
362 Ljkall{k+1} = Lk;
363 lamall{k+1} = lam;
364end
365end
Definition Station.m:245