LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
solver_nc.m
1function [Q,U,R,T,C,X,lG,STeff,it,method] = solver_nc(sn, options)
2
3M = sn.nstations; %number of stations
4nservers = sn.nservers;
5NK = sn.njobs'; % initial population per class
6sched = sn.sched;
7C = sn.nchains;
8SCV = sn.scv;
9V = cellsum(sn.visits);
10ST = 1 ./ sn.rates;
11ST(isnan(ST)) = 0;
12ST0 = ST;
13
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.');
21 end
22 Nchain = zeros(1,C);
23 for c=1:C
24 inchain = sn.inchain{c};
25 Nchain(c) = sum(NK(inchain)); %#ok<FNDSB>
26 end
27 if any(isinf(Nchain))
28 line_error(mfilename, 'LCFS NC requires a closed queueing network.');
29 end
30 % Check for self-loops in routing matrix
31 rt = sn.rt;
32 nclasses = sn.nclasses;
33 for ist = [lcfsStat, lcfsprStat]
34 for r = 1:nclasses
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.');
37 end
38 end
39 end
40 % Call specialized LCFS NC solver
41 [Q,U,R,T,C,X,lG] = solver_nc_lcfsqn(sn, options, lcfsStat, lcfsprStat);
42 STeff = ST;
43 it = 1;
44 method = 'lcfsqn.ca';
45 return;
46elseif ~isempty(lcfsStat)
47 % LCFS without LCFS-PR is not supported
48 line_error(mfilename, 'LCFS scheduling requires a paired LCFS-PR station.');
49end
50
51Nchain = zeros(1,C);
52for c=1:C
53 inchain = sn.inchain{c};
54 Nchain(c) = sum(NK(inchain)); %#ok<FNDSB>
55end
56openChains = find(isinf(Nchain));
57closedChains = find(~isinf(Nchain));
58
59gamma = zeros(1,M);
60eta_1 = zeros(1,M);
61eta = ones(1,M);
62C = sn.nchains;
63
64if all(sched~=SchedStrategy.FCFS) options.iter_max=1; end
65it = 0;
66while max(abs(1-eta./eta_1)) > options.iter_tol & it < options.iter_max
67 it = it + 1;
68 eta_1 = eta;
69
70 if it==1
71 lambda = zeros(1,C);
72 [Lchain,STchain,Vchain,alpha,Nchain] = sn_get_demands_chain(sn);
73 for c=1:C
74 inchain = sn.inchain{c};
75 isOpenChain = any(isinf(sn.njobs(inchain)));
76 for ist=1:M
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);
80 end
81 end
82 end
83 else
84 for c=1:C
85 inchain = sn.inchain{c};
86 for ist=1:M
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);
90 end
91 end
92 end
93
94 STchain(~isfinite(STchain))=0;
95 Lchain(~isfinite(Lchain))=0;
96
97 Lms = zeros(M,C);
98 Z = zeros(M,C);
99 Zms = zeros(M,C);
100 infServers = [];
101 for ist=1:M
102 if isinf(nservers(ist)) % infinite server
103 infServers(end+1) = ist;
104 Lms(ist,:) = 0;
105 Z(ist,:) = Lchain(ist,:);
106 Zms(ist,:) = 0;
107 else
108 if strcmpi(options.method,'exact') && nservers(ist)>1
109 %options.method = 'default';
110 if options.verbose
111 line_warning(mfilename,sprintf('%s does not support exact multiserver yet. Switching to approximate method.\n', 'SolverNC'));
112 end
113 end
114 % Seidmann's approximation
115 Lms(ist,:) = Lchain(ist,:) / nservers(ist);
116 Z(ist,:) = 0;
117 Zms(ist,:) = Lchain(ist,:) * (nservers(ist)-1)/nservers(ist);
118 end
119 end
120
121 % step 1
122 [lG, Xchain, Qchain, method] = pfqn_nc(lambda,Lms,Nchain,sum(Z,1)+sum(Zms,1), options);
123
124 if sum(Zms,1) > GlobalConstants.FineTol
125 % in this case, we need to use the iterative approximation below
126 Xchain=[];
127 Qchain=[];
128 end
129
130 if isempty(lG)
131 [Q,U,R,T,C,X,lG,STeff,it,method] = deal([],[],[],[],[],[],[],[],1,options.method);
132 return
133 end
134
135 if isempty(Xchain)
136 Xchain=lambda;
137 Qchain = zeros(M,C);
138 for r=closedChains
139 % An approximate normalizing-constant method (e.g. panacea) may report
140 % that this model is outside its domain by returning an empty lG. The
141 % base-model solve above already returns gracefully in that case; the
142 % per-class and per-station subproblems must do the same rather than
143 % assigning [] into a scalar slot (which errors with a size mismatch).
144 lGr_r = pfqn_nc(lambda,Lms,oner(Nchain,r),sum(Z,1)+sum(Zms,1), options);
145 if isempty(lGr_r)
146 [Q,U,R,T,C,X,lG,STeff,it,method] = deal([],[],[],[],[],[],[],[],1,options.method);
147 return
148 end
149 lGr(r) = lGr_r;
150 Xchain(r) = exp(lGr(r) - lG);
151 for ist=1:M
152 if Lchain(ist,r)>0
153 if isinf(nservers(ist)) % infinite server
154 Qchain(ist,r) = Lchain(ist,r) * Xchain(r);
155 else
156 % add replica of station i and move job of class r
157 % in separate class
158 % this is the most costly operation so we record
159 % method here
160 [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);
161 if isempty(lGar_ist_r)
162 [Q,U,R,T,C,X,lG,STeff,it,method] = deal([],[],[],[],[],[],[],[],1,options.method);
163 return
164 end
165 lGar(ist,r) = lGar_ist_r;
166 Qchain(ist,r) = Zms(ist,r) * Xchain(r) + Lms(ist,r) * exp(lGar(ist,r) - lG);
167 end
168 end
169 end
170 Qchain(isnan(Qchain))=0;
171 end
172 for r=openChains
173 for ist=1:M
174 Qchain(ist,r) = lambda(r)*Lchain(ist,r)/(1-lambda(openChains)*Lchain(ist,openChains)'/nservers(ist))*(1+sum(Qchain(ist,closedChains)));
175 end
176 end
177 else
178 % just fill the delay servers
179 for r=1:C
180 for ist=1:M
181 if Lchain(ist,r)>0
182 if isinf(nservers(ist)) % infinite server
183 Qchain(ist,r) = Lchain(ist,r) * Xchain(r);
184 end
185 end
186 end
187 end
188 end
189
190 if isnan(Xchain)
191 if options.verbose
192 line_warning(mfilename,'Normalizing constant computations produced a floating-point range exception. Model is likely too large.\n');
193 end
194 end
195
196 Z = sum(Z(1:M,:),1);
197
198 Rchain = Qchain ./ repmat(Xchain,M,1) ./ Vchain;
199 Rchain(infServers,:) = Lchain(infServers,:) ./ Vchain(infServers,:);
200 Tchain = repmat(Xchain,M,1) .* Vchain;
201
202 %Uchain = Tchain .* Lchain;
203 %Cchain = Nchain ./ Xchain - Z;
204
205 [Q,U,R,T,~,X] = sn_deaggregate_chain_results(sn, Lchain, ST, STchain, Vchain, alpha, [], [], Rchain, Tchain, [], Xchain);
206 STeff = ST;% effective service time at the last iteration
207 [ST,gamma,~,~,~,~,eta] = npfqn_nonexp_approx(options.config.highvar,sn,ST0,V,SCV,T,U,gamma,nservers);
208end
209
210Q=abs(Q); R=abs(R); X=abs(X); U=abs(U);
211X(~isfinite(X))=0; U(~isfinite(U))=0; Q(~isfinite(Q))=0; R(~isfinite(R))=0;
212
213% renormalize qlen and tput to correct for unforeseen population constraint deviations
214for c=1:sn.nchains
215 inchain = sn.inchain{c};
216 Nchain(c) = sum(NK(inchain)); %#ok<FNDSB>
217 if isfinite(Nchain(c))
218 q_den = sum(sum(Q(:,inchain)));
219 if q_den > 0
220 ratio = Nchain(c)/ q_den;
221 else
222 ratio = 0;
223 end
224 Q(:,inchain) = ratio * Q(:,inchain);
225 X(inchain) = ratio * X(inchain);
226 T(:,inchain) = ratio * T(:,inchain);
227 U(:,inchain) = ratio * U(:,inchain);
228 R(:,inchain) = Q(:,inchain) ./ T(:,inchain);
229 end
230end
231end
Definition Station.m:245