LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
solver_amvald_forward.m
1function [Wchain, STeff] = solver_amvald_forward(M, K, nservers, schedparam, lldscaling, cdscaling, sched, classprio, gamma, tau, Qchain_in, Xchain_in, Uchain_in, STchain_in, Vchain_in, Nchain_in, SCVchain_in, options)
2
3%Uhiprio = zeros(M,K); % utilization due to "permanent jobs" in DPS
4
5if isempty(gamma)
6 gamma = zeros(M,K);
7end
8
9Nt = sum(Nchain_in(isfinite(Nchain_in)));
10if all(isinf(Nchain_in))
11 delta = 1;
12else
13 delta = (Nt - 1) / Nt;
14end
15
16deltaclass = (Nchain_in - 1) ./ Nchain_in;
17deltaclass(isinf(Nchain_in)) = 1;
18
19ocl = find(isinf(Nchain_in));
20ccl = find(isfinite(Nchain_in) & Nchain_in>0);
21nnzclasses = find(Nchain_in>0);
22nnzclasses_eprio = cell(1,length(nnzclasses));
23nnzclasses_hprio = cell(1,length(nnzclasses));
24nnzclasses_ehprio = cell(1,length(nnzclasses));
25if max(classprio) ~= min(classprio)
26 for r = nnzclasses
27 nnzclasses_eprio{r} = intersect(nnzclasses, find(classprio == classprio(r))); % equal prio
28 nnzclasses_hprio{r} = intersect(nnzclasses, find(classprio < classprio(r))); % higher prio (lower value = higher priority)
29 nnzclasses_ehprio{r} = intersect(nnzclasses, find(classprio <= classprio(r))); % equal or higher prio
30 end
31else
32 for r = nnzclasses
33 nnzclasses_eprio{r} = nnzclasses;
34 nnzclasses_hprio{r} = [];
35 nnzclasses_ehprio{r} = [];
36 end
37end
38
39%% evaluate lld and cd correction factors
40totArvlQlenSeenByOpen = zeros(K,M,1);
41interpTotArvlQlen = zeros(M,1);
42totArvlQlenSeenByClosed = zeros(M,K);
43stationaryQlen = zeros(M,K);
44selfArvlQlenSeenByClosed = zeros(M,K);
45for k=1:M
46 interpTotArvlQlen(k) = delta * sum(Qchain_in(k,nnzclasses));
47 for r = nnzclasses
48 selfArvlQlenSeenByClosed(k,r) = deltaclass(r) * Qchain_in(k,r); % qlen of same class as arriving one
49 switch sched(k)
50 case {SchedStrategy.HOL}
51 totArvlQlenSeenByOpen(r,k) = sum(Qchain_in(k,nnzclasses_ehprio{r}));
52 totArvlQlenSeenByClosed(k,r) = deltaclass(r) * Qchain_in(k,r) + sum(Qchain_in(k,setdiff(nnzclasses_ehprio{r},r)));
53 otherwise
54 totArvlQlenSeenByOpen(r,k) = sum(Qchain_in(k,nnzclasses));
55 totArvlQlenSeenByClosed(k,r) = deltaclass(r) * Qchain_in(k,r) + sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r);
56 end
57 stationaryQlen(k,r) = Qchain_in(k,r); % qlen of same class as arriving one
58 end
59end
60
61%% all methods use limited-load dependent (LLD) and class-dependent (CD) corrections from QD-AMVA
62if isempty(lldscaling)
63 lldscaling = ones(M,ceil(Nt));
64end
65
66switch options.method
67 case {'lin', 'qdlin'}
68 if isempty(nnzclasses) || isempty(ccl)
69 % gamma is populated only for closed classes, so with none the
70 % Linearizer correction is identically zero and the lld term
71 % degenerates to the uncorrected one.
72 lldterm = pfqn_lldfun(1 + interpTotArvlQlen, lldscaling);
73 else
74 lldterm = ones(M,K);
75 Ncl = Nchain_in(ccl); Ncl = Ncl(:); % |ccl| x 1
76 for r=nnzclasses
77 % Linearizer fraction correction seen by an arriving class-r
78 % job, evaluated at every station: entry k uses gamma(r,k,:).
79 gcorr = reshape(gamma(r,:,ccl), M, numel(ccl)) * Ncl - reshape(gamma(r,:,r), M, 1);
80 lldterm(:,r) = pfqn_lldfun(1 + interpTotArvlQlen + gcorr, lldscaling);
81 end
82 end
83 otherwise
84 lldterm = pfqn_lldfun(1 + interpTotArvlQlen, lldscaling);
85end
86
87cdterm = ones(M,K);
88switch options.method
89 case {'lin', 'qdlin'}
90 for r=nnzclasses
91 if ~isempty(cdscaling)
92 if isfinite(Nchain_in(r))
93 % self-fraction correction per station: entry k uses gamma(r,k,r)
94 gself = (Nchain_in(r) - 1) * reshape(gamma(r,:,r), M, 1);
95 cdterm(:,r) = pfqn_cdfun(1 + selfArvlQlenSeenByClosed + gself, cdscaling, r); % qd-amva class-dependence term beta_{i,r}
96 else
97 % gamma is zero for open classes, so the correction vanishes
98 % (the (Nchain-1) factor would otherwise be Inf*0 = NaN)
99 cdterm(:,r) = pfqn_cdfun(1 + stationaryQlen, cdscaling, r); % qd-amva class-dependence term beta_{i,r}
100 end
101 end
102 end
103 otherwise
104 for r=nnzclasses
105 if ~isempty(cdscaling)
106 if isfinite(Nchain_in(r))
107 cdterm(:,r) = pfqn_cdfun(1 + selfArvlQlenSeenByClosed, cdscaling, r); % qd-amva class-dependence term beta_{i,r}
108 else
109 cdterm(:,r) = pfqn_cdfun(1 + stationaryQlen, cdscaling, r); % qd-amva class-dependence term beta_{i,r}
110 end
111 end
112 end
113end
114
115switch options.config.multiserver
116 case 'softmin' % softmin on every station, may not always converge
117 switch options.method
118 case {'lin', 'qdlin'}
119 g = 0;
120 for r=ccl
121 g = g + ((Nt-1)/Nt) * Nchain_in(r) * gamma(ccl,:,r);
122 end
123 msterm = pfqn_lldfun(1 + interpTotArvlQlen + mean(g, 1)', [], nservers); % if native qd then account for multiserver in the correction terms
124 otherwise
125 msterm = pfqn_lldfun(1 + interpTotArvlQlen + (Nt-1)*mean(gamma(ccl,:), 1)', [], nservers); % if native qd then account for multiserver in the correciton terms
126 end
127 case 'seidmann'
128 msterm = ones(M,1) ./ nservers(:);
129 msterm(msterm==0) = 1; % infinite server case
130 case 'default' % softmin on ps stations, seidmann on fcfs stations
131 switch options.method
132 case {'lin', 'qdlin'}
133 g = 0;
134 for r=ccl
135 g = g + ((Nt-1)/Nt) * Nchain_in(r) * gamma(ccl,:,r);
136 end
137 msterm = pfqn_lldfun(1 + interpTotArvlQlen + mean(g,1)', [], nservers); % if native qd then account for multiserver in the correction terms
138 otherwise
139 g = 0;
140 for r=ccl
141 g = g + (Nt-1)*gamma(r,:);
142 end
143 msterm = pfqn_lldfun(1 + interpTotArvlQlen + mean(g), [], nservers); % if native qd then account for multiserver in the correction terms
144 end
145 fcfstypeset = find(sched==SchedStrategy.FCFS | sched==SchedStrategy.SIRO | sched==SchedStrategy.LCFSPR);
146 msterm(fcfstypeset) = 1 ./ nservers(fcfstypeset);
147 case 'suri'
148 msterm = ones(M,1); % No demand scaling; multiserver handled via suriFactor in Wchain
149 otherwise
150 line_error(mfilename,'Unrecognized multiserver approximation method');
151end
152
153% Compute Suri correction factor per station
154suriFactor = ones(M,1);
155if strcmp(options.config.multiserver, 'suri')
156 suri_alpha = 4.464;
157 suri_beta = 0.676;
158 for k=1:M
159 c = nservers(k);
160 if c > 1 && isfinite(c)
161 rho_k = min(sum(Uchain_in(k,:), 'omitnan') / c, 1 - options.tol);
162 if rho_k > 0
163 suriFactor(k) = rho_k^(suri_alpha * (c^suri_beta - 1)) / c;
164 else
165 suriFactor(k) = 1 / c;
166 end
167 elseif isinf(c) || c == 0
168 suriFactor(k) = 0;
169 end
170 end
171end
172
173Wchain = zeros(M,K);
174
175STeff = zeros(size(STchain_in)); % effective service time
176lldterm = repmat(lldterm, 1, K);
177for r=nnzclasses
178 for k=1:M
179 STeff(k,r) = STchain_in(k,r) * lldterm(k,r) * msterm(k) * cdterm(k,r);
180 end
181end
182
183%% if amva.qli or amva.fli, update now totArvlQlenSeenByClosed with STeff
184switch options.method
185 case 'qli' % Wang-Sevcik queue line
186 infset = sched == SchedStrategy.INF;
187 for k=1:M
188 switch sched(k)
189 case {SchedStrategy.HOL}
190 for r = nnzclasses
191 if Nchain_in(r) == 1
192 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r);
193 else
194 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r));
195 qliden = sum(STeff(infset,r));
196 for m=1:M
197 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses_ehprio{r})) - Qchain_in(m,r));
198 end
199 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - (1/(Nchain_in(r)-1))*(Qchain_in(k,r) - qlinum/qliden);
200 end
201 end
202 otherwise
203 for r = nnzclasses
204 if Nchain_in(r) == 1
205 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r);
206 else
207 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r));
208 qliden = sum(STeff(infset,r));
209 for m=1:M
210 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses)) - Qchain_in(m,r));
211 end
212 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - (1/(Nchain_in(r)-1))*(Qchain_in(k,r) - qlinum/qliden);
213 end
214 end
215 end
216 end
217 case 'fli' % Wang-Sevcik fraction line
218 infset = sched == SchedStrategy.INF;
219 for k=1:M
220 switch sched(k)
221 case {SchedStrategy.HOL}
222 for r = nnzclasses
223 if Nchain_in(r) == 1
224 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r);
225 else
226 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r));
227 qliden = sum(STeff(infset,r));
228 for m=1:M
229 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses_ehprio{r})) - Qchain_in(m,r));
230 end
231 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - (2/Nchain_in(r))*Qchain_in(k,r) + qlinum/qliden;
232 end
233 end
234 otherwise
235 for r = nnzclasses
236 if Nchain_in(r) == 1
237 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r);
238 else
239 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r));
240 qliden = sum(STeff(infset,r));
241 for m=1:M
242 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses)) - Qchain_in(m,r));
243 end
244 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - (2/Nchain_in(r))*Qchain_in(k,r) + qlinum/qliden;
245 end
246 end
247
248 end
249 end
250end
251
252%% compute response times from current queue-lengths
253for ir=1:length(nnzclasses)
254 r=nnzclasses(ir);
255 sd = nnzclasses;
256 sd(ir)=[];
257 %sdprio = setdiff(nnzclasses_ehprio{r},r);
258
259 for k=1:M
260
261 switch sched(k)
262 case SchedStrategy.INF
263 Wchain(k,r) = STeff(k,r);
264
265 case SchedStrategy.PS
266 switch options.method
267 case {'qd', 'lin', 'qdlin'} % QD-LIN interpolation
268 switch options.config.multiserver
269 case 'seidmann' % in this case, qd handles only lld and cd scalings
270 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
271 if ismember(r,ocl)
272 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
273 else
274 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + interpTotArvlQlen(k) + Nchain_in(ccl)*permute(gamma(r,k,ccl),3:-1:1) - gamma(r,k,r));
275 end
276 case {'default','softmin'}
277 if ismember(r,ocl)
278 Wchain(k,r) = STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
279 else
280 switch options.method
281 case {'lin', 'qdlin'} % Linearizer
282 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + interpTotArvlQlen(k) + Nchain_in(ccl)*permute(gamma(r,k,ccl),3:-1:1) - gamma(r,k,r));
283 otherwise
284 Wchain(k,r) = STeff(k,r) * (1 + interpTotArvlQlen(k) + (Nt-1)*gamma(r,k));
285 end
286 end
287 case 'suri'
288 if ismember(r,ocl)
289 Wchain(k,r) = STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k) * suriFactor(k));
290 else
291 switch options.method
292 case {'lin', 'qdlin'}
293 Wchain(k,r) = STeff(k,r) * (1 + (interpTotArvlQlen(k) + Nchain_in(ccl)*permute(gamma(r,k,ccl),3:-1:1) - gamma(r,k,r)) * suriFactor(k));
294 otherwise
295 Wchain(k,r) = STeff(k,r) * (1 + (interpTotArvlQlen(k) + (Nt-1)*gamma(r,k)) * suriFactor(k));
296 end
297 end
298 end
299 otherwise
300 switch options.config.multiserver
301 case 'seidmann'
302 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
303 if ismember(r,ocl)
304 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
305 else
306 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k));
307 end
308 case {'default','softmin'}
309 if ismember(r,ocl)
310 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
311 else
312 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k));
313 end
314 case 'suri'
315 if ismember(r,ocl)
316 Wchain(k,r) = STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k) * suriFactor(k));
317 else
318 Wchain(k,r) = STeff(k,r) * (1 + (totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k)) * suriFactor(k));
319 end
320 end
321 end
322
323 case SchedStrategy.DPS
324 w = schedparam; % DPS weight
325 tss = Inf; % time-scale separation threshold, this was originally at 5, presently it is disabled
326
327 if nservers(k) > 1
328 % Multi-server DPS: seidmann-style correction
329 % STeff already contains 1/nservers(k) factor from chain aggregation
330 Wchain(k,r) = STeff(k,r) * (nservers(k) - 1); % serial think time correction
331 end
332
333 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + selfArvlQlenSeenByClosed(k,r)); % class-r
334 for s=sd % slowdown due to classes s!=r
335 if w(k,s) == w(k,r) % handle gracefully 0/0 case
336 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,s);
337 elseif w(k,s)/w(k,r)<=tss
338 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,s) * w(k,s)/w(k,r);
339 elseif w(k,s)/w(k,r)>tss
340 % if there is time-scale separation, do nothing
341 % all is accounted for by 1/(1-Uhiprio)
342 end
343 end
344
345 case {SchedStrategy.FCFS, SchedStrategy.SIRO, SchedStrategy.LCFSPR}
346 if STeff(k,r) > 0
347 Uchain_r = Uchain_in ./ repmat(Xchain_in,M,1) .* (repmat(Xchain_in,M,1) + repmat(tau(r,:),M,1));
348
349 if nservers(k)>1
350 deltaclass_r = ones(size(Xchain_in));
351 deltaclass_r(r) = deltaclass(r);
352 if sum(deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) < 0.75 % light-load case
353 Bk = ((deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:))); % note: this is in 0-1 as a utilization
354 else % high-load case
355 Bk = (deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)).^(nservers(k)-1);
356 end
357 else
358 Bk = ones(1,K);
359 end
360
361 if nservers(k)==1 && (~isempty(lldscaling) || ~isempty(cdscaling))
362 switch options.config.highvar % high SCV
363 case 'hvmva'
364 Wchain(k,r) = STeff(k,r) * (1-sum(Uchain_r(k,ccl)));
365 for s=ccl
366 Wchain(k,r) = Wchain(k,r) + STeff(k,s) * Uchain_r(k,s) * (1 + SCVchain_in(k,s))/2; % high SCV
367 end
368 otherwise % default
369 Wchain(k,r) = STeff(k,r);
370 end
371 if any(ismember(ocl,r))
372 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r) + STeff(k,sd)*stationaryQlen(k,sd)');
373 else
374 switch options.method
375 %case {'default', 'amva.lin', 'lin', 'amva.qdlin','qdlin'} % Linearizer
376 % Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) + STeff(k,sd)*stationaryQlen(k,sd)') + (STeff(k,ccl).*Nchain(ccl)*permute(gamma(r,k,ccl),3:-1:1) - STeff(k,r)*gamma(r,k,r));
377 %case {'default', 'amva.lin', 'lin', 'amva.qdlin', 'qdlin'}
378 % fraction = Qchain_in ./ repmat(Nchain_in, size(Qchain_in, 1), 1);
379 % Wchain(k, r) = Wchain(k, r) + STeff(k, r) * (Nchain_in(ccl) * fraction(k, ccl)' - fraction(k, r)) + STeff(k, r) * (Nchain_in(ccl)*permute(gamma(r,k,ccl),3:-1:1) - gamma(r,k,r));
380 otherwise
381 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) + STeff(k,sd)*stationaryQlen(k,sd)');
382 end
383 end
384 else
385 switch options.config.multiserver
386 case 'softmin'
387 Wchain(k,r) = STeff(k,r); % high SCV
388 if any(ismember(ocl,r))
389 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,r) * Bk(r) + STeff(k,sd) * (stationaryQlen(k,sd) .* Bk(sd))';
390 else
391 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
392 % Rolia-Sevcik - method of layers - Sec IV.
393 switch options.method
394 %case {'default', 'amva.lin', 'lin', 'amva.qdlin','qdlin'} % Linearizer
395 % Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) + STeff(k,sd) * (stationaryQlen(k,sd) .* Bk(sd))' + (STeff(k,ccl).*Nchain(ccl)*permute(gamma(r,k,ccl),3:-1:1) - STeff(k,r)*gamma(r,k,r));
396 otherwise
397 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) + STeff(k,sd) * (stationaryQlen(k,sd) .* Bk(sd))';
398 end
399 end
400 case {'default','seidmann'}
401 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
402 Wchain(k,r) = Wchain(k,r) + STeff(k,r); % high SCV
403 if any(ismember(ocl,r))
404 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * deltaclass(r) * stationaryQlen(k,r)*Bk(r) + STeff(k,sd).*Bk(sd)*stationaryQlen(k,sd)');
405 else
406 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
407 % Rolia-Sevcik - method of layers - Sec IV. (1/nservers(k)) term already in STeff
408 switch options.method
409 %case {'default', 'amva.lin', 'lin', 'amva.qdlin','qdlin'} % Linearizer
410 % Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r) + STeff(k,sd).*Bk(sd)*stationaryQlen(k,sd)') + (STeff(k,ccl).*Nchain(ccl)*permute(gamma(r,k,ccl),3:-1:1) - STeff(k,r)*gamma(r,k,r));
411 otherwise
412 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r) + STeff(k,sd).*Bk(sd)*stationaryQlen(k,sd)');
413 end
414 end
415 case 'suri'
416 % Suri multiserver: W = S * (1 + L_m * suriFactor)
417 Wchain(k,r) = STeff(k,r);
418 if any(ismember(ocl,r))
419 L_m = deltaclass(r) * stationaryQlen(k,r);
420 for s=sd
421 L_m = L_m + stationaryQlen(k,s);
422 end
423 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * L_m * suriFactor(k);
424 else
425 L_m = selfArvlQlenSeenByClosed(k,r);
426 for s=sd
427 L_m = L_m + stationaryQlen(k,s);
428 end
429 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * L_m * suriFactor(k);
430 end
431 end
432 end
433 end
434
435 case {SchedStrategy.HOL} % non-preemptive priority
436 if STeff(k,r) > 0
437 Uchain_r = Uchain_in ./ repmat(Xchain_in,M,1) .* (repmat(Xchain_in,M,1) + repmat(tau(r,:),M,1));
438
439 switch options.config.np_priority
440 case {'default','cl'} % Chandy-Lakshmi
441 UHigherPrio=0;
442 for h=nnzclasses_hprio{r}
443 UHigherPrio = UHigherPrio + Vchain_in(k,h)*STeff(k,h)*(Xchain_in(h)-Qchain_in(k,h)*tau(h));
444 end
445 prioScaling = min([max([options.tol,1-UHigherPrio]),1-options.tol]);
446 case 'shadow' % Sevcik's shadow server
447 UHigherPrio=0;
448 for h=nnzclasses_hprio{r}
449 UHigherPrio = UHigherPrio + Vchain_in(k,h)*STeff(k,h)*Xchain_in(h);
450 end
451 prioScaling = min([max([options.tol,1-UHigherPrio]),1-options.tol]);
452 end
453
454 if nservers(k)>1
455 if sum(deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) < 0.75 % light-load case
456 switch options.config.multiserver
457 case 'softmin'
458 Bk = ((deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:))); % note: this is in 0-1 as a utilization
459 case {'default','seidmann'}
460 Bk = ((deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) / nservers(k)); % note: this is in 0-1 as a utilization
461 case 'suri'
462 Bk = ones(1,K); % not used; suriFactor handles multiserver correction
463 end
464 else % high-load case
465 switch options.config.multiserver
466 case 'softmin'
467 Bk = (deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)).^nservers(k); % Rolia
468 case {'default','seidmann'}
469 Bk = (deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:) / nservers(k)).^nservers(k); % Rolia
470 case 'suri'
471 Bk = ones(1,K); % not used; suriFactor handles multiserver correction
472 end
473 end
474 else
475 Bk = ones(1,K);
476 end
477
478 if nservers(k)==1 && (~isempty(lldscaling) || ~isempty(cdscaling))
479 switch options.config.highvar % high SCV
480 case 'hvmva'
481 Wchain(k,r) = (STeff(k,r) / prioScaling) * (1-sum(Uchain_r(k,ccl)));
482 for s=ccl
483 UHigherPrio_s=0;
484 for h=nnzclasses_hprio{s}
485 UHigherPrio_s = UHigherPrio_s + Vchain_in(k,h)*STeff(k,h)*(Xchain_in(h)-Qchain_in(k,h)*tau(h));
486 end
487 prioScaling_s = min([max([options.tol,1-UHigherPrio_s]),1-options.tol]);
488 Wchain(k,r) = Wchain(k,r) + (STeff(k,s) / prioScaling_s) * Uchain_r(k,s) * (1 + SCVchain_in(k,s))/2; % high SCV correction
489 end
490 otherwise % default
491 Wchain(k,r) = STeff(k,r) / prioScaling;
492 end
493
494 if any(ismember(ocl,r))
495 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r)) / prioScaling;
496 else
497 %switch options.method
498 %case {'default', 'amva.lin', 'lin', 'amva.qdlin','qdlin'} % Linearizer
499 % %Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) + STeff(k,sdprio)*stationaryQlen(k,sdprio)') + (STeff(k,[r,sdprio]).*Nchain([r,sdprio])*permute(gamma(r,k,[r,sdprio]),3:-1:1) - STeff(k,r)*gamma(r,k,r));
500 % Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) - STeff(k,r)*gamma(r,k,r)) / prioScaling;
501 % otherwise
502 %Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) + STeff(k,sdprio)*stationaryQlen(k,sdprio)');
503 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)) / prioScaling;
504 %end
505 end
506 else
507 switch options.config.multiserver
508 case 'softmin'
509 Wchain(k,r) = STeff(k,r) / prioScaling; % high SCV
510 if any(ismember(ocl,r))
511 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,r) * Bk(r) / prioScaling;
512 else
513 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
514 % Rolia-Sevcik - method of layers - Sec IV.
515 %switch options.method
516 %case {'default', 'amva.lin', 'lin', 'amva.qdlin','qdlin'} % Linearizer
517 % %Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) + STeff(k,sdprio) * (stationaryQlen(k,sdprio) .* Bk(sdprio))' + (STeff(k,[r,sdprio]).*Nchain([r,sdprio])*permute(gamma(r,k,[r,sdprio]),3:-1:1) - STeff(k,r)*gamma(r,k,r));
518 % Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) / prioScaling + (STeff(k,[r]).*Nchain([r])*permute(gamma(r,k,[r]),3:-1:1) - STeff(k,r)*gamma(r,k,r)) / prioScaling;
519 % otherwise
520 %Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) + STeff(k,sdprio) * (stationaryQlen(k,sdprio) .* Bk(sdprio))';
521 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) / prioScaling;
522 %end
523 end
524 case {'default','seidmann'}
525 Wchain(k,r) = STeff(k,r) * (nservers(k)-1)/prioScaling; % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
526 Wchain(k,r) = Wchain(k,r) + STeff(k,r)/prioScaling; % high SCV
527 if any(ismember(ocl,r))
528 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r)*Bk(r))/prioScaling;
529 else
530 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r)/prioScaling;
531 end
532 case 'suri'
533 % Suri multiserver: W = S * (1 + L_m * suriFactor) / prioScaling
534 Wchain(k,r) = STeff(k,r) / prioScaling;
535 if any(ismember(ocl,r))
536 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r) * suriFactor(k)) / prioScaling;
537 else
538 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * suriFactor(k)) / prioScaling;
539 end
540 end
541 end
542 end
543
544 end
545 end
546end
547end
Definition Station.m:245