1function [W_bar, W_bar_n] = map_m1ps_cdfrespt(C, D, mu, x, varargin)
2% MAP_M1PS_CDFRESPT Compute sojourn time distribution in MAP/M/1-PS queue
4% W_bar = MAP_M1PS_CDFRESPT(C, D, mu, x) computes the complementary
5% distribution function of the sojourn time in a MAP/M/1 processor-sharing
6% queue at the points specified in x.
8% [W_bar, W_bar_n] = MAP_M1PS_CDFRESPT(C, D, mu, x) also returns the
9% conditional complementary distributions W_bar_n{i}
for customers finding
10% i-1 customers in the system on arrival.
12% [...] = MAP_M1PS_CDFRESPT(C, D, mu, x,
'Param', Value) specifies optional
14%
'Epsilon' - Truncation parameter
for queue length (
default: 1e-11)
15%
'EpsilonPrime' - Truncation parameter for uniformization (default: 1e-10)
16%
'Verbose' - Display computation progress (default: false)
19% C - M x M matrix governing MAP transitions without arrivals
20% D - M x M matrix governing MAP transitions with arrivals
21% mu - Service rate (scalar, mu > 0)
22% x - Vector of time points at which to evaluate W_bar(x) = Pr[W > x]
25% W_bar - Vector of same size as x, containing Pr[W > x]
26% W_bar_n - Cell array of conditional distributions (optional)
28% The processor-sharing (PS) discipline shares the server equally among
29% all customers. When n customers are present, each receives service at
32% The algorithm implements Theorem 1 from:
33% Masuyama, H., & Takine, T. (2003). Sojourn time distribution in a
34% MAP/M/1 processor-sharing queue. Operations Research Letters, 31(6),
38% % M/M/1-PS queue with lambda=0.8, mu=1
39% lambda = 0.8; mu = 1;
40% C = -lambda; D = lambda; % Poisson arrivals
41% x = linspace(0, 10, 100);
42% W_bar = map_m1ps_cdfrespt(C, D, mu, x);
44% xlabel(
'x'); ylabel(
'Pr[W > x]');
45% title(
'Sojourn time distribution for M/M/1-PS');
47% Copyright (c) 2012-2025, Imperial College London
50%% Parse input arguments
52addRequired(p,
'C', @(x) ismatrix(x) && size(x,1) == size(x,2));
53addRequired(p,
'D', @(x) ismatrix(x) && size(x,1) == size(x,2));
54addRequired(p,
'mu', @(x) isscalar(x) && x > 0);
55addRequired(p,
'x', @(x) isnumeric(x) && all(x >= 0));
56addParameter(p,
'Epsilon', 1e-11, @(x) isscalar(x) && x > 0 && x < 1);
57addParameter(p,
'EpsilonPrime', 1e-10, @(x) isscalar(x) && x > 0 && x < 1);
58addParameter(p,
'Verbose',
false, @islogical);
60parse(p, C, D, mu, x, varargin{:});
61epsilon = p.Results.Epsilon;
62epsilon_prime = p.Results.EpsilonPrime;
63verbose = p.Results.Verbose;
67if size(D, 1) ~= M || size(D, 2) ~= M
68 error(
'MAP_M1PS_CDFRESPT:DimensionMismatch',
'C and D must have the same size');
74%% Compute MAP parameters
75% Stationary probability vector pi of the underlying Markov chain
76% Solve: pi*(C + D) = 0, pi*e = 1
78% Replace last row of Q with normalization constraint
89 fprintf('MAP/M/1-PS Sojourn Time Computation\n
');
90 fprintf(' M (states): %d\n
', M);
91 fprintf(' lambda (arrival rate): %.4f\n
', lambda);
92 fprintf(' mu (service rate): %.4f\n
', mu);
93 fprintf(' rho (utilization): %.4f\n
', lambda/mu);
96% Check stability condition
99 error('MAP_M1PS_CDFRESPT:Unstable
', ...
100 'System
is unstable (rho = %.4f >= 1)
', rho);
105 fprintf('Computing R matrix...\n
');
107R = compute_R_matrix(C, D, mu);
110 fprintf(' R = %.6f\n
', R);
113%% Determine truncation point N(epsilon) for queue length
114% Find minimum N such that: (1/lambda) * sum_{n=0}^N pi_0 * R^n * D * e > 1 - epsilon
115% where pi_0 = pi * (I - R)
118% Compute spectral radius of R to estimate required N
119rho_R = max(abs(eig(R)));
122 error('MAP_M1PS_CDFRESPT:UnstableR
', 'R matrix has spectral radius >= 1');
125% Estimate N based on spectral radius:
126% We need rho_R^N < epsilon * (1 - rho_R)
127% N > log(epsilon * (1 - rho_R)) / log(rho_R)
129 N_estimate = ceil(log(epsilon * (1 - rho_R)) / log(rho_R));
134% Cap at reasonable maximum to avoid excessive computation
136N_epsilon = min(max(N_estimate, 10), N_max);
139 fprintf(
' Spectral radius of R: %.6f\n', rho_R);
140 fprintf(
' Estimated N: %d, using N(epsilon): %d (capped at %d)\n', N_estimate, N_epsilon, N_max);
143%% Compute uniformization parameter theta
144theta = max(abs(diag(C)));
147x = x(:)
'; % Ensure row vector
148num_points = length(x);
149W_bar = zeros(1, num_points);
152 W_bar_n = cell(N_epsilon + 1, 1);
154 W_bar_n{n+1} = zeros(1, num_points);
158%% Compute sojourn time distribution for each x
159for idx = 1:num_points
162 % Determine truncation points L and R_upper for uniformization
163 % Find L and R_upper such that: sum_{k=L}^R_upper Poisson(theta+mu, x_val) > 1 - epsilon_prime
164 mean_val = (theta + mu) * x_val;
166 % Use Poisson quantiles to find L and R_upper
168 L = max(0, floor(mean_val - 10*sqrt(mean_val)));
169 R_upper = ceil(mean_val + 10*sqrt(mean_val));
171 % Refine to meet epsilon_prime requirement
172 pmf = poisspdf(L:R_upper, mean_val);
173 cumsum_pmf = sum(pmf);
174 while cumsum_pmf < 1 - epsilon_prime && R_upper < 10000
175 R_upper = R_upper + 10;
176 pmf = poisspdf(L:R_upper, mean_val);
177 cumsum_pmf = sum(pmf);
186 if verbose && idx == 1
187 fprintf(' K(epsilon_prime): %d (uniformization truncation)\n
', K_max);
190 % Compute h_{n,k} for n=0,...,N_epsilon and k=0,...,K_max
191 if verbose && idx == 1
192 fprintf('Computing h_{n,k} recursion...\n
');
194 h = compute_h_recursive(C, D, mu, N_epsilon, K_max, theta);
196 % Compute W_bar(x) using equation (8)
197 % W_bar(x) = (1/lambda) * sum_{n=0}^{N} pi_0 * R^n * D * sum_{k=L}^{R} ...
198 % [(theta+mu)^k * x^k / k!] * exp(-(theta+mu)*x) * h_{n,k}
200 theta_plus_mu = theta + mu;
203 % Compute pi_0 * R^n * D
209 weight = pi_0 * R_power_n * D;
215 % Use poisspdf to avoid numerical overflow with factorial
216 poisson_term = poisspdf(k, theta_plus_mu * x_val);
217 sum_k = sum_k + poisson_term * h{n+1, k+1};
220 term_n = (1/lambda) * weight * sum_k;
221 W_bar(idx) = W_bar(idx) + term_n;
223 % Store conditional distribution if requested
225 W_bar_n{n+1}(idx) = sum(sum_k) / M; % Average over states
231 fprintf('Computation complete.\n
');
236%% ========================================================================
237% LOCAL HELPER FUNCTIONS
238% ========================================================================
240function R = compute_R_matrix(C, D, mu)
241% Compute rate matrix R for MAP/M/1 queue
242% Solves: D + R(C - mu*I) + mu*R^2 = O
247% For scalar case (M=1), use quadratic formula
249 % mu*R^2 + (C - mu)*R + D = 0
253 discriminant = b^2 - 4*a*c;
256 error('compute_R_matrix:NoRealSolution
', 'No real solution for R
');
260 R1 = (-b - sqrt(discriminant)) / (2*a);
261 R2 = (-b + sqrt(discriminant)) / (2*a);
263 % Choose minimal nonnegative solution
266 elseif R2 >= 0 && R2 < 1
269 error('compute_R_matrix:NoValidSolution
', 'No valid solution in [0,1) for R
');
272 % For matrix case, use fixed-point iteration
273 % From D + R*(C - mu*I) + mu*R^2 = 0, we can derive:
274 % R*(mu*I - C) = D + mu*R^2
275 % R = (D + mu*R^2) * inv(mu*I - C)
276 % which gives the fixed-point iteration: R_new = (D + mu*R_old^2) / (mu*I - C)
278 % Initial approximation
283 % Precompute (mu*I - C) for efficiency
284 muI_minus_C = mu*I - C;
286 for iter = 1:max_iter
288 % Fixed-point iteration
289 R = (D + mu*(R*R)) / muI_minus_C;
292 if norm(R - R_old, inf) < tol
298 warning('compute_R_matrix:SlowConvergence
', ...
299 'R computation did not converge within %d iterations
', max_iter);
303% Ensure non-negativity (numerical errors might produce small negative values)
307check = D + R*(C - mu*I) + mu*(R*R);
308if norm(check, inf) > 1e-4
309 warning('compute_R_matrix:LargeResidual
', ...
310 'Large residual in R computation: ||residual|| = %e
', norm(check, inf));
315function h = compute_h_recursive(C, D, mu, N, K, theta)
316% Recursive computation of h_{n,k} coefficients
318% The h_{n,k} vectors satisfy the recursion (Theorem 1):
319% h_{n,0} = e (vector of ones), for n = 0, 1, ...
320% h_{n,k+1} = 1/(theta+mu) * [n*mu/(n+1) * h_{n-1,k} + (theta*I + C) * h_{n,k}
322% where h_{-1,k} = 0 for all k
328% Pre-compute constant matrices
329theta_plus_mu = theta + mu;
330theta_I_plus_C = theta * I + C;
332% Initialize cell array to store h_{n,k}
333% h{n+1, k+1} stores h_{n,k} (shift indices by 1)
336% Base case: h_{n,0} = e for all n
341% Recursive computation: fill column by column (increasing k)
344 % Compute h_{n,k+1} using the recursion formula
345 % h_{n,k+1} = 1/(theta+mu) * [n*mu/(n+1) * h_{n-1,k}
346 % + (theta*I + C) * h_{n,k}
350 term2 = theta_I_plus_C * h{n+1, k+1};
353 % First term: n*mu/(n+1) * h_{n-1,k}
355 term1 = (n * mu / (n + 1)) * h{n, k+1};
358 % Third term: D * h_{n+1,k}
360 term3 = D * h{n+2, k+1};
363 h{n+1, k+2} = (term1 + term2 + term3) / theta_plus_mu;