LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
pfqn_pas_is.m
1function [G, lG, Q] = pfqn_pas_is(N, mu, H, options)
2% [G, LG, Q] = PFQN_PAS_IS(N, MU, H, OPTIONS)
3%
4% Importance-sampling (IS) estimate of the normalizing constant of a SINGLE
5% communicating class of a cyclic two-station pass-and-swap (P&S) queueing
6% network with swap graph H. This is the Monte-Carlo
7% counterpart of the exact convolution PFQN_PASNC: it estimates the
8% same per-communicating-class constant G_C but scales to populations where the
9% exact count-lattice convolution becomes expensive.
10%
11% Model. Two OI/P&S stations (1 = upstream, 2 = downstream of the cycle) hold
12% all N jobs (no delay). With a non-empty swap graph the ordered-state chain is
13% reducible; the recurrent communicating class is the set of splits of the
14% orderings that are non-decreasing w.r.t. the placement partial order induced
15% by H (Comte & Dorsman, 2021, arXiv:2009.12299). Writing D for that set of
16% orderings and Phi_m for the balanced-fairness balance function of station m,
17% G_C = sum_{c in D} sum_{k=0}^{ell} Phi_1(c_{1..k}) Phi_2(c_{ell..k+1}),
18% where c_{1..k} is the length-k prefix placed at station 1 and c_{ell..k+1} the
19% reversed suffix placed at station 2. Along a fixed ordering q the balanced-
20% fairness value is the ordered product of reciprocal rank rates,
21% Phi_m(q) = prod_{p=1}^{|q|} 1 / mu_m(supp(q_{1..p})),
22% which depends only on the support reached at each position (OI property).
23%
24% Auto-normalized IS (notebook generator IS_3). Orderings c are drawn from D by
25% placing, at each step, a uniformly random placement-order-minimal present
26% class; the draw probability p(c) is the product of the reciprocal branching
27% factors. Then, for any coefficient xi,
28% G_C[xi] = E_{C~p}[ (sum_k xi(C,k) Phi_1(C_{1..k}) Phi_2(C_{ell..k+1})) / p(C) ],
29% and E[xi] = G_C[xi]/G_C[1] reuses the SAME samples for numerator and
30% denominator (auto-normalized IS; A. Owen, MCM notes; convergence per
31% Agapiou et al. 2017). Taking xi = number of class-r jobs in the prefix yields
32% the mean queue length of class r at station 1.
33%
35% N - (1 x R) closed population vector (the macrostate), finite.
36% mu - cell {1 x 2} of function handles. mu{m}(n) returns the total OI
37% rank rate of station m given the per-class occupancy (count)
38% vector n (1 x R); OI, so it depends only on supp(n), i.e. the sum
39% of the capacities of the servers compatible with the present
40% classes. This is exactly the svcRateFun stored on an OI/PAS node.
41% H - (R x R) swap-graph adjacency. An ordering is feasible iff it is
42% non-decreasing w.r.t. H: class a may not precede class b whenever
43% H(b,a) ~= 0. The empty/all-zero graph reduces D to all orderings
44% (pure OI); the estimate then targets the OI constant of PFQN_OI_NC.
45% options - solver options (optional). Fields used:
46% .samples number of IS samples (default 1e4);
47% .seed RNG seed for reproducibility (optional);
48% .verbose print progress (default false).
49%
50% Returns:
51% G - IS estimate of the communicating-class normalizing constant G_C.
52% lG - log(G).
53% Q - (2 x R) IS estimate of the mean per-class queue length; Q(1,:) at
54% station 1, Q(2,:) = N - Q(1,:) at station 2.
55%
56% Example (two OI/P&S queues, R=5, star swap graph):
57% mu1 = [1 2 0.5]; nb1 = {1,2,3,[1 3],[2 3]};
58% mu2 = [1 2]; nb2 = {1,2,[1 2],1,2};
59% rate = @(nb,mu,n) sum(mu(unique([nb{n>0}])));
60% mu = {@(n) rate(nb1,mu1,n), @(n) rate(nb2,mu2,n)};
61% H = [0 0 0 1 0; 0 0 0 0 1; 0 0 0 1 1; 0 0 0 0 0; 0 0 0 0 0];
62% [G,lG,Q] = pfqn_pas_is([1 1 1 3 3], mu, H, struct('samples',1e5));
63%
64% See also PFQN_PASNC, PFQN_PASNCM, PFQN_OI_NC, PAS_SWAP2PREC.
65%
66% Copyright (c) 2012-2026, Imperial College London
67% All rights reserved.
68
69if nargin < 4, options = struct(); end
70if nargin < 3, H = []; end
71if ~iscell(mu), mu = {mu}; end
72if numel(mu) ~= 2
73 line_error(mfilename, 'pfqn_pas_is models a two-station pass-and-swap tandem: mu must have exactly two rate functions.');
74end
75
76R = numel(N);
77N = round(N(:)');
78if any(~isfinite(N))
79 line_error(mfilename, 'pfqn_pas_is requires finite (closed) populations.');
80end
81if isempty(H), H = zeros(R, R); end
82H = (H ~= 0);
83if ~isequal(size(H), [R R])
84 line_error(mfilename, 'H must be a (R x R) swap-graph adjacency matrix.');
85end
86
87nsamples = 1e4;
88if isfield(options, 'samples') && ~isempty(options.samples)
89 nsamples = round(options.samples);
90end
91if isfield(options, 'seed') && ~isempty(options.seed)
92 rng(options.seed);
93end
94verbose = isfield(options, 'verbose') && ~isempty(options.verbose) && options.verbose;
95
96ell = sum(N);
97
98% Placement-order logic (feasible orderings) is isolated in PAS_PLACEMENT:
99% placeable(x) returns the classes drawable next given remaining counts x.
100[~, placeable] = pas_placement(H);
101
102if ell == 0
103 G = 1; lG = 0; Q = zeros(2, R);
104 return
105end
106
107nCoef = R + 1; % xi = [1, n_{1,1}, ..., n_{1,R}]
108accum = zeros(1, nCoef);
109Nmat = N; % row template for feasibility masking
110
111for s = 1:nsamples
112 % ---- draw an ordering c from D (auto-normalized IS, generator IS_3) ----
113 x = Nmat; % remaining per-class jobs to place
114 c = zeros(1, ell);
115 logp = 0; % log p(c) = -sum log(branching factor)
116 for ppos = 1:ell
117 avail = placeable(x); % placement-order-minimal present classes
118 na = numel(avail);
119 if na == 0
120 line_error(mfilename, 'swap graph induces no feasible ordering (cyclic placement order).');
121 end
122 pick = avail(randi(na));
123 c(ppos) = pick;
124 logp = logp - log(na);
125 x(pick) = x(pick) - 1;
126 end
127 p_c = exp(logp);
128
129 % ---- split-convolution sample value for every coefficient at once ------
130 % Precompute prefix balance Phi_1 up to each cut and suffix balance Phi_2.
131 % Phi1cut(k+1) = Phi_1(c_{1..k}); Phi2cut(k+1) = Phi_2(reversed c_{k+1..ell})
132 Phi1 = ones(1, ell + 1);
133 cnt1 = zeros(ell + 1, R);
134 supp = zeros(1, R); phi = 1; occ = zeros(1, R);
135 for k = 1:ell
136 cls = c(k);
137 supp(cls) = 1; occ(cls) = occ(cls) + 1;
138 phi = phi / mu{1}(supp);
139 Phi1(k + 1) = phi;
140 cnt1(k + 1, :) = occ;
141 end
142 % Station 2 receives the reversed suffix c(ell), c(ell-1), ..., c(k+1). Scan
143 % positions ell..1 accumulating support; Phi2cut(k) is the balance of the
144 % reversed suffix c_{ell..k} (length ell-k+1), so at cut k station 2 holds
145 % c_{ell..k+1} whose balance is Phi2cut(k+1) (and 1 for the empty suffix).
146 Phi2cut = ones(1, ell + 1);
147 supp = zeros(1, R); phi = 1;
148 for k = ell:-1:1
149 cls = c(k);
150 supp(cls) = 1;
151 phi = phi / mu{2}(supp);
152 Phi2cut(k) = phi;
153 end
154
155 % sample_val(coef) = sum_{k=0}^{ell} xi_coef(k) * Phi1(k) * Phi2cut-at-k
156 sv = zeros(1, nCoef);
157 for k = 0:ell
158 w = Phi1(k + 1) * Phi2cut_at(Phi2cut, k, ell);
159 sv(1) = sv(1) + w; % xi = 1
160 if k > 0
161 sv(2:end) = sv(2:end) + w * cnt1(k + 1, :); % xi = n_{1,r}
162 end
163 end
164 accum = accum + sv / p_c;
165
166 if verbose && mod(s, max(1, floor(nsamples / 10))) == 0
167 line_printf('\npfqn_pas_is: %d/%d samples', s, nsamples);
168 end
169end
170
171est = accum / nsamples;
172G = est(1);
173lG = log(G);
174Q = zeros(2, R);
175if G > 0
176 Q(1, :) = est(2:end) / G;
177end
178Q(2, :) = N - Q(1, :);
179end
180
181function v = Phi2cut_at(Phi2cut, k, ell)
182% Balance of the reversed suffix c_{ell..k+1} (length ell-k) at cut k.
183if k >= ell
184 v = 1; % empty suffix
185else
186 v = Phi2cut(k + 1); % accumulated from position ell down to k+1
187end
188end
Definition Station.m:245