LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
pfqn_ab_amva.m
1%{
2%{
3 % @file pfqn_ab_amva.m
4 % @brief Akyildiz-Bolch AMVA method for multi-server BCMP networks.
5%}
6%}
7
8%{
9%{
10 % @brief Akyildiz-Bolch AMVA method for multi-server BCMP networks.
11 % @fn pfqn_ab_amva(D, N, V, nservers, sched, fcfsSchmidt, marginalProbMethod)
12 % @param D Service time matrix (M x K).
13 % @param N Population vector (1 x K).
14 % @param V Visit ratio matrix (M x K).
15 % @param nservers Number of servers at each station (M x 1).
16 % @param sched Scheduling strategies for each station.
17 % @param fcfsSchmidt Whether to use Schmidt formula for FCFS stations.
18 % @param marginalProbMethod Method for marginal probability calculation ("ab" or "scat").
19 % @return QN Mean queue lengths.
20 % @return UN Utilization.
21 % @return RN Residence times.
22 % @return CN Cycle times.
23 % @return XN System throughput.
24 % @return totiter Total number of iterations.
25%}
26%}
27function [QN,UN,RN,CN,XN,totiter] = pfqn_ab_amva(D,N,V,nservers,sched,fcfsSchmidt,marginalProbMethod)
28% [QN,UN,RN,CN,XN,totiter] = PFQN_AB_AMVA(D,N,V,NSERVERS,SCHED,FCFSSCHMIDT,MARGINALPROBMETHOD)
29%
30% Akyildiz-Bolch AMVA method for multi-server BCMP networks.
31%
32% Copyright (c) 2012-2026, Imperial College London
33% All rights reserved.
34
35if nargin < 6
36 fcfsSchmidt = false;
37end
38if nargin < 7
39 marginalProbMethod = 'ab';
40end
41
42M = size(D, 1);
43K = size(D, 2);
44
45[QN, UN, RN, CN, XN, totiter] = ab_linearizer(K, M, N, nservers, sched, V, D, fcfsSchmidt, marginalProbMethod);
46
47end
48
49function [QN, UN, RN, CN, XN, totiter] = ab_linearizer(K, M, population, nservers, type, v, s, fcfsSchmidt, marginalProbMethod)
50% Akyildiz-Bolch linearizer method for multi-server BCMP networks.
51
52% Initialize queue length matrix
53L = zeros(M, K);
54for i = 1:M
55 for r = 1:K
56 L(i, r) = population(r) / M;
57 end
58end
59
60% Initialize L_without_r matrices (cell array of M x K matrices)
61lWithoutR = cell(1, K);
62for r = 1:K
63 lWithoutR{r} = zeros(M, K);
64 for i = 1:M
65 for t = 1:K
66 if r == t
67 lWithoutR{r}(i, t) = (population(r) - 1) / M;
68 else
69 lWithoutR{r}(i, t) = L(i, r);
70 end
71 end
72 end
73end
74
75% Fractional changes matrix (initialized to 0)
76D = zeros(M, K, K);
77
78% STEP 1: Apply core at full population
79[LUpdated, ~, ~, ~, ~, ~] = pfqn_ab_core(K, M, population, nservers, type, v, s, 100, D, L, fcfsSchmidt, marginalProbMethod);
80
81% STEP 2: Apply core at N-e_k populations
82for r = 1:K
83 populationWithoutC = population;
84 populationWithoutC(r) = population(r) - 1;
85
86 lWithoutC = zeros(M, K);
87 for j = 1:M
88 for c = 1:K
89 lWithoutC(j, c) = lWithoutR{c}(j, c);
90 end
91 end
92
93 [retQ, ~, ~, ~, ~, ~] = pfqn_ab_core(K, M, populationWithoutC, nservers, type, v, s, 100, D, lWithoutC, fcfsSchmidt, marginalProbMethod);
94
95 for j = 1:M
96 for c = 1:K
97 lWithoutR{c}(j, r) = retQ(j, c);
98 end
99 end
100end
101
102% STEP 3: Compute estimates of F_mk(N) and F_mk(N-e_j)
103for i = 1:M
104 for r = 1:K
105 F_ir = LUpdated(i, r) / population(r);
106 for t = 1:K
107 if r == t
108 divisor = population(r) - 1;
109 else
110 divisor = population(r);
111 end
112 if divisor ~= 0
113 F_irt = lWithoutR{r}(i, t) / divisor;
114 else
115 F_irt = 0;
116 end
117 if isnan(F_irt)
118 F_irt = 0;
119 end
120 D(i, r, t) = F_irt - F_ir;
121 end
122 end
123end
124
125% STEP 4: Apply core at full population using L values from step 1 and D values from step 3
126[QN, UN, RN, CN, XN, totiter] = pfqn_ab_core(K, M, population, nservers, type, v, s, 100, D, LUpdated, fcfsSchmidt, marginalProbMethod);
127
128end
129
130function [QN, UN, W, CN, XN, totiter] = pfqn_ab_core(K, M, population, nservers, type, v, s, maxiter, D, lIn, fcfsSchmidt, marginalProbMethod)
131% Akyildiz-Bolch core method for multi-server BCMP networks.
132
133L = lIn;
134tol = 1 / (4000 + 16 * sum(population));
135
136totiter = 0;
137W = zeros(M, K);
138
139while totiter < maxiter
140 F = zeros(M, K);
141 lWithoutJ = zeros(M, K, K);
142
143 for i = 1:M
144 for r = 1:K
145 if population(r) > 0
146 F(i, r) = L(i, r) / population(r);
147 else
148 F(i, r) = 0;
149 end
150 end
151 end
152
153 for i = 1:M
154 for r = 1:K
155 for t = 1:K
156 if r == t
157 scalar = population(r) - 1;
158 else
159 scalar = population(r);
160 end
161 lWithoutJ(i, r, t) = scalar * (F(i, r) + D(i, r, t));
162 end
163 end
164 end
165
166 for i = 1:M
167 for r = 1:K
168 if type(i) == SchedStrategy.INF
169 W(i, r) = s(i, r);
170 elseif nservers(i) == 1
171 totalQueueLengthKvecC = 0;
172 for c = 1:K
173 totalQueueLengthKvecC = totalQueueLengthKvecC + lWithoutJ(i, c, r);
174 end
175 W(i, r) = s(i, r) * (1 + totalQueueLengthKvecC);
176 elseif fcfsSchmidt && type(i) == SchedStrategy.FCFS
177 waitTime = 0;
178 nvec = pprod(population);
179 while all(nvec >= 0)
180 if nvec(r) > 0
181 Bcn = getBcnForAB(s, i, r, nvec, K, nservers(i));
182 prob = getMarginalProb(oner(nvec, r), oner(population, r), population, lIn(i, r), K, i);
183 waitTime = waitTime + (Bcn * prob);
184 end
185 nvec = pprod(nvec, population);
186 end
187 if waitTime <= 1e-3
188 waitTime = 0;
189 end
190 W(i, r) = waitTime;
191 else
192 queueLength = 0;
193 for j = 1:K
194 queueLength = queueLength + lWithoutJ(i, j, r);
195 end
196 numServers = floor(nservers(i));
197 multiServerStationWeightedQueueLength = 0;
198 if numServers > 1
199 populationWithoutR = population;
200 populationWithoutR(r) = populationWithoutR(r) - 1;
201 marginalProbs = findMarginalProbs(queueLength, numServers, populationWithoutR, r, marginalProbMethod);
202
203 for j = 1:(numServers-1)
204 if isfield(marginalProbs, num2str(j)) || isKey(marginalProbs, j)
205 prob_j = marginalProbs(j);
206 else
207 prob_j = 0;
208 end
209 multiServerStationWeightedQueueLength = multiServerStationWeightedQueueLength + prob_j * (numServers - j);
210 end
211 end
212 waitTime = (s(i, r) / numServers) * (1 + queueLength + multiServerStationWeightedQueueLength);
213 W(i, r) = waitTime;
214 end
215 end
216 end
217
218 % Calculate cycle time for each class
219 CN = zeros(1, K);
220 for r = 1:K
221 cycleTime = 0;
222 for i = 1:M
223 cycleTime = cycleTime + v(i, r) * W(i, r);
224 end
225 CN(r) = cycleTime;
226 end
227
228 % Calculate queue length L_ir = N_r * W_ir / C_r
229 iterationQueueLength = zeros(M, K);
230 for i = 1:M
231 for r = 1:K
232 if CN(r) > 0
233 queueLength = population(r) * (v(i, r) * W(i, r) / CN(r));
234 else
235 queueLength = 0;
236 end
237 iterationQueueLength(i, r) = queueLength;
238 end
239 end
240
241 % Check convergence
242 maxDifference = 0;
243 for i = 1:M
244 for r = 1:K
245 if population(r) > 0
246 difference = abs(L(i, r) - iterationQueueLength(i, r)) / population(r);
247 maxDifference = max(maxDifference, difference);
248 end
249 end
250 end
251
252 totiter = totiter + 1;
253 L = iterationQueueLength;
254
255 if maxDifference < tol
256 break
257 end
258end
259
260% Calculate throughput
261XN = zeros(1, K);
262for r = 1:K
263 if W(1, r) > 0
264 XN(r) = L(1, r) / W(1, r);
265 else
266 XN(r) = 0;
267 end
268end
269
270% Calculate utilization
271UN = zeros(M, K);
272for i = 1:M
273 for r = 1:K
274 if s(i, r) > 0
275 if type(i) == SchedStrategy.INF
276 UN(i, r) = XN(r) * s(i, r);
277 else
278 UN(i, r) = (XN(r) * s(i, r)) / nservers(i);
279 end
280 else
281 UN(i, r) = 0;
282 end
283 end
284end
285
286QN = L;
287
288end
289
290function Bcn = getBcnForAB(D, i, c, nvec, K, ns)
291% Calculate Bcn for AB algorithm
292Bcn = D(i, c);
293if sum(nvec) > 1
294 eps_val = 1e-12;
295 sumVal = 0;
296 for t = 1:K
297 sumVal = sumVal + nvec(t) * D(i, t);
298 end
299 Bcn = Bcn + (max(0, sum(nvec) - ns) / max(ns * (sum(nvec) - 1), eps_val) * (sumVal - D(i, c)));
300end
301end
302
303function prob = getMarginalProb(n, k, K_pop, L_jr, R, j)
304% Compute marginal probability using binomial distribution
305prob = 1;
306for r = 1:R
307 frac = L_jr / K_pop(r);
308 if frac ~= 0 && K_pop(r) > 0 && n(r) >= 0 && n(r) <= K_pop(r)
309 term1 = nchoosek(K_pop(r), n(r));
310 term2 = frac^n(r);
311 term3 = (1 - frac)^(K_pop(r) - n(r));
312 prob = prob * (term1 * term2 * term3);
313 end
314end
315end
316
317function marginalProbs = findMarginalProbs(avgJobs, numServers, population, classIdx, marginalProbMethod)
318% Finds marginal probabilities using specified method.
319
320marginalProbs = containers.Map('KeyType', 'double', 'ValueType', 'double');
321
322if strcmp(marginalProbMethod, 'scat')
323 floorVal = floor(avgJobs);
324 ceilVal = floorVal + 1;
325 marginalProbs(floorVal) = ceilVal - avgJobs;
326 marginalProbs(ceilVal) = avgJobs - floorVal;
327 return
328end
329
330% AB method
331ALPHA = 45.0;
332BETA = 0.7;
333
334w = weightFun(population, ALPHA, BETA);
335
336floorVal = floor(avgJobs);
337ceiling = floorVal + 1;
338maxVal = min((2 * floorVal) + 1, numServers - 2);
339
340for j = 0:maxVal
341 if j <= floorVal
342 lDist = floorVal - j;
343 lowerVal = floorVal - lDist;
344 upperVal = ceiling + lDist;
345 if lDist > 25
346 prob = 0;
347 else
348 if floorVal < population(classIdx)
349 if upperVal ~= lowerVal
350 prob = w(floorVal+1, lDist+1) * ((upperVal - avgJobs) / (upperVal - lowerVal));
351 else
352 prob = 0;
353 end
354 else
355 prob = 0;
356 end
357 end
358 marginalProbs(j) = prob;
359 else
360 uDist = j - ceiling;
361 if uDist > 25
362 marginalProbs(j) = 0;
363 elseif j > population(classIdx) - 1 && uDist < 25
364 if isKey(marginalProbs, population(classIdx) - 1)
365 existingProb = marginalProbs(population(classIdx) - 1);
366 else
367 existingProb = 0;
368 end
369 if isKey(marginalProbs, floorVal - uDist)
370 mp_floor_udist = marginalProbs(floorVal - uDist);
371 else
372 mp_floor_udist = 0;
373 end
374 newProb = existingProb + (w(floorVal+1, uDist+1) - mp_floor_udist);
375 marginalProbs(population(classIdx) - 1) = newProb;
376 else
377 if isKey(marginalProbs, floorVal - uDist)
378 mp_floor_udist = marginalProbs(floorVal - uDist);
379 else
380 mp_floor_udist = 0;
381 end
382 newProb = w(floorVal+1, uDist+1) - mp_floor_udist;
383 marginalProbs(j) = newProb;
384 end
385 end
386end
387
388end
389
390function w = weightFun(population, alpha, beta)
391% Computes weight function for marginal probability calculation.
392
393maxClassPopulation = max(population);
394
395% Calculate scaling function PR
396scalingFun = zeros(1, maxClassPopulation + 1);
397if maxClassPopulation >= 1
398 scalingFun(2) = alpha; % scalingFun[1] in 0-indexed = scalingFun(2) in 1-indexed
399 for n = 2:maxClassPopulation
400 scalingFun(n+1) = beta * scalingFun(n);
401 end
402end
403
404% Calculate weight function W (using 1-indexed matrices)
405w = zeros(maxClassPopulation + 1, maxClassPopulation + 1);
406w(1, 1) = 1.0; % weightFun[0][0] = 1.0
407
408for l = 1:maxClassPopulation
409 for j = 0:(l-1)
410 w(l+1, j+1) = w(l, j+1) - (w(l, j+1) * scalingFun(l+1)) / 100.0;
411 end
412 sumVal = 0;
413 for j = 0:(l-1)
414 sumVal = sumVal + w(l+1, j+1);
415 end
416 w(l+1, l+1) = 1 - sumVal;
417end
418
419end