1function [Q,U,R,T,C,X,lG,totiter] = solver_mna_closed(sn, options)
3config = options.config;
9scv = sn.scv; scv(isnan(scv))=0;
15V = cellsum(sn.visits);
32 case {SchedStrategy.FCFS, SchedStrategy.INF,SchedStrategy.PS}
34 pie{ist}{k} = map_pie(PH{ist}{k});
35 D0{ist,k} = PH{ist}{k}{1};
36 if any(isnan(D0{ist,k}))
37 D0{ist,k} = -GlobalConstants.Immediate;
39 PH{ist}{k} = map_exponential(GlobalConstants.Immediate);
46lambda_lb = zeros(1,K);
47lambda_ub = zeros(1,K);
49 lambda_ub(k) = min(sn.rates(find(sn.nservers<Inf),k));
55a1 = []; a2 = []; % flow iterates shared with the nested sweeps
59% outer bisection on the per-class throughputs, driven against the closed
60% population target QNc by the generic DA driver; each sweep runs the inner
61% flow fixed point on the arrival rates a1 and SCVs a2
63outopts.config.da_nanstop = true; % legacy while-loop exited on NaN convergence measure
64[~, it_out] = da_fpi(@mna_outer_sweep, QN, outopts);
70 Q(ist,k) = sn.njobs(k);
71 T(ist,k) = sn.njobs(k)*sn.rates(ist,k);
72 R(ist,k) = Q(ist,k) ./ T(ist,k);
73 U(ist,k) = S(ist,k)*T(ist,k);
78 inchain = sn.inchain{c};
79 if isfinite(sn.njobs(c))
80 Q(:,c) = sn.njobs(c) .* Q(:,c) / sum(Q(:,c));
85 case SchedStrategy.INF
101 function [xnew, xref] = mna_outer_sweep(~, itout)
105 lambda_lb(k) = lambda(k);
107 lambda_ub(k) = lambda(k);
109 lambda(k) = (lambda_ub(k) + lambda_lb(k)) / 2;
129 if sn.nodetype(sn.stationToNode(jst)) ~= NodeType.Source
132 if rt((ist-1)*K+r, (jst-1)*K+s)>0
133 f2((ist-1)*K+r, (jst-1)*K+s) = 1; % C^2ij,r
142 inopts.iter_max = options.iter_max + 1; % legacy while-loop executed one extra sweep at the cap
143 inopts.config.da_nanstop = true;
144 da_fpi(@mna_flow_sweep, [a1(:); a2(:)], inopts);
148 ist = sn.nodeToStation(ind);
150 case {SchedStrategy.FCFS}
151 mu_ist = sn.rates(ist,1:K);
152 mu_ist(isnan(mu_ist))=0;
153 rho_ist_class = a1(ist,1:K)./(GlobalConstants.FineTol+sn.rates(ist,1:K));
154 rho_ist_class(isnan(rho_ist_class))=0;
155 lambda_ist = sum(a1(ist,:));
156 mi = sn.nservers(ist);
157 rho_ist = sum(rho_ist_class) / mi;
158 if rho_ist < 1-options.tol
162 arri_class = map_exponential(Inf);
164 arri_class = APH.fitMeanAndSCV(1/a1(ist,k),a2(ist,k)).getProcess; % MMAP repres of arrival process for class k at node ist
165 %arri_class = map_exponential(1/a1(ist,k));
166 arri_class = {arri_class{1},arri_class{2},arri_class{2}};
169 arri_node = arri_class;
171 %arri_node = mmap_super(arri_node,arri_class, 'default');
173 arri_node = mmap_super_safe({arri_node,arri_class}, config.space_max, 'default'); % combine arrival process from different class
178 maxLevel = sum(N(isfinite(N)))+1;
179 D = {arri_node{[1,3:end]}};
181 if map_lambda(D)< GlobalConstants.FineTol
183 pdistr = [1-GlobalConstants.FineTol, GlobalConstants.FineTol];
184 Qret{k} = GlobalConstants.FineTol / sn.rates(ist);
187 [pdistr] = MMAPPH1FCFS(D, {pie{ist}{:}}, {D0{ist,:}}, 'ncDistr
', maxLevel);
188 % rough approximation
190 pdistr_k = abs(pdistr(1:(N(k)+1)));
191 pdistr_k(end) = abs(1-sum(pdistr(1:end-1)));
192 pdistr_k = pdistr_k / sum(pdistr_k(1:(N(k)+1)));
193 Qret{k} = max(0,min(N(k),(0:N(k))*pdistr_k(1:(N(k)+1))'));
197 Q(ist,:) = cell2mat(Qret);
200 Q(ist,k) = sn.njobs(k);
205 R(ist,k) = Q(ist,k) ./ T(ist,k);
215 function [xnew, xref] = mna_flow_sweep(~, itnum)
216 xref = [a1(:); a2(:)];
218 inchain = sn.inchain{c};
219 Q(:,c) = sn.njobs(c) .* Q(:,c) / sum(Q(:,c));
226 Q(sn.refstat(k),k) = sn.njobs(k);
234 % update throughputs at all stations
237 inchain = sn.inchain{c};
239 T(m,inchain) = V(m,inchain) .* lambda(c);
248 lambda_i = sum(T(ist,:));
252 a1(ist,r) = a1(ist,r) + T(jst,s)*rt((jst-1)*K+s, (ist-1)*K+r);
253 a2(ist,r) = a2(ist,r) + (1/lambda_i) * f2((jst-1)*K+s, (ist-1)*K+r)*T(jst,s)*rt((jst-1)*K+s, (ist-1)*K+r);
259 % update flow trhough queueing station
262 ist = sn.nodeToStation(ind);
263 switch sn.nodetype(ind)
269 case SchedStrategy.INF
272 d2(ist,s) = a2(ist,s);
276 inchain = sn.inchain{c};
278 T(ist,k) = a1(ist,k);
279 U(ist,k) = S(ist,k)*T(ist,k);
280 Q(ist,k) = T(ist,k).*S(ist,k)*V(ist,k);
281 R(ist,k) = Q(ist,k)/T(ist,k);
284 case SchedStrategy.PS
286 inchain = sn.inchain{c};
288 T(ist,k) = lambda(c)*V(ist,k);
289 U(ist,k) = S(ist,k)*T(ist,k);
291 %Nc = sum(sn.njobs(inchain)); % closed population
292 Uden = min([1-GlobalConstants.FineTol,sum(U(ist,:))]);
294 Q(ist,k) = (U(ist,k)-U(ist,k)^(sum(sn.njobs(inchain))+1))/(1-Uden); % geometric bound type approximation
295 %Q(ist,k) = UN(ist,k)/(1-Uden);
296 R(ist,k) = Q(ist,k)/T(ist,k);
299 case {SchedStrategy.FCFS}
300 mu_ist = sn.rates(ist,1:K);
301 mu_ist(isnan(mu_ist))=0;
302 rho_ist_class = a1(ist,1:K)./(GlobalConstants.FineTol+sn.rates(ist,1:K));
303 rho_ist_class(isnan(rho_ist_class))=0;
304 lambda_ist = sum(a1(ist,:));
305 mi = sn.nservers(ist);
306 rho_ist = sum(rho_ist_class) / mi;
307 if rho_ist < 1-options.tol
310 mubar(ist) = lambda_ist ./ rho_ist;
314 c2(ist) = c2(ist) + a1(ist,r)/lambda_ist * (mubar(ist)/mi/mu_ist(r))^2 * (scv(ist,r)+1 );
319 d2(ist) = 1 + rho_ist^2*(c2(ist)-1)/sqrt(mi) + (1 - rho_ist^2) *(sum(a2(ist,:))-1);
322 Q(ist,k) = sn.njobs(k);
327 T(ist,k) = a1(ist,k);
328 U(ist,k) = T(ist,k) * S(ist,k) /sn.nservers(ist);
329 R(ist,k) = Q(ist,k) ./ T(ist,k);
335 switch sn.nodetype(ind)
337 line_error(mfilename,
'Fork nodes not supported yet by QNA solver.');
343 % splitting - update flow scvs
346 if sn.nodetype(sn.stationToNode(jst)) ~= NodeType.Source
349 if rt((ist-1)*K+r, (jst-1)*K+s)>0
350 f2((ist-1)*K+r, (jst-1)*K+s) = 1 + rt((ist-1)*K+r, (jst-1)*K+s) * (d2(ist)-1);
357 xnew = [a1(:); a2(:)];