LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
BMAP.m
1classdef BMAP < MarkedMAP
2 % Batch Markovian Arrival Process (BMAP)
3 %
4 % BMAP is a point process where arrivals occur in batches.
5 % Uses the standard BMAP representation:
6 % - D0: infinitesimal generator for transitions without arrivals
7 % - D1: rate matrix for transitions generating 1 arrival
8 % - D2: rate matrix for transitions generating 2 arrivals
9 % - ...
10 % - Dk: rate matrix for transitions generating k arrivals
11 %
12 % BMAP extends MarkedMAP where each "mark" k represents a batch size k.
13 %
14 % Copyright (c) 2012-2026, Imperial College London
15 % All rights reserved.
16
17 methods
18 % Constructor
19 function self = BMAP(D)
20 % SELF = BMAP(D)
21 %
22 % D is a cell array {D0, D1, D2, ..., Dk} where:
23 % - D0: transitions without arrivals
24 % - Dk: transitions generating k arrivals (for k >= 1)
25 %
26 % The number of marking types K equals the maximum batch size
27 % (i.e., K = length(D) - 2 when D also includes D1_total,
28 % or K = length(D) - 1 otherwise)
29
30 if nargin == 0
31 D = {};
32 end
33
34 % Determine K (number of marking types = max batch size)
35 % If D = {D0, D1, D2, ..., Dk}, then K = k (max batch size)
36 % MarkedMAP expects either:
37 % - {D0, D1_total, D11, D12, ..., D1K} with K marking types
38 % - {D0, D11, D12, ..., D1K} with K marking types
39
40 if isempty(D)
41 K = 0;
42 else
43 % Assume format {D0, D1, D2, ..., Dk} where Dk generates k arrivals
44 % Need to convert to MarkedMAP format {D0, D1_total, D1, D2, ..., Dk}
45 % where D1_total = sum(D1, D2, ..., Dk)
46 K = length(D) - 1; % max batch size
47
48 % Compute total arrival matrix
49 D1_total = D{2};
50 for k = 3:length(D)
51 D1_total = D1_total + D{k};
52 end
53
54 % Create MarkedMAP cell array
55 D_mmap = cell(1, K+2);
56 D_mmap{1} = D{1}; % D0
57 D_mmap{2} = D1_total; % D1_total
58 for k = 1:K
59 D_mmap{2+k} = D{1+k}; % Dk (batch size k)
60 end
61
62 D = D_mmap;
63 end
64
65 % Call parent MarkedMAP constructor
66 self@MarkedMAP(D, K);
67
68 % Fix self.process which is incorrectly set by MarkedMAP constructor
69 % MarkedMAP constructor has a bug on line 33-37 where it creates
70 % a cell array of size K-1 instead of K+2
71 self.process = D;
72
73 % Validate generator
74 self.validateGenerator();
75 end
76
77 % Validate that D0 + sum(Dk) forms a proper infinitesimal generator
78 function validateGenerator(self)
79 D0 = self.D(0);
80 nPhases = length(D0);
81
82 % Compute D0 + sum(Dk)
83 generator = D0;
84 for k = 1:self.getMaxBatchSize()
85 generator = generator + self.D(1, k-1);
86 end
87
88 % Check row sums (should be close to zero)
89 rowSums = sum(generator, 2);
90 maxRowSum = max(abs(rowSums));
91
92 if maxRowSum > 1e-6
93 warning('BMAP:InvalidGenerator', ...
94 'BMAP generator row sums are not zero (max: %.2e). Consider calling normalize().', maxRowSum);
95 end
96 end
97
98 % Get maximum batch size
99 function k = getMaxBatchSize(self)
100 % K = GETMAXBATCHSIZE()
101 %
102 % Returns the maximum batch size k where Dk is defined
103 k = self.getNumberOfTypes();
104 end
105
106 % Get mean batch size
107 function mean_bs = getMeanBatchSize(self)
108 % MEAN_BS = GETMEANBATCHSIZE()
109 %
110 % Computes the mean batch size as a weighted average:
111 % E[batch size] = sum(k * rate_k) / sum(rate_k)
112
113 % Get stationary distribution using D0 and D1_total
114 D0 = self.D(0);
115 D1_total = self.D(1);
116 pi = map_pie({D0, D1_total});
117
118 % Compute weighted average
119 totalRate = 0;
120 weightedSum = 0;
121 maxBatch = self.getMaxBatchSize();
122
123 for k = 1:maxBatch
124 Dk = self.D(1, k-1);
125 rate_k = sum(pi * Dk * ones(size(Dk, 1), 1));
126 totalRate = totalRate + rate_k;
127 weightedSum = weightedSum + k * rate_k;
128 end
129
130 if totalRate > 0
131 mean_bs = weightedSum / totalRate;
132 else
133 mean_bs = 0;
134 end
135 end
136
137 % Get batch rates
138 function rates = getBatchRates(self)
139 % RATES = GETBATCHRATES()
140 %
141 % Returns array where rates(k) is the rate of batch size k arrivals
142
143 D0 = self.D(0);
144 D1_total = self.D(1);
145 maxBatch = self.getMaxBatchSize();
146
147 % Get stationary distribution
148 pi = map_pie({D0, D1_total});
149
150 % Compute rate for each batch size
151 rates = zeros(1, maxBatch);
152 for k = 1:maxBatch
153 Dk = self.D(1, k-1);
154 rates(k) = sum(pi * Dk * ones(size(Dk, 1), 1));
155 end
156 end
157
158 % Override toString-like display
159 function display(self)
160 % DISPLAY(SELF)
161 fprintf('BMAP(phases=%d, maxBatchSize=%d)\n', ...
162 self.getNumberOfPhases(), self.getMaxBatchSize());
163 end
164
165 % Get distribution name
166 function name = getName(self)
167 % NAME = GETNAME()
168 %
169 % Returns the name of this distribution type
170 name = 'BMAP';
171 end
172
173 % Sample from BMAP (returns inter-arrival times and batch sizes)
174 function [X, B] = sample(self, n)
175 % [X, B] = SAMPLE(N)
176 %
177 % Sample n batches from the BMAP
178 % Returns:
179 % X: inter-arrival times (between batches)
180 % B: batch sizes for each arrival
181
182 if nargin < 2
183 n = 1;
184 end
185
186 % Use parent MarkedMAP sampling
187 % This returns inter-arrival times and class labels
188 [X, C] = sample@MarkedMAP(self, n);
189
190 % Convert class labels to batch sizes
191 % Class k corresponds to batch size k
192 B = C;
193 end
194
195 % Sample only inter-batch times
196 function X = sampleInterBatch(self, n)
197 % X = SAMPLEINTERBATCH(N)
198 %
199 % Sample n inter-batch arrival times
200 % (ignoring batch sizes)
201
202 if nargin < 2
203 n = 1;
204 end
205
206 % Sample from aggregate MAP
207 map = self.toMAP();
208 X = map.sample(n);
209 end
210
211 % Get inter-batch MAP
212 function map = getInterBatchMAP(self)
213 % MAP = GETINTERBATCHMAP()
214 %
215 % Returns the underlying MAP for inter-batch arrivals
216 map = self.toMAP();
217 end
218 end
219
220 methods (Static)
221 % Factory method: create BMAP from MAP + batch size distribution
222 function bmap = fromMAPWithBatchPMF(D0, D1, batchSizes, pmf)
223 % BMAP = FROMMAPWITHBATCHPMF(D0, D1, BATCHSIZES, PMF)
224 %
225 % Create BMAP from a base MAP and batch size distribution
226 %
227 % Inputs:
228 % D0: base MAP's D0 matrix (transitions without batch arrivals)
229 % D1: base MAP's D1 matrix (inter-batch arrival transitions)
230 % batchSizes: array of batch sizes (e.g., [1, 2, 4, 8])
231 % pmf: probability mass function for batch sizes (must sum to 1)
232 %
233 % Output:
234 % bmap: BMAP constructed from the base MAP and batch distribution
235
236 if length(batchSizes) ~= length(pmf)
237 line_error(mfilename, 'Batch sizes and PMF must have the same length');
238 end
239
240 % Normalize PMF
241 pmf = pmf / sum(pmf);
242
243 % Find maximum batch size
244 maxBatch = max(batchSizes);
245
246 % Create D matrices: Dk = D1 * pmf(batchSize==k)
247 D = cell(1, maxBatch + 1);
248 D{1} = D0; % D0
249
250 % Initialize Dk matrices to zero
251 for k = 1:maxBatch
252 D{1+k} = zeros(size(D0));
253 end
254
255 % Set Dk based on batch sizes and PMF
256 for i = 1:length(batchSizes)
257 k = batchSizes(i);
258 if k < 1 || k > maxBatch
259 line_error(mfilename, sprintf('Invalid batch size: %d', k));
260 end
261 D{1+k} = D{1+k} + D1 * pmf(i);
262 end
263
264 % Create BMAP
265 bmap = BMAP(D);
266 end
267
268 % Generate random BMAP
269 function bmap = rand(order, maxBatchSize)
270 % BMAP = RAND(ORDER, MAXBATCHSIZE)
271 %
272 % Generate random BMAP using uniform random numbers
273 %
274 % Inputs:
275 % order: number of phases (default: 2)
276 % maxBatchSize: maximum batch size (default: 3)
277
278 if nargin < 1
279 order = 2;
280 end
281 if nargin < 2
282 maxBatchSize = 3;
283 end
284
285 % Generate random MarkedMAP and interpret as BMAP
286 mmap = MarkedMAP.rand(order, maxBatchSize);
287
288 % Convert to BMAP format
289 D = cell(1, maxBatchSize + 1);
290 D{1} = mmap.D(0); % D0
291 for k = 1:maxBatchSize
292 D{1+k} = mmap.D(1, k-1); % Dk
293 end
294
295 bmap = BMAP(D);
296 end
297 end
298end