LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
solver_ssa_analyzer.m
1function [QN,UN,RN,TN,CN,XN,runtime,method,tranSysState,tranSync,sn,QNCI,UNCI,RNCI,TNCI,ANCI,WNCI] = solver_ssa_analyzer(sn, options)
2% [QN,UN,RN,TN,CN,XN,RUNTIME] = SOLVER_SSA_ANALYZER(SN, OPTIONS)
3% Wrapper that selects the most suitable SSA performance-analysis back-end.
4%
5% If every station uses scheduling policy INF, EXT, or PS (and the network
6% has no cache nodes), the faster Next-Reaction-Method analyser
7% -> solver_ssa_analyzer_nrm
8% is invoked. Otherwise the original serial / parallel analysers are used.
9%
10% Copyright (c) 2012-2026, Imperial College London
11% All rights reserved.
12
13Tstart = tic;
14
15line_debug('SSA analyzer starting: method=%s, nstations=%d, nclasses=%d', options.method, sn.nstations, sn.nclasses);
16
17% Convert non-Markovian distributions to PH
18sn = sn_nonmarkov_toph(sn, options);
19
20% Capture initial state after conversion (state may have been expanded for MAPs)
21init_state = sn.state;
22
23% Initialize CI outputs
24M = sn.nstations;
25K = sn.nclasses;
26QNCI = [];
27UNCI = [];
28RNCI = [];
29TNCI = [];
30ANCI = [];
31WNCI = [];
32
33% Check if confidence intervals are requested
34[confintEnabled, confintLevel] = Solver.parseConfInt(options.confint);
35
36% -------------------------------------------------------------------------
37% Pick analysis back-end
38% -------------------------------------------------------------------------
39switch options.method
40 case {'default'} % "default" prefers NRM for closed QNs with INF/PS
41 allowedSched = [SchedStrategy.INF, SchedStrategy.EXT, SchedStrategy.PS];
42 nrmSupported = all(arrayfun(@(s) any(s==allowedSched), sn.sched)) && ...
43 all(sn.nodetype ~= NodeType.Cache) && ...
44 sn_is_population_model(sn) && ...
45 all(sn.procid(sn.procid~=ProcessType.DISABLED) == ProcessType.EXP); % all exp
46
47 line_debug('Checking NRM eligibility: schedOK=%d, noCache=%d, isPopModel=%d, allExp=%d', ...
48 all(arrayfun(@(s) any(s==allowedSched), sn.sched)), ...
49 all(sn.nodetype ~= NodeType.Cache), ...
50 sn_is_population_model(sn), ...
51 all(sn.procid(sn.procid~=ProcessType.DISABLED) == ProcessType.EXP));
52
53 if nrmSupported
54 line_debug('Default method: using NRM (Next Reaction Method)\n');
55 line_debug('Using NRM method (fast path), calling solver_ssa_analyzer_nrm');
56 [XN,UN,QN,RN,TN,CN,tranSysState,tranSync,sn] = ...
57 solver_ssa_analyzer_nrm(sn, options);
58 method = 'nrm';
59 % Compute CI using batch means if enabled
60 if confintEnabled && ~isempty(tranSysState) && length(tranSysState) > 1
61 [QNCI, UNCI, RNCI, TNCI, ANCI, WNCI] = ssa_compute_batch_means_ci(tranSysState, sn, confintLevel);
62 end
63 runtime = toc(Tstart);
64 return
65 else
66 % otherwise fall through to serial selection
67 line_debug('Default method: using serial SSA\n');
68 line_debug('NRM not supported, falling back to serial method');
69 options.method = 'serial';
70 end
71
72 case 'nrm'
73 line_debug('Using explicit NRM method, calling solver_ssa_analyzer_nrm');
74
75 [XN,UN,QN,RN,TN,CN,tranSysState,tranSync,sn] = ...
76 solver_ssa_analyzer_nrm(sn, options);
77 method = 'nrm';
78 sn.method = 'default/nrm';
79 % Compute CI using batch means if enabled
80 if confintEnabled && ~isempty(tranSysState) && length(tranSysState) > 1
81 [QNCI, UNCI, RNCI, TNCI, ANCI, WNCI] = ssa_compute_batch_means_ci(tranSysState, sn, confintLevel);
82 end
83 runtime = toc(Tstart);
84 return
85 case 'ssa' % alias for serial path below
86 line_debug('Using ssa alias, redirecting to serial method');
87 options.method = 'serial';
88 sn.method = 'default/serial';
89end
90
91% SERIAL / PARALLEL ANALYSERS (legacy paths) ------------------------------
92switch options.method
93 case {'serial'}
94 line_debug('Using serial method, calling solver_ssa_analyzer_serial');
95 [XN,UN,QN,RN,TN,CN,tranSysState,tranSync,sn] = ...
96 solver_ssa_analyzer_serial(sn, init_state, options, false);
97 method = 'serial';
98
99 case {'para','parallel'}
100 line_debug('Using parallel method, calling solver_ssa_analyzer_parallel');
101 try
102 [XN,UN,QN,RN,TN,CN,tranSysState,tranSync,sn] = ...
103 solver_ssa_analyzer_parallel(sn, init_state, options);
104 method = 'parallel';
105 catch ME
106 if strcmp(ME.identifier,'MATLAB:spmd:NoPCT')
107 line_printf(['Parallel Computing Toolbox unavailable – ',...
108 'falling back to serial SSA.\n']);
109 [XN,UN,QN,RN,TN,CN,tranSysState,tranSync,sn] = ...
110 solver_ssa_analyzer_serial(sn, init_state, options, true);
111 method = 'serial';
112 else
113 rethrow(ME);
114 end
115 end
116
117 otherwise
118 error('solver_ssa_analyzer:UnknownMethod', ...
119 'Unknown analysis method: %s', options.method);
120end
121
122% Compute CI using batch means if enabled
123if confintEnabled && ~isempty(tranSysState) && length(tranSysState) > 1
124 [QNCI, UNCI, RNCI, TNCI, ANCI, WNCI] = ssa_compute_batch_means_ci(tranSysState, sn, confintLevel);
125end
126
127runtime = toc(Tstart);
128end
129
130function [QNCI, UNCI, RNCI, TNCI, ANCI, WNCI] = ssa_compute_batch_means_ci(tranSysState, sn, confintLevel)
131% SSA_COMPUTE_BATCH_MEANS_CI Compute confidence intervals using batch means method
132%
133% tranSysState{1} contains the cumulative time at each sample
134% tranSysState{2:end} contain the state vectors for each stateful node
135
136M = sn.nstations;
137K = sn.nclasses;
138QNCI = zeros(M, K);
139UNCI = zeros(M, K);
140RNCI = zeros(M, K);
141TNCI = zeros(M, K);
142ANCI = zeros(M, K);
143WNCI = zeros(M, K);
144
145% Extract time and state data
146if iscell(tranSysState) && length(tranSysState) > 1
147 times = tranSysState{1};
148 nSamples = length(times);
149
150 if nSamples < 20
151 % Not enough samples for batch means
152 return;
153 end
154
155 % Number of batches (use 10-30 batches for good CI estimation)
156 numBatches = min(20, floor(nSamples / 10));
157 if numBatches < 2
158 return;
159 end
160 batchSize = floor(nSamples / numBatches);
161
162 % Discard initial transient (first 10% of samples)
163 transientCutoff = max(1, floor(nSamples * 0.1));
164
165 % Extract queue length data from tranSysState
166 % tranSysState{2:end} contains state vectors for each stateful node
167 % We need to compute marginal queue lengths per station/class
168
169 % Compute batch means for queue lengths
170 for ist = 1:M
171 isf = sn.stationToStateful(ist);
172 if isf > 0 && (1 + isf) <= length(tranSysState)
173 stateData = tranSysState{1 + isf};
174 if isempty(stateData)
175 continue;
176 end
177
178 for k = 1:K
179 % Extract queue length for this station/class from state data
180 % The state data format depends on the scheduling strategy
181 % For simplicity, we'll use the marginal extraction
182 ind = sn.stationToNode(ist);
183
184 % Compute time-weighted batch means
185 batchMeans = zeros(1, numBatches);
186 for b = 1:numBatches
187 startIdx = transientCutoff + (b-1) * batchSize + 1;
188 endIdx = min(transientCutoff + b * batchSize, nSamples);
189 if startIdx > nSamples || startIdx >= endIdx
190 continue;
191 end
192
193 % Compute time-weighted average for this batch
194 % times contains cumulative times, compute inter-sample durations
195 if startIdx > 1
196 prevTime = times(startIdx - 1);
197 else
198 prevTime = 0;
199 end
200 batchTimes = times(startIdx:endIdx);
201
202 if length(batchTimes) >= 1
203 % Compute time duration each state was held
204 if startIdx == 1
205 dt = [batchTimes(1); diff(batchTimes)];
206 else
207 dt = [batchTimes(1) - prevTime; diff(batchTimes)];
208 end
209
210 % Extract queue lengths from state data
211 % For now, sum all columns to get total jobs at the station
212 % This works for most queue types where state represents job counts
213 qLengths = sum(stateData(startIdx:endIdx, :), 2);
214
215 totalTime = sum(dt);
216 if totalTime > 0
217 batchMeans(b) = sum(qLengths .* dt) / totalTime;
218 end
219 end
220 end
221
222 % Count valid batches (non-NaN)
223 validMask = ~isnan(batchMeans);
224 batchMeans = batchMeans(validMask);
225 nBatches = length(batchMeans);
226
227 if nBatches >= 2
228 % Compute mean and standard error
229 batchMean = mean(batchMeans);
230 batchStd = std(batchMeans);
231 stdErr = batchStd / sqrt(nBatches);
232
233 % t-critical value for confidence level
234 alpha = 1 - confintLevel;
235 tCrit = tinv(1 - alpha/2, nBatches - 1);
236
237 % Confidence interval half-width
238 QNCI(ist, k) = tCrit * stdErr;
239 end
240 end
241 end
242 end
243
244 % For utilization, response time, and throughput CIs, use relative scaling
245 % These are derived from queue length CI using Little's law relationships
246 UNCI = QNCI; % Simplified - utilization CI scales similarly
247 RNCI = QNCI; % Response time CI - would need service rate info
248 TNCI = QNCI; % Throughput CI - would need arrival rate info
249end
250end
Definition mmt.m:92