3 % @file pfqn_sens_mva.m
4 % @brief Exact per-station queue-length variances and covariances
for closed
5 % product-form queueing networks, computed by an MVA-like moment
6 % recursion that does not require
the full sensitivity Jacobian.
10function mom = pfqn_sens_mva(L,N,Z,mi)
13 % @brief Exact second moments (variances and per-station covariances) of
the
14 % queue lengths of a closed product-form (BCMP) queueing network. The
15 % moments are obtained by an MVA-type recursion evaluated on
the same
16 % population lattice as pfqn_mva, so no derivative of
the model
is ever
17 % formed and
the cost
is O(M*R^2) per lattice point rather than
the
18 % O(M^2*R^2) of
the differentiated-MVA kernel used by pfqn_sens.
20 % The recursion
is obtained by differentiating
the Reiser-Lavenberg MVA
21 % equation Q(j,v|N) = X(v|N) * L(j,v) * (mi(j) + Qtot(j|N-e_v)) with
22 % respect to
the visit ratio theta(i,k) of
class k at station i and
23 % rescaling. Writing W(k,i;v,j|N) = Cov[n(i,k),n(j,v)] at population N,
25 % W(k,i;v,j|N) = Q(j,v|N) * ( Q(i,k|N-e_v) - Q(i,k|N) )
26 % + [i==j & k==v] * Q(j,v|N)
27 % + X(v|N) * L(j,v) * sum_t W(k,i;t,j|N-e_v)
29 % with W(.|0) = 0. This routine evaluates
the same-station
case i==j,
30 % which
is self-contained:
the inner sum then only involves same-station
31 % terms, so a single scalar Ssum(j,k|N) = sum_t W(k,j;t,j|N) carried
32 % along
the lattice closes
the recursion. The cross-station
case i~=j
is
33 % not self-contained (it couples every station pair) and costs as much as
34 %
the full Jacobian, so it
is left to pfqn_sens.
36 % Setting i==j and mi==1 reproduces Corollary 1 of
the reference below,
37 % i.e. its equations (2.9a)
for the variance and (2.10) for
the
38 % covariance;
the station multiplicity mi cancels identically because
39 % X(v|N)*L(j,v)*(mi(j)+Qtot(j|N-e_v)) = Q(j,v|N)
is the MVA equation for
40 % any mi. The equivalent statement for an infinite-server station,
41 % equation (2.9b) of
the reference,
is recovered automatically because
42 % LINE folds
the delay into
the think time Z, which enters only through
43 % X(v|N) and carries no queue-length moment of its own.
45 % Reference: E. de Souza e Silva and R. R. Muntz, "Simple Relationships
46 % Among Moments of Queue Lengths in Product Form Queueing Networks",
47 % IEEE Trans. Computers 37(9):1125-1129, 1988 (Theorems 1-2 and
48 % Corollary 1). The underlying identity Cov[n(i,k),n(j,v)] =
49 % theta(i,k) * dQ(j,v)/dtheta(i,k)
is the k=2 case of Theorem 1 of
50 % I. F. Akyildiz and J. C. Strelen, "Moment Analysis for Load-Dependent
51 % Mixed Product Form Queueing Networks", IEEE Trans. Communications
52 % 39(6):828-832, 1991.
54 % @fn pfqn_sens_mva(L, N, Z, mi)
55 % @param L Service demand matrix (M x R), L(i,r) = visits_ir / rate_ir.
56 % @param N Population vector (1 x R).
57 % @param Z Think time vector (1 x R). Default: zeros.
58 % @param mi (Optional) Server multiplicity vector (1 x M). Default: ones.
59 % @return mom A struct with
the base measures and their second moments:
60 % .X (1 x R), .Q (M x R), .U (M x R), .R (M x R) base MVA measures,
61 % identical to pfqn_mva(L,N,Z,mi).
62 % .QCov (M x R x R) QCov(i,r,s) = Cov[n(i,r),n(i,s)],
the queue-length
63 % covariance of classes r and s at station i. Symmetric in (r,s).
64 % .QVar (M x R) QVar(i,r) = QCov(i,r,r) = Var[n(i,r)].
65 % .QTotVar (M x 1) QTotVar(i) = Var[sum_r n(i,r)],
the variance of
the
66 % total queue length at station i, i.e. sum_{r,s} QCov(i,r,s). This
is
67 % Theorem 3 of
the reference, obtained here without a capacity
69 % .QCovAsym (scalar) max |W(r,s) - W(s,r)| over
the covariance entries
70 % before symmetrization. The two triangles come from differentiating two
71 % different classes
' MVA equations, so this is an independent residual of
72 % the recursion and should sit at roundoff; a large value signals a bug.
75 % - Restricted to closed populations. Mixed and load-dependent models are
76 % handled by pfqn_sens_mvaldmx.
77 % - For a station of multiplicity mi(i)>1, which LINE treats as mi(i)
78 % identical replicas sharing the demand row L(i,:), the moments returned are
79 % those of the aggregate queue length over the replicas.
84if nargin < 3 || isempty(Z)
88if nargin < 4 || isempty(mi)
93 line_error(mfilename,
'demand matrix and population vector have different number of classes');
96 line_error(mfilename,
'pfqn_sens_mva requires a closed population; use pfqn_sens_mvaldmx for mixed models');
99X = zeros(1,R); Q = zeros(M,R); U = zeros(M,R); C = zeros(M,R);
103 mom = pack(X,Q,U,C,QCov);
107% population-lattice odometer, identical to pfqn_mva and to
the sens_mva kernel
108% of pfqn_sens so that
the base measures agree entry by entry
111 prods(w) = prod(ones(1,R-(w+1)+1) + N(w+1:R));
114while N(firstnonempty) == 0
115 firstnonempty = firstnonempty - 1;
119Qtot = zeros(totpop,M); % Qtot(m,i) = sum_r Q(i,r) at population m
120Qcls = zeros(totpop,M,R); % Qcls(m,i,r) = Q(i,r) at population m
121Xall = zeros(totpop,R); % Xall(m,r) = X(r) at population m
122Ssum = zeros(totpop,M,R); % Ssum(m,j,k) = sum_t Cov[n(j,k),n(j,t)] at pop m
126rows = ones(1,R); % rows(s) = lattice index of n - e_s
129 % ---- mean value analysis step at population n -----------------------
138 pos = pos + n(w)*prods(w);
143 % when n(s)==0
the index collapses to
the empty population, whose
144 % stored moments are zero; X(s)
is then zero and every term that reads
145 % rows(s)
is annihilated, so no guard
is needed
150 C(i,s) = L(i,s) * (mi(i) + Qtot(row,i));
151 CNtot = CNtot + C(i,s);
155 Xall(currentpop,s) = X(s);
157 Q(i,s) = X(s) * C(i,s);
158 Qcls(currentpop,i,s) = Q(i,s);
159 Qtot(currentpop,i) = Qtot(currentpop,i) + Q(i,s);
164 % ---- moment step at population n ------------------------------------
165 % W(k,j;t,j|n) = Q(j,t|n)*(Q(j,k|n-e_t) - Q(j,k|n)) + [k==t]*Q(j,t|n)
166 % + X(t|n)*L(j,t)*Ssum(j,k|n-e_t)
169 Qjk = Qcls(currentpop,j,k);
172 Qjt = Qcls(currentpop,j,t);
173 wkt = Qjt * (Qcls(rows(t),j,k) - Qjk);
177 wkt = wkt + Xall(currentpop,t) * L(j,t) * Ssum(rows(t),j,k);
181 Ssum(currentpop,j,k) = sk;
185 % ---- odometer advance ------------------------------------------------
187 while (s>0 && n(s)==N(s)) || s>firstnonempty
200 currentpop = currentpop + 1;
206 U(i,r) = X(r) * L(i,r);
210mom = pack(X,Q,U,C,QCov);
213% =========================================================================
214function mom = pack(X,Q,U,C,QCov)
216mom.X = X; mom.Q = Q; mom.U = U; mom.R = C;
217% Symmetrize. The recursion obtains W(k,j;t,j) by differentiating class t's MVA
218% equation and W(t,j;k,j) by differentiating class k's, so
the two triangles are
219% numerically distinct expressions that agree only up to roundoff. Averaging
220% them keeps QCov exactly symmetric, as a covariance matrix must be. The raw
221% discrepancy
is reported in .QCovAsym rather than discarded, so that a genuine
222% disagreement cannot hide behind
the averaging.
224QCov = (QCov + permute(QCov,[1 3 2])) / 2;
225mom.QCovAsym = max(max(max(abs(QCovRaw - permute(QCovRaw,[1 3 2])))));
226if isempty(mom.QCovAsym)
233 QVar(i,r) = QCov(i,r,r);
235 QTotVar(i) = sum(sum(QCov(i,:,:)));
239mom.QTotVar = QTotVar;