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 = min(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 line_error(mfilename,'Unrecognized multiserver approximation method
');
212STeff = zeros(size(STchain_in)); % effective service time
213lldterm = repmat(lldterm, 1, K);
214% ljdterm is already (M, K) - contains either LJD or LJCD values
217 STeff(k,r) = STchain_in(k,r) * lldterm(k,r) * msterm(k) * cdterm(k,r) * ljdterm(k,r);
221%% if amva.qli or amva.fli, update now totArvlQlenSeenByClosed with STeff
223 case 'qli
' % Wang-Sevcik queue line
224 infset = sched == SchedStrategy.INF;
227 case {SchedStrategy.HOL}
230 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r);
232 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r));
233 qliden = sum(STeff(infset,r));
235 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses_ehprio{r})) - Qchain_in(m,r));
237 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - (1/(Nchain_in(r)-1))*(Qchain_in(k,r) - qlinum/qliden);
243 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r);
245 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r));
246 qliden = sum(STeff(infset,r));
248 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses)) - Qchain_in(m,r));
250 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - (1/(Nchain_in(r)-1))*(Qchain_in(k,r) - qlinum/qliden);
255 case 'fli
' % Wang-Sevcik fraction line
256 infset = sched == SchedStrategy.INF;
259 case {SchedStrategy.HOL}
262 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r);
264 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r));
265 qliden = sum(STeff(infset,r));
267 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses_ehprio{r})) - Qchain_in(m,r));
269 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - (2/Nchain_in(r))*Qchain_in(k,r) + qlinum/qliden;
275 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r);
277 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r));
278 qliden = sum(STeff(infset,r));
280 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses)) - Qchain_in(m,r));
282 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - (2/Nchain_in(r))*Qchain_in(k,r) + qlinum/qliden;
290%% compute response times from current queue-lengths
291for ir=1:length(nnzclasses)
295 %sdprio = setdiff(nnzclasses_ehprio{r},r);
300 case SchedStrategy.INF
301 Wchain(k,r) = STeff(k,r);
303 case SchedStrategy.PS
304 switch options.method
305 case {'qd
', 'lin
', 'qdlin
'} % QD-LIN interpolation
306 switch options.config.multiserver
307 case 'seidmann
' % in this case, qd handles only lld and cd scalings
308 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
310 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
312 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));
314 case {'default','softmin
'}
316 Wchain(k,r) = STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
318 switch options.method
319 case {'lin
', 'qdlin
'} % Linearizer
320 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));
322 Wchain(k,r) = STeff(k,r) * (1 + interpTotArvlQlen(k) + (Nt-1)*gamma(r,k));
327 switch options.config.multiserver
329 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
331 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
333 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k));
335 case {'default','softmin
'}
337 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
339 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k));
344 case SchedStrategy.DPS
346 line_error(mfilename,'Multi-server DPS not supported yet in AMVA solver.
')
348 w = schedparam; % DPS weight
349 tss = Inf; % time-scale separation threshold, this was originally at 5, presently it is disabled
350 %Uhiprio(k,r) = sum(Uchain(k,w(k,:)>tss*w(k,r))); % disabled at the moment
351 %STeff(k,r) = STeff(k,r) / (1-Uhiprio(k,r));
353 Wchain(k,r) = STeff(k,r) * (1 + selfArvlQlenSeenByClosed(k,r)); % class-r
354 for s=sd % slowdown due to classes s!=r
355 if w(k,s) == w(k,r) % handle gracefully 0/0 case
356 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,s);
357 elseif w(k,s)/w(k,r)<=tss
358 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,s) * w(k,s)/w(k,r);
359 elseif w(k,s)/w(k,r)>tss
360 % if there is time-scale separation, do nothing
361 % all is accounted for by 1/(1-Uhiprio)
366 case {SchedStrategy.FCFS, SchedStrategy.SIRO, SchedStrategy.LCFSPR}
368 Uchain_r = Uchain_in ./ repmat(Xchain_in,M,1) .* (repmat(Xchain_in,M,1) + repmat(tau(r,:),M,1));
371 deltaclass_r = ones(size(Xchain_in));
372 deltaclass_r(r) = deltaclass(r);
373 if sum(deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) < 0.75 % light-load case
374 Bk = ((deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:))); % note: this is in 0-1 as a utilization
375 else % high-load case
376 Bk = (deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)).^(nservers(k)-1);
382 hasLjd = ~isempty(ljdscaling) && any(~cellfun(@isempty, ljdscaling));
383 if nservers(k)==1 && (~isempty(lldscaling) || ~isempty(cdscaling) || hasLjd)
384 switch options.config.highvar % high SCV
386 Wchain(k,r) = STeff(k,r) * (1-sum(Uchain_r(k,ccl)));
388 Wchain(k,r) = Wchain(k,r) + STeff(k,s) * Uchain_r(k,s) * (1 + SCVchain_in(k,s))/2; % high SCV
391 Wchain(k,r) = STeff(k,r);
393 if any(ismember(ocl,r))
394 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r) + STeff(k,sd)*stationaryQlen(k,sd)');
396 switch options.method
397 %
case {
'default',
'amva.lin',
'lin',
'amva.qdlin',
'qdlin'} % Linearizer
398 % 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));
399 %case {'default', 'amva.lin
', 'lin
', 'amva.qdlin
', 'qdlin
'}
400 % fraction = Qchain_in ./ repmat(Nchain_in, size(Qchain_in, 1), 1);
401 % 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));
403 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) + STeff(k,sd)*stationaryQlen(k,sd)
');
407 switch options.config.multiserver
409 Wchain(k,r) = STeff(k,r); % high SCV
410 if any(ismember(ocl,r))
411 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,r) * Bk(r) + STeff(k,sd) * (stationaryQlen(k,sd) .* Bk(sd))';
413 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
414 % Rolia-Sevcik - method of layers - Sec IV.
415 switch options.method
416 %
case {
'default',
'amva.lin',
'lin',
'amva.qdlin',
'qdlin'} % Linearizer
417 % 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));
419 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) + STeff(k,sd) * (stationaryQlen(k,sd) .* Bk(sd))';
422 case {
'default',
'seidmann'}
423 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
424 Wchain(k,r) = Wchain(k,r) + STeff(k,r); % high SCV
425 if any(ismember(ocl,r))
426 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * deltaclass(r) * stationaryQlen(k,r)*Bk(r) + STeff(k,sd).*Bk(sd)*stationaryQlen(k,sd)
');
428 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
429 % Rolia-Sevcik - method of layers - Sec IV. (1/nservers(k)) term already in STeff
430 switch options.method
431 %case {'default', 'amva.lin
', 'lin
', 'amva.qdlin
','qdlin
'} % Linearizer
432 % 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));
434 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r) + STeff(k,sd).*Bk(sd)*stationaryQlen(k,sd)
');
441 case {SchedStrategy.HOL} % non-preemptive priority
443 Uchain_r = Uchain_in ./ repmat(Xchain_in,M,1) .* (repmat(Xchain_in,M,1) + repmat(tau(r,:),M,1));
445 switch options.config.np_priority
446 case {'default','cl
'} % Chandy-Lakshmi
448 for h=nnzclasses_hprio{r}
449 UHigherPrio = UHigherPrio + Vchain_in(k,h)*STeff(k,h)*(Xchain_in(h)-Qchain_in(k,h)*tau(h));
451 prioScaling = min([max([options.tol,1-UHigherPrio]),1-options.tol]);
452 case 'shadow
' % Sevcik's shadow server
454 for h=nnzclasses_hprio{r}
455 UHigherPrio = UHigherPrio + Vchain_in(k,h)*STeff(k,h)*Xchain_in(h);
457 prioScaling = min([max([options.tol,1-UHigherPrio]),1-options.tol]);
461 if sum(deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) < 0.75 % light-load case
462 switch options.config.multiserver
464 Bk = ((deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:))); % note:
this is in 0-1 as a utilization
465 case {
'default',
'seidmann'}
466 Bk = ((deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) / nservers(k)); % note:
this is in 0-1 as a utilization
468 else % high-load
case
469 switch options.config.multiserver
471 Bk = (deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)).^nservers(k); % Rolia
472 case {
'default',
'seidmann'}
473 Bk = (deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:) / nservers(k)).^nservers(k); % Rolia
480 hasLjd = ~isempty(ljdscaling) && any(~cellfun(@isempty, ljdscaling));
481 if nservers(k)==1 && (~isempty(lldscaling) || ~isempty(cdscaling) || hasLjd)
482 switch options.config.highvar % high SCV
484 Wchain(k,r) = (STeff(k,r) / prioScaling) * (1-sum(Uchain_r(k,ccl)));
487 for h=nnzclasses_hprio{s}
488 UHigherPrio_s = UHigherPrio_s + Vchain_in(k,h)*STeff(k,h)*(Xchain_in(h)-Qchain_in(k,h)*tau(h));
490 prioScaling_s = min([max([options.tol,1-UHigherPrio_s]),1-options.tol]);
491 Wchain(k,r) = Wchain(k,r) + (STeff(k,s) / prioScaling_s) * Uchain_r(k,s) * (1 + SCVchain_in(k,s))/2; % high SCV correction
494 Wchain(k,r) = STeff(k,r) / prioScaling;
497 if any(ismember(ocl,r))
498 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r)) / prioScaling;
500 %
switch options.method
501 %
case {
'default',
'amva.lin',
'lin',
'amva.qdlin',
'qdlin'} % Linearizer
502 % %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));
503 % Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) - STeff(k,r)*gamma(r,k,r)) / prioScaling;
505 %Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) + STeff(k,sdprio)*stationaryQlen(k,sdprio)');
506 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)) / prioScaling;
510 switch options.config.multiserver
512 Wchain(k,r) = STeff(k,r) / prioScaling; % high SCV
513 if any(ismember(ocl,r))
514 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,r) * Bk(r) / prioScaling;
516 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
517 % Rolia-Sevcik - method of layers - Sec IV.
518 %
switch options.method
519 %
case {
'default',
'amva.lin',
'lin',
'amva.qdlin',
'qdlin'} % Linearizer
520 % %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));
521 % 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;
523 %Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) + STeff(k,sdprio) * (stationaryQlen(k,sdprio) .* Bk(sdprio))';
524 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) / prioScaling;
527 case {
'default',
'seidmann'}
528 Wchain(k,r) = STeff(k,r) * (nservers(k)-1)/prioScaling; % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
529 Wchain(k,r) = Wchain(k,r) + STeff(k,r)/prioScaling; % high SCV
530 if any(ismember(ocl,r))
531 %Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r)*Bk(r) + STeff(k,sdprio).*Bk(sdprio)*stationaryQlen(k,sdprio)
');
532 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r)*Bk(r))/prioScaling;
534 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
535 % Rolia-Sevcik - method of layers - Sec IV. (1/nservers(k)) term already in STeff
536 %switch options.method
537 %case {'default', 'amva.lin
', 'lin
', 'amva.qdlin
','qdlin
'} % Linearizer
538 % %Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r) + STeff(k,sdprio).*Bk(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));
539 % 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;
541 %Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r) + STeff(k,sdprio).*Bk(sdprio)*stationaryQlen(k,sdprio)
');
542 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r)/prioScaling;