1function runtime = runAnalyzer(self, options)
8 options = self.getOptions;
10sn = getStruct(self); %
this gets modified later on so pass by copy
12% Convert non-Markovian distributions to PH
13sn = sn_nonmarkov_toph(sn, options);
15orig_method = options.method;
16self.runAnalyzerChecks(options);
17Solver.resetRandomGeneratorSeed(options.seed);
19% Show library attribution
if verbose and not yet shown
20if options.verbose ~= VerboseLevel.SILENT && ~GlobalConstants.isLibraryAttributionShown()
21 libs = SolverFLD.getLibrariesUsed(sn, options);
23 line_printf(
'The solver will leverage %s.\n', strjoin(libs,
', '));
24 GlobalConstants.setLibraryAttributionShown(
true);
28%options.lang =
'java';
30hasOpenClasses = sn_has_open_classes(sn);
33 jmodel = LINE2JLINE(self.model);
34 %M = jmodel.getNumberOfStatefulNodes;
35 M = jmodel.getNumberOfStations;
36 R = jmodel.getNumberOfClasses;
38 case {
'default',
'closing',
'matrix'}
39 jsolver = JLINE.SolverFluid(jmodel, options);
41 line_warning(mfilename,
'This solver does not support the specified method. Setting to default.\n');
42 options.method =
'default';
43 jsolver = JLINE.SolverFluid(jmodel, options);
45 [QN,UN,RN,WN,AN,TN] = JLINE.arrayListToResults(jsolver.getAvgTable);
49 QN = reshape(QN
',R,M)';
50 UN = reshape(UN
',R,M)';
51 RN = reshape(RN
',R,M)';
52 WN = reshape(WN
',R,M)';
53 AN = reshape(AN
',R,M)';
54 TN = reshape(TN
',R,M)';
57 self.setAvgResults(QN,UN,RN,TN,AN,WN,CN,XN,runtime,options.method,lastiter);
58 self.result.Prob.logNormConstAggr = lG;
59 self.result.solverSpecific.sn = JLINE.from_jline_struct(jmodel);
60 self.result.solverSpecific.odeStateVec = JLINE.from_jline_matrix(jsolver.result.odeStateVec);
64 case {
'matrix',
'pnorm'}
65 % Matrix method now supports mixed/open models per Ruuskanen et al., PEVA 151 (2021)
67 line_error(mfilename,
'The matrix solver does not support DPS scheduling. Use options.method=''closing'' instead.');
70 options.method =
'closing';
72 % Use matrix method as
default unless DPS
is present
74 options.method =
'closing';
76 options.method =
'matrix';
78 case {
'statedep',
'softmin'}
80 case {
'diffusion',
'fluid.diffusion'}
81 % Diffusion approximation - validated in solver_fluid_diffusion
82 %
do nothing here, validation happens in the solver itself
83 case {
'mfq',
'fluid.mfq',
'butools'}
84 % Markovian fluid queue method
using BUTools
for single-queue analysis
85 % Validation and fallback happens in solver_fluid_analyzer
87 line_error(mfilename,sprintf(
'The ''%s'' method is unsupported by this solver.',options.method));
91if isinf(options.timespan(1))
92 if options.verbose == 2
93 line_warning(mfilename,'%s requires options.timespan(1) to be finite. Setting it to 0.\n',mfilename);
95 options.timespan(1) = 0;
98if options.timespan(1) == options.timespan(2)
99 line_warning(mfilename,'%s: timespan
is a single point, unsupported. Setting options.timespace(1) to 0.\n',mfilename);
100 options.timespan(1) = 0;
103if self.enableChecks && ~self.supports(self.model)
104 line_error(mfilename,'This model contains features not supported by the solver.');
107self.setOptions(options);
114Q = zeros(M,K); R = zeros(M,K); T = zeros(M,K);
115U = zeros(M,K); C = zeros(1,K); X = zeros(1,K);
118s0prior = sn.stateprior;
119s0_sz = cellfun(@(x) size(x,1), s0)';
120s0_id = pprod(s0_sz-1);
122while s0_id>=0 % for all possible initial states
125 if sn.isstateful(ind)
126 isf = sn.nodeToStateful(ind);
127 s0prior_val = s0prior_val * s0prior{isf}(1+s0_id(isf)); % update prior
128 %sn.state{isf} = s0{isf}(1+s0_id(isf),:); % assign initial state to network
129 self.model.nodes{ind}.setState(s0{isf}(1+s0_id(isf),:));
132 sn = self.model.getStruct;
133 sn = sn_nonmarkov_toph(sn, options); % Re-apply conversion after fresh
struct
137 % [Qfull, Ufull, Rfull, Tfull, Cfull, Xfull, t, Qfull_t, Ufull_t, Tfull_t, lastSol] = JLINE.runFluidAnalyzer(self.model, options);
139 [Qfull, Ufull, Rfull, Tfull, Cfull, Xfull, t, Qfull_t, Ufull_t, Tfull_t, lastSol, iter, aoiResults] = solver_fluid_analyzer(sn, options);
142 [t,uniqueIdx] = unique(t);
143 if isempty(lastSol) %
if solution fails
144 Q = NaN*ones(M,K); R = NaN*ones(M,K);
145 T = NaN*ones(M,K); U = NaN*ones(M,K);
146 C = NaN*ones(1,K); X = NaN*ones(1,K);
147 Qt = cell(M,K); Ut = cell(M,K); Tt = cell(M,K);
150 Qt{ist,r} = [NaN,NaN];
151 Ut{ist,r} = [NaN,NaN];
152 Tt{ist,r} = [NaN,NaN];
156 if isempty(self.result) && max(size(Qt))==0 %~exist(
'Qt',
'var')
157 Q = Qfull*s0prior_val;
158 R = Rfull*s0prior_val;
159 T = Tfull*s0prior_val;
160 U = Ufull*s0prior_val;
161 C = Cfull*s0prior_val;
162 X = Xfull*s0prior_val;
168 Qfull_t{ist,r} = Qfull_t{ist,r}(uniqueIdx);
169 Ufull_t{ist,r} = Ufull_t{ist,r}(uniqueIdx);
170 Tfull_t{ist,r} = Tfull_t{ist,r}(uniqueIdx);
171 Qt{ist,r} = [Qfull_t{ist,r} * s0prior_val,t];
172 Ut{ist,r} = [Ufull_t{ist,r} * s0prior_val,t];
173 Tt{ist,r} = [Tfull_t{ist,r} * s0prior_val,t];
177 Q = Q + Qfull*s0prior_val;
178 R = R + Rfull*s0prior_val;
179 T = T + Tfull*s0prior_val;
180 U = U + Ufull*s0prior_val;
181 C = C + Cfull*s0prior_val;
182 X = X + Xfull*s0prior_val;
185 [t,uniqueIdx] = unique(t);
186 Qfull_t{ist,r} = Qfull_t{ist,r}(uniqueIdx);
187 Ufull_t{ist,r} = Ufull_t{ist,r}(uniqueIdx);
188 % Tfull_t{i,r} = Tfull_t{i,r}(uniqueIdx);
190 tunion =
union(Qt{ist,r}(:,2), t);
191 dataOld = interp1(Qt{ist,r}(:,2),Qt{ist,r}(:,1),tunion);
192 dataNew = interp1(t,Qfull_t{ist,r},tunion);
193 Qt{ist,r} = [dataOld + s0prior_val * dataNew, tunion];
195 dataOld = interp1(Ut{ist,r}(:,2),Ut{ist,r}(:,1),tunion);
196 dataNew = interp1(t,Ufull_t{ist,r},tunion);
197 Ut{ist,r} = [dataOld + s0prior_val * dataNew, tunion];
199 % dataOld = interp1(Tt{i,r}(:,2),Tt{i,r}(:,1),tunion);
200 % dataNew = interp1(t,Tfull_t{i,r},tunion);
201 % Tt{i,r} = [dataOld + s0prior_val * dataNew, tunion];
207 s0_id=pprod(s0_id,s0_sz-1); % update initial state
209% Now we restore the original state
211 if sn.isstateful(ind)
212 isf = sn.nodeToStateful(ind);
213 self.model.nodes{ind}.setState(cur_state{isf});
217self.result.solverSpecific = lastSol;
218% Store AoI results
if available
219if exist(
'aoiResults',
'var') && ~isempty(aoiResults)
220 self.result.solverSpecific.aoiResults = aoiResults;
222QN = Q; UN=U; RN=R; TN=T; CN=C; XN=X;
223% Compute average arrival rate at steady-state
224AN = sn_get_arvr_from_tput(sn, TN, self.getAvgTputHandles());
225if strcmp(orig_method,
'default') && ~strcmp(options.method,
'default')
226 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,['default/',options.method],iter);
228 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,options.method,iter);
231self.setTranAvgResults(Qt,Ut,Rt,Tt,Ct,Xt,runtime);