LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
runAnalyzer.m
1function runtime = runAnalyzer(self, options)
2% RUNTIME = RUN()
3% Run the solver
4
5T0=tic;
6iter = NaN;
7if nargin<2
8 options = self.getOptions;
9end
10sn = getStruct(self); % this gets modified later on so pass by copy
11
12% Convert non-Markovian distributions to PH
13sn = sn_nonmarkov_toph(sn, options);
14
15orig_method = options.method;
16self.runAnalyzerChecks(options);
17Solver.resetRandomGeneratorSeed(options.seed);
18
19% Show library attribution if verbose and not yet shown
20if options.verbose ~= VerboseLevel.SILENT && ~GlobalConstants.isLibraryAttributionShown()
21 libs = SolverFLD.getLibrariesUsed(sn, options);
22 if ~isempty(libs)
23 line_printf('The solver will leverage %s.\n', strjoin(libs, ', '));
24 GlobalConstants.setLibraryAttributionShown(true);
25 end
26end
27
28%options.lang = 'java';
29
30hasOpenClasses = sn_has_open_classes(sn);
31switch options.lang
32 case {'java'}
33 line_debug(options, 'FLD: using lang=java, delegating to JLINE');
34 jmodel = LINE2JLINE(self.model);
35 %M = jmodel.getNumberOfStatefulNodes;
36 M = jmodel.getNumberOfStations;
37 R = jmodel.getNumberOfClasses;
38 switch options.method
39 case {'default', 'closing', 'matrix', 'rmf'}
40 jsolver = JLINE.SolverFluid(jmodel, options);
41 otherwise
42 line_warning(mfilename,'This solver does not support the specified method. Setting to default.\n');
43 options.method = 'default';
44 jsolver = JLINE.SolverFluid(jmodel, options);
45 end
46 [QN,UN,RN,WN,AN,TN] = JLINE.arrayListToResults(jsolver.getAvgTable);
47 runtime = toc(T0);
48 CN = [];
49 XN = [];
50 QN = reshape(QN',R,M)';
51 UN = reshape(UN',R,M)';
52 RN = reshape(RN',R,M)';
53 WN = reshape(WN',R,M)';
54 AN = reshape(AN',R,M)';
55 TN = reshape(TN',R,M)';
56 lG = NaN;
57 lastiter = NaN;
58 self.setAvgResults(QN,UN,RN,TN,AN,WN,CN,XN,runtime,options.method,lastiter);
59 self.result.Prob.logNormConstAggr = lG;
60 self.result.solverSpecific.sn = JLINE.from_jline_struct(jmodel);
61 self.result.solverSpecific.odeStateVec = JLINE.from_jline_matrix(jsolver.result.odeStateVec);
62 return
63 case 'matlab'
64 line_debug(options, 'FLD: using lang=matlab');
65 switch options.method
66 case {'matrix','pnorm'}
67 line_debug(options, 'FLD method: matrix/pnorm requested');
68 % Matrix method now supports mixed/open models per Ruuskanen et al., PEVA 151 (2021)
69 if sn_has_dps(sn)
70 line_error(mfilename,'The matrix solver does not support DPS scheduling. Use options.method=''closing'' instead.');
71 end
72 case {'closing'}
73 options.method = 'closing';
74 line_debug(options, 'FLD method: closing');
75 case {'default'}
76 % Use rmf for cache models, closing for DPS, matrix otherwise
77 if any(sn.nodetype == NodeType.Cache)
78 options.method = 'rmf';
79 elseif sn_has_dps(sn)
80 options.method = 'closing';
81 else
82 options.method = 'matrix';
83 end
84 line_debug(options, 'FLD default method resolved to: %s', options.method);
85 case {'statedep','softmin'}
86 line_debug(options, 'FLD method: %s', options.method);
87 % do nothing
88 case {'diffusion','fluid.diffusion'}
89 line_debug(options, 'FLD method: diffusion approximation');
90 % Diffusion approximation - validated in solver_fluid_diffusion
91 % do nothing here, validation happens in the solver itself
92 case {'mfq','fluid.mfq','butools'}
93 line_debug(options, 'FLD method: Markovian fluid queue (BUTools)');
94 % Markovian fluid queue method using BUTools for single-queue analysis
95 % Validation and fallback happens in solver_fluid_analyzer
96 case {'rmf','fluid.rmf'}
97 line_debug(options, 'FLD method: refined mean field (cache analysis)');
98 % Refined mean field method for multi-list cache analysis
99 % Uses DDPP framework with 1/N correction
100 otherwise
101 line_error(mfilename,sprintf('The ''%s'' method is unsupported by this solver.',options.method));
102 end
103end
104
105if isinf(options.timespan(1))
106 if options.verbose == 2
107 line_warning(mfilename,'%s requires options.timespan(1) to be finite. Setting it to 0.\n',mfilename);
108 end
109 options.timespan(1) = 0;
110end
111
112if options.timespan(1) == options.timespan(2)
113 line_warning(mfilename,'%s: timespan is a single point, unsupported. Setting options.timespace(1) to 0.\n',mfilename);
114 options.timespan(1) = 0;
115end
116
117if self.enableChecks && ~self.supports(self.model)
118 line_error(mfilename,'This model contains features not supported by the solver.');
119end
120
121self.setOptions(options);
122
123M = sn.nstations;
124K = sn.nclasses;
125
126%%
127lastSol= [];
128Q = zeros(M,K); R = zeros(M,K); T = zeros(M,K);
129U = zeros(M,K); C = zeros(1,K); X = zeros(1,K);
130Qt=[];
131s0 = sn.space;
132s0prior = sn.stateprior;
133s0_sz = cellfun(@(x) size(x,1), s0)';
134s0_id = pprod(s0_sz-1);
135cur_state = sn.state;
136while s0_id>=0 % for all possible initial states
137 s0prior_val = 1;
138 for ind=1:sn.nnodes
139 if sn.isstateful(ind)
140 isf = sn.nodeToStateful(ind);
141 s0prior_val = s0prior_val * s0prior{isf}(1+s0_id(isf)); % update prior
142 %sn.state{isf} = s0{isf}(1+s0_id(isf),:); % assign initial state to network
143 self.model.nodes{ind}.setState(s0{isf}(1+s0_id(isf),:));
144 end
145 end
146 sn = self.model.getStruct;
147 sn = sn_nonmarkov_toph(sn, options); % Re-apply conversion after fresh struct
148 if s0prior_val > 0
149 %useJLine = false;
150 %if useJLine
151 % [Qfull, Ufull, Rfull, Tfull, Cfull, Xfull, t, Qfull_t, Ufull_t, Tfull_t, lastSol] = JLINE.runFluidAnalyzer(self.model, options);
152 %else
153 [Qfull, Ufull, Rfull, Tfull, Cfull, Xfull, t, Qfull_t, Ufull_t, Tfull_t, lastSol, iter, aoiResults] = solver_fluid_analyzer(sn, options);
154 %end
155
156 [t,uniqueIdx] = unique(t);
157 if isempty(lastSol) % if solution fails
158 Q = NaN*ones(M,K); R = NaN*ones(M,K);
159 T = NaN*ones(M,K); U = NaN*ones(M,K);
160 C = NaN*ones(1,K); X = NaN*ones(1,K);
161 Qt = cell(M,K); Ut = cell(M,K); Tt = cell(M,K);
162 for ist=1:M
163 for r=1:K
164 Qt{ist,r} = [NaN,NaN];
165 Ut{ist,r} = [NaN,NaN];
166 Tt{ist,r} = [NaN,NaN];
167 end
168 end
169 else
170 if isempty(self.result) && max(size(Qt))==0 %~exist('Qt','var')
171 Q = Qfull*s0prior_val;
172 R = Rfull*s0prior_val;
173 T = Tfull*s0prior_val;
174 U = Ufull*s0prior_val;
175 C = Cfull*s0prior_val;
176 X = Xfull*s0prior_val;
177 Qt = cell(M,K);
178 Ut = cell(M,K);
179 Tt = cell(M,K);
180 for ist=1:M
181 for r=1:K
182 if ~isempty(Qfull_t{ist,r}) && length(Qfull_t{ist,r}) >= max(uniqueIdx)
183 Qfull_t{ist,r} = Qfull_t{ist,r}(uniqueIdx);
184 Ufull_t{ist,r} = Ufull_t{ist,r}(uniqueIdx);
185 Tfull_t{ist,r} = Tfull_t{ist,r}(uniqueIdx);
186 Qt{ist,r} = [Qfull_t{ist,r} * s0prior_val,t];
187 Ut{ist,r} = [Ufull_t{ist,r} * s0prior_val,t];
188 Tt{ist,r} = [Tfull_t{ist,r} * s0prior_val,t];
189 else
190 Qt{ist,r} = [NaN,NaN];
191 Ut{ist,r} = [NaN,NaN];
192 Tt{ist,r} = [NaN,NaN];
193 end
194 end
195 end
196 else
197 Q = Q + Qfull*s0prior_val;
198 R = R + Rfull*s0prior_val;
199 T = T + Tfull*s0prior_val;
200 U = U + Ufull*s0prior_val;
201 C = C + Cfull*s0prior_val;
202 X = X + Xfull*s0prior_val;
203 for ist=1:M
204 for r=1:K
205 [t,uniqueIdx] = unique(t);
206 Qfull_t{ist,r} = Qfull_t{ist,r}(uniqueIdx);
207 Ufull_t{ist,r} = Ufull_t{ist,r}(uniqueIdx);
208 % Tfull_t{i,r} = Tfull_t{i,r}(uniqueIdx);
209
210 tunion = union(Qt{ist,r}(:,2), t);
211 dataOld = interp1(Qt{ist,r}(:,2),Qt{ist,r}(:,1),tunion);
212 dataNew = interp1(t,Qfull_t{ist,r},tunion);
213 Qt{ist,r} = [dataOld + s0prior_val * dataNew, tunion];
214
215 dataOld = interp1(Ut{ist,r}(:,2),Ut{ist,r}(:,1),tunion);
216 dataNew = interp1(t,Ufull_t{ist,r},tunion);
217 Ut{ist,r} = [dataOld + s0prior_val * dataNew, tunion];
218
219 % dataOld = interp1(Tt{i,r}(:,2),Tt{i,r}(:,1),tunion);
220 % dataNew = interp1(t,Tfull_t{i,r},tunion);
221 % Tt{i,r} = [dataOld + s0prior_val * dataNew, tunion];
222 end
223 end
224 end
225 end
226 end
227 s0_id=pprod(s0_id,s0_sz-1); % update initial state
228end
229% Now we restore the original state
230for ind=1:sn.nnodes
231 if sn.isstateful(ind)
232 isf = sn.nodeToStateful(ind);
233 self.model.nodes{ind}.setState(cur_state{isf});
234 end
235end
236runtime = toc(T0);
237self.result.solverSpecific = lastSol;
238% Store AoI results if available
239if exist('aoiResults', 'var') && ~isempty(aoiResults)
240 self.result.solverSpecific.aoiResults = aoiResults;
241end
242QN = Q; UN=U; RN=R; TN=T; CN=C; XN=X;
243
244% For cache models solved with rmf, update hit/miss probs in the model
245if any(strcmp(options.method, {'rmf','fluid.rmf'})) && any(sn.nodetype == NodeType.Cache)
246 caches = find(sn.nodetype == NodeType.Cache);
247 % Retrieve hitprob/missprob from the cacheqn result stored in lastSol
248 if isfield(lastSol, 'cacheHitProb')
249 for cIdx = 1:length(caches)
250 ind = caches(cIdx);
251 self.model.nodes{ind}.setResultHitProb(lastSol.cacheHitProb(cIdx,:));
252 self.model.nodes{ind}.setResultMissProb(lastSol.cacheMissProb(cIdx,:));
253 end
254 self.model.refreshStruct(true);
255 sn = self.model.getStruct(true);
256 end
257end
258
259% Compute average arrival rate at steady-state
260AN = sn_get_arvr_from_tput(sn, TN, self.getAvgTputHandles());
261if strcmp(orig_method,'default') && ~strcmp(options.method,'default')
262 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,['default/',options.method],iter);
263else
264 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,options.method,iter);
265end
266Rt={}; Xt={}; Ct={};
267self.setTranAvgResults(Qt,Ut,Rt,Tt,Ct,Xt,runtime);
268end
Definition mmt.m:124