LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
solver_mna_open.m
1function [Q,U,R,T,C,X,lG,totiter] = solver_mna_open(sn, options)
2
3config = options.config;
4config.space_max = 32;
5if ~isfield(config, 'dep_scv')
6 config.dep_scv = 'qna'; % 'qna' for Whitt formula, 'etaqa' for QBD joint moments
7end
8
9K = sn.nclasses;
10rt = sn.rt;
11S = 1./sn.rates;
12scv = sn.scv; scv(isnan(scv))=0;
13
14PH = sn.proc;
15I = sn.nnodes;
16M = sn.nstations;
17C = sn.nchains;
18V = cellsum(sn.visits);
19Q = zeros(M,K);
20%QN_1 = Q+Inf;
21
22U = zeros(M,K);
23R = zeros(M,K);
24T = zeros(M,K);
25X = zeros(1,K);
26
27lambda = zeros(1,C);
28
29it = 0;
30pie = {};
31D0 = {};
32
33% get service process
34for ist=1:M
35 switch sn.sched(ist)
36 case {SchedStrategy.FCFS, SchedStrategy.INF,SchedStrategy.PS}
37 for k=1:K
38 pie{ist}{k} = map_pie(PH{ist}{k});
39 D0{ist,k} = PH{ist}{k}{1};
40 if any(isnan(D0{ist,k}))
41 D0{ist,k} = -GlobalConstants.Immediate;
42 pie{ist}{k} = 1;
43 PH{ist}{k} = map_exponential(GlobalConstants.Immediate);
44 end
45 end
46 end
47end
48
49a1 = zeros(M,K);
50a2 = zeros(M,K);
51mubar = [];
52c2 = [];
53d2 = zeros(M,1);
54f2 = zeros(M*K,M*K);
55for ist=1:M
56 for jst=1:M
57 if sn.nodetype(sn.stationToNode(jst)) ~= NodeType.Source
58 for r=1:K
59 for s=1:K
60 if rt((ist-1)*K+r, (jst-1)*K+s)>0
61 f2((ist-1)*K+r, (jst-1)*K+s) = 1; % C^2ij,r
62 end
63 end
64 end
65 end
66 end
67end
68lambdas_inchain = cell(1,C);
69scvs_inchain = cell(1,C);
70d2c = [];
71for c=1:C
72 inchain = sn.inchain{c};
73 sourceIdx = sn.refstat(inchain(1));
74 lambdas_inchain{c} = sn.rates(sourceIdx,inchain);
75 scvs_inchain{c} = scv(sourceIdx,inchain);
76 lambda(c) = sum(lambdas_inchain{c}(isfinite(lambdas_inchain{c})));
77 d2c(c) = da_traffic_superpos(lambdas_inchain{c},scvs_inchain{c});
78 T(sourceIdx,inchain') = lambdas_inchain{c};
79
80end
81d2(sourceIdx)=d2c(sourceIdx,:)*lambda'/sum(lambda);
82
83%% main iteration
84% flow fixed point on the per-station arrival rates a1 and SCVs a2, driven
85% by the generic DA successive-substitution driver
86fpopts = options;
87fpopts.iter_max = options.iter_max + 1; % legacy while-loop executed one extra sweep at the cap
88fpopts.config.da_nanstop = true; % legacy while-loop exited on NaN convergence measure
89[~, it] = da_fpi(@mna_sweep, [a1(:); a2(:)], fpopts);
90
91 function [xnew, xref] = mna_sweep(~, itnum)
92 xref = [a1(:); a2(:)];
93 % update throughputs at all stations
94 if itnum==1
95 for c=1:C
96 inchain = sn.inchain{c};
97 for m=1:M
98 T(m,inchain) = V(m,inchain) .* lambda(c);
99 end
100 end
101 end
102
103 % superposition
104 for ist=1:M
105 a1(ist,:) = 0;
106 a2(ist,:) = 0;
107 lambda_i = sum(T(ist,:));
108 for jst=1:M
109 for r=1:K
110 for s=1:K
111 a1(ist,r) = a1(ist,r) + T(jst,s)*rt((jst-1)*K+s, (ist-1)*K+r);
112 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);
113 end
114 end
115 end
116 end
117
118 % update flow trhough queueing station
119 for ind=1:I
120 if sn.isstation(ind)
121 ist = sn.nodeToStation(ind);
122
123 switch sn.sched(ist)
124 case SchedStrategy.INF
125 for r=1:K
126 for s=1:K
127 d2(ist,s) = a2(ist,s);
128 end
129 end
130 for c=1:C
131 inchain = sn.inchain{c};
132 for k=inchain
133 T(ist,k) = a1(ist,k);
134 U(ist,k) = S(ist,k)*T(ist,k);
135 Q(ist,k) = T(ist,k).*S(ist,k)*V(ist,k);
136 R(ist,k) = Q(ist,k)/T(ist,k);
137 end
138 end
139 case SchedStrategy.PS
140 for c=1:C
141 inchain = sn.inchain{c};
142 for k=inchain
143 TN(ist,k) = lambda(c)*V(ist,k);
144 UN(ist,k) = S(ist,k)*TN(ist,k);
145 end
146 %Nc = sum(sn.njobs(inchain)); % closed population
147 Uden = min([1-GlobalConstants.FineTol,sum(UN(ist,:))]);
148 for k=inchain
149 %QN(ist,k) = (UN(ist,k)-UN(ist,k)^(Nc+1))/(1-Uden); % geometric bound type approximation
150 QN(ist,k) = UN(ist,k)/(1-Uden);
151 RN(ist,k) = QN(ist,k)/TN(ist,k);
152 end
153 end
154 case {SchedStrategy.FCFS}
155 mu_ist = sn.rates(ist,1:K);
156 mu_ist(isnan(mu_ist))=0;
157 rho_ist_class = a1(ist,1:K)./(GlobalConstants.FineTol+sn.rates(ist,1:K));
158 rho_ist_class(isnan(rho_ist_class))=0;
159 lambda_ist = sum(a1(ist,:));
160 mi = sn.nservers(ist);
161 rho_ist = sum(rho_ist_class) / mi;
162 if rho_ist < 1-options.tol
163 if strcmp(config.dep_scv, 'etaqa') && mi == 1
164 % ETAQA-based departure SCV via QBD joint moments
165 try
166 % fit aggregate arrival MAP from parametric info
167 arri_agg = APH.fitMeanAndSCV(1/lambda_ist, sum(a2(ist,:))).getProcess;
168 serv_agg = APH.fitMeanAndSCV(1/sum(mu_ist(mu_ist>0).*a1(ist,mu_ist>0))/lambda_ist, ...
169 sum(a1(ist,:).*scv(ist,:))/lambda_ist).getProcess;
170 JM = qbd_depproc_jointmom(arri_agg, serv_agg, [1,0; 2,0]);
171 E1 = JM(1); E2 = JM(2);
172 d2(ist) = (E2 - E1^2) / E1^2;
173 catch
174 % fall back to QNA formula on failure
175 for k=1:K
176 mubar(ist) = lambda_ist ./ rho_ist;
177 c2(ist) = -1;
178 for r=1:K
179 if mu_ist(r)>0
180 c2(ist) = c2(ist) + a1(ist,r)/lambda_ist * (mubar(ist)/mi/mu_ist(r))^2 * (scv(ist,r)+1 );
181 end
182 end
183 end
184 d2(ist) = 1 + rho_ist^2*(c2(ist)-1)/sqrt(mi) + (1 - rho_ist^2) *(sum(a2(ist,:))-1);
185 end
186 else
187 % QNA Whitt formula
188 for k=1:K
189 mubar(ist) = lambda_ist ./ rho_ist;
190 c2(ist) = -1;
191 for r=1:K
192 if mu_ist(r)>0
193 c2(ist) = c2(ist) + a1(ist,r)/lambda_ist * (mubar(ist)/mi/mu_ist(r))^2 * (scv(ist,r)+1 );
194 end
195 end
196 end
197 d2(ist) = 1 + rho_ist^2*(c2(ist)-1)/sqrt(mi) + (1 - rho_ist^2) *(sum(a2(ist,:))-1);
198 end
199 else
200 for k=1:K
201 Q(ist,k) = sn.njobs(k);
202 end
203 d2(ist) = 1;
204 end
205 for k=1:K
206 T(ist,k) = a1(ist,k);
207 U(ist,k) = T(ist,k) * S(ist,k) /sn.nservers(ist);
208
209 end
210 end
211
212 else % not a station
213 switch sn.nodetype(ind)
214 case NodeType.Fork
215 line_error(mfilename,'Fork nodes not supported yet by QNA solver.');
216 end
217 end
218 end
219
220
221 % splitting - update flow scvs
222 for ist=1:M
223 for jst=1:M
224 if sn.nodetype(sn.stationToNode(jst)) ~= NodeType.Source
225 for r=1:K
226 for s=1:K
227 if rt((ist-1)*K+r, (jst-1)*K+s)>0
228 f2((ist-1)*K+r, (jst-1)*K+s) = 1 + rt((ist-1)*K+r, (jst-1)*K+s) * (d2(ist)-1);
229 end
230 end
231 end
232 end
233 end
234 end
235 xnew = [a1(:); a2(:)];
236 end
237
238
239for ind=1:I
240 if sn.isstation(ind)
241 ist = sn.nodeToStation(ind);
242 switch sn.sched(ist)
243 case {SchedStrategy.FCFS}
244 mu_ist = sn.rates(ist,1:K);
245 mu_ist(isnan(mu_ist))=0;
246 rho_ist_class = a1(ist,1:K)./(GlobalConstants.FineTol+sn.rates(ist,1:K));
247 rho_ist_class(isnan(rho_ist_class))=0;
248 lambda_ist = sum(a1(ist,:));
249 mi = sn.nservers(ist);
250 rho_ist = sum(rho_ist_class) / mi;
251 if rho_ist < 1-options.tol
252 for k=1:K
253 if a1(ist,k)==0
254 arri_class = map_exponential(Inf);
255 else
256 arri_class = APH.fitMeanAndSCV(1/a1(ist,k),a2(ist,k)).getProcess; % MMAP repres of arrival process for class k at node ist
257 %arri_class = Erlang.fit(1/a1(ist,k),a2(ist,k)).getProcess;
258 %arri_class = map_exponential(1/a1(ist,k));
259 arri_class = {arri_class{1},arri_class{2},arri_class{2}};
260 end
261 if k==1
262 arri_node = arri_class;
263 else
264 arri_node = mmap_super(arri_node,arri_class, 'default');
265
266 %arri_node = mmap_super_safe({arri_node,arri_class}, config.space_max, 'default'); % combine arrival process from different class
267 end
268 end
269 isFiniteCap = isfinite(sn.cap(ist));
270 if isFiniteCap
271 capK = sn.cap(ist);
272 [isMmck, muMmck] = mam_detect_mmck(sn, ist, K, arri_node);
273 if isMmck
274 aggrLambda_ist = sum(a1(ist,1:K), 'omitnan');
275 exactRes = qsys_mmck(aggrLambda_ist, muMmck, sn.nservers(ist), capK);
276 meanQ_fc = exactRes.meanQueueLength;
277 lossProb_fc = exactRes.lossProbability;
278 else
279 [meanQ_fc, lossProb_fc, ~] = mam_truncate_renorm( ...
280 {arri_node{[1,3:end]}}, {pie{ist}{:}}, {D0{ist,:}}, capK);
281 end
282 lambdaInflow = a1(ist,1:K);
283 lambdaInflow(isnan(lambdaInflow)) = 0;
284 T_eff = lambdaInflow * (1 - lossProb_fc);
285 sumT = sum(T_eff);
286 if sumT > 0
287 Savg_eff = sum(T_eff .* S(ist,1:K), 'omitnan') / sumT;
288 Wq = max(0, meanQ_fc / sumT - Savg_eff);
289 else
290 Wq = 0;
291 end
292 for k=1:K
293 T(ist,k) = T_eff(k);
294 U(ist,k) = T(ist,k) * S(ist,k) / sn.nservers(ist);
295 if T(ist,k) > 0
296 R(ist,k) = Wq + S(ist,k);
297 Q(ist,k) = T(ist,k) * R(ist,k);
298 else
299 R(ist,k) = 0;
300 Q(ist,k) = 0;
301 end
302 end
303 else
304 Qret = cell(1,K);
305 [Qret{1:K}] = MMAPPH1FCFS({arri_node{[1,3:end]}}, {pie{ist}{:}}, {D0{ist,:}}, 'ncMoms', 1);
306 Q(ist,:) = cell2mat(Qret);
307 for k=1:K
308 R(ist,k) = Q(ist,k) ./ T(ist,k);
309 end
310 end
311 else
312 for k=1:K
313 Q(ist,k) = sn.njobs(k);
314 R(ist,k) = Q(ist,k) ./ T(ist,k);
315 end
316 end
317 end
318
319 end
320end
321
322C = sum(R,1);
323Q = abs(Q);
324Q(isnan(Q))=0;
325U(isnan(U))=0;
326R(isnan(R))=0;
327C(isnan(C))=0;
328X(isnan(X))=0;
329lG = 0;
330totiter = it;
331end
Definition Station.m:245