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, jdscaling, 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
115% joint-dependence term eta_i (non-product-form). Evaluated identically to
116% cdterm; kept in a separate field/term to preserve the product-form vs joint
117% distinction (see pfqn_jdfun). cd and jd are mutually exclusive per station,
118% so at most one of cdterm/jdterm differs from 1 at any station.
119jdterm = ones(M,K);
120switch options.method
121 case {'lin', 'qdlin'}
122 for r=nnzclasses
123 if ~isempty(jdscaling)
124 if isfinite(Nchain_in(r))
125 gself = (Nchain_in(r) - 1) * reshape(gamma(r,:,r), M, 1);
126 jdterm(:,r) = pfqn_jdfun(1 + selfArvlQlenSeenByClosed + gself, jdscaling, r);
127 else
128 jdterm(:,r) = pfqn_jdfun(1 + stationaryQlen, jdscaling, r);
129 end
130 end
131 end
132 otherwise
133 for r=nnzclasses
134 if ~isempty(jdscaling)
135 if isfinite(Nchain_in(r))
136 jdterm(:,r) = pfqn_jdfun(1 + selfArvlQlenSeenByClosed, jdscaling, r);
137 else
138 jdterm(:,r) = pfqn_jdfun(1 + stationaryQlen, jdscaling, r);
139 end
140 end
141 end
142end
143
144switch options.config.multiserver
145 case 'softmin' % softmin on every station, may not always converge
146 switch options.method
147 case {'lin', 'qdlin'}
148 g = 0;
149 for r=ccl
150 g = g + ((Nt-1)/Nt) * Nchain_in(r) * gamma(ccl,:,r);
151 end
152 msterm = pfqn_lldfun(1 + interpTotArvlQlen + mean(g, 1)', [], nservers); % if native qd then account for multiserver in the correction terms
153 otherwise
154 msterm = pfqn_lldfun(1 + interpTotArvlQlen + (Nt-1)*mean(gamma(ccl,:), 1)', [], nservers); % if native qd then account for multiserver in the correciton terms
155 end
156 case 'seidmann'
157 msterm = ones(M,1) ./ nservers(:);
158 msterm(msterm==0) = 1; % infinite server case
159 case 'default' % softmin on ps stations, seidmann on fcfs stations
160 switch options.method
161 case {'lin', 'qdlin'}
162 g = 0;
163 for r=ccl
164 g = g + ((Nt-1)/Nt) * Nchain_in(r) * gamma(ccl,:,r);
165 end
166 msterm = pfqn_lldfun(1 + interpTotArvlQlen + mean(g,1)', [], nservers); % if native qd then account for multiserver in the correction terms
167 otherwise
168 g = 0;
169 for r=ccl
170 g = g + (Nt-1)*gamma(r,:);
171 end
172 msterm = pfqn_lldfun(1 + interpTotArvlQlen + mean(g), [], nservers); % if native qd then account for multiserver in the correction terms
173 end
174 fcfstypeset = find(sched==SchedStrategy.FCFS | sched==SchedStrategy.SIRO | sched==SchedStrategy.LCFSPR);
175 msterm(fcfstypeset) = 1 ./ nservers(fcfstypeset);
176 case 'suri'
177 msterm = ones(M,1); % No demand scaling; multiserver handled via suriFactor in Wchain
178 otherwise
179 line_error(mfilename,'Unrecognized multiserver approximation method');
180end
181
182% Compute Suri correction factor per station
183suriFactor = ones(M,1);
184if strcmp(options.config.multiserver, 'suri')
185 suri_alpha = 4.464;
186 suri_beta = 0.676;
187 for k=1:M
188 c = nservers(k);
189 if c > 1 && isfinite(c)
190 rho_k = min(sum(Uchain_in(k,:), 'omitnan') / c, 1 - options.tol);
191 if rho_k > 0
192 suriFactor(k) = rho_k^(suri_alpha * (c^suri_beta - 1)) / c;
193 else
194 suriFactor(k) = 1 / c;
195 end
196 elseif isinf(c) || c == 0
197 suriFactor(k) = 0;
198 end
199 end
200end
201
202Wchain = zeros(M,K);
203
204STeff = zeros(size(STchain_in)); % effective service time
205lldterm = repmat(lldterm, 1, K);
206for r=nnzclasses
207 for k=1:M
208 STeff(k,r) = STchain_in(k,r) * lldterm(k,r) * msterm(k) * cdterm(k,r) * jdterm(k,r);
209 end
210end
211
212%% if amva.qli or amva.fli, update now totArvlQlenSeenByClosed with STeff
213switch options.method
214 case 'qli' % Wang-Sevcik queue line
215 infset = sched == SchedStrategy.INF;
216 for k=1:M
217 switch sched(k)
218 case {SchedStrategy.HOL}
219 for r = nnzclasses
220 if Nchain_in(r) == 1
221 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r);
222 else
223 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r));
224 qliden = sum(STeff(infset,r));
225 for m=1:M
226 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses_ehprio{r})) - Qchain_in(m,r));
227 end
228 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - (1/(Nchain_in(r)-1))*(Qchain_in(k,r) - qlinum/qliden);
229 end
230 end
231 otherwise
232 for r = nnzclasses
233 if Nchain_in(r) == 1
234 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r);
235 else
236 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r));
237 qliden = sum(STeff(infset,r));
238 for m=1:M
239 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses)) - Qchain_in(m,r));
240 end
241 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - (1/(Nchain_in(r)-1))*(Qchain_in(k,r) - qlinum/qliden);
242 end
243 end
244 end
245 end
246 case 'fli' % Wang-Sevcik fraction line
247 infset = sched == SchedStrategy.INF;
248 for k=1:M
249 switch sched(k)
250 case {SchedStrategy.HOL}
251 for r = nnzclasses
252 if Nchain_in(r) == 1
253 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r);
254 else
255 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses_ehprio{r})) - Qchain_in(k,r));
256 qliden = sum(STeff(infset,r));
257 for m=1:M
258 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses_ehprio{r})) - Qchain_in(m,r));
259 end
260 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses_ehprio{r})) - (2/Nchain_in(r))*Qchain_in(k,r) + qlinum/qliden;
261 end
262 end
263 otherwise
264 for r = nnzclasses
265 if Nchain_in(r) == 1
266 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r);
267 else
268 qlinum = STeff(k,r) * (1+sum(Qchain_in(k,nnzclasses)) - Qchain_in(k,r));
269 qliden = sum(STeff(infset,r));
270 for m=1:M
271 qliden = qliden + STeff(m,r) * (1+sum(Qchain_in(m,nnzclasses)) - Qchain_in(m,r));
272 end
273 totArvlQlenSeenByClosed(k,r) = sum(Qchain_in(k,nnzclasses)) - (2/Nchain_in(r))*Qchain_in(k,r) + qlinum/qliden;
274 end
275 end
276
277 end
278 end
279end
280
281%% compute response times from current queue-lengths
282for ir=1:length(nnzclasses)
283 r=nnzclasses(ir);
284 sd = nnzclasses;
285 sd(ir)=[];
286 %sdprio = setdiff(nnzclasses_ehprio{r},r);
287
288 for k=1:M
289
290 switch sched(k)
291 case SchedStrategy.INF
292 Wchain(k,r) = STeff(k,r);
293
294 case SchedStrategy.PS
295 switch options.method
296 case {'qd', 'lin', 'qdlin'} % QD-LIN interpolation
297 switch options.config.multiserver
298 case 'seidmann' % in this case, qd handles only lld and cd scalings
299 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
300 if ismember(r,ocl)
301 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
302 else
303 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));
304 end
305 case {'default','softmin'}
306 if ismember(r,ocl)
307 Wchain(k,r) = STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
308 else
309 switch options.method
310 case {'lin', 'qdlin'} % Linearizer
311 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));
312 otherwise
313 Wchain(k,r) = STeff(k,r) * (1 + interpTotArvlQlen(k) + (Nt-1)*gamma(r,k));
314 end
315 end
316 case 'suri'
317 if ismember(r,ocl)
318 Wchain(k,r) = STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k) * suriFactor(k));
319 else
320 switch options.method
321 case {'lin', 'qdlin'}
322 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));
323 otherwise
324 Wchain(k,r) = STeff(k,r) * (1 + (interpTotArvlQlen(k) + (Nt-1)*gamma(r,k)) * suriFactor(k));
325 end
326 end
327 end
328 otherwise
329 switch options.config.multiserver
330 case 'seidmann'
331 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
332 if ismember(r,ocl)
333 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
334 else
335 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k));
336 end
337 case {'default','softmin'}
338 if ismember(r,ocl)
339 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k));
340 else
341 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k));
342 end
343 case 'suri'
344 if ismember(r,ocl)
345 Wchain(k,r) = STeff(k,r) * (1 + totArvlQlenSeenByOpen(r,k) * suriFactor(k));
346 else
347 Wchain(k,r) = STeff(k,r) * (1 + (totArvlQlenSeenByClosed(k) + (Nt-1)*gamma(r,k)) * suriFactor(k));
348 end
349 end
350 end
351
352 case SchedStrategy.DPS
353 w = schedparam; % DPS weight
354 tss = Inf; % time-scale separation threshold, this was originally at 5, presently it is disabled
355
356 if nservers(k) > 1
357 % Multi-server DPS: seidmann-style correction
358 % STeff already contains 1/nservers(k) factor from chain aggregation
359 Wchain(k,r) = STeff(k,r) * (nservers(k) - 1); % serial think time correction
360 end
361
362 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * (1 + selfArvlQlenSeenByClosed(k,r)); % class-r
363 for s=sd % slowdown due to classes s!=r
364 if w(k,s) == w(k,r) % handle gracefully 0/0 case
365 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,s);
366 elseif w(k,s)/w(k,r)<=tss
367 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,s) * w(k,s)/w(k,r);
368 elseif w(k,s)/w(k,r)>tss
369 % if there is time-scale separation, do nothing
370 % all is accounted for by 1/(1-Uhiprio)
371 end
372 end
373
374 case {SchedStrategy.FCFS, SchedStrategy.SIRO, SchedStrategy.LCFSPR}
375 if STeff(k,r) > 0
376 Uchain_r = Uchain_in ./ repmat(Xchain_in,M,1) .* (repmat(Xchain_in,M,1) + repmat(tau(r,:),M,1));
377
378 if nservers(k)>1
379 deltaclass_r = ones(size(Xchain_in));
380 deltaclass_r(r) = deltaclass(r);
381 if sum(deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) < 0.75 % light-load case
382 Bk = ((deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:))); % note: this is in 0-1 as a utilization
383 else % high-load case
384 Bk = (deltaclass_r .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)).^(nservers(k)-1);
385 end
386 else
387 Bk = ones(1,K);
388 end
389
390 if nservers(k)==1 && (~isempty(lldscaling) || ~isempty(cdscaling) || ~isempty(jdscaling))
391 switch options.config.highvar % high SCV
392 case 'hvmva'
393 Wchain(k,r) = STeff(k,r) * (1-sum(Uchain_r(k,ccl)));
394 for s=ccl
395 Wchain(k,r) = Wchain(k,r) + STeff(k,s) * Uchain_r(k,s) * (1 + SCVchain_in(k,s))/2; % high SCV
396 end
397 otherwise % default
398 Wchain(k,r) = STeff(k,r);
399 end
400 if any(ismember(ocl,r))
401 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r) + STeff(k,sd)*stationaryQlen(k,sd)');
402 else
403 switch options.method
404 %case {'default', 'amva.lin', 'lin', 'amva.qdlin','qdlin'} % Linearizer
405 % 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));
406 %case {'default', 'amva.lin', 'lin', 'amva.qdlin', 'qdlin'}
407 % fraction = Qchain_in ./ repmat(Nchain_in, size(Qchain_in, 1), 1);
408 % 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));
409 otherwise
410 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) + STeff(k,sd)*stationaryQlen(k,sd)');
411 end
412 end
413 else
414 switch options.config.multiserver
415 case 'softmin'
416 Wchain(k,r) = STeff(k,r); % high SCV
417 if any(ismember(ocl,r))
418 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,r) * Bk(r) + STeff(k,sd) * (stationaryQlen(k,sd) .* Bk(sd))';
419 else
420 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
421 % Rolia-Sevcik - method of layers - Sec IV.
422 switch options.method
423 %case {'default', 'amva.lin', 'lin', 'amva.qdlin','qdlin'} % Linearizer
424 % 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));
425 otherwise
426 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) + STeff(k,sd) * (stationaryQlen(k,sd) .* Bk(sd))';
427 end
428 end
429 case {'default','seidmann'}
430 Wchain(k,r) = STeff(k,r) * (nservers(k)-1); % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
431 Wchain(k,r) = Wchain(k,r) + STeff(k,r); % high SCV
432 if any(ismember(ocl,r))
433 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * deltaclass(r) * stationaryQlen(k,r)*Bk(r) + STeff(k,sd).*Bk(sd)*stationaryQlen(k,sd)');
434 else
435 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
436 % Rolia-Sevcik - method of layers - Sec IV. (1/nservers(k)) term already in STeff
437 switch options.method
438 %case {'default', 'amva.lin', 'lin', 'amva.qdlin','qdlin'} % Linearizer
439 % 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));
440 otherwise
441 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r) + STeff(k,sd).*Bk(sd)*stationaryQlen(k,sd)');
442 end
443 end
444 case 'suri'
445 % Suri multiserver: W = S * (1 + L_m * suriFactor)
446 Wchain(k,r) = STeff(k,r);
447 if any(ismember(ocl,r))
448 L_m = deltaclass(r) * stationaryQlen(k,r);
449 for s=sd
450 L_m = L_m + stationaryQlen(k,s);
451 end
452 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * L_m * suriFactor(k);
453 else
454 L_m = selfArvlQlenSeenByClosed(k,r);
455 for s=sd
456 L_m = L_m + stationaryQlen(k,s);
457 end
458 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * L_m * suriFactor(k);
459 end
460 end
461 end
462 end
463
464 case {SchedStrategy.HOL} % non-preemptive priority
465 if STeff(k,r) > 0
466 Uchain_r = Uchain_in ./ repmat(Xchain_in,M,1) .* (repmat(Xchain_in,M,1) + repmat(tau(r,:),M,1));
467
468 switch options.config.np_priority
469 case {'default','cl'} % Chandy-Lakshmi
470 UHigherPrio=0;
471 for h=nnzclasses_hprio{r}
472 UHigherPrio = UHigherPrio + Vchain_in(k,h)*STeff(k,h)*(Xchain_in(h)-Qchain_in(k,h)*tau(h));
473 end
474 prioScaling = min([max([options.tol,1-UHigherPrio]),1-options.tol]);
475 case 'shadow' % Sevcik's shadow server
476 UHigherPrio=0;
477 for h=nnzclasses_hprio{r}
478 UHigherPrio = UHigherPrio + Vchain_in(k,h)*STeff(k,h)*Xchain_in(h);
479 end
480 prioScaling = min([max([options.tol,1-UHigherPrio]),1-options.tol]);
481 end
482
483 if nservers(k)>1
484 if sum(deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) < 0.75 % light-load case
485 switch options.config.multiserver
486 case 'softmin'
487 Bk = ((deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:))); % note: this is in 0-1 as a utilization
488 case {'default','seidmann'}
489 Bk = ((deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)) / nservers(k)); % note: this is in 0-1 as a utilization
490 case 'suri'
491 Bk = ones(1,K); % not used; suriFactor handles multiserver correction
492 end
493 else % high-load case
494 switch options.config.multiserver
495 case 'softmin'
496 Bk = (deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:)).^nservers(k); % Rolia
497 case {'default','seidmann'}
498 Bk = (deltaclass .* Xchain_in .* Vchain_in(k,:) .* STeff(k,:) / nservers(k)).^nservers(k); % Rolia
499 case 'suri'
500 Bk = ones(1,K); % not used; suriFactor handles multiserver correction
501 end
502 end
503 else
504 Bk = ones(1,K);
505 end
506
507 if nservers(k)==1 && (~isempty(lldscaling) || ~isempty(cdscaling) || ~isempty(jdscaling))
508 switch options.config.highvar % high SCV
509 case 'hvmva'
510 Wchain(k,r) = (STeff(k,r) / prioScaling) * (1-sum(Uchain_r(k,ccl)));
511 for s=ccl
512 UHigherPrio_s=0;
513 for h=nnzclasses_hprio{s}
514 UHigherPrio_s = UHigherPrio_s + Vchain_in(k,h)*STeff(k,h)*(Xchain_in(h)-Qchain_in(k,h)*tau(h));
515 end
516 prioScaling_s = min([max([options.tol,1-UHigherPrio_s]),1-options.tol]);
517 Wchain(k,r) = Wchain(k,r) + (STeff(k,s) / prioScaling_s) * Uchain_r(k,s) * (1 + SCVchain_in(k,s))/2; % high SCV correction
518 end
519 otherwise % default
520 Wchain(k,r) = STeff(k,r) / prioScaling;
521 end
522
523 if any(ismember(ocl,r))
524 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r)) / prioScaling;
525 else
526 %switch options.method
527 %case {'default', 'amva.lin', 'lin', 'amva.qdlin','qdlin'} % Linearizer
528 % %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));
529 % Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) - STeff(k,r)*gamma(r,k,r)) / prioScaling;
530 % otherwise
531 %Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) + STeff(k,sdprio)*stationaryQlen(k,sdprio)');
532 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r)) / prioScaling;
533 %end
534 end
535 else
536 switch options.config.multiserver
537 case 'softmin'
538 Wchain(k,r) = STeff(k,r) / prioScaling; % high SCV
539 if any(ismember(ocl,r))
540 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * stationaryQlen(k,r) * Bk(r) / prioScaling;
541 else
542 % FCFS approximation + reducing backlog proportionally to server utilizations; somewhat similar to
543 % Rolia-Sevcik - method of layers - Sec IV.
544 %switch options.method
545 %case {'default', 'amva.lin', 'lin', 'amva.qdlin','qdlin'} % Linearizer
546 % %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));
547 % 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;
548 % otherwise
549 %Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) + STeff(k,sdprio) * (stationaryQlen(k,sdprio) .* Bk(sdprio))';
550 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * Bk(r) / prioScaling;
551 %end
552 end
553 case {'default','seidmann'}
554 Wchain(k,r) = STeff(k,r) * (nservers(k)-1)/prioScaling; % multi-server correction with serial think time, (1/nservers(k)) term already in STeff
555 Wchain(k,r) = Wchain(k,r) + STeff(k,r)/prioScaling; % high SCV
556 if any(ismember(ocl,r))
557 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r)*Bk(r))/prioScaling;
558 else
559 Wchain(k,r) = Wchain(k,r) + STeff(k,r) * selfArvlQlenSeenByClosed(k,r)*Bk(r)/prioScaling;
560 end
561 case 'suri'
562 % Suri multiserver: W = S * (1 + L_m * suriFactor) / prioScaling
563 Wchain(k,r) = STeff(k,r) / prioScaling;
564 if any(ismember(ocl,r))
565 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * stationaryQlen(k,r) * suriFactor(k)) / prioScaling;
566 else
567 Wchain(k,r) = Wchain(k,r) + (STeff(k,r) * selfArvlQlenSeenByClosed(k,r) * suriFactor(k)) / prioScaling;
568 end
569 end
570 end
571 end
572
573 end
574 end
575end
576end