1function [Wchain, STeff] = solver_amvald_forward(M, K, nservers, schedparam, lldscaling, cdscaling, ljdscaling, ljdcutoffs, ljcdscaling, ljcdcutoffs, sched, classprio, gamma, tau, Qchain_in, Xchain_in, Uchain_in, STchain_in, Vchain_in, Nchain_in, SCVchain_in, options)
3%Uhiprio = zeros(M,K); % utilization due to
"permanent jobs" in DPS
9Nt = sum(Nchain_in(isfinite(Nchain_in)));
10if all(isinf(Nchain_in))
13 delta = (Nt - 1) / Nt;
16deltaclass = (Nchain_in - 1) ./ Nchain_in;
17deltaclass(isinf(Nchain_in)) = 1;
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)
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
33 nnzclasses_eprio{r} = nnzclasses;
34 nnzclasses_hprio{r} = [];
35 nnzclasses_ehprio{r} = [];
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);
46 interpTotArvlQlen(k) = delta * sum(Qchain_in(k,nnzclasses));
48 selfArvlQlenSeenByClosed(k,r) = deltaclass(r) * Qchain_in(k,r); % qlen of same
class as arriving one
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)));
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);
57 stationaryQlen(k,r) = Qchain_in(k,r); % qlen of same
class as arriving one
61%% all methods use limited-load dependent (LLD) and
class-dependent (CD) corrections from QD-AMVA
63 lldscaling = ones(M,ceil(Nt));
68 if isempty(nnzclasses)
69 lldterm = pfqn_lldfun(1 + interpTotArvlQlen, lldscaling);
74 lldterm(:,r) = pfqn_lldfun(1 + interpTotArvlQlen + Nchain_in(ccl)*permute(gamma(r,k,ccl),3:-1:1) - gamma(r,k,r), lldscaling);
79 lldterm = pfqn_lldfun(1 + interpTotArvlQlen, lldscaling);
86 if ~isempty(cdscaling)
87 if isfinite(Nchain_in(r))
88 cdterm(:,r) = pfqn_cdfun(1 + selfArvlQlenSeenByClosed + (Nchain_in(r) - 1)*gamma(r,k,r), cdscaling); % qd-amva
class-dependence term
90 cdterm(:,r) = pfqn_cdfun(1 + stationaryQlen + (Nchain_in(r) - 1)*gamma(r,k,r), cdscaling); % qd-amva
class-dependence term
96 if ~isempty(cdscaling)
97 if isfinite(Nchain_in(r))
98 cdterm(:,r) = pfqn_cdfun(1 + selfArvlQlenSeenByClosed, cdscaling); % qd-amva
class-dependence term
100 cdterm(:,r) = pfqn_cdfun(1 + stationaryQlen, cdscaling); % qd-amva
class-dependence term
106%% Joint dependence correction terms
107% Both LJD and LJCD are indexed by population vector n = (n1, n2, ..., nK)
108% - LJD: scaling = table[idx(n)] - same scaling applied to all
classes
109% - LJCD: scaling_r = table_r[idx(n)] - each class r has its own table
110% If LJCD
is set for a station, it overrides LJD for that station.
112% For FES (Flow-Equivalent Server), the scaling tables contain throughputs X(n).
113% Since these are rates, we divide to get time scaling: ljdterm = 1/X(n).
114% For multi-class, we interpolate using neighboring population states.
116ljdterm = ones(M, K); % Combined term: (M x K) matrix
117hasLjcd = ~isempty(ljcdscaling) && any(~cellfun(@isempty, ljcdscaling));
118hasLjd = ~isempty(ljdscaling) && any(~cellfun(@isempty, ljdscaling));
122 % Get population vector from queue lengths at station k
123 nvec = Qchain_in(k, :);
125 if hasLjcd && ~isempty(ljcdscaling{k})
126 % LJCD: per-class scaling
127 % The scaling table contains throughputs X(n) indexed by population n.
128 % For FES, the
"population" is the number of jobs at the station.
129 % Use ceiling of queue length + 1 to account for the arriving job.
130 cutoffs = ljcdcutoffs{k};
132 % For FES, use ceiling of queue length as the population index
133 % The +1 helps
for single-
class but not multi-class
135 nIndex = ceil(nvec + 1);
136 nIndex = max(1, min(nIndex, cutoffs));
139 nIndex = max(0, min(nIndex, cutoffs));
141 idx = ljd_linearize(nIndex, cutoffs);
144 if r <= length(ljcdscaling{k}) && ~isempty(ljcdscaling{k}{r})
145 table = ljcdscaling{k}{r};
147 % Lookup throughput at population index
148 if idx <= length(table)
154 % Convert rate to time scaling (divide by throughput)
155 if Xval > GlobalConstants.FineTol
156 ljdterm(k, r) = 1.0 / Xval;
158 ljdterm(k, r) = 1.0; % No scaling when throughput
is zero
163 elseif hasLjd && ~isempty(ljdscaling{k})
164 % LJD: single scaling applied to all
classes
165 % Lookup: idx = linearize(n1, ..., nK), then table[idx]
166 nClamped = max(0, min(ceil(nvec), ljdcutoffs(k, :)));
167 idx = ljd_linearize(nClamped, ljdcutoffs(k, :));
168 if idx <= length(ljdscaling{k})
169 ljdterm(k, :) = ljdscaling{k}(idx); % Same value
for all
classes
174switch options.config.multiserver
175 case 'softmin' % softmin on every station, may not always converge
176 switch options.method
177 case {
'lin',
'qdlin'}
180 g = g + ((Nt-1)/Nt) * Nchain_in(r) * gamma(ccl,:,r);
182 msterm = pfqn_lldfun(1 + interpTotArvlQlen + mean(g, 1)
', [], nservers); % if native qd then account for multiserver in the correction terms
184 msterm = pfqn_lldfun(1 + interpTotArvlQlen + (Nt-1)*mean(gamma(ccl,:), 1)', [], nservers); %
if native qd then account
for multiserver in the correciton terms
187 msterm = ones(M,1) ./ nservers(:);
188 msterm(msterm==0) = 1; % infinite server
case
189 case 'default' % softmin on ps stations, seidmann on fcfs stations
190 switch options.method
191 case {
'lin',
'qdlin'}
194 g = g + ((Nt-1)/Nt) * Nchain_in(r) * gamma(ccl,:,r);
196 msterm = pfqn_lldfun(1 + interpTotArvlQlen + mean(g,1)
', [], nservers); % if native qd then account for multiserver in the correction terms
200 g = g + (Nt-1)*gamma(r,:);
202 msterm = pfqn_lldfun(1 + interpTotArvlQlen + mean(g), [], nservers); % if native qd then account for multiserver in the correction terms
204 fcfstypeset = find(sched==SchedStrategy.FCFS | sched==SchedStrategy.SIRO | sched==SchedStrategy.LCFSPR);
205 msterm(fcfstypeset) = 1 ./ nservers(fcfstypeset);
207 msterm = ones(M,1); % No demand scaling; multiserver handled via suriFactor in Wchain
209 line_error(mfilename,'Unrecognized multiserver approximation method
');
212% Compute Suri correction factor per station
213suriFactor = ones(M,1);
214if strcmp(options.config.multiserver, 'suri
')
219 if c > 1 && isfinite(c)
220 rho_k = min(sum(Uchain_in(k,:), 'omitnan
') / c, 1 - options.tol);
222 suriFactor(k) = rho_k^(suri_alpha * (c^suri_beta - 1)) / c;
224 suriFactor(k) = 1 / c;
226 elseif isinf(c) || c == 0
234STeff = zeros(size(STchain_in)); % effective service time
235lldterm = repmat(lldterm, 1, K);
236% ljdterm is already (M, K) - contains either LJD or LJCD values
239 STeff(k,r) = STchain_in(k,r) * lldterm(k,r) * msterm(k) * cdterm(k,r) * ljdterm(k,r);
243%% if amva.qli or amva.fli, update now totArvlQlenSeenByClosed with STeff
245 case 'qli
' % Wang-Sevcik queue line
246 infset = sched == SchedStrategy.INF;
249 case {SchedStrategy.HOL}
252 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r);
254 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r));
255 qliden = sum(STeff(infset,r));
257 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses_ehprio{r})) - Qchain_in(m,r));
259 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - (1/(Nchain_in(r)-1))*(Qchain_in(k,r) - qlinum/qliden);
265 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r);
267 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r));
268 qliden = sum(STeff(infset,r));
270 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses)) - Qchain_in(m,r));
272 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - (1/(Nchain_in(r)-1))*(Qchain_in(k,r) - qlinum/qliden);
277 case 'fli
' % Wang-Sevcik fraction line
278 infset = sched == SchedStrategy.INF;
281 case {SchedStrategy.HOL}
284 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r);
286 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r));
287 qliden = sum(STeff(infset,r));
289 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses_ehprio{r})) - Qchain_in(m,r));
291 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - (2/Nchain_in(r))*Qchain_in(k,r) + qlinum/qliden;
297 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r);
299 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r));
300 qliden = sum(STeff(infset,r));
302 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses)) - Qchain_in(m,r));
304 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - (2/Nchain_in(r))*Qchain_in(k,r) + qlinum/qliden;
312%% compute response times from current queue-lengths
313for ir=1:length(nnzclasses)
317 %sdprio = setdiff(nnzclasses_ehprio{r},r);
322 case SchedStrategy.INF
323 Wchain(k,r) = STeff(k,r);
325 case SchedStrategy.PS
326 switch options.method
327 case {'qd
', 'lin
', 'qdlin
'} % QD-LIN interpolation
328 switch options.config.multiserver
329 case 'seidmann
' % in this case, qd handles only lld and cd scalings
330 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
332 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
334 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));
336 case {'default','softmin
'}
338 Wchain(k,r) = STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
340 switch options.method
341 case {'lin
', 'qdlin
'} % Linearizer
342 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));
344 Wchain(k,r) = STeff(k,r) * (1 + interpTotArvlQlen(k) + (Nt-1)*gamma(r,k));
349 Wchain(k,r) = STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k) * suriFactor(k));
351 switch options.method
352 case {'lin
', 'qdlin
'}
353 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));
355 Wchain(k,r) = STeff(k,r) * (1 + (interpTotArvlQlen(k) + (Nt-1)*gamma(r,k)) * suriFactor(k));
360 switch options.config.multiserver
362 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
364 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
366 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k));
368 case {'default','softmin
'}
370 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
372 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k));
376 Wchain(k,r) = STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k) * suriFactor(k));
378 Wchain(k,r) = STeff(k,r) * (1 + (totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k)) * suriFactor(k));
383 case SchedStrategy.DPS
384 w = schedparam; % DPS weight
385 tss = Inf; % time-scale separation threshold, this was originally at 5, presently it is disabled
388 % Multi-server DPS: seidmann-style correction
389 % STeff already contains 1/nservers(k) factor from chain aggregation
390 Wchain(k,r) = STeff(k,r) * (nservers(k) - 1); % serial think time correction
393 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + selfArvlQlenSeenByClosed(k,r)); % class-r
394 for s=sd % slowdown due to classes s!=r
395 if w(k,s) == w(k,r) % handle gracefully 0/0 case
396 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,s);
397 elseif w(k,s)/w(k,r)<=tss
398 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,s) * w(k,s)/w(k,r);
399 elseif w(k,s)/w(k,r)>tss
400 % if there is time-scale separation, do nothing
401 % all is accounted for by 1/(1-Uhiprio)
405 case {SchedStrategy.FCFS, SchedStrategy.SIRO, SchedStrategy.LCFSPR}
407 Uchain_r = Uchain_in ./ repmat(Xchain_in,M,1) .* (repmat(Xchain_in,M,1) + repmat(tau(r,:),M,1));
410 deltaclass_r = ones(size(Xchain_in));
411 deltaclass_r(r) = deltaclass(r);
412 if sum(deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) < 0.75 % light-load case
413 Bk = ((deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:))); % note: this is in 0-1 as a utilization
414 else % high-load case
415 Bk = (deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)).^(nservers(k)-1);
421 hasLjd = ~isempty(ljdscaling) && any(~cellfun(@isempty, ljdscaling));
422 if nservers(k)==1 && (~isempty(lldscaling) || ~isempty(cdscaling) || hasLjd)
423 switch options.config.highvar % high SCV
425 Wchain(k,r) = STeff(k,r) * (1-sum(Uchain_r(k,ccl)));
427 Wchain(k,r) = Wchain(k,r) + STeff(k,s) * Uchain_r(k,s) * (1 + SCVchain_in(k,s))/2; % high SCV
430 Wchain(k,r) = STeff(k,r);
432 if any(ismember(ocl,r))
433 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r) + STeff(k,sd)*stationaryQlen(k,sd)');
435 switch options.method
436 %
case {
'default',
'amva.lin',
'lin',
'amva.qdlin',
'qdlin'} % Linearizer
437 % 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));
438 %case {'default', 'amva.lin
', 'lin
', 'amva.qdlin
', 'qdlin
'}
439 % fraction = Qchain_in ./ repmat(Nchain_in, size(Qchain_in, 1), 1);
440 % 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));
442 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) + STeff(k,sd)*stationaryQlen(k,sd)
');
446 switch options.config.multiserver
448 Wchain(k,r) = STeff(k,r); % high SCV
449 if any(ismember(ocl,r))
450 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,r) * Bk(r) + STeff(k,sd) * (stationaryQlen(k,sd) .* Bk(sd))';
452 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
453 % Rolia-Sevcik - method of layers - Sec IV.
454 switch options.method
455 %
case {
'default',
'amva.lin',
'lin',
'amva.qdlin',
'qdlin'} % Linearizer
456 % 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));
458 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) + STeff(k,sd) * (stationaryQlen(k,sd) .* Bk(sd))';
461 case {
'default',
'seidmann'}
462 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
463 Wchain(k,r) = Wchain(k,r) + STeff(k,r); % high SCV
464 if any(ismember(ocl,r))
465 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * deltaclass(r) * stationaryQlen(k,r)*Bk(r) + STeff(k,sd).*Bk(sd)*stationaryQlen(k,sd)
');
467 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
468 % Rolia-Sevcik - method of layers - Sec IV. (1/nservers(k)) term already in STeff
469 switch options.method
470 %case {'default', 'amva.lin
', 'lin
', 'amva.qdlin
','qdlin
'} % Linearizer
471 % 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));
473 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r) + STeff(k,sd).*Bk(sd)*stationaryQlen(k,sd)
');
477 % Suri multiserver: W = S * (1 + L_m * suriFactor)
478 Wchain(k,r) = STeff(k,r);
479 if any(ismember(ocl,r))
480 L_m = deltaclass(r) * stationaryQlen(k,r);
482 L_m = L_m + stationaryQlen(k,s);
484 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * L_m * suriFactor(k);
486 L_m = selfArvlQlenSeenByClosed(k,r);
488 L_m = L_m + stationaryQlen(k,s);
490 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * L_m * suriFactor(k);
496 case {SchedStrategy.HOL} % non-preemptive priority
498 Uchain_r = Uchain_in ./ repmat(Xchain_in,M,1) .* (repmat(Xchain_in,M,1) + repmat(tau(r,:),M,1));
500 switch options.config.np_priority
501 case {'default','cl
'} % Chandy-Lakshmi
503 for h=nnzclasses_hprio{r}
504 UHigherPrio = UHigherPrio + Vchain_in(k,h)*STeff(k,h)*(Xchain_in(h)-Qchain_in(k,h)*tau(h));
506 prioScaling = min([max([options.tol,1-UHigherPrio]),1-options.tol]);
507 case 'shadow
' % Sevcik's shadow server
509 for h=nnzclasses_hprio{r}
510 UHigherPrio = UHigherPrio + Vchain_in(k,h)*STeff(k,h)*Xchain_in(h);
512 prioScaling = min([max([options.tol,1-UHigherPrio]),1-options.tol]);
516 if sum(deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) < 0.75 % light-load case
517 switch options.config.multiserver
519 Bk = ((deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:))); % note:
this is in 0-1 as a utilization
520 case {
'default',
'seidmann'}
521 Bk = ((deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) / nservers(k)); % note:
this is in 0-1 as a utilization
523 Bk = ones(1,K); % not used; suriFactor handles multiserver correction
525 else % high-load
case
526 switch options.config.multiserver
528 Bk = (deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)).^nservers(k); % Rolia
529 case {
'default',
'seidmann'}
530 Bk = (deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:) / nservers(k)).^nservers(k); % Rolia
532 Bk = ones(1,K); % not used; suriFactor handles multiserver correction
539 hasLjd = ~isempty(ljdscaling) && any(~cellfun(@isempty, ljdscaling));
540 if nservers(k)==1 && (~isempty(lldscaling) || ~isempty(cdscaling) || hasLjd)
541 switch options.config.highvar % high SCV
543 Wchain(k,r) = (STeff(k,r) / prioScaling) * (1-sum(Uchain_r(k,ccl)));
546 for h=nnzclasses_hprio{s}
547 UHigherPrio_s = UHigherPrio_s + Vchain_in(k,h)*STeff(k,h)*(Xchain_in(h)-Qchain_in(k,h)*tau(h));
549 prioScaling_s = min([max([options.tol,1-UHigherPrio_s]),1-options.tol]);
550 Wchain(k,r) = Wchain(k,r) + (STeff(k,s) / prioScaling_s) * Uchain_r(k,s) * (1 + SCVchain_in(k,s))/2; % high SCV correction
553 Wchain(k,r) = STeff(k,r) / prioScaling;
556 if any(ismember(ocl,r))
557 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r)) / prioScaling;
559 %
switch options.method
560 %
case {
'default',
'amva.lin',
'lin',
'amva.qdlin',
'qdlin'} % Linearizer
561 % %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));
562 % Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) - STeff(k,r)*gamma(r,k,r)) / prioScaling;
564 %Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) + STeff(k,sdprio)*stationaryQlen(k,sdprio)');
565 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)) / prioScaling;
569 switch options.config.multiserver
571 Wchain(k,r) = STeff(k,r) / prioScaling; % high SCV
572 if any(ismember(ocl,r))
573 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,r) * Bk(r) / prioScaling;
575 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
576 % Rolia-Sevcik - method of layers - Sec IV.
577 %
switch options.method
578 %
case {
'default',
'amva.lin',
'lin',
'amva.qdlin',
'qdlin'} % Linearizer
579 % %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));
580 % 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;
582 %Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) + STeff(k,sdprio) * (stationaryQlen(k,sdprio) .* Bk(sdprio))';
583 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) / prioScaling;
586 case {
'default',
'seidmann'}
587 Wchain(k,r) = STeff(k,r) * (nservers(k)-1)/prioScaling; % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
588 Wchain(k,r) = Wchain(k,r) + STeff(k,r)/prioScaling; % high SCV
589 if any(ismember(ocl,r))
590 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r)*Bk(r))/prioScaling;
592 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r)/prioScaling;
595 % Suri multiserver: W = S * (1 + L_m * suriFactor) / prioScaling
596 Wchain(k,r) = STeff(k,r) / prioScaling;
597 if any(ismember(ocl,r))
598 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r) * suriFactor(k)) / prioScaling;
600 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * suriFactor(k)) / prioScaling;