4 % @brief DAC (Distribution Analysis by Chain) method
for joint queue-length distributions.
10 % @brief DAC (Distribution Analysis by Chain) method
for joint queue-length distributions.
11 % @fn pfqn_dac(L, N, Z, mu)
12 % @param L Service demand matrix (MxR).
13 % @param N Population vector (1xR).
14 % @param Z Think time vector (1xR,
default: zeros).
15 % @param mu Load-dependent rate matrix (MxNt, default: ones).
16 % @return Pjoint Joint queue-length probabilities over
the aggregate state space.
17 % @return states Aggregate states, one per row of Pjoint.
18 % @return XN Chain throughputs.
19 % @return QN Mean queue lengths.
20 % @return UN
Station utilizations.
21 % @return CN Cycle times.
22 % @return pi Marginal queue-length probabilities.
25function [Pjoint,states,XN,QN,UN,CN,pi] = pfqn_dac(L,N,Z,mu)
26% [PJOINT,STATES,XN,QN,UN,CN,PI]=PFQN_DAC(L,N,Z,MU)
28% Distribution Analysis by Chain (DAC) for closed product-form queueing
29% networks with single-server fixed-rate, infinite-server and queue-dependent
30% service centers. Unlike MVA, RECAL or MVAC,
the recursion returns
the whole
31% set of joint queue-length probabilities, which are required e.g. in
32% availability modeling.
34% The recursion proceeds chain by chain over a related network in which every
35% chain holds a single customer, a transformation that leaves
the aggregate
36% queue-length distribution unchanged. Given
the distribution of a network
37% with k-1 such chains, adding one customer of a chain with demands r gives
39% c_j = sum_{n=1..k} (n/mu_j(n)) * P_j^{k-1}(n-1)
40% lambda_k = 1 / sum_j r_j c_j
41%
P^k(n) = lambda_k * sum_j r_j (n_j/mu_j(n_j)) *
P^{k-1}(n-e_j)
43% where lambda_k
is the throughput of
the customer being added and 1/c_j
is
44%
the throughput of a chain visiting center j only. The recursion conserves
45% probability mass by construction, hence it
is numerically stable.
48% L (MxR) service demand of chain r at station j
49% N (1xR) number of customers of chain r
50% Z (1xR) think time of chain r. If sum(Z)>0 an extra infinite-server
51% station
is appended, so that STATES has M+1 columns and its
52% last
column holds
the think-station population.
53% mu (MxNt) service rate of station j with n customers, Nt=sum(N).
54% Defaults to ones(M,Nt), i.e. single-server fixed rate. Use
55% mu(j,:)=1:Nt for infinite server and mu(j,n)=min(n,c) for a
59% Pjoint (SxR) probability of
the aggregate state in
the corresponding row
60% of STATES, S=nchoosek(Nt+J-1,J-1) with J
the number of centers
61% states (SxJ) aggregate states, states(s,j) = customers at center j
62% XN (1xR) throughput of chain r
63% QN (MxR) mean number of chain-r customers at station j
64% UN (Mx1) utilization of station j, i.e. 1-P_j(0)
65% CN (1xR) cycle time of chain r, exclusive of think time
66% pi (Mx(Nt+1)) pi(j,n+1) = marginal probability of n jobs at station j
68% Example (availability model, de Souza e Silva 1987, Section 3):
69% L = [5,0; 0,10; 2,1]; N = [1,3]; mu = [1,1,1,1; 1,2,2,2; 1,1,1,1];
70% [
P,S] = pfqn_dac(L,N,[0,0],mu);
71% AV = sum(
P(S(:,1)==1 & S(:,2)>=1)); % system available
74% E. de Souza e Silva,
"Distribution Analysis of Product Form Queueing
75% Networks", UCLA Computer Science Department, CSD-870023, April 1987.
78if nargin<3 || isempty(Z)
84if nargin<4 || isempty(mu)
85 mu = ones(M,max(Nt,1));
89 line_error(mfilename,'Population vector must be non-negative.');
92 line_error(mfilename,'The mu matrix must have one row per station.');
94if Nt>0 && size(mu,2)<Nt
95 line_error(mfilename,'The mu matrix must have at least sum(N) columns.');
98% A non-zero think time
is modelled as an appended infinite-server center.
102 mux = [mu(:,1:max(Nt,1)); 1:max(Nt,1)];
105 mux = mu(:,1:max(Nt,1));
125 if all(Lx(:,active(idx))<=0)
126 line_error(mfilename,'Chain %d has null demand at every center.',active(idx));
130% Enumerate
the aggregate state space level by level and precompute, for each
131% state at level k,
the index of that state with one more job at center j.
132[lvstates,succ] = dac_lattice(J,Nt);
134% Chains are ordered so that
the last D added are distinct, which lets all
135% per-chain measures reuse
the common prefix of
the recursion.
138 prefix = [prefix, repmat(active(idx),1,N(active(idx))-1)]; %
#ok<AGROW>
142% Prefix of
the recursion, shared by every per-chain run.
145for idx=1:numel(prefix)
146 [p,~,~] = dac_step(p,Lx(:,prefix(idx)),mux,k,lvstates,succ);
150% Base run over
the tail, saving
the intermediate distributions S_0..S_{D-1}.
156 [pb,lam,Lq] = dac_step(pb,Lx(:,tail(idx)),mux,kb,lvstates,succ);
163states = lvstates{Nt+1};
167% The base run already places chain tail(D) last.
170QN(:,r) = N(r)*Lq(1:M);
172% Re-run
the tail with chain tail(idx) moved last, restarting from S_{idx}.
176 order = [tail(idx+1:D), tail(idx)];
178 [pc,lam,Lq] = dac_step(pc,Lx(:,order(t)),mux,kc,lvstates,succ);
183 QN(:,r) = N(r)*Lq(1:M);
186% Marginal queue-length probabilities at
the full population.
189 pi(j,:) = accumarray(states(:,j)+1,Pjoint,[Nt+1,1])
';
193CN(active) = N(active)./XN(active) - Z(active);
196% Enumerate the aggregate state space and the successor index map.
197function [lvstates,succ] = dac_lattice(J,Nt)
198lvstates = cell(1,Nt+1);
201 lvstates{k+1} = dac_compositions(J,k);
203% Binomial table for ranking compositions in lexicographic order.
210 C(a+1,b+1) = C(a,b) + C(a,b+1);
222 ix(i,j) = dac_rank(t,k+1,J,C);
229% All J-part compositions of k, in lexicographic order.
230function A = dac_compositions(J,k)
237 B = dac_compositions(J-1,k-v);
238 A = [A; repmat(v,size(B,1),1), B]; %#ok<AGROW>
242% Lexicographic rank of composition n of k into J parts.
243function idx = dac_rank(n,k,J,C)
249 idx = idx + C(s+J-j,J-j);
255% One step of the recursion: add a single customer with demands r to a network
256% holding k customers, returning the distribution at level k+1, the throughput
257% of the added customer and its per-center presence probabilities.
258function [pn,lam,Lq] = dac_step(p,r,mu,k,lvstates,succ)
261% Marginal queue lengths of the network with k customers.
264 marg(j,:) = accumarray(S(:,j)+1,p,[k+1,1])';
269 c(j) = c(j) + (n/mu(j,n))*marg(j,n);
275pn = zeros(size(lvstates{k+2},1),1);
281 w = lam*r(j)*(nj./mu(j,nj)').*p;
282 pn = pn + accumarray(ix(:,j),w,[numel(pn),1]);