LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
runAnalyzer.m
1function [runtime, tranSysState, tranSync] = runAnalyzer(self, options)
2% [RUNTIME, TRANSYSSTATE] = RUNANALYZER()
3%
4% Run the LDES solver on the queueing network model.
5% For LayeredNetwork models, use SolverLDES from line-apps.
6
7T0 = tic;
8if nargin < 2
9 options = self.getOptions;
10end
11self.runAnalyzerChecks(options);
12Solver.resetRandomGeneratorSeed(options.seed);
13
14line_debug('LDES solver starting: lang=%s, samples=%d, seed=%d', options.lang, options.samples, options.seed);
15
16tranSysState = [];
17tranSync = [];
18
19% Check if confidence intervals are requested
20[confintEnabled, confintLevel] = Solver.parseConfInt(options.confint);
21
22switch options.lang
23 case 'java'
24 line_debug('Default method: using Java LDES discrete-event simulation\n');
25 line_debug('Using Java LDES backend');
26 % Convert model to Java
27 jmodel = LINE2JLINE(self.model);
28
29 % Create Java solver with LDES-specific options via JLINE wrapper
30 jsolver = JLINE.SolverLDES(jmodel, options);
31
32 % Regular Network analysis
33 [runtime] = runNetworkAnalyzer(self, jmodel, jsolver, confintEnabled, options);
34 otherwise
35 line_error(mfilename, 'SolverLDES currently only supports Java backend. Use options.lang = ''java''.');
36end
37
38runtime = toc(T0);
39end
40
41function [runtime] = runNetworkAnalyzer(self, jmodel, jsolver, confintEnabled, options)
42% RUNNETWORKANALYZER Run LDES analysis for regular Network models
43
44M = jmodel.getNumberOfStations;
45R = jmodel.getNumberOfClasses;
46
47% Check if this is transient analysis
48isTransient = isfield(options, 'timespan') && length(options.timespan) >= 2 && ...
49 isfinite(options.timespan(2));
50
51if isTransient
52 % Run transient analysis directly
53 runTransientAnalyzer(self, jsolver, M, R, options);
54 runtime = 0; % Runtime tracked inside transient analyzer
55 return;
56end
57
58% Steady-state analysis
59[QN, UN, RN, WN, AN, TN] = JLINE.arrayListToResults(jsolver.getAvgTable(true));
60
61CN = JLINE.from_jline_matrix(jsolver.getAvgSysRespT());
62XN = JLINE.from_jline_matrix(jsolver.getAvgSysTput());
63runtime = jsolver.result.runtime;
64QN = reshape(QN', R, M)';
65UN = reshape(UN', R, M)';
66RN = reshape(RN', R, M)';
67TN = reshape(TN', R, M)';
68WN = reshape(WN', R, M)';
69AN = reshape(AN', R, M)';
70
71% Extract FCR metrics and append to result matrices
72sn = self.model.getStruct;
73F = sn.nregions;
74if F > 0
75 result = jsolver.result;
76 isValidMatrix = @(x) ~isempty(x) && isa(x, 'jline.util.matrix.Matrix');
77 if isValidMatrix(result.QNfcr)
78 QNfcr = JLINE.from_jline_matrix(result.QNfcr);
79 UNfcr = JLINE.from_jline_matrix(result.UNfcr);
80 RNfcr = JLINE.from_jline_matrix(result.RNfcr);
81 TNfcr = JLINE.from_jline_matrix(result.TNfcr);
82 WNfcr = JLINE.from_jline_matrix(result.WNfcr);
83 % ANfcr is NaN for FCR (not applicable)
84 ANfcr = NaN(F, R);
85 % Append FCR rows to station metrics
86 QN = [QN; QNfcr];
87 UN = [UN; UNfcr];
88 RN = [RN; RNfcr];
89 TN = [TN; TNfcr];
90 WN = [WN; WNfcr];
91 AN = [AN; ANfcr];
92 end
93end
94
95% Print samples like SSA does
96if options.verbose
97 line_printf('LDES samples: %8d\n', options.samples);
98end
99
100self.setAvgResults(QN, UN, RN, TN, AN, WN, CN, XN, runtime, options.method, options.samples);
101
102% Marshal cache hit/miss/expected-latency results from the Java model back onto
103% the MATLAB Cache nodes (LDES is Java-backed; the native solvers set these
104% directly). For retrieval (delayed-hit) systems the miss ratio is pi_{i,0} and
105% the expected latency is the measured retrieval latency.
106for ind = 1:sn.nnodes
107 if sn.nodetype(ind) == NodeType.Cache
108 mcache = self.model.nodes{ind};
109 % Clear any cache hit/miss/delayed/latency split left on this node by a
110 % previously run solver BEFORE marshalling. getRoutingMatrix bakes a
111 % populated actualHitProb into the cache routing, so a stale split from
112 % e.g. a prior SSA run would otherwise survive a failed or partial
113 % marshal below and make the reported cache metrics order-dependent
114 % (LDES would echo the prior solver). Cleared first so any marshalling
115 % failure leaves the node empty (reported as NaN) rather than stale.
116 mcache.setResultHitProb(sparse([]));
117 mcache.setResultMissProb(sparse([]));
118 mcache.setResultDelayedHitProb(sparse([]));
119 mcache.setResultResidT(sparse([]));
120 try
121 jcache = jmodel.getNodeByName(mcache.getName());
122 catch
123 jcache = [];
124 end
125 if ~isempty(jcache)
126 % Marshal each field independently: a single missing accessor (e.g.
127 % getResidT on an older jline.jar still on MATLAB's static classpath)
128 % must NOT discard the hit/miss/delayed results that ARE available.
129 try, hp = JLINE.from_jline_matrix(jcache.getHitRatio()); if ~isempty(hp), mcache.setResultHitProb(hp); end; catch, end
130 try, mp = JLINE.from_jline_matrix(jcache.getMissRatio()); if ~isempty(mp), mcache.setResultMissProb(mp); end; catch, end
131 try, dhp = JLINE.from_jline_matrix(jcache.getDelayedHitRatio()); if ~isempty(dhp), mcache.setResultDelayedHitProb(dhp); end; catch, end
132 try, lp = JLINE.from_jline_matrix(jcache.getResidT()); if ~isempty(lp), mcache.setResultResidT(lp); end; catch, end
133 end
134 end
135end
136
137% NB: the cache hit/miss/delayed split is stored on the Cache node above
138% (setResultHitProb etc.). The node-table reconstruction in @NetworkSolver/
139% getAvgNode resyncs that split from the node into a LOCAL struct copy, so the
140% reported throughputs reflect THIS simulation without persisting the split into
141% the shared model.sn (refreshStruct(true) would bake it into sn.rtnodes and
142% perturb a subsequently-run exact solver such as CTMC -- order dependence).
143
144% Extract confidence intervals from Java solver results
145if confintEnabled
146 result = jsolver.result;
147 % Helper to check for non-null Java objects
148 isValidMatrix = @(x) ~isempty(x) && isa(x, 'jline.util.matrix.Matrix');
149 if isValidMatrix(result.QNCI)
150 QNCI = JLINE.from_jline_matrix(result.QNCI);
151 QNCI = reshape(QNCI', R, M)';
152 else
153 QNCI = [];
154 end
155 if isValidMatrix(result.UNCI)
156 UNCI = JLINE.from_jline_matrix(result.UNCI);
157 UNCI = reshape(UNCI', R, M)';
158 else
159 UNCI = [];
160 end
161 if isValidMatrix(result.RNCI)
162 RNCI = JLINE.from_jline_matrix(result.RNCI);
163 RNCI = reshape(RNCI', R, M)';
164 else
165 RNCI = [];
166 end
167 if isValidMatrix(result.TNCI)
168 TNCI = JLINE.from_jline_matrix(result.TNCI);
169 TNCI = reshape(TNCI', R, M)';
170 else
171 TNCI = [];
172 end
173 if isValidMatrix(result.ANCI)
174 ANCI = JLINE.from_jline_matrix(result.ANCI);
175 ANCI = reshape(ANCI', R, M)';
176 else
177 ANCI = [];
178 end
179 if isValidMatrix(result.WNCI)
180 WNCI = JLINE.from_jline_matrix(result.WNCI);
181 WNCI = reshape(WNCI', R, M)';
182 else
183 WNCI = [];
184 end
185 % Store CI results
186 self.setAvgResultsCI(QNCI, UNCI, RNCI, TNCI, ANCI, WNCI, [], []);
187end
188
189end
190
191function runTransientAnalyzer(self, jsolver, Mjava, R, options)
192% RUNTRANSIENTANALYZER Run transient analysis for LDES
193
194T0 = tic;
195
196% Get MATLAB model structure for correct station count
197sn = self.model.getStruct;
198M = sn.nstations; % Use MATLAB station count for cell arrays
199
200% Run transient analysis on Java side
201jsolver.getTranAvg();
202result = jsolver.result;
203runtime = toc(T0);
204
205% Check if transient results are available (result.QNt is a Java 2D array)
206if ~isempty(result.QNt) && ~isempty(result.t)
207 % Get number of time points
208 Tmax = result.t.length();
209 if Tmax > 0
210 % Convert Java transient results to MATLAB format
211 % result.QNt(ist,r) is a Matrix(numTimePoints, 2) with columns [value, time]
212 % Use MATLAB station count for cell arrays so getTranAvg can index correctly
213 QNt = cell(M, R);
214 UNt = cell(M, R);
215 RNt = cell(M, R); % Not computed by LDES, will be empty
216 TNt = cell(M, R);
217 CNt = cell(1, R);
218 XNt = cell(1, R);
219
220 % Initialize all cells to NaN
221 for ist = 1:M
222 for r = 1:R
223 QNt{ist, r} = NaN;
224 UNt{ist, r} = NaN;
225 RNt{ist, r} = NaN;
226 TNt{ist, r} = NaN;
227 end
228 end
229
230 % Extract data from Java results (indexed by Java station count)
231 for ist = 1:Mjava
232 for r = 1:R
233 % Queue length transient
234 try
235 jmatrix = result.QNt(ist, r);
236 if ~isempty(jmatrix) && jmatrix.getNumRows() > 0
237 nRows = jmatrix.getNumRows();
238 matData = NaN(nRows, 2);
239 for p = 1:nRows
240 matData(p, 1) = jmatrix.get(p-1, 0); % value
241 matData(p, 2) = jmatrix.get(p-1, 1); % time
242 end
243 QNt{ist, r} = matData;
244 else
245 QNt{ist, r} = NaN;
246 end
247 catch
248 QNt{ist, r} = NaN;
249 end
250
251 % Utilization transient
252 try
253 jmatrix = result.UNt(ist, r);
254 if ~isempty(jmatrix) && jmatrix.getNumRows() > 0
255 nRows = jmatrix.getNumRows();
256 matData = NaN(nRows, 2);
257 for p = 1:nRows
258 matData(p, 1) = jmatrix.get(p-1, 0); % value
259 matData(p, 2) = jmatrix.get(p-1, 1); % time
260 end
261 UNt{ist, r} = matData;
262 else
263 UNt{ist, r} = NaN;
264 end
265 catch
266 UNt{ist, r} = NaN;
267 end
268
269 % Throughput transient
270 try
271 jmatrix = result.TNt(ist, r);
272 if ~isempty(jmatrix) && jmatrix.getNumRows() > 0
273 nRows = jmatrix.getNumRows();
274 matData = NaN(nRows, 2);
275 for p = 1:nRows
276 matData(p, 1) = jmatrix.get(p-1, 0); % value
277 matData(p, 2) = jmatrix.get(p-1, 1); % time
278 end
279 TNt{ist, r} = matData;
280 else
281 TNt{ist, r} = NaN;
282 end
283 catch
284 TNt{ist, r} = NaN;
285 end
286
287 % Response time transient not computed by LDES
288 RNt{ist, r} = NaN;
289 end
290 end
291
292 % CNt and XNt not computed for transient
293 for r = 1:R
294 CNt{1, r} = NaN;
295 XNt{1, r} = NaN;
296 end
297
298 % Store transient results
299 self.setTranAvgResults(QNt, UNt, RNt, TNt, CNt, XNt, runtime);
300
301 % Also compute and store steady-state estimates from final transient values
302 QN = NaN(M, R);
303 UN = NaN(M, R);
304 RN = NaN(M, R);
305 TN = NaN(M, R);
306 WN = NaN(M, R);
307 AN = NaN(M, R);
308 CN = NaN(1, R);
309 XN = NaN(1, R);
310
311 for ist = 1:M
312 for r = 1:R
313 if ~isscalar(QNt{ist, r}) && ~isnan(QNt{ist, r}(end, 1))
314 QN(ist, r) = QNt{ist, r}(end, 1);
315 end
316 if ~isscalar(UNt{ist, r}) && ~isnan(UNt{ist, r}(end, 1))
317 UN(ist, r) = UNt{ist, r}(end, 1);
318 end
319 if ~isscalar(TNt{ist, r}) && ~isnan(TNt{ist, r}(end, 1))
320 TN(ist, r) = TNt{ist, r}(end, 1);
321 end
322 end
323 end
324
325 self.setAvgResults(QN, UN, RN, TN, AN, WN, CN, XN, runtime, options.method, 0);
326 end
327end
328
329% Print verbose output if requested
330if options.verbose
331 line_printf('LDES transient analysis complete, timespan = [%g, %g]\n', ...
332 options.timespan(1), options.timespan(2));
333end
334end
Definition mmt.m:124