1function [G, lG, Q] = pfqn_oi_is(N, mu, options)
2% [G, LG, Q] = PFQN_OI_IS(N, MU, OPTIONS)
4% Importance-sampling (IS) estimate of
the normalizing constant of a closed
5% two-station order-independent (OI) tandem. This
is PFQN_PAS_IS with an EMPTY
6% swap graph: it does not restrict
the sampled orderings to a pass-and-swap
7% communicating
class but samples over ALL microstates (every ordering of
the
8% present jobs
is feasible), thereby recovering
the plain OI normalizing
9% constant of PFQN_OI_NC (which it estimates by Monte Carlo rather than exact
10% balanced-fairness convolution).
12% Model. Two OI stations (1 = upstream, 2 = downstream) hold all N jobs (no
13% delay). The ordered-state chain
is irreducible, so
the communicating
class is
14%
the full set of orderings D = all permutations of
the job multiset. Writing
15% Phi_m
for the balanced-fairness balance function of station m,
16% G = sum_{c in D} sum_{k=0}^{ell} Phi_1(c_{1..k}) Phi_2(c_{ell..k+1}),
17% with
the ordered product Phi_m(q) = prod_{p=1}^{|q|} 1/mu_m(supp(q_{1..p})).
19% Auto-normalized IS. Orderings c are drawn by placing, at each step, a
20% uniformly random present
class (no placement constraint);
the draw probability
21% p(c)
is the product of
the reciprocal branching factors. Then
22% G[xi] = E_{C~p}[ (sum_k xi(C,k) Phi_1(C_{1..k}) Phi_2(C_{ell..k+1})) / p(C) ],
23% and E[xi] = G[xi]/G[1] reuses
the same samples (
auto-normalized IS). Taking
24% xi = number of
class-r jobs in
the prefix yields
the class-r mean queue length
28% N - (1 x R) closed population vector (
the macrostate), finite.
29% mu - cell {1 x 2} of function handles. mu{m}(n) returns
the total OI
30% rank rate of station m
for the per-
class occupancy (
count) vector
31% n (1 x R); OI, so it depends only on supp(n). This
is the
32% svcRateFun stored on an OI station.
33% options - solver options (optional). Fields used:
34% .samples number of IS samples (
default 1e4);
35% .seed RNG seed
for reproducibility (optional);
36% .verbose print progress (
default false).
39% G - IS estimate of
the OI normalizing constant (== PFQN_OI_NC with Z=0).
41% Q - (2 x R) IS estimate of
the mean per-
class queue length; Q(1,:) at
42% station 1, Q(2,:) = N - Q(1,:) at station 2.
44% Example (two OI queues, R=5, no swap graph):
45% mu1 = [1 2 0.5]; nb1 = {1,2,3,[1 3],[2 3]};
46% mu2 = [1 2]; nb2 = {1,2,[1 2],1,2};
47% rate = @(nb,muv,n) sum(muv(unique([nb{n>0}])));
48% mu = {@(n) rate(nb1,mu1,n), @(n) rate(nb2,mu2,n)};
49% [G,lG,Q] = pfqn_oi_is([1 1 1 3 3], mu,
struct(
'samples',1e5));
51% See also PFQN_PAS_IS, PFQN_OI_NC, PFQN_OI_FNC.
53% Copyright (c) 2012-2026, Imperial College London
56if nargin < 3, options =
struct(); end
57if ~iscell(mu), mu = {mu}; end
59 line_error(mfilename,
'pfqn_oi_is models a two-station OI tandem: mu must have exactly two rate functions.');
65 line_error(mfilename, 'pfqn_oi_is requires finite (closed) populations.
');
69if isfield(options, 'samples
') && ~isempty(options.samples)
70 nsamples = round(options.samples);
72if isfield(options, 'seed
') && ~isempty(options.seed)
75verbose = isfield(options, 'verbose
') && ~isempty(options.verbose) && options.verbose;
79 G = 1; lG = 0; Q = zeros(2, R);
83nCoef = R + 1; % xi = [1, n_{1,1}, ..., n_{1,R}]
84accum = zeros(1, nCoef);
87 % ---- draw an ordering c by placing a uniformly random present class -----
88 x = N; % remaining per-class jobs to place
92 avail = find(x > 0); % OI: every present class is placeable
94 pick = avail(randi(na));
96 logp = logp - log(na);
97 x(pick) = x(pick) - 1;
101 % ---- prefix balance Phi_1 and per-class counts at each cut -------------
102 Phi1 = ones(1, ell + 1);
103 cnt1 = zeros(ell + 1, R);
104 supp = zeros(1, R); phi = 1; occ = zeros(1, R);
107 supp(cls) = 1; occ(cls) = occ(cls) + 1;
108 phi = phi / mu{1}(supp);
110 cnt1(k + 1, :) = occ;
112 % ---- reversed-suffix balance Phi_2 (station 2 = reversed suffix) -------
113 Phi2cut = ones(1, ell + 1);
114 supp = zeros(1, R); phi = 1;
118 phi = phi / mu{2}(supp);
122 % ---- split-convolution sample value for every coefficient -------------
123 sv = zeros(1, nCoef);
130 w = Phi1(k + 1) * w2;
133 sv(2:end) = sv(2:end) + w * cnt1(k + 1, :);
136 accum = accum + sv / p_c;
138 if verbose && mod(s, max(1, floor(nsamples / 10))) == 0
139 line_printf('\npfqn_oi_is: %d/%d samples
', s, nsamples);
143est = accum / nsamples;
148 Q(1, :) = est(2:end) / G;
150Q(2, :) = N - Q(1, :);