LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
pfqn_oi_is.m
1function [G, lG, Q] = pfqn_oi_is(N, mu, options)
2% [G, LG, Q] = PFQN_OI_IS(N, MU, OPTIONS)
3%
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).
11%
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})).
18%
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
25% at station 1.
26%
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).
37%
38% Returns:
39% G - IS estimate of the OI normalizing constant (== PFQN_OI_NC with Z=0).
40% lG - log(G).
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.
43%
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));
50%
51% See also PFQN_PAS_IS, PFQN_OI_NC, PFQN_OI_FNC.
52%
53% Copyright (c) 2012-2026, Imperial College London
54% All rights reserved.
55
56if nargin < 3, options = struct(); end
57if ~iscell(mu), mu = {mu}; end
58if numel(mu) ~= 2
59 line_error(mfilename, 'pfqn_oi_is models a two-station OI tandem: mu must have exactly two rate functions.');
60end
61
62R = numel(N);
63N = round(N(:)');
64if any(~isfinite(N))
65 line_error(mfilename, 'pfqn_oi_is requires finite (closed) populations.');
66end
67
68nsamples = 1e4;
69if isfield(options, 'samples') && ~isempty(options.samples)
70 nsamples = round(options.samples);
71end
72if isfield(options, 'seed') && ~isempty(options.seed)
73 rng(options.seed);
74end
75verbose = isfield(options, 'verbose') && ~isempty(options.verbose) && options.verbose;
76
77ell = sum(N);
78if ell == 0
79 G = 1; lG = 0; Q = zeros(2, R);
80 return
81end
82
83nCoef = R + 1; % xi = [1, n_{1,1}, ..., n_{1,R}]
84accum = zeros(1, nCoef);
85
86for s = 1:nsamples
87 % ---- draw an ordering c by placing a uniformly random present class -----
88 x = N; % remaining per-class jobs to place
89 c = zeros(1, ell);
90 logp = 0;
91 for ppos = 1:ell
92 avail = find(x > 0); % OI: every present class is placeable
93 na = numel(avail);
94 pick = avail(randi(na));
95 c(ppos) = pick;
96 logp = logp - log(na);
97 x(pick) = x(pick) - 1;
98 end
99 p_c = exp(logp);
100
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);
105 for k = 1:ell
106 cls = c(k);
107 supp(cls) = 1; occ(cls) = occ(cls) + 1;
108 phi = phi / mu{1}(supp);
109 Phi1(k + 1) = phi;
110 cnt1(k + 1, :) = occ;
111 end
112 % ---- reversed-suffix balance Phi_2 (station 2 = reversed suffix) -------
113 Phi2cut = ones(1, ell + 1);
114 supp = zeros(1, R); phi = 1;
115 for k = ell:-1:1
116 cls = c(k);
117 supp(cls) = 1;
118 phi = phi / mu{2}(supp);
119 Phi2cut(k) = phi;
120 end
121
122 % ---- split-convolution sample value for every coefficient -------------
123 sv = zeros(1, nCoef);
124 for k = 0:ell
125 if k >= ell
126 w2 = 1;
127 else
128 w2 = Phi2cut(k + 1);
129 end
130 w = Phi1(k + 1) * w2;
131 sv(1) = sv(1) + w;
132 if k > 0
133 sv(2:end) = sv(2:end) + w * cnt1(k + 1, :);
134 end
135 end
136 accum = accum + sv / p_c;
137
138 if verbose && mod(s, max(1, floor(nsamples / 10))) == 0
139 line_printf('\npfqn_oi_is: %d/%d samples', s, nsamples);
140 end
141end
142
143est = accum / nsamples;
144G = est(1);
145lG = log(G);
146Q = zeros(2, R);
147if G > 0
148 Q(1, :) = est(2:end) / G;
149end
150Q(2, :) = N - Q(1, :);
151end
Definition Station.m:245