2 % @brief Solves a general QBD process with Rational Arrival Process components
4 % @author LINE Development Team
8 % @brief Equilibrium analysis of a Quasi-Birth-and-Death process with
9 % Rational Arrival Process (RAP) components
12 % The process
is specified directly by its level-independent blocks
13 % (A0,A1,A2) and its boundary blocks (B0,B1), where A0 drives level
14 % increases, A2 drives level decreases and A1
the within-level evolution.
15 % Unlike a Markovian QBD
the blocks need not be nonnegative: they are only
16 % required to be conservative, (A0+A1+A2)*e = 0, and to define a genuine
17 % RAP through
the prediction-process interpretation. This makes qbd_rap
18 % strictly more general than qbd_raprap1, which builds a product-space QBD
19 % from two INDEPENDENT RAPs; here
the arrival process and
the sequence of
20 % service times may be driven from a shared phase space and therefore be
24 % N. G. Bean and B. F. Nielsen,
"Quasi-Birth-and-Death Processes with
25 % Rational Arrival Process Components", Stochastic Models, 26(3), 2010,
26 % pp. 309-334 (DTU technical report IMM-2007-20). The equilibrium
27 % construction below
is their Theorem 7 and
the stability test
is their
28 % Corollary 8. The argument rests on
the prediction-process interpretation
29 % of a RAP due to Asmussen and Bladt, which
is what allows a QBD argument
30 % to be carried over to matrices that are not nonnegative;
the same
31 % prediction process underlies
the conditional-vector RAP sampler in
34 % @par Algorithm (Theorem 7):
35 % 1. Solve A0*G^2 + A1*G + A2 = 0 for G.
38 % 4. Find
the row vector pihat0 with pihat0*(B1 + R*A2) = 0, pihat0*e = 1.
39 % 5. pi0 = K*pihat0 with K chosen so that pi0*inv(I-R)*e = 1.
40 % 6. pi_n = pi0*R^n, and
the marginal level probability
is pi_n*e.
41 % The process
is positive recurrent iff Sp(R) < 1 and step 4 has a solution.
43 % @par Computation of G:
44 % The blocks are not nonnegative, so
the probabilistic iterations used for
45 % Markovian QBDs (logarithmic reduction, cyclic reduction) carry no
47 % case open (
"The issue of justifying algorithms for the evaluation of the
48 % matrix G for such processes has not been undertaken", Section 6). Two
49 % paths are therefore taken:
50 % - If A2 has rank one, A2 = u*v, then G = e*v/(v*e) solves
the equation
51 % exactly. This
is immediate from conservativity: G
is idempotent and
52 % (A0+A1)*e = -A2*e = -u*(v*e), so (A0+A1)*e*v/(v*e) = -u*v = -A2. This
53 %
is the case covered by
the paper
's example, and the residual is checked.
54 % - Otherwise the quadratic matrix equation is solved numerically by
55 % natural functional iteration G <- inv(-A1)*(A2 + A0*G^2) used as a warm
56 % start, followed by Newton's method on
the Sylvester-form Jacobian,
57 % (A0*G+A1)*H + A0*H*G = -(A0*G^2 + A1*G + A2), solved through its
58 % Kronecker expansion. If
the residual does not reach roundoff level, or
59 %
the iterate does not satisfy
the stochastic-analogue constraint G*e = e,
60 % an error
is raised rather than returning an unconverged G.
64 % [levelProb, QN, R, G, U, spr, pqueue, pi0] = qbd_rap(A0, A1, A2)
65 % [levelProb, QN, R, G, U, spr, pqueue, pi0] = qbd_rap(A0, A1, A2, B0, B1)
66 % [levelProb, QN, R, G, U, spr, pqueue, pi0] = qbd_rap(A0, A1, A2, B0, B1, numLevels)
69 % This
is the block-level core of
the RAP QBD family. qbd_raprap1
is the
70 % thin wrapper over it that builds
the product-space blocks of two
71 % INDEPENDENT RAPs; callers with a coupled model, in which arrivals and
72 % services share a phase space, must call qbd_rap directly because no
73 % product form exists to
factor out.
77 % <tr><th>Name<th>Description
78 % <tr><td>A0<td>Level-up block (m x m)
79 % <tr><td>A1<td>Local block (m x m)
80 % <tr><td>A2<td>Level-down block (m x m)
81 % <tr><td>B0<td>(Optional) boundary level-up block,
default A0
82 % <tr><td>B1<td>(Optional) boundary local block,
default A1
83 % <tr><td>numLevels<td>(Optional) highest level reported,
default 20
88 % <tr><th>Name<th>Description
89 % <tr><td>levelProb<td>Row vector of marginal level probabilities, levels 0..numLevels
90 % <tr><td>QN<td>Mean queue length (exact, pi0*R*inv(I-R)^2*e)
91 % <tr><td>R<td>Rate matrix R
92 % <tr><td>G<td>Matrix G solving A0*G^2 + A1*G + A2 = 0
93 % <tr><td>U<td>Matrix U = A1 + A0*G
94 % <tr><td>spr<td>Spectral radius Sp(R)
95 % <tr><td>pqueue<td>(numLevels+1) x m matrix of
the vectors pi_n
96 % <tr><td>pi0<td>Level-0 vector pi_0,
the boundary vector of Theorem 7
102 % A1 = [-1 0 0; -2/3 -1 1; 2/3 -1 -1];
103 % Da = [14/5 -9/10 -9/10; 26/15 -8/15 -8/15; 58/15 -19/15 -19/15];
104 % Ds = [1; 2/3; 4/3]*[3 -1 -1];
105 % [levelProb, QN] = qbd_rap(g*Da, A1, (1-g)*Ds, g*Da, g*A1, 8);
106 % % levelProb reproduces Table 1 of Bean and Nielsen (2010)
109function [levelProb, QN, R, G, U, spr, pqueue, pi0] = qbd_rap(A0, A1, A2, B0, B1, numLevels)
110% [LEVELPROB,QN,R,G,U,SPR,PQUEUE,PI0]=QBD_RAP(A0,A1,A2,B0,B1,NUMLEVELS)
113 line_error(mfilename, 'qbd_rap requires at least
the blocks A0, A1 and A2.');
115if nargin < 4 || isempty(B0)
118if nargin < 5 || isempty(B1)
121if nargin < 6 || isempty(numLevels)
126if size(A1,2) ~= m || any(size(A0) ~= [m m]) || any(size(A2) ~= [m m]) ...
127 || any(size(B0) ~= [m m]) || any(size(B1) ~= [m m])
128 line_error(mfilename, 'All QBD blocks must be square and of
the same order.');
130if numLevels < 0 || numLevels ~= round(numLevels)
131 line_error(mfilename, 'numLevels must be a nonnegative integer.');
136blockScale = max([norm(A0,'fro'), norm(A1,'fro'), norm(A2,'fro'), 1]);
138% Conservativity of
the repeating portion, (A0+A1+A2)*e = 0. This
is the
139% RAP analogue of
the generator row-sum condition and every step below
141if norm((A0+A1+A2)*e, inf) > 1e-8*blockScale
142 line_error(mfilename, sprintf(['The repeating blocks are not conservative: ' ...
143 '||(A0+A1+A2)*e||_inf = %g. A QBD with RAP components requires ' ...
144 '(A0+A1+A2)*e = 0.'], norm((A0+A1+A2)*e, inf)));
146if norm((B0+B1)*e, inf) > 1e-8*blockScale
147 line_error(mfilename, sprintf(['The boundary blocks are not conservative: ' ...
148 '||(B0+B1)*e||_inf = %g. A QBD with RAP components requires ' ...
149 '(B0+B1)*e = 0 at level 0.'], norm((B0+B1)*e, inf)));
153G = qbd_rap_g(A0, A1, A2, blockScale);
155% Steps 2 and 3: U and R.
158 line_error(mfilename, 'The matrix U = A1 + A0*G
is singular, R = A0*inv(-U) does not exist.');
162% Corollary 8(i): positive recurrence.
163spr = max(abs(eig(R)));
164% The threshold carries a 1e-12 margin: at
the null-recurrent boundary
165% Sp(R) equals 1 in exact arithmetic but rounds to either side, and
the
166% three codebases must agree on rejecting it. Any model within 1e-12 of
the
167% boundary has an unbounded queue regardless.
169 line_error(mfilename, sprintf(['The process
is not positive recurrent: ' ...
170 'Sp(R) = %.15g >= 1 (Corollary 8 of Bean and Nielsen, 2010).'], spr));
173% Step 4: boundary vector, pihat0*(B1 + R*A2) = 0 normalised to pihat0*e = 1.
174% The left null space
is extracted from
the SVD of V.' with a relative
175% tolerance: V
is only singular up to
the accuracy with which R was
176% computed, so
the absolute default tolerance of null()
is too strict here.
178[~, Sv, W] = svd(V.');
180nullTol = 1e-8*max(sv(1),1);
182 line_error(mfilename, sprintf(['The boundary equation x*(B1 + R*A2) = 0 has no ' ...
183 'nontrivial solution (smallest singular value %g against tolerance %g), so ' ...
184 '
the process
is not positive recurrent (Corollary 8(ii) of Bean and ' ...
185 'Nielsen, 2010).'], sv(end), nullTol));
187if m > 1 && sv(end-1) <= nullTol
188 line_error(mfilename, ['The boundary equation x*(B1 + R*A2) = 0 has a solution ' ...
189 'space of dimension greater than one,
the equilibrium vector
is not unique.']);
192if abs(pihat0*e) < 1e-12*norm(pihat0,inf)
193 line_error(mfilename, 'The boundary vector cannot be normalised, x*e = 0.');
195pihat0 = pihat0/(pihat0*e);
197% Step 5: level-0 vector.
198K = 1/(pihat0*((I-R)\e));
201% Consistency of
the supplied boundary up-block:
the level-0 balance
202% equation pi0*B0 + pi1*A1 + pi2*A2 = 0 must hold with pi_n = pi0*R^n.
203bal = pi0*B0 + pi0*R*A1 + pi0*R*R*A2;
204if norm(bal, inf) > 1e-8*blockScale*max(norm(pi0,inf),1)
205 line_error(mfilename, sprintf(['The boundary block B0
is inconsistent with
the ' ...
206 'repeating blocks: ||pi0*B0 + pi1*A1 + pi2*A2||_inf = %g. The level-0 ' ...
207 'balance equation of Theorem 7 requires pi0*(B0-A0) = 0.'], norm(bal,inf)));
210% Step 6: level vectors and marginal level distribution.
211pqueue = zeros(numLevels+1, m);
217levelProb = (pqueue*e).';
219% Exact mean queue length, sum_n n*pi0*R^n*e = pi0*R*inv(I-R)^2*e.
220QN = pi0*R*((I-R)\((I-R)\e));
224 % @brief Solves A0*G^2 + A1*G + A2 = 0
for the matrix G
226 % @details Uses
the exact rank-one closed form when A2 has rank one, and
227 % otherwise functional iteration followed by Newton
's method. Never returns
228 % an unconverged iterate.
230function G = qbd_rap_g(A0, A1, A2, blockScale)
233resTol = 1e-10*blockScale;
235% Rank-one A2 = u*v admits the closed form G = e*v/(v*e), which is the case
236% deliberately chosen in the example of Bean and Nielsen (2010) precisely so
237% that G is available a priori.
239if numel(sv) > 1 && sv(1) > 0 && sv(2) <= 1e-10*sv(1)
242 if abs(v*e) < 1e-12*norm(v,inf)
243 line_error(mfilename, [
'A2 has rank one but its right factor v satisfies ' ...
244 'v*e = 0, so the closed form G = e*v/(v*e) is undefined.']);
247 res = norm(A0*G*G + A1*G + A2,
'fro');
249 line_error(mfilename, sprintf([
'The rank-one closed form for G leaves a ' ...
250 'residual ||A0*G^2 + A1*G + A2||_F = %g, which is above the roundoff ' ...
251 'level %g.'], res, resTol));
256% General
case. Natural functional iteration G <- inv(-A1)*(A2 + A0*G^2)
257% gives a warm start; it
is the standard Markovian iteration but has no
258% convergence guarantee
for blocks that are not nonnegative.
260 line_error(mfilename,
'The local block A1 is singular, the iteration for G cannot be started.');
264 Gnew = (-A1)\(A2 + A0*G*G);
265 if norm(Gnew-G,
'fro') <= 1e-14*max(norm(G,
'fro'),1)
270 if ~all(isfinite(G(:)))
274if ~all(isfinite(G(:)))
278% Newton's method on F(G) = A0*G^2 + A1*G + A2. The derivative in
the
279% direction H
is (A0*G+A1)*H + A0*H*G, a Sylvester-type operator solved here
280% through its Kronecker expansion (I kron (A0*G+A1) + G' kron A0)*vec(H).
283 res = A0*G*G + A1*G + A2;
284 if norm(res, 'fro') <= resTol
287 J = kron(Im, A0*G + A1) + kron(G.', A0);
291 H = reshape(-(J\res(:)), m, m);
293 if ~all(isfinite(G(:)))
299if all(isfinite(G(:)))
300 res = norm(A0*G*G + A1*G + A2, 'fro');
302if ~(res <= resTol) || norm(G*e - e, inf) > 1e-8
303 line_error(mfilename, sprintf(['Could not compute
the matrix G for this QBD with ' ...
304 'RAP components: residual ||A0*G^2 + A1*G + A2||_F = %g against a tolerance ' ...
305 'of %g, and ||G*e-e||_inf = %g. The blocks are not nonnegative, so neither ' ...
306 '
the functional iteration nor Newton''s method
is guaranteed to converge, and ' ...
307 '
the justification of algorithms for G in this setting
is left as an open ' ...
308 'problem in Section 6 of N. G. Bean and B. F. Nielsen, "Quasi-Birth-and-Death ' ...
309 'Processes with Rational Arrival Process Components", Stochastic Models, 26(3), ' ...
310 '2010, pp. 309-334. Supply a model with a rank-one A2, for which G
is available ' ...
311 'in closed form.'], res, resTol, norm(G*e-e,inf)));