1function [QN, UN, RN, TN, piAgg, GM] = solver_mam_qsys(arrival, service, options)
2% SOLVER_MAM_QSYS Unified solver
for MAP/BMAP queueing systems with single server
4% [QN, UN, RN, TN, PI, GM] = SOLVER_MAM_QSYS(ARRIVAL, SERVICE) solves a queueing
5% system with Markovian arrival and service processes. Automatically detects
6% whether arrivals or service are batched and applies the appropriate
7% matrix-analytic method:
8% - BMAP/MAP/1: M/G/1 type analysis (batch arrivals, single service)
9% - MAP/BMAP/1: GI/M/1 type analysis (single arrivals, batch service)
12% arrival - Arrival process: MAP object, BMAP object, or cell array
13% MAP: {D0, D1} or MAP
object
14% BMAP: {D0, D1, D2, ..., DK} or BMAP
object
15% service - Service process: MAP object, BMAP object, or cell array
16% MAP: {S0, S1} or MAP
object
17% BMAP: {S0, S1, S2, ..., SK} or BMAP
object
18% options - (optional) Options structure with fields:
19% .nMoments: number of queue length moments to compute (default: 3)
22% QN - Mean queue length E[N]
23% UN - Server utilization rho
24% RN - Mean response time E[R]
25% TN - Throughput (arrival rate)
26% piAgg - Aggregated stationary probabilities
27% GM - G matrix (M/G/1 type) or R matrix (GI/M/1 type)
30% BMAP/MAP/1 - Batch arrivals, single service (M/G/1 type)
31% Level increases by batch size (1, 2, 3, ...), decreases by 1
32% MAP/BMAP/1 - Single arrivals, batch service (GI/M/1 type)
33% Level increases by 1, decreases by batch size (1, 2, 3, ...)
36% Stathopoulos, Riska, Hua, Smirni: ETAQA algorithm
37% MAMSolver: www.cs.wm.edu/MAMSolver
41% Copyright (c) 2012-2026, Imperial College London
44%% Input validation and setup
48if ~isfield(options,
'nMoments')
52%% Determine arrival type (MAP or BMAP)
53[arrivalMatrices, arrivalIsBatch, ma] = parseProcess(arrival, 'arrival');
55%% Determine service type (MAP or BMAP)
56[serviceMatrices, serviceIsBatch, ms] = parseProcess(service, 'service');
58%% Route to appropriate solver based on queue type
59if arrivalIsBatch && ~serviceIsBatch
60 % BMAP/MAP/1 queue - M/G/1 type analysis
61 [QN, UN, RN, TN, piAgg, GM] = solveBMAPMAP1(arrivalMatrices, serviceMatrices, ma, ms, options);
62elseif ~arrivalIsBatch && serviceIsBatch
63 % MAP/BMAP/1 queue - GI/M/1 type analysis
64 [QN, UN, RN, TN, piAgg, GM] = solveMAPBMAP1(arrivalMatrices, serviceMatrices, ma, ms, options);
65elseif ~arrivalIsBatch && ~serviceIsBatch
66 % MAP/MAP/1 queue - treat as BMAP/MAP/1 with batch size 1
67 [QN, UN, RN, TN, piAgg, GM] = solveBMAPMAP1(arrivalMatrices, serviceMatrices, ma, ms, options);
69 % BMAP/BMAP/1 - both batched (not yet supported)
70 error('BMAP/BMAP/1 queues with both batch arrivals and batch service are not yet supported');
75%% Helper function to parse arrival/service process
76function [matrices, isBatch, nPhases] = parseProcess(proc, procType)
78 K = proc.getMaxBatchSize();
79 matrices = cell(1, K + 1);
80 matrices{1} = proc.D(0); % D0
82 matrices{k+1} = proc.D(1, k); % Dk (batch size k)
85 nPhases = size(matrices{1}, 1);
86 elseif isa(proc,
'MAP')
87 matrices = {proc.D(0), proc.D(1)};
89 nPhases = size(matrices{1}, 1);
92 isBatch = length(proc) > 2; % More than {D0, D1} means batch process
93 nPhases = size(proc{1}, 1);
95 error(
'%s must be a MAP object, BMAP object, or cell array', procType);
99 for k = 1:length(matrices)
100 if size(matrices{k}, 1) ~= nPhases || size(matrices{k}, 2) ~= nPhases
101 error(
'All %s matrices must be %dx%d', procType, nPhases, nPhases);
106%% BMAP/MAP/1 solver
using M/G/1 type analysis
107function [QN, UN, RN, TN, pi, G] = solveBMAPMAP1(D, S, ma, ms, options)
108% Solves BMAP/MAP/1
using M/G/1 type matrix-analytic methods
110% M/G/1 type structure (level can jump UP by any amount, DOWN by exactly 1):
111% A0 = I_ma \otimes S1 (service completion, level -1)
112% A1 = D0 \otimes I_ms + I_ma \otimes S0 (phase changes, level 0)
113% A_{k+1} = D_k \otimes I_ms (batch arrival size k, level +k)
115K = length(D) - 1; % max batch size
for arrivals
116m = ma * ms; % Combined phases per level
118% Extract MAP service matrices
122%% Construct M/G/1 type matrices
using Kronecker products
126A = zeros(m, m * (K + 2));
128% A0 = I_ma \otimes S1 (service completion)
132% A1 = D0 \otimes I_ms + I_ma \otimes S0 (phase changes only)
133A1 = kron(D{1}, I_ms) + kron(I_ma, S0);
136% A_{k+1} = D_k \otimes I_ms
for k >= 1 (batch arrivals)
138 Ak = kron(D{k+1}, I_ms);
139 A(:, (k+1)*m + 1 : (k+2)*m) = Ak;
142% B = [B0, B1, B2, ..., BK]
for level 0 (empty queue)
143B = zeros(m, m * (K + 1));
145% B0: At level 0, no service (add S1 back as self-loop)
146B0 = kron(D{1}, I_ms) + kron(I_ma, S0 + S1);
149% B_k = D_k \otimes I_ms
for k >= 1 (batch arrivals from empty queue)
151 Bk = kron(D{k+1}, I_ms);
152 B(:, k*m + 1 : (k+1)*m) = Bk;
155%% Verify stability condition
157D1_total = zeros(ma, ma);
159 D1_total = D1_total + D{k+1};
162% Stationary distribution of BMAP
163pi_bmap = map_prob({D0, D1_total});
166% Total customer arrival rate: sum_k (k * π * Dk * e)
169 rate_k = pi_bmap * D{k+1} * e_ma;
170 lambda_total = lambda_total + k * rate_k;
173% Compute service rate from MAP
174pi_map = map_prob({S0, S1});
176mu = pi_map * S1 * e_ms; % Service rate
179rho = lambda_total / mu;
182 warning(
'solver_mam_qsys:Unstable', ...
183 'System is unstable (rho = %.4f >= 1). Results may be invalid.', rho);
186%% Compute G matrix
using MG1_G_ETAQA
189%% Compute stationary probabilities
using MG1_pi_ETAQA
190pi = MG1_pi_ETAQA(B, A, G);
192%% Compute queue length moments
using MG1_qlen_ETAQA
193qlen_moments = zeros(1, options.nMoments);
194for n = 1:options.nMoments
195 qlen_moments(n) = MG1_qlen_ETAQA(B, A, pi, n);
198%% Compute performance metrics
199QN = qlen_moments(1); % Mean queue length (E[N])
200UN = rho; % Utilization
201TN = lambda_total; % Throughput (total arrival rate)
202RN = QN / TN; % Mean response time (Little
's law: E[R] = E[N] / λ)
206%% MAP/BMAP/1 solver using GI/M/1 type analysis
207function [QN, UN, RN, TN, piAgg, R] = solveMAPBMAP1(C, D, ma, ms, options)
208% Solves MAP/BMAP/1 using GI/M/1 type matrix-analytic methods
210% GI/M/1 type structure (level jumps UP by 1, DOWN by any amount):
211% A0 = C1 \otimes I_ms (MAP arrival, level +1)
212% A1 = C0 \otimes I_ms + I_ma \otimes D0 (phase changes, level 0)
213% A_{k+1} = I_ma \otimes D_k (batch size k service, level -k)
217K = length(D) - 1; % max batch size for service
218m = ma * ms; % Combined phases per level
221% Check MAP is valid generator
222rowSumsC = sum(C0 + C1, 2);
223if max(abs(rowSumsC)) > 1e-10
224 error('MAP matrices C0 + C1 must have zero row sums
');
227% Check BMAP is valid generator
230 DTotal = DTotal + D{k+1};
232rowSumsD = sum(DTotal, 2);
233if max(abs(rowSumsD)) > 1e-10
234 error('BMAP matrices D0 + D1 + ... + DK must have zero row sums
');
237%% Compute arrival and service rates
238% Arrival rate from MAP
239piC = map_prob({C0, C1});
240lambdaArr = piC * C1 * ones(ma, 1);
242% Service rate from BMAP (total customers served per unit time)
243piD = map_prob({D{1}, DTotal - D{1}}); % D0, sum of D1...DK
246 muTotal = muTotal + k * (piD * D{k+1} * ones(ms, 1));
250rho = lambdaArr / muTotal;
253 warning('solver_mam_qsys:Unstable
', ...
254 'System
is unstable (rho = %.4f >= 1). Results may be invalid.
', rho);
257%% Construct A matrix for GI/M/1-type (repeating part)
258A = zeros(m * (K + 2), m);
260% A0: MAP arrival (level +1)
261A0 = kron(C1, eye(ms));
264% A1: Phase changes only (level 0)
265A1 = kron(C0, eye(ms)) + kron(eye(ma), D{1});
268% A_{k+1}: Batch service of size k (level -k)
270 Ak = kron(eye(ma), D{k+1});
271 A((k+1)*m+1:(k+2)*m, :) = Ak;
274%% Construct B matrix for boundary levels
275B = zeros(m * (K + 1) + m, m);
277% B1 (level 0 -> level 0): Phase changes only, no service from empty
278B1 = kron(C0, eye(ms)) + kron(eye(ma), D{1});
279% Add service transitions that would go to negative levels back to level 0
281 B1 = B1 + kron(eye(ma), D{k+1});
285% B2, B3, ..., B_{K+1}: Transitions to level 0 from levels 1, 2, ..., K
289 Bj = Bj + kron(eye(ma), D{k+1});
291 B(m + (j-1)*m + 1 : m + j*m, :) = Bj;
294%% Compute R matrix using GI/M/1 ETAQA
297%% Compute stationary probabilities using GI/M/1 ETAQA
298piAgg = GIM1_pi_ETAQA(B, A, R, 'Boundary
', A0);
300%% Compute performance metrics
301% Mean queue length using ETAQA moments
302QN = GIM1_qlen_ETAQA(B, A, R, piAgg, 1, 'Boundary
', A0);
304% Throughput equals arrival rate (in steady state)
310% Mean response time via Little's Law