1function [Q,U,R,T,C,X,lG,STeff,it,method] = solver_nc(sn, options)
3M = sn.nstations; %number of stations
5NK = sn.njobs
'; % initial population per class
14% Check for special LCFS + LCFS-PR 2-station network
15lcfsStat = find(sched == SchedStrategy.LCFS);
16lcfsprStat = find(sched == SchedStrategy.LCFSPR);
17if ~isempty(lcfsStat) && ~isempty(lcfsprStat)
18 % Validate LCFS network topology
19 if length(lcfsStat) ~= 1 || length(lcfsprStat) ~= 1
20 line_error(mfilename, 'LCFS NC
requires exactly one LCFS and one LCFS-PR station.
');
24 inchain = sn.inchain{c};
25 Nchain(c) = sum(NK(inchain)); %#ok<FNDSB>
28 line_error(mfilename, 'LCFS NC
requires a closed queueing network.
');
30 % Check for self-loops in routing matrix
32 nclasses = sn.nclasses;
33 for ist = [lcfsStat, lcfsprStat]
35 if rt((ist-1)*nclasses+r, (ist-1)*nclasses+r) > 0
36 line_error(mfilename, 'LCFS NC does not support self-loops at stations.
');
40 % Call specialized LCFS NC solver
41 [Q,U,R,T,C,X,lG] = solver_nc_lcfsqn(sn, options, lcfsStat, lcfsprStat);
46elseif ~isempty(lcfsStat)
47 % LCFS without LCFS-PR is not supported
48 line_error(mfilename, 'LCFS scheduling
requires a paired LCFS-PR station.
');
53 inchain = sn.inchain{c};
54 Nchain(c) = sum(NK(inchain)); %#ok<FNDSB>
56openChains = find(isinf(Nchain));
57closedChains = find(~isinf(Nchain));
64if all(sched~=SchedStrategy.FCFS) options.iter_max=1; end
66while max(abs(1-eta./eta_1)) > options.iter_tol & it < options.iter_max
72 [Lchain,STchain,Vchain,alpha,Nchain] = sn_get_demands_chain(sn);
74 inchain = sn.inchain{c};
75 isOpenChain = any(isinf(sn.njobs(inchain)));
77 % we assume that the visits in L(i,inchain) are equal to 1
78 if isOpenChain && ist == sn.refstat(inchain(1)) % if this is a source ST = 1 / arrival rates
79 lambda(c) = 1 ./ STchain(ist,c);
85 inchain = sn.inchain{c};
87 % we assume that the visits in L(i,inchain) are equal to 1
88 STchain(ist,c) = ST(ist,inchain) * alpha(ist,inchain)';
89 Lchain(ist,c) = Vchain(ist,c) * STchain(ist,c);
94 STchain(~isfinite(STchain))=0;
95 Lchain(~isfinite(Lchain))=0;
102 if isinf(nservers(ist)) % infinite server
103 infServers(end+1) = ist;
105 Z(ist,:) = Lchain(ist,:);
108 if strcmpi(options.method,
'exact') && nservers(ist)>1
109 %options.method =
'default';
111 line_warning(mfilename,sprintf(
'%s does not support exact multiserver yet. Switching to approximate method.\n',
'SolverNC'));
114 % Seidmann
's approximation
115 Lms(ist,:) = Lchain(ist,:) / nservers(ist);
117 Zms(ist,:) = Lchain(ist,:) * (nservers(ist)-1)/nservers(ist);
122 [lG, Xchain, Qchain, method] = pfqn_nc(lambda,Lms,Nchain,sum(Z,1)+sum(Zms,1), options);
124 if sum(Zms,1) > GlobalConstants.FineTol
125 % in this case, we need to use the iterative approximation below
131 [Q,U,R,T,C,X,lG,STeff,it,method] = deal([],[],[],[],[],[],[],[],1,options.method);
139 lGr(r) = pfqn_nc(lambda,Lms,oner(Nchain,r),sum(Z,1)+sum(Zms,1), options);
140 Xchain(r) = exp(lGr(r) - lG);
143 if isinf(nservers(ist)) % infinite server
144 Qchain(ist,r) = Lchain(ist,r) * Xchain(r);
146 % add replica of station i and move job of class r
148 % this is the most costly operation so we record
150 [lGar(ist,r),~,~,method] = pfqn_nc([lambda,0],[Lms(setdiff(1:size(Lms,1),ist),:),zeros(size(Lms,1)-1,1); Lms(ist,:),1], [oner(Nchain,r),1], [sum(Z,1)+sum(Zms,1),0], options);
151 Qchain(ist,r) = Zms(ist,r) * Xchain(r) + Lms(ist,r) * exp(lGar(ist,r) - lG);
155 Qchain(isnan(Qchain))=0;
159 Qchain(ist,r) = lambda(r)*Lchain(ist,r)/(1-lambda(openChains)*Lchain(ist,openChains)'/nservers(ist))*(1+sum(Qchain(ist,closedChains)));
163 % just fill the delay servers
167 if isinf(nservers(ist)) % infinite server
168 Qchain(ist,r) = Lchain(ist,r) * Xchain(r);
177 line_warning(mfilename,
'Normalizing constant computations produced a floating-point range exception. Model is likely too large.\n');
183 Rchain = Qchain ./ repmat(Xchain,M,1) ./ Vchain;
184 Rchain(infServers,:) = Lchain(infServers,:) ./ Vchain(infServers,:);
185 Tchain = repmat(Xchain,M,1) .* Vchain;
187 %Uchain = Tchain .* Lchain;
188 %Cchain = Nchain ./ Xchain - Z;
190 [Q,U,R,T,~,X] = sn_deaggregate_chain_results(sn, Lchain, ST, STchain, Vchain, alpha, [], [], Rchain, Tchain, [], Xchain);
191 STeff = ST;% effective service time at the last iteration
192 [ST,gamma,~,~,~,~,eta] = npfqn_nonexp_approx(options.config.highvar,sn,ST0,V,SCV,T,U,gamma,nservers);
195Q=abs(Q); R=abs(R); X=abs(X); U=abs(U);
196X(~isfinite(X))=0; U(~isfinite(U))=0; Q(~isfinite(Q))=0; R(~isfinite(R))=0;
198% renormalize qlen and tput to correct
for unforeseen population constraint deviations
200 inchain = sn.inchain{c};
201 Nchain(c) = sum(NK(inchain)); %#ok<FNDSB>
202 if isfinite(Nchain(c))
203 q_den = sum(sum(Q(:,inchain)));
205 ratio = Nchain(c)/ q_den;
209 Q(:,inchain) = ratio * Q(:,inchain);
210 X(inchain) = ratio * X(inchain);
211 T(:,inchain) = ratio * T(:,inchain);
212 U(:,inchain) = ratio * U(:,inchain);
213 R(:,inchain) = Q(:,inchain) ./ T(:,inchain);