LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
pfqn_cftp.m
1%{
2%{
3 % @file pfqn_cftp.m
4 % @brief Perfect/approximate stationary state sampler for closed
5 % single-class multiserver product-form networks.
6%}
7%}
8
9%{
10%{
11 % @brief Draws states exactly distributed according to the product-form
12 % stationary distribution of a closed single-class Jackson network
13 % with multiple servers, using monotone Coupling From The Past
14 % (Propp-Wilson) as proposed by Kijima and Matsui (WSC 2005,
15 % "Approximate/Perfect Samplers for Closed Jackson Networks").
16 % @fn pfqn_cftp(L, N, S, nsamples, method)
17 % @param L Service demand (visit ratio / service rate) vector, one entry
18 % per station, L(i) = theta_i/mu_i.
19 % @param N Total closed population K (scalar, single class).
20 % @param S Number of servers per station (default: 1; use Inf for a
21 % delay/infinite-server station).
22 % @param nsamples Number of independent samples to draw (default: 1).
23 % @param method 'cftp' for exact/perfect sampling (default) or 'approx'
24 % for the rapidly-mixing approximate sampler M_A.
25 % @return Q Empirical mean queue length per station (1 x M).
26 % @return X Sampled states, one per row (nsamples x M), each row sums to N.
27 % @return T Per-sample coalescence horizon ('cftp') or mixing steps used
28 % ('approx'), returned as (nsamples x 1) for diagnostics.
29%}
30%}
31function [Q,X,T] = pfqn_cftp(L,N,S,nsamples,method)
32% [Q,X,T] = PFQN_CFTP(L,N,S,NSAMPLES,METHOD)
33%
34% Exact (perfect) stationary state sampling for closed single-class
35% multiserver product-form networks via monotone Coupling From The Past.
36%
37% Reference: S. Kijima and T. Matsui, "Approximate/Perfect Samplers for
38% Closed Jackson Networks", Proc. Winter Simulation Conference, 2005.
39%
40% Input:
41% L - demands (stations x 1), L(i) = theta_i/mu_i
42% N - total population K (scalar)
43% S - servers per station (stations x 1), Inf for infinite server
44% NSAMPLES - number of independent samples (default 1)
45% METHOD - 'cftp' (exact, default) or 'approx' (rapidly mixing M_A)
46%
47% Output:
48% Q - empirical mean queue length (1 x stations)
49% X - sampled states (nsamples x stations), each row sums to N
50% T - coalescence horizon / mixing steps per sample (nsamples x 1)
51
52L = L(:).'; % row vector of demands
53M = numel(L);
54if nargin < 3 || isempty(S)
55 S = ones(1,M);
56end
57S = S(:).';
58if nargin < 4 || isempty(nsamples)
59 nsamples = 1;
60end
61if nargin < 5 || isempty(method)
62 method = 'cftp';
63end
64K = round(N);
65
66if M < 2
67 error('pfqn_cftp: at least two stations are required.');
68end
69if any(L <= 0)
70 error('pfqn_cftp: all demands L must be strictly positive.');
71end
72
73% Precompute cumulative log service factors:
74% logfac(i,m+1) = sum_{t=1}^m log(min(t,S(i))), m = 0..K
75% so that log alpha_i(m) = m*log(L(i)) - logfac(i,m+1).
76logfac = zeros(M,K+1);
77for i = 1:M
78 acc = 0;
79 for m = 1:K
80 acc = acc + log(min(m,S(i)));
81 logfac(i,m+1) = acc;
82 end
83end
84logL = log(L);
85
86X = zeros(nsamples,M);
87T = zeros(nsamples,1);
88for smp = 1:nsamples
89 switch lower(method)
90 case 'cftp'
91 [X(smp,:),T(smp)] = draw_cftp(logL,logfac,K,M);
92 case 'approx'
93 [X(smp,:),T(smp)] = draw_approx(logL,logfac,K,M);
94 otherwise
95 error('pfqn_cftp: unknown method ''%s''.',method);
96 end
97end
98Q = mean(X,1);
99end
100
101% ---- one exact draw via monotone CFTP ------------------------------------
102function [x,horizon] = draw_cftp(logL,logfac,K,M)
103% top state x_U = (K,0,...,0), bottom state x_L = (0,...,0,K)
104u = []; % u(t): uniform for step t before present
105Tback = 1;
106while true
107 old = numel(u);
108 % prepend randomness for the newly exposed (older) steps T .. 2T-1;
109 % older steps sit at higher indices and are applied first
110 u(old+1:Tback) = rand(1,Tback-old); %#ok<AGROW>
111 xU = [K, zeros(1,M-1)];
112 xL = [zeros(1,M-1), K];
113 for t = Tback:-1:1 % oldest step first
114 xU = monotone_update(xU,u(t),logL,logfac,M);
115 xL = monotone_update(xL,u(t),logL,logfac,M);
116 end
117 if isequal(xU,xL)
118 x = xU;
119 horizon = Tback;
120 return;
121 end
122 Tback = 2*Tback;
123end
124end
125
126% ---- monotone update on a consecutive pair -------------------------------
127function x = monotone_update(x,u,logL,logfac,M)
128% single uniform u in [0,1) encodes: pair index (integer part) and the
129% split Lambda (fractional part), per Kijima-Matsui section 4.1
130lam = 1 + u*(M-1); % in [1,M)
131j = floor(lam); % pair (j, j+1), 1 <= j <= M-1
132if j > M-1, j = M-1; end
133Lambda = lam - j; % uniform in [0,1)
134k = x(j) + x(j+1);
135l = split_index(logL,logfac,j,j+1,k,Lambda);
136x(j) = l;
137x(j+1) = k - l;
138end
139
140% ---- inverse-CDF split: smallest l with Lambda <= g^k_{ij}(l) ------------
141function l = split_index(logL,logfac,i,j,k,Lambda)
142% w(s) propto alpha_i(s) * alpha_j(k-s), s = 0..k
143s = 0:k;
144lw = (s.*logL(i) - logfac(i,s+1)) + ((k-s).*logL(j) - logfac(j,k-s+1));
145lw = lw - max(lw);
146w = exp(lw);
147cdf = cumsum(w);
148cdf = cdf / cdf(end);
149l = find(Lambda <= cdf,1,'first') - 1; % s index (0-based) -> l
150if isempty(l), l = k; end
151end
152
153% ---- approximate rapidly-mixing sampler M_A ------------------------------
154function [x,steps] = draw_approx(logL,logfac,K,M,eps)
155if nargin < 5, eps = 1e-2; end
156steps = ceil(M*(M-1)/2 * log(K/eps)); % mixing-time bound (Theorem 1)
157x = mnrnd_start(K,M);
158for t = 1:steps
159 p = randperm(M,2); % distinct pair, not necessarily adjacent
160 i = p(1); j = p(2);
161 k = x(i) + x(j);
162 l = split_index(logL,logfac,i,j,k,rand);
163 x(i) = l;
164 x(j) = k - l;
165end
166end
167
168function x = mnrnd_start(K,M)
169% arbitrary feasible start: all customers at station 1
170x = [K, zeros(1,M-1)];
171end
Definition Station.m:245