LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
pfqn_schmidt.m
1%{
2%{
3 % @file pfqn_schmidt.m
4 % @brief Schmidt's exact MVA for networks with general scheduling disciplines.
5%}
6%}
7
8%{
9%{
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.
20 % @return CN Cycle times.
21 % @return T Results table.
22%}
23%}
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)
26
27% utilization in general ld case does not work
28[M,R] = size(D);
29closedClasses = 1:R;
30XN = zeros(1,R);
31UN = zeros(M,R);
32CN = zeros(M,R);
33QN = zeros(M,R);
34
35% Default visit ratios to ones if not provided
36if nargin < 5 || isempty(v)
37 v = ones(M,R);
38end
39
40% Compute pure service times from demands: S_pure = D / v
41% D is demands (= visit_ratio * service_time), so S_pure = D / v
42% Bcn calculations need pure service times, not demands
43S_pure = D ./ max(v, 1e-12); % Protect against division by zero
44
45C = length(closedClasses); % number of closed classes
46Dc = D(:,closedClasses);
47Nc = N(closedClasses);
48prods = zeros(1,C); % needed for fast hashing
49for r=1:C
50 prods(r)=prod(Nc(1:r-1)+1);
51end
52% Start at nc=(0,...,0)
53kvec = pprod(Nc);
54% Initialize L and Pc
55L = cell(1, M); % mean queue-length
56Pc = cell(1, M); % state probabilities (empty cells for stations that don't need them)
57for ist=1:M
58 % Always initialize L for ALL stations (queue lengths needed everywhere)
59 L{ist} = zeros(R, prod(1+Nc)); % mean queue-length
60 switch sched(ist)
61 case SchedStrategy.INF
62 % No Pc needed for infinite server
63 case SchedStrategy.PS
64 if ~all(S(ist,:) == 1)
65 % Multi-server PS needs state probabilities
66 Pc{ist} = zeros(1 + sum(Nc), prod(1+Nc)); % Pr(j|N)
67 end
68 case SchedStrategy.FCFS
69 if all(D(ist,:)==D(ist,1)) % class-independent
70 if ~all(S(ist,:) == 1) % multi server
71 Pc{ist} = zeros(1 + sum(Nc), prod(1+Nc)); % Pr(j|N)
72 end
73 else % class-dependent - needs vector probabilities
74 Pc{ist} = zeros(prod(1+Nc), prod(1+Nc)); % Pr(jvec|N)
75 end
76 end
77end
78% Per-station throughput like Java: x(ist,c,hkvec) = v(ist,c) * kvec(c) / denom
79x = zeros(M,C,prod(1+Nc));
80w = zeros(M,C,prod(1+Nc));
81for ist=1:M
82 if ~isempty(Pc{ist})
83 Pc{ist}(1 + 0, hashpop(kvec,Nc,C,prods)) = 1.0; %Pj(0|0) = 1
84 end
85end
86u = zeros(M,C);
87% Population recursion
88while all(kvec>=0) && all(kvec <= Nc)
89 nc = sum(kvec);
90 kprods = zeros(1,C); % needed for fast hashing
91 for r=1:C
92 kprods(r)=prod(kvec(1:r-1)+1);
93 end
94 for ist=1:M
95 for c=1:C
96 hkvec = hashpop(kvec,Nc,C,prods);
97 hkvec_c = hashpop(oner(kvec,c),Nc,C,prods);
98 if size(S(ist,:)) == 1
99 ns = S(ist);
100 else
101 ns = S(ist,c);
102 end
103 if kvec(c) > 0
104 switch sched(ist)
105 case SchedStrategy.INF
106 w(ist,c,hkvec) = D(ist,c);
107 case SchedStrategy.PS
108 if ns == 1
109 % Sum queue lengths of ALL classes (arrival theorem)
110 totalQueueLength = sum(L{ist}(:, hkvec_c));
111 w(ist,c,hkvec) = Dc(ist,c) * (1 + totalQueueLength);
112 else
113 % Sum queue lengths of ALL classes (arrival theorem)
114 totalQueueLength = sum(L{ist}(:, hkvec_c));
115 w(ist,c,hkvec) = (Dc(ist,c) / ns) * (1 + totalQueueLength);
116 for j=1:ns-1
117 % Pc{ist}(j,...) = Pr(j-1 jobs) due to MATLAB 1-indexing
118 w(ist,c,hkvec) = w(ist,c,hkvec) + (ns-1-(j-1))*Pc{ist}(j, hkvec_c) * (Dc(ist,c) / ns);
119 end
120 end
121 case SchedStrategy.FCFS
122 if all(D(ist,:)==D(ist,1)) % product-form case
123 if ns == 1
124 % Sum queue lengths of ALL classes (arrival theorem)
125 totalQueueLength = sum(L{ist}(:, hkvec_c));
126 w(ist,c,hkvec) = Dc(ist,c) * (1 + totalQueueLength);
127 else
128 % Sum queue lengths of ALL classes (arrival theorem)
129 totalQueueLength = sum(L{ist}(:, hkvec_c));
130 w(ist,c,hkvec) = (Dc(ist,c) / ns) * (1 + totalQueueLength);
131 for j=1:ns-1
132 % Pc{ist}(j,...) = Pr(j-1 jobs) due to MATLAB 1-indexing
133 w(ist,c,hkvec) = w(ist,c,hkvec) + (ns-1-(j-1))*Pc{ist}(j, hkvec_c) * (Dc(ist,c) / ns);
134 end
135 end
136 else
137 if ns == 1
138 % Sum queue lengths of ALL classes (arrival theorem)
139 totalQueueLength = sum(L{ist}(:, hkvec_c));
140 w(ist,c,hkvec) = Dc(ist,c) * (1 + totalQueueLength);
141 else
142 % Multi-server FCFS class-dependent case
143 nvec = pprod(kvec);
144 while nvec >= 0
145 if nvec(c) > 0
146 % Use Nc and prods for hash (matches Java)
147 hnvec_c = hashpop(oner(nvec,c),Nc,C,prods);
148 % Bcn calculation for multi-server using pure service times
149 if sum(nvec) <= ns
150 Bcn = S_pure(ist,c);
151 else
152 % Weighted average service time based on queue composition
153 % Use epsilon protection for division (matches Java)
154 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));
155 end
156 w(ist,c,hkvec) = w(ist,c,hkvec) + Bcn * Pc{ist}(hnvec_c, hkvec_c);
157 end
158 nvec = pprod(nvec, kvec);
159 end
160 end
161 end
162 end
163 end
164 end
165 end
166 % Compute throughputs (per-station like Java)
167 for c=1:C
168 % denom = sum over i of (v(i,c) * w(i,c,hkvec))
169 denom = 0;
170 for ist=1:M
171 denom = denom + v(ist,c) * w(ist,c,hkvec);
172 end
173 % Per-station throughput: x(ist,c) = v(ist,c) * N(c) / denom
174 for ist=1:M
175 if denom > 0
176 x(ist,c,hkvec) = v(ist,c) * kvec(c) / denom;
177 else
178 x(ist,c,hkvec) = 0;
179 end
180 end
181 end
182 % Update queue lengths: L = x * w
183 for ist=1:M
184 for c=1:C
185 L{ist}(c,hkvec) = x(ist,c,hkvec) * w(ist,c,hkvec);
186 end
187 if size(S(ist,:)) == 1
188 ns = S(ist);
189 else
190 ns = S(ist,c);
191 end
192 switch sched(ist)
193 case SchedStrategy.PS
194 if ns > 1
195 for n=1:min(S(ist),sum(kvec))
196 for c=1:C
197 if kvec(c) > 0
198 hkvec_c = hashpop(oner(kvec,c),Nc,C,prods);
199 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 end
201 end
202 Pc{ist}(1 + 0, hkvec) = max(eps,1-sum(Pc{ist}(1 + (1:min(S(ist),sum(kvec))), hkvec)));
203 end
204 end
205 case SchedStrategy.FCFS
206 if all(D(ist,:)==D(ist,1))
207 if ns > 1
208 for n=1:(min(ns,sum(kvec))-1)
209 for c=1:C
210 if kvec(c) > 0
211 hkvec_c = hashpop(oner(kvec,c),Nc,C,prods);
212 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 end
214 end
215 Pc{ist}(1 + 0, hkvec) = max(eps,1-sum(Pc{ist}(1 + (1:min(ns,sum(kvec))), hkvec)));
216 end
217 end
218 else
219 nvec = pprod(kvec);
220 nvec = pprod(nvec, kvec); % Skip zero vector like Java
221 sumOfAllProbs = 0;
222 while nvec >= 0
223 % Use Nc and prods for hash (matches Java)
224 hnvec = hashpop(nvec,Nc,C,prods);
225 prob = 0;
226 for c=1:C
227 if nvec(c)>0
228 % Use Nc and prods for hash (matches Java)
229 hnvec_c = hashpop(oner(nvec,c),Nc,C,prods);
230 hkvec_c = hashpop(oner(kvec,c),Nc,C,prods);
231 % Bcn calculation using pure service times (matches Java getBcn)
232 Bcn = S_pure(ist,c);
233 if sum(nvec) > 1
234 sumVal = nvec*S_pure(ist,:)';
235 Bcn = Bcn + max(0,sum(nvec)-ns)/max(ns*(sum(nvec)-1), 1e-12) * (sumVal - S_pure(ist,c));
236 end
237 % Use 1/sum(nvec) instead of 1/nvec(c) to match Java
238 capacity_inv = 1/sum(nvec);
239 classProb = Bcn * capacity_inv * x(ist,c,hkvec) * Pc{ist}(hnvec_c, hkvec_c);
240 prob = prob + classProb;
241 end
242 end
243 Pc{ist}(hnvec, hkvec) = prob;
244 sumOfAllProbs = sumOfAllProbs + prob;
245 nvec = pprod(nvec, kvec);
246 end
247 Pc{ist}(1 + 0, hkvec) = max(1e-12, 1 - sumOfAllProbs);
248 end
249 end
250 end
251 kvec = pprod(kvec, Nc);
252end
253
254% Throughput - compute system throughput as N(c) / sum(w) like Java
255for c=1:C
256 totalResponseTime = 0;
257 for ist=1:M
258 totalResponseTime = totalResponseTime + w(ist,c,hkvec);
259 end
260 if totalResponseTime > 0
261 XN(c) = Nc(c) / totalResponseTime;
262 else
263 XN(c) = 0;
264 end
265end
266if M>1
267 XN = repmat(XN,M,1);
268end
269% Utilization
270UN(1:M,closedClasses) = u(1:M,1:C); % this will return 0
271% Response time
272CN(1:M,closedClasses) = w(1:M,1:C,hkvec);
273for ist=1:M
274 QN(ist,closedClasses) = L{ist}(closedClasses,hkvec);
275end
276
277T = table(XN,CN,QN,UN); % for display purposes
278
279end