4 % @brief Convolution Algorithm
for exact normalizing constant computation.
8function [Gn,lGn]=pfqn_ca(L,N,Z)
11 % @brief Convolution Algorithm
for exact normalizing constant computation.
12 % @fn pfqn_ca(L, N, Z)
13 % @param L Service demand matrix.
14 % @param N Population vector.
15 % @param Z Think time vector.
16 % @
return Gn Normalizing constant.
17 % @
return lGn Logarithm of
the normalizing constant.
21if nargin<3 || isempty(Z)
25 lGn = - sum(factln(N)) + sum(N.*log(sum(Z,1)));
42% Demand scaling, so that lGn stays computable once G(N) leaves
the
43%
double-precision range. The recursion below runs in linear space, so it
44% overflows to Inf as soon as G(N) > realmax, i.e. log G > 709.78 -- and lGn
45% was then returned as Inf even though log G
is perfectly representable. This
46%
is the floating-point range problem Reiser and Lavenberg (1980, JACM 27(2),
47% p.319) report for
the convolution algorithm, and
the scaling remedy
is Lam
48% (1982), "Dynamic scaling and growth behavior of queuing network normalization
51% Every state in G(N) carries
the same total population sum(N), so dividing all
52% demands and think times by a constant c divides G(N) by exactly c^sum(N):
53% G(N; L/c, Z/c) = G(N; L, Z) / c^sum(N)
54% hence log G = log G_scaled + sum(N) log c, which
is exact, not an
57% c must be chosen to CENTRE log G_scaled near 0, not merely to shrink
the
58% demands. G(N) can leave
the double range in EITHER direction: Reiser (1981,
59% Perf. Eval. 1:7-18, Sec. 6.1) reports
the unnormalized convolution
60% UNDERFLOWING (< 1e-75, losing all significant digits) on his Fig. 5
61% central-server model for K > 160, and OVERFLOWING (> 1e75) on
the same model
62% if
the think time
is raised. Scaling by max(L),
the textbook choice, only
63% shrinks G and so makes
the underflow strictly worse -- on Reiser's model it
64% turns a representable G(200) ~ 1e-87 into an underflow to 0.
66% log G
is estimated first, from
the largest SINGLE-STATE term, which
is a
67% lower bound on G(N) and in practice within O(log
#states) of log G:
68% all jobs at one queueing station i : sum_r N_r log L_ir
69% all jobs at
the delay : sum_r [N_r log Z_r - log N_r!]
70% On Reiser
's model at K=200 this gives max(-460.5, -264.1) = -264.1 against a
71% true log G of about -263, i.e. accurate enough to place the scaled value well
72% inside the exponent range.
74% c is then the power of two nearest exp(lGest/sum(N)), so that
75% log G_scaled = log G - sum(N) log c is near 0. A power of two matters: it
76% shifts exponents only, so L/c and Z/c stay exactly representable and the
77% recursion is bit-for-bit the unscaled one with shifted exponents.
85 t = t + N(r)*log(L(i,r));
91 if ok, lGest = max(lGest, t); end
93if any(Z > 0) % all jobs at the delay
98 t = t + N(r)*log(sum(Z(:,r))) - factln(N(r));
104 if ok, lGest = max(lGest, t); end
109 kscale = round(lGest/(Nt*log(2)));
111cscale = pow2(kscale);
115G = ones(M+1,prod(N+1)); % stores G across recursion
121 G(m,idxn) = G(m-1,idxn); % norm constant with m-1 queues
125 idxn_1r = hashpop(n,N);
127 G(m,idxn) = G(m,idxn) + L(m-1,r)*G(m,idxn_1r);
133% Undo the scaling in log space: log G = log G_scaled + sum(N) log c. lGn is
134% therefore finite whenever log G itself is, even though Gn may legitimately
135% overflow to Inf (the true constant really is outside double range).
136lGn = log(G(M+1,end)) + sum(N)*kscale*log(2);
137% Gn is recovered by scaling the mantissa back with pow2 (an exact exponent
138% adjustment), not as exp(lGn): on models that never overflowed this returns
139% bit-for-bit the value the unscaled recursion used to return, and it still
140% goes to Inf when the constant genuinely leaves double range -- in which case
141% lGn above remains finite and usable.
142Gn = pow2(G(M+1,end), sum(N)*kscale);
145function idx=hashpop(n,N,R,prods)
146% IDX=HASHPOP(N,N,R,PRODS)
148% hash a population vector in n: 0<=n<=N
153 idx= idx + prod(N(1:r-1)+1)*n(r);
158 idx= idx + prods(r)*n(r);
163function [n]=pprod(n,N)
166% sequentially generate all vectors n: 0<=n<=N
168% n=pprod(n,N) - next state
182while s>0 && n(s)==N(s)