4 % @brief Schmidt
's exact MVA for networks with general scheduling disciplines.
10 % @brief Schmidt's exact MVA
for networks with general scheduling disciplines.
11 % @fn pfqn_schmidt(D, N, S, sched, v)
12 % @param D Service demand matrix.
13 % @param N Population vector.
14 % @param S Number of servers per station (matrix or vector).
15 % @param sched Scheduling discipline per station.
16 % @param v Visit ratio matrix (optional, defaults to ones).
17 % @
return XN System throughput.
18 % @
return QN Mean queue lengths.
19 % @
return UN Utilization (M x R), per station-
class, D*X/nservers.
20 % @
return CN Cycle times.
21 % @
return T Results table.
24function [XN,QN,UN,CN,T] = pfqn_schmidt(D,N,S,sched,v)
25% [XN,QN,UN,CN] = PFQN_SCHMIDT(D,N,S,SCHED,V)
34% Default visit ratios to ones
if not provided
35if nargin < 5 || isempty(v)
39% Compute pure service times from demands: S_pure = D / v
40% D
is demands (= visit_ratio * service_time), so S_pure = D / v
41% Bcn calculations need pure service times, not demands
42S_pure = D ./ max(v, 1e-12); % Protect against division by zero
44C = length(closedClasses); % number of closed classes
45Dc = D(:,closedClasses);
47prods = zeros(1,C); % needed
for fast hashing
49 prods(r)=prod(Nc(1:r-1)+1);
51% Start at nc=(0,...,0)
54L = cell(1, M); % mean queue-length
55Pc = cell(1, M); % state probabilities (empty cells
for stations that don
't need them)
57 % Always initialize L for ALL stations (queue lengths needed everywhere)
58 L{ist} = zeros(R, prod(1+Nc)); % mean queue-length
60 case SchedStrategy.INF
61 % No Pc needed for infinite server
63 if ~all(S(ist,:) == 1)
64 % Multi-server PS needs state probabilities
65 Pc{ist} = zeros(1 + sum(Nc), prod(1+Nc)); % Pr(j|N)
67 case SchedStrategy.FCFS
68 if all(D(ist,:)==D(ist,1)) % class-independent
69 if ~all(S(ist,:) == 1) % multi server
70 Pc{ist} = zeros(1 + sum(Nc), prod(1+Nc)); % Pr(j|N)
72 else % class-dependent - needs vector probabilities
73 Pc{ist} = zeros(prod(1+Nc), prod(1+Nc)); % Pr(jvec|N)
77% Per-station throughput like Java: x(ist,c,hkvec) = v(ist,c) * kvec(c) / denom
78x = zeros(M,C,prod(1+Nc));
79w = zeros(M,C,prod(1+Nc));
82 Pc{ist}(1 + 0, hashpop(kvec,Nc,C,prods)) = 1.0; %Pj(0|0) = 1
86while all(kvec>=0) && all(kvec <= Nc)
88 kprods = zeros(1,C); % needed for fast hashing
90 kprods(r)=prod(kvec(1:r-1)+1);
94 hkvec = hashpop(kvec,Nc,C,prods);
95 hkvec_c = hashpop(oner(kvec,c),Nc,C,prods);
96 if size(S(ist,:)) == 1
103 case SchedStrategy.INF
104 w(ist,c,hkvec) = D(ist,c);
105 case SchedStrategy.PS
107 % Sum queue lengths of ALL classes (arrival theorem)
108 totalQueueLength = sum(L{ist}(:, hkvec_c));
109 w(ist,c,hkvec) = Dc(ist,c) * (1 + totalQueueLength);
111 % Sum queue lengths of ALL classes (arrival theorem)
112 totalQueueLength = sum(L{ist}(:, hkvec_c));
113 w(ist,c,hkvec) = (Dc(ist,c) / ns) * (1 + totalQueueLength);
115 % Pc{ist}(j,...) = Pr(j-1 jobs) due to MATLAB 1-indexing
116 w(ist,c,hkvec) = w(ist,c,hkvec) + (ns-1-(j-1))*Pc{ist}(j, hkvec_c) * (Dc(ist,c) / ns);
119 case SchedStrategy.FCFS
120 if all(D(ist,:)==D(ist,1)) % product-form case
122 % Sum queue lengths of ALL classes (arrival theorem)
123 totalQueueLength = sum(L{ist}(:, hkvec_c));
124 w(ist,c,hkvec) = Dc(ist,c) * (1 + totalQueueLength);
126 % Sum queue lengths of ALL classes (arrival theorem)
127 totalQueueLength = sum(L{ist}(:, hkvec_c));
128 w(ist,c,hkvec) = (Dc(ist,c) / ns) * (1 + totalQueueLength);
130 % Pc{ist}(j,...) = Pr(j-1 jobs) due to MATLAB 1-indexing
131 w(ist,c,hkvec) = w(ist,c,hkvec) + (ns-1-(j-1))*Pc{ist}(j, hkvec_c) * (Dc(ist,c) / ns);
136 % Sum queue lengths of ALL classes (arrival theorem)
137 totalQueueLength = sum(L{ist}(:, hkvec_c));
138 w(ist,c,hkvec) = Dc(ist,c) * (1 + totalQueueLength);
140 % Multi-server FCFS class-dependent case
144 % Use Nc and prods for hash (matches Java)
145 hnvec_c = hashpop(oner(nvec,c),Nc,C,prods);
146 % Bcn calculation for multi-server using pure service times
150 % Weighted average service time based on queue composition
151 % Use epsilon protection for division (matches Java)
152 Bcn = S_pure(ist,c) + max(0,sum(nvec)-ns)/max(ns*(sum(nvec)-1), 1e-12) * (nvec*S_pure(ist,:)' - S_pure(ist,c));
154 w(ist,c,hkvec) = w(ist,c,hkvec) + Bcn * Pc{ist}(hnvec_c, hkvec_c);
156 nvec = pprod(nvec, kvec);
164 % Compute throughputs (per-station like Java)
166 % denom = sum over i of (v(i,c) * w(i,c,hkvec))
169 denom = denom + v(ist,c) * w(ist,c,hkvec);
171 % Per-station throughput: x(ist,c) = v(ist,c) * N(c) / denom
174 x(ist,c,hkvec) = v(ist,c) * kvec(c) / denom;
180 % Update queue lengths: L = x * w
183 L{ist}(c,hkvec) = x(ist,c,hkvec) * w(ist,c,hkvec);
185 if size(S(ist,:)) == 1
191 case SchedStrategy.PS
193 for n=1:min(S(ist),sum(kvec))
196 hkvec_c = hashpop(oner(kvec,c),Nc,C,prods);
197 Pc{ist}(1 + n, hkvec) = Pc{ist}(1 + n, hkvec) + Dc(ist,c) * (1/n) * x(ist,c,hkvec) * Pc{ist}(1+(n-1), hkvec_c);
200 Pc{ist}(1 + 0, hkvec) = max(eps,1-sum(Pc{ist}(1 + (1:min(S(ist),sum(kvec))), hkvec)));
203 case SchedStrategy.FCFS
204 if all(D(ist,:)==D(ist,1))
206 for n=1:(min(ns,sum(kvec))-1)
209 hkvec_c = hashpop(oner(kvec,c),Nc,C,prods);
210 Pc{ist}(1 + n, hkvec) = Pc{ist}(1 + n, hkvec) + Dc(ist,c) * (1/n) * x(ist,c,hkvec) * Pc{ist}(1+(n-1), hkvec_c);
213 Pc{ist}(1 + 0, hkvec) = max(eps,1-sum(Pc{ist}(1 + (1:min(ns,sum(kvec))), hkvec)));
218 nvec = pprod(nvec, kvec); % Skip zero vector like Java
221 % Use Nc and prods
for hash (matches Java)
222 hnvec = hashpop(nvec,Nc,C,prods);
226 % Use Nc and prods
for hash (matches Java)
227 hnvec_c = hashpop(oner(nvec,c),Nc,C,prods);
228 hkvec_c = hashpop(oner(kvec,c),Nc,C,prods);
229 % Bcn calculation
using pure service times (matches Java getBcn)
232 sumVal = nvec*S_pure(ist,:)
';
233 Bcn = Bcn + max(0,sum(nvec)-ns)/max(ns*(sum(nvec)-1), 1e-12) * (sumVal - S_pure(ist,c));
235 % Use 1/sum(nvec) instead of 1/nvec(c) to match Java
236 capacity_inv = 1/sum(nvec);
237 classProb = Bcn * capacity_inv * x(ist,c,hkvec) * Pc{ist}(hnvec_c, hkvec_c);
238 prob = prob + classProb;
241 Pc{ist}(hnvec, hkvec) = prob;
242 sumOfAllProbs = sumOfAllProbs + prob;
243 nvec = pprod(nvec, kvec);
245 Pc{ist}(1 + 0, hkvec) = max(1e-12, 1 - sumOfAllProbs);
249 kvec = pprod(kvec, Nc);
252% Throughput - compute system throughput as N(c) / sum(w) like Java
254 totalResponseTime = 0;
256 totalResponseTime = totalResponseTime + w(ist,c,hkvec);
258 if totalResponseTime > 0
259 XN(c) = Nc(c) / totalResponseTime;
267% Utilization Law: a c-server station holds D*X/c of its capacity. XN has been
268% replicated over the stations above, so read the per-class throughput from its
269% first row -- linear indexing XN(c) into the (M x R) replica would silently
270% return the WRONG class's throughput whenever M > 1.
279 UN(m,closedClasses(c)) = D(m,closedClasses(c)) * Xc(closedClasses(c)) / ns;
283CN(1:M,closedClasses) = w(1:M,1:C,hkvec);
285 QN(ist,closedClasses) = L{ist}(closedClasses,hkvec);
288T = table(XN,CN,QN,UN); %
for display purposes