3 % @file pfqn_schmidt_ext.m
4 % @brief Extended Schmidt MVA algorithm with queue-aware alpha corrections.
10 % @brief Extended Schmidt MVA algorithm with queue-aware alpha corrections.
11 % @fn pfqn_schmidt_ext(D, N, S, sched)
12 % @param D Service demand matrix (M x R).
13 % @param N Population vector (1 x R).
14 % @param S Number of servers per station (M x 1).
15 % @param sched Scheduling discipline per station.
16 % @
return XN System throughput.
17 % @
return QN Mean queue lengths.
18 % @
return UN Utilization.
19 % @
return CN Cycle times.
20 % @
return T Results table.
23function [XN,QN,UN,CN,T] = pfqn_schmidt_ext(D,N,S,sched)
24% [XN,QN,UN,CN,T] = PFQN_SCHMIDT_EXT(D,N,S,SCHED)
26% Extended Schmidt MVA algorithm with queue-aware alpha corrections.
27% A queue-aware version of the Schmidt algorithm that precomputes alpha values
28%
for improved accuracy in networks with
class-dependent FCFS scheduling.
30% Reference: R. Schmidt,
"An approximate MVA algorithm for exponential,
31% class-dependent multiple server stations," Performance Evaluation,
32% vol. 29, no. 4, pp. 245-254, 1997.
34% Copyright (c) 2012-2026, Imperial College London
44C = length(closedClasses);
45Dc = D(:, closedClasses);
48% Precompute alphas
for FCFS stations
51 if sched(i) == SchedStrategy.FCFS
52 % Check
if class-dependent
53 classIndependent =
true;
56 classIndependent = false;
63 % Create modified problem with tagged customer
64 D_mod = zeros(M, R + 1);
65 N_mod = zeros(1, R + 1);
74 D_mod(j, k) = D(j, k);
76 D_mod(j, R + 1) = D(j, r);
84 % Create extended sched array
85 sched_mod = [sched(:)', SchedStrategy.FCFS];
87 % Run basic Schmidt to get alpha values
88 [~, ~, U_alpha, ~, ~] = pfqn_schmidt(D_mod, N_mod, S, sched_mod);
89 alphas{i, r} = U_alpha;
95% Compute products
for hashing
98 prods(r) = prod(Nc(1:r-1) + 1);
101% Start at nc=(0,...,0)
108 % Always initialize L
for ALL stations (queue lengths needed everywhere)
109 L{ist} = zeros(R, prod(1 + Nc));
111 case SchedStrategy.INF
112 % No Pc needed
for infinite server
113 case SchedStrategy.PS
114 if ~all(S(ist, :) == 1)
115 % Multi-server PS needs state probabilities
116 Pc{ist} = zeros(1 + sum(Nc), prod(1 + Nc));
118 case SchedStrategy.FCFS
119 classIndependent = all(D(ist, :) == D(ist, 1));
121 if ~all(S(ist, :) == 1)
122 Pc{ist} = zeros(1 + sum(Nc), prod(1 + Nc));
125 % Class-dependent needs vector probabilities
126 Pc{ist} = zeros(prod(1 + Nc), prod(1 + Nc));
131x = zeros(C, prod(1 + Nc));
132w = zeros(M, C, prod(1 + Nc));
136 Pc{ist}(1 + 0, hashpop(kvec, Nc, C, prods)) = 1.0;
140% Population recursion
141while all(kvec >= 0) && all(kvec <= Nc)
142 kprods = zeros(1, C);
144 kprods(r) = prod(kvec(1:r-1) + 1);
149 hkvec = hashpop(kvec, Nc, C, prods);
150 hkvec_c = hashpop(oner(kvec, c), Nc, C, prods);
152 if length(S(ist, :)) == 1
160 case SchedStrategy.INF
161 w(ist, c, hkvec) = D(ist, c);
163 case SchedStrategy.PS
165 % Sum queue lengths of ALL
classes (arrival theorem)
166 totalQueueLength = sum(L{ist}(:, hkvec_c));
167 w(ist, c, hkvec) = Dc(ist, c) * (1 + totalQueueLength);
169 % Sum queue lengths of ALL
classes (arrival theorem)
170 totalQueueLength = sum(L{ist}(:, hkvec_c));
171 w(ist, c, hkvec) = (Dc(ist, c) / ns) * (1 + totalQueueLength);
173 % Pc{ist}(j,...) = Pr(j-1 jobs) due to MATLAB 1-indexing
174 w(ist, c, hkvec) = w(ist, c, hkvec) + (ns - 1 - (j - 1)) * Pc{ist}(j, hkvec_c) * (Dc(ist, c) / ns);
178 case SchedStrategy.FCFS
179 classIndependent = all(D(ist, :) == D(ist, 1));
183 % Sum queue lengths of ALL
classes (arrival theorem)
184 totalQueueLength = sum(L{ist}(:, hkvec_c));
185 w(ist, c, hkvec) = Dc(ist, c) * (1 + totalQueueLength);
190 % Use Nc and prods for hash (matches Java)
191 hnvec_c = hashpop(oner(nvec, c), Nc, C, prods);
193 % Use extended Bcn with alpha
194 if Nc(c) > 1 && ~isempty(alphas{ist, c})
195 Bcn = getBcnExt(alphas{ist, c}, D, ist, c, nvec, C, ns, R);
197 Bcn = getBcn(D, ist, c, nvec, C, ns);
200 w(ist, c, hkvec) = w(ist, c, hkvec) + Bcn * Pc{ist}(hnvec_c, hkvec_c);
202 nvec = pprod(nvec, kvec);
206 % Class-independent: treat like PS
208 % Sum queue lengths of ALL
classes (arrival theorem)
209 totalQueueLength = sum(L{ist}(:, hkvec_c));
210 w(ist, c, hkvec) = Dc(ist, c) * (1 + totalQueueLength);
212 % Sum queue lengths of ALL
classes (arrival theorem)
213 totalQueueLength = sum(L{ist}(:, hkvec_c));
214 w(ist, c, hkvec) = (Dc(ist, c) / ns) * (1 + totalQueueLength);
216 % Pc{ist}(j,...) = Pr(j-1 jobs) due to MATLAB 1-indexing
217 w(ist, c, hkvec) = w(ist, c, hkvec) + (ns - 1 - (j - 1)) * Pc{ist}(j, hkvec_c) * (Dc(ist, c) / ns);
226 % Compute throughputs
228 sumW = sum(w(1:M, c, hkvec));
230 x(c, hkvec) = kvec(c) / sumW;
237 % Update queue lengths
240 L{ist}(c, hkvec) = x(c, hkvec) * w(ist, c, hkvec);
243 if length(S(ist, :)) == 1
250 case SchedStrategy.PS
252 for n = 1:min(S(ist), sum(kvec))
255 hkvec_c = hashpop(oner(kvec, c), Nc, C, prods);
256 Pc{ist}(1 + n, hkvec) = Pc{ist}(1 + n, hkvec) + Dc(ist, c) * (1/n) * x(c, hkvec) * Pc{ist}(1 + (n - 1), hkvec_c);
259 Pc{ist}(1 + 0, hkvec) = max(eps, 1 - sum(Pc{ist}(1 + (1:min(S(ist), sum(kvec))), hkvec)));
263 case SchedStrategy.FCFS
264 classIndependent = all(D(ist, :) == D(ist, 1));
268 nvec = pprod(nvec, kvec);
271 % Use Nc and prods
for hash (matches Java)
272 hnvec = hashpop(nvec, Nc, C, prods);
277 % Use Nc and prods
for hash (matches Java)
278 hnvec_c = hashpop(oner(nvec, r), Nc, C, prods);
279 hkvec_c = hashpop(oner(kvec, r), Nc, C, prods);
281 if Nc(r) > 1 && ~isempty(alphas{ist, r})
282 Bcn = getBcnExt(alphas{ist, r}, D, ist, r, nvec, C, ns, R);
284 Bcn = getBcn(D, ist, r, nvec, C, ns);
287 capacity_inv = 1 / sum(nvec);
289 prob_c = Pc{ist}(hnvec_c, hkvec_c);
290 classProb = Bcn * capacity_inv * x_ir * prob_c;
291 prob = prob + classProb;
294 Pc{ist}(hnvec, hkvec) = prob;
295 sumOfAllProbs = sumOfAllProbs + prob;
296 nvec = pprod(nvec, kvec);
298 Pc{ist}(1 + 0, hkvec) = max(1e-12, 1 - sumOfAllProbs);
300 % Class-independent multi-server
304 % Assuming all
classes visit
if D > 0
312 meanQueueLength = meanQueueLength + L{ist}(r, hkvec);
315 for n = 1:(min(ns, sum(kvec))-1)
316 if K_j > 0 && n <= K_j
317 frac = meanQueueLength / K_j;
318 x1 = nchoosek(K_j, n);
320 x3 = (1 - frac)^(K_j - n);
322 Pc{ist}(1 + n, hkvec) = prob;
329 sum1 = sum1 + D(ist, r) * x(r, hkvec);
332 sum2 = sum2 + (ns - n) * Pc{ist}(1 + n, hkvec);
334 term = (sum1 + sum2) / ns;
335 Pc{ist}(1 + 0, hkvec) = max(1e-12, 1 - term);
341 kvec = pprod(kvec, Nc);
344% Extract
final results
348XN(closedClasses) = x(1:C, hkvecFinal);
350 XN = repmat(XN, M, 1);
356 UN(m, c) = (D(m, c) * XN(c)) / S(m);
361CN(1:M, closedClasses) = w(1:M, 1:C, hkvecFinal);
365 QN(ist, closedClasses) = L{ist}(closedClasses, hkvecFinal);
368T = table(XN, CN, QN, UN);
372function Bcn = getBcn(D, i, c, nvec, C, ns)
373% Standard Bcn calculation
379 sumVal = sumVal + nvec(t) * D(i, t);
381 Bcn = Bcn + (max(0, sum(nvec) - ns) / max(ns * (sum(nvec) - 1), eps_val) * (sumVal - D(i, c)));
385function Bcn = getBcnExt(u, D, i, c, nvec, C, ns, R)
386% Extended Bcn with alpha corrections
389% u
is the utilization matrix from the alpha computation (M x R+1)
390% The last column (R+1)
is the tagged customer utilization
391totalNonPinnedTime = sum(u(i, 1:C)) - u(i, C + 1);
393if totalNonPinnedTime > 0
396 prob = u(i, s) / totalNonPinnedTime;
397 weightedProb = weightedProb + (prob / D(i, s));
403 meanInterdepartureTime = 1.0 / (ns * weightedProb);
405 meanInterdepartureTime = 0;
411 Bcn = Bcn + (max(0, sum(nvec) - ns) * meanInterdepartureTime);
414if isnan(Bcn) || isinf(Bcn)