1function [G, lG] = pfqn_pas_nc(Z, N, mu, prec, options)
2% [G, LG] = PFQN_PAS_NC(Z, N, MU, PREC, OPTIONS)
4% Normalizing constant of a closed pass-and-swap (
P&S) queueing network that
5% comprises a single aggregated infinite-server (delay) node and an arbitrary
6% number of order-independent (OI) /
P&S stations, restricted to the recurrent
7% communicating
class selected by the placement order PREC.
9% With a non-empty swap graph the ordered-state chain
is reducible (Comte &
10% Dorsman, 2021, arXiv:2009.12299): the recurrent communicating classes are the
11% placement-order-adhering sets and the product
form pi(c) = prod_m Phi_m(c_m)/G_C
12% holds per class. This routine returns that per-class constant G_C. It
is a
13% MICROSTATE routine: it walks the ordered chains position by position, because
14% with a placement order the reachable set
is a set of ORDERINGS and does not
15% collapse onto the count lattice. For the plain OI case (empty PREC, every
16% ordering feasible) the count lattice does suffice and PFQN_NCOI computes the
17% same G at far lower cost; use
this routine only when a placement order
is
18% present, or as a microstate reference.
20% Method. Build station M
's chain head-first: appending class r at chain
21% position k = sum(occ)+1 is admissible iff the placement order allows it (no
22% class already placed at that station must come after r), and contributes the
23% reciprocal OI prefix rate 1/mu_M(occ+e_r); the chain may be finalized only
24% when occ is a placement-order ideal at full multiplicity, whereupon the
25% recursion moves to station M-1. When every P&S station has been peeled the
26% residual population sits at the delay node with the multinomial weight
27% prod_r Z_r^{N_r}/N_r!. With PREC empty this is exactly the balanced-fairness
28% convolution of Bonald & Proutiere (2003) evaluated ordering by ordering,
29% Phi(0) = 1, Phi(n) = (1/mu(n)) * sum_{r: n_r>0} Phi(n - e_r).
31% COST. The recursion visits one node per feasible ordered prefix, so with an
32% empty PREC the node count is sum_{b<=N} C(|b|+M-1,M-1) * |b|!/prod_r b_r!,
33% i.e. factorial in the total population sum(N). A placement order prunes the
34% orderings (a total order leaves a single one per count split), which is what
35% makes the microstate walk affordable in the P&S case.
38% Z - (1 x R) think-time demand vector of the aggregated delay node.
39% Z(r) = 1/sigma_r for a delay with per-class rate sigma_r.
40% N - (1 x R) closed population vector, finite.
41% mu - cell array {1 x M} of function handles, one per P&S station. Each
42% mu{m}(n) returns the total service rate of station m given the
43% per-class occupancy (count) vector n (1 x R). For an OI station the
44% rate depends only on the support of n (which classes are present),
45% i.e. the sum of the capacities of the compatible servers. May be
46% empty to model a pure delay network.
47% prec - placement order. Either a cell {1 x M} of (R x R) precedence
48% matrices, one per station, or a single (R x R) matrix broadcast to
49% every station, with prec{m}(i,j) ~= 0 iff class i must be placed
50% before class j at station m (the closure returned by PAS_PLACEMENT,
51% fed by the global DAG of PAS_SWAP2ORDER). Empty or all-zero means no
52% order: every ordering is feasible and G is the plain OI constant.
53% NOTE the orientation: around a cycle 1->2->...->M->1 the chain of
54% each downstream station is traversed in the opposite direction, so
55% the downstream stations take the TRANSPOSE of the upstream order
56% (prec = {P, P'}
for a two-station cycle). Passing the same
P to both
57% stations of a cycle silently returns a smaller, wrong G.
58% options - solver options (optional, currently unused; accepted
for
59% signature parity with the other pfqn_* routines).
62% G - Normalizing constant G_C of the communicating class.
65% Example (two
P&S stations in a cycle with swap graph SWAP, no delay):
66% H = pas_swap2order(swap, {@(c) mu1, @(c) mu2});
67%
P = pas_placement(H);
68% G = pfqn_pas_nc([], N, {@(n) mu1, @(n) mu2}, {
P,
P'});
70% See also PFQN_NCOI, PFQN_PAS_IS, PAS_PLACEMENT, PAS_SWAP2ORDER.
72% Copyright (c) 2012-2026, Imperial College London
76 options = struct(); %#ok<NASGU>
81if nargin < 3 || isempty(mu)
93 line_error(mfilename, 'Z and N must have the same number of classes.
');
96 line_error(mfilename, 'pfqn_pas_nc
requires finite (closed) populations.
');
103% Normalize the placement order to one logical (R x R) matrix per station.
108 prec = repmat({prec}, 1, M);
112 prec = repmat({false(R)}, 1, M);
113elseif numel(prec) == 1 && M > 1
114 prec = repmat(prec, 1, M);
117 line_error(mfilename, 'prec must supply one precedence matrix per station.
');
123 if any(size(prec{m}) ~= [R, R])
124 line_error(mfilename, 'each precedence matrix must be R x R.
');
126 prec{m} = logical(prec{m} ~= 0);
130G = pas_nc_rec(Z, N, N, mu, prec, M, zeros(1, R));
134function G = pas_nc_rec(Z, N, Norig, mu, prec, m, occ)
135% Head-peeling recursion. N is the population still available to stations
136% m,m-1,...,1 and to the delay node; Norig is the total population (for the
137% order-ideal test); occ is the per-class chain already placed at station m.
141 % Base case: the residual population N sits at the delay node with
142 % unnormalized weight prod_r Z_r^{N_r} / N_r!.
147 G = 0; % class r has population but no delay demand: infeasible
150 logf = logf + N(r) * log(Z(r)) - gammaln(N(r) + 1);
157% Step A: finalize station m's chain here and peel to station m-1, but only if
158% the accumulated occupancy
is a placement-order ideal of station m (a class
159% present here requires all its order-predecessors present at full multiplicity;
160% otherwise the split
is unreachable within the communicating
class).
161if pas_nc_isideal(occ, prec{m}, Norig)
162 G = pas_nc_rec(Z, N, Norig, mu, prec, m - 1, zeros(1, R));
167% Step B: append one more
class r at the next chain position of station m,
168% contributing the reciprocal OI prefix rate.
173 if N(r) > 0 && ~any(precm(r, placed))
176 mu_r = active(occ + e_r);
182 G = G + (1 / mu_r) * pas_nc_rec(Z, Nm, Norig, mu, prec, m, occ + e_r);
187function tf = pas_nc_isideal(occ, precm, Norig)
188% True iff occ
is a placement-order ideal at full multiplicity:
for every
189% i prec j, occ(j) > 0
requires occ(i) = Norig(i). Reduces to support
190% downward-closure when Norig == 1, and to
"always true" for an empty order.
195 if precm(i, j) && occ(j) > 0 && occ(i) < Norig(i)