LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
pfqn_dac.m
1%{
2%{
3 % @file pfqn_dac.m
4 % @brief DAC (Distribution Analysis by Chain) method for joint queue-length distributions.
5%}
6%}
7
8%{
9%{
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.
23%}
24%}
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)
27%
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.
33%
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
38%
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)
42%
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.
46%
47% Inputs:
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
56% c-server station.
57%
58% Outputs:
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
67%
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
72%
73% References:
74% E. de Souza e Silva, "Distribution Analysis of Product Form Queueing
75% Networks", UCLA Computer Science Department, CSD-870023, April 1987.
76
77[M,R] = size(L);
78if nargin<3 || isempty(Z)
79 Z = zeros(1,R);
80end
81N = N(:)';
82Z = Z(:)';
83Nt = sum(N);
84if nargin<4 || isempty(mu)
85 mu = ones(M,max(Nt,1));
86end
87
88if any(N<0)
89 line_error(mfilename,'Population vector must be non-negative.');
90end
91if size(mu,1)~=M
92 line_error(mfilename,'The mu matrix must have one row per station.');
93end
94if Nt>0 && size(mu,2)<Nt
95 line_error(mfilename,'The mu matrix must have at least sum(N) columns.');
96end
97
98% A non-zero think time is modelled as an appended infinite-server center.
99hasZ = sum(Z)>0;
100if hasZ
101 Lx = [L; Z];
102 mux = [mu(:,1:max(Nt,1)); 1:max(Nt,1)];
103else
104 Lx = L;
105 mux = mu(:,1:max(Nt,1));
106end
107J = size(Lx,1);
108
109% Trivial population
110if Nt==0
111 states = zeros(1,J);
112 Pjoint = 1;
113 XN = zeros(1,R);
114 QN = zeros(M,R);
115 UN = zeros(M,1);
116 CN = zeros(1,R);
117 pi = zeros(M,1);
118 pi(:,1) = 1;
119 return
120end
121
122active = find(N>0);
123D = numel(active);
124for idx=1:D
125 if all(Lx(:,active(idx))<=0)
126 line_error(mfilename,'Chain %d has null demand at every center.',active(idx));
127 end
128end
129
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);
133
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.
136prefix = zeros(1,0);
137for idx=1:D
138 prefix = [prefix, repmat(active(idx),1,N(active(idx))-1)]; %#ok<AGROW>
139end
140tail = active;
141
142% Prefix of the recursion, shared by every per-chain run.
143p = 1;
144k = 0;
145for idx=1:numel(prefix)
146 [p,~,~] = dac_step(p,Lx(:,prefix(idx)),mux,k,lvstates,succ);
147 k = k+1;
148end
149
150% Base run over the tail, saving the intermediate distributions S_0..S_{D-1}.
151Sp = cell(1,D);
152Sp{1} = p;
153pb = p;
154kb = k;
155for idx=1:D
156 [pb,lam,Lq] = dac_step(pb,Lx(:,tail(idx)),mux,kb,lvstates,succ);
157 kb = kb+1;
158 if idx<D
159 Sp{idx+1} = pb;
160 end
161end
162Pjoint = pb;
163states = lvstates{Nt+1};
164
165XN = zeros(1,R);
166QN = zeros(M,R);
167% The base run already places chain tail(D) last.
168r = tail(D);
169XN(r) = N(r)*lam;
170QN(:,r) = N(r)*Lq(1:M);
171
172% Re-run the tail with chain tail(idx) moved last, restarting from S_{idx}.
173for idx=1:D-1
174 pc = Sp{idx};
175 kc = k+idx-1;
176 order = [tail(idx+1:D), tail(idx)];
177 for t=1:numel(order)
178 [pc,lam,Lq] = dac_step(pc,Lx(:,order(t)),mux,kc,lvstates,succ);
179 kc = kc+1;
180 end
181 r = tail(idx);
182 XN(r) = N(r)*lam;
183 QN(:,r) = N(r)*Lq(1:M);
184end
185
186% Marginal queue-length probabilities at the full population.
187pi = zeros(M,Nt+1);
188for j=1:M
189 pi(j,:) = accumarray(states(:,j)+1,Pjoint,[Nt+1,1])';
190end
191UN = 1-pi(:,1);
192CN = zeros(1,R);
193CN(active) = N(active)./XN(active) - Z(active);
194end
195
196% Enumerate the aggregate state space and the successor index map.
197function [lvstates,succ] = dac_lattice(J,Nt)
198lvstates = cell(1,Nt+1);
199succ = cell(1,Nt+1);
200for k=0:Nt
201 lvstates{k+1} = dac_compositions(J,k);
202end
203% Binomial table for ranking compositions in lexicographic order.
204C = zeros(Nt+J,J+1);
205for a=0:(Nt+J-1)
206 for b=0:min(a,J)
207 if b==0
208 C(a+1,b+1) = 1;
209 else
210 C(a+1,b+1) = C(a,b) + C(a,b+1);
211 end
212 end
213end
214for k=0:Nt-1
215 S = lvstates{k+1};
216 nS = size(S,1);
217 ix = zeros(nS,J);
218 for i=1:nS
219 for j=1:J
220 t = S(i,:);
221 t(j) = t(j)+1;
222 ix(i,j) = dac_rank(t,k+1,J,C);
223 end
224 end
225 succ{k+1} = ix;
226end
227end
228
229% All J-part compositions of k, in lexicographic order.
230function A = dac_compositions(J,k)
231if J==1
232 A = k;
233 return
234end
235A = zeros(0,J);
236for v=0:k
237 B = dac_compositions(J-1,k-v);
238 A = [A; repmat(v,size(B,1),1), B]; %#ok<AGROW>
239end
240end
241
242% Lexicographic rank of composition n of k into J parts.
243function idx = dac_rank(n,k,J,C)
244idx = 1;
245rem = k;
246for j=1:J-1
247 for v=0:n(j)-1
248 s = rem-v;
249 idx = idx + C(s+J-j,J-j);
250 end
251 rem = rem-n(j);
252end
253end
254
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)
259J = numel(r);
260S = lvstates{k+1};
261% Marginal queue lengths of the network with k customers.
262marg = zeros(J,k+1);
263for j=1:J
264 marg(j,:) = accumarray(S(:,j)+1,p,[k+1,1])';
265end
266c = zeros(J,1);
267for j=1:J
268 for n=1:k+1
269 c(j) = c(j) + (n/mu(j,n))*marg(j,n);
270 end
271end
272lam = 1/(r(:)'*c);
273Lq = lam*r(:).*c;
274ix = succ{k+1};
275pn = zeros(size(lvstates{k+2},1),1);
276for j=1:J
277 if r(j)<=0
278 continue
279 end
280 nj = S(:,j)+1;
281 w = lam*r(j)*(nj./mu(j,nj)').*p;
282 pn = pn + accumarray(ix(:,j),w,[numel(pn),1]);
283end
284end
Definition Station.m:245