LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
runAnalyzer.m
1function runtime = runAnalyzer(self, options)
2% RUNTIME = RUNANALYZER(OPTIONS)
3% Run the solver
4
5if nargin<2
6 options = self.getOptions;
7end
8
9self.runAnalyzerChecks(options);
10
11sn = self.getStruct();
12if isfield(sn,'immfeed') && ~isempty(sn.immfeed) && any(sn.immfeed(:))
13 line_warning(mfilename,'SolverMVA does not handle immediate feedback (immfeed); the solver will treat self-loops as class-switching with re-queueing.\n');
14end
15
16Solver.resetRandomGeneratorSeed(options.seed);
17
18% Show library attribution if verbose and not yet shown
19if options.verbose ~= VerboseLevel.SILENT && ~GlobalConstants.isLibraryAttributionShown()
20 sn = self.getStruct();
21 libs = SolverMVA.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
28iter = 0;
29%options.lang='java';
30
31switch options.lang
32 case 'java'
33 line_debug(options, 'MVA: using lang=java, delegating to JLINE');
34 sn = getStruct(self); % doesn't need initial state
35 jmodel = LINE2JLINE(self.model);
36 %M = jmodel.getNumberOfStatefulNodes;
37 M = jmodel.getNumberOfStations;
38 R = jmodel.getNumberOfClasses;
39 jsolver = JLINE.SolverMVA(jmodel, options);
40 [QN,UN,RN,WN,AN,TN] = JLINE.arrayListToResults(jsolver.getAvgTable);
41 runtime = jsolver.result.runtime;
42 CN = [];
43 XN = [];
44 QN = reshape(QN',R,M)';
45 UN = reshape(UN',R,M)';
46 RN = reshape(RN',R,M)';
47 TN = reshape(TN',R,M)';
48 WN = reshape(WN',R,M)';
49 AN = reshape(AN',R,M)';
50 lG = NaN;
51 lastiter = NaN;
52 for ind = 1:sn.nnodes
53 if sn.nodetype(ind) == NodeType.Cache
54 jnode = jmodel.getNodeByIndex(ind-1);
55 self.model.nodes{ind}.setResultHitProb(JLINE.from_jline_matrix(jnode.getHitRatio()));
56 self.model.nodes{ind}.setResultMissProb(JLINE.from_jline_matrix(jnode.getMissRatio()));
57 % Retrieval-cache extras (delayed-hit ratio, per-list hit ratio
58 % and expected latency) so getAvgCacheTable matches the native path.
59 self.model.nodes{ind}.setResultDelayedHitProb(JLINE.from_jline_matrix(jnode.getDelayedHitRatio()));
60 self.model.nodes{ind}.setResultHitProbList(JLINE.from_jline_matrix(jnode.getHitRatioByList()));
61 self.model.nodes{ind}.setResultItemProb(JLINE.from_jline_matrix(jnode.getItemProb()));
62 self.model.nodes{ind}.setResultResidT(JLINE.from_jline_matrix(jnode.getResidT()));
63 end
64 end
65 %self.model.refreshChains();
66 self.model.refreshStruct(true);
67 self.setAvgResults(QN,UN,RN,TN,AN,WN,CN,XN,runtime,options.method,lastiter);
68 self.result.Prob.logNormConstAggr = lG;
69 return
70 case 'matlab'
71 line_debug(options, 'MVA: using lang=matlab');
72 sn = getStruct(self); % doesn't need initial state
73 forkLoop = true;
74 forkIter = 0;
75 % create artificial classes arrival rates
76 forkLambda = GlobalConstants.FineTol * ones(1, 2*sn.nclasses*sum(sn.nodetype==NodeType.Fork));
77 QN = GlobalConstants.Immediate * ones(1, sn.nclasses);
78 QN_1 = 0*QN;
79 UN = 0*QN;
80 while (forkLoop && forkIter < options.iter_max)
81 if self.model.hasFork
82 forkIter = forkIter + 1;
83 line_debug(options, 'Fork-join iteration %d', forkIter);
84 if forkIter == 1
85 switch options.config.fork_join
86 case {'heidelberger-trivedi', 'ht'}
87 [nonfjmodel, fjclassmap, fjforkmap, fj_auxiliary_delays] = ModelAdapter.ht(self.model);
88 line_debug(options, 'Fork-join method: heidelberger-trivedi');
89 case {'mmt', 'default', 'fjt'}
90 [nonfjmodel, fjclassmap, fjforkmap, fanout] = ModelAdapter.mmt(self.model, forkLambda);
91 line_debug(options, 'Fork-join method: mmt');
92 [outer_forks, parent_forks] = ModelAdapter.sortForks(sn, fjforkmap, fjclassmap, nonfjmodel);
93 end
94 elseif ~strcmp(options.config.fork_join, 'heidelberger-trivedi') & ~strcmp(options.config.fork_join, 'ht')
95 %line_printf('Fork-join iteration %d\n',forkIter);
96 nonfjSource = nonfjmodel.getSource;
97 for r=1:length(fjclassmap) % r is the auxiliary class
98 s = fjclassmap(r);
99 if s>0
100 if fanout(r)>0
101 if ~nonfjSource.arrivalProcess{r}.isDisabled
102 nonfjSource.arrivalProcess{r}.setRate((fanout(r)-1)*forkLambda(r));
103 end
104 end
105 end
106 end
107 nonfjmodel.refreshRates();
108 end
109 sn = nonfjmodel.getStruct(false); % this ensures that we solve nonfjmodel instead of the original model
110 line_debug(options, 'Fork-join iter %d: rebuilt nonfjmodel struct (nstations=%d, nclasses=%d)', forkIter, sn.nstations, sn.nclasses);
111 % Convergence check: handle zero/NaN queue lengths from size mismatch and Immediate activities
112 qn_ratio = QN_1 ./ QN;
113 qn_ratio(isnan(qn_ratio)) = 1; % 0/0 = NaN → treat as converged (ratio=1)
114 qn_ratio(isinf(qn_ratio)) = 0; % x/0 = Inf → treat as not converged (ratio=0, error=1)
115 if isequal(size(QN_1), size(QN)) && max(abs(1 - qn_ratio(:))) < GlobalConstants.CoarseTol && (forkIter > 2)
116 line_debug(options, 'Fork-join iter %d: converged (max ratio error < CoarseTol)', forkIter);
117 forkLoop = false;
118 else
119 if self.model.hasOpenClasses
120 sourceIndex = self.model.getSource.index;
121 UNnosource = UN; UNnosource(sourceIndex,:) = 0;
122 if any(find(sum(UNnosource(:,isinf(sn.njobs(1:size(QN,2)))),2)>0.99 * sn.nservers))
123 line_warning(mfilename,'The model may be unstable: the utilization of station %i for open classes exceeds 99 percent.\n',maxpos(sum(UNnosource,2)));
124 end
125 end
126 QN_1 = QN;
127 end
128 else
129 forkLoop = false;
130 end
131 line_debug(options, 'Product-form check: hasProductForm=%d (exact method requested)', self.model.hasProductFormSolution);
132 if strcmp(options.method,'exact') && ~self.model.hasProductFormSolution
133 line_error(mfilename,'The exact method requires the model to have a product-form solution. This model does not have one.\nYou can use Network.hasProductFormSolution() to check before running the solver.\n Run the ''mva'' method to obtain an approximation based on the exact MVA algorithm.\n');
134 end
135 if strcmp(options.method,'mva') && ~self.model.hasProductFormSolution
136 line_warning(mfilename,'The exact method requires the model to have a product-form solution. This model does not have one.\nYou can use Network.hasProductFormSolution() to check before running the solver.\nSolverMVA will return an approximation generated by an exact MVA algorithm.');
137 end
138
139 method = options.method;
140
141 % Check for size-based policies (SRPT, PSJF, FB, LRPT, SETF) in multiclass open systems
142 queueIdx = find(sn.nodetype == NodeType.Queue);
143 isSizeBasedPolicy = false;
144 if ~isempty(queueIdx)
145 schedType = sn.sched(sn.nodeToStation(queueIdx(1)));
146 isSizeBasedPolicy = ismember(schedType, [SchedStrategy.SRPT, SchedStrategy.PSJF, SchedStrategy.FB, SchedStrategy.LRPT, SchedStrategy.SETF]);
147 end
148
149 ci_cache = find(sn.nodetype == NodeType.Cache, 1);
150 hasRetrieval = ~isempty(ci_cache) && isfield(sn.nodeparam{ci_cache}, 'retrievalSystemCapacity') ...
151 && sn.nodeparam{ci_cache}.retrievalSystemCapacity > 0;
152 if hasRetrieval % delayed-hit (retrieval-system) cache
153 line_debug(options, 'Delayed-hit retrieval cache, routing to mva_retrieval_analyzer');
154 [QN,UN,RN,TN,CN,XN,lG,hitprob,missprob,delayedprob,hitproblist,itemprob,latency,runtime,actualmethod] = solver_mva_retrieval_analyzer(sn, options);
155 lastiter = NaN;
156 for ind = 1:sn.nnodes
157 if sn.nodetype(ind) == NodeType.Cache
158 self.model.nodes{ind}.setResultHitProb(hitprob);
159 self.model.nodes{ind}.setResultMissProb(missprob);
160 self.model.nodes{ind}.setResultDelayedHitProb(delayedprob);
161 self.model.nodes{ind}.setResultHitProbList(hitproblist);
162 self.model.nodes{ind}.setResultItemProb(itemprob);
163 self.model.nodes{ind}.setResultResidT(latency);
164 end
165 end
166 self.model.refreshStruct(true);
167 elseif sn.nclosedjobs == 0 && length(sn.nodetype)==3 && all(sort(sn.nodetype)' == sort([NodeType.Source,NodeType.Queue,NodeType.Sink])) && isSizeBasedPolicy
168 % Multiclass open system with size-based scheduling (SRPT, PSJF, FB, LRPT, SETF)
169 line_debug(options, 'Size-based scheduling detected (%s), routing to qsys_sizebased_analyzer', char(schedType));
170 [QN,UN,RN,TN,CN,XN,lG,runtime,lastiter] = solver_mva_qsys_sizebased_analyzer(sn, options, schedType);
171 elseif sn.nclasses==1 && sn.nclosedjobs == 0 && length(sn.nodetype)==3 && all(sort(sn.nodetype)' == sort([NodeType.Source,NodeType.Queue,NodeType.Sink])) % is an open queueing system
172 line_debug(options, 'Single-class open queueing system (Source-Queue-Sink), routing to qsys_analyzer');
173 [QN,UN,RN,TN,CN,XN,lG,runtime,lastiter] = solver_mva_qsys_analyzer(sn, options);
174 elseif sn.nclasses>1 && sn.nclosedjobs == 0 && length(sn.nodetype)==3 && all(sort(sn.nodetype)' == sort([NodeType.Source,NodeType.Queue,NodeType.Sink])) && sn.sched(find(sn.nodetype==NodeType.Queue)) == SchedStrategy.POLLING % is an open polling system
175 line_debug(options, 'Multiclass open polling system, routing to polling_analyzer');
176 [QN,UN,RN,TN,CN,XN,lG,runtime,lastiter] = solver_mva_polling_analyzer(sn, options);
177 elseif sn.nclosedjobs == 0 && length(sn.nodetype)==3 && all(sort(sn.nodetype)' == sort([NodeType.Source,NodeType.Cache,NodeType.Sink])) % is a non-rentrant cache
178 line_debug(options, 'Non-reentrant cache (Source-Cache-Sink), routing to cache_analyzer');
179 % random initialization
180 for ind = 1:sn.nnodes
181 if sn.nodetype(ind) == NodeType.Cache
182 prob = self.model.nodes{ind}.server.hitClass;
183 prob(prob>0) = 0.5;
184 self.model.nodes{ind}.setResultHitProb(prob);
185 self.model.nodes{ind}.setResultMissProb(1-prob);
186 end
187 end
188 self.model.refreshChains();
189 % start iteration
190 [QN,UN,RN,TN,CN,XN,lG,runtime,lastiter,actualmethod,hitproblist,itemprob] = solver_mva_cache_analyzer(sn, options);
191
192 for ind = 1:sn.nnodes
193 if sn.nodetype(ind) == NodeType.Cache
194 self.model.nodes{ind}.setResultHitProbList(hitproblist);
195 self.model.nodes{ind}.setResultItemProb(itemprob);
196 hitClass = self.model.nodes{ind}.getHitClass;
197 missClass = self.model.nodes{ind}.getMissClass;
198 hitprob = zeros(1,length(hitClass));
199 for k=1:length(self.model.nodes{ind}.getHitClass)
200 chain_k = sn.chains(:,k)>0;
201 inchain = sn.chains(chain_k,:)>0;
202 h = hitClass(k);
203 m = missClass(k);
204 if h>0 && m>0
205 hitprob(k) = XN(h) / sum(XN(inchain),"omitnan"); %#ok<NANSUM>
206 end
207 end
208 self.model.nodes{ind}.setResultHitProb(hitprob);
209 self.model.nodes{ind}.setResultMissProb(1-hitprob);
210 end
211 end
212 %self.model.refreshChains();
213 self.model.refreshStruct(true);
214 else % queueing network
215 if any(sn.nodetype == NodeType.Cache) % if integrated caching-queueing
216 line_debug(options, 'Integrated caching-queueing network, routing to cacheqn_analyzer');
217 [QN,UN,RN,TN,CN,XN,lG,hitprob,missprob,runtime,lastiter] = solver_mva_cacheqn_analyzer(self, options);
218 for ind = 1:sn.nnodes
219 if sn.nodetype(ind) == NodeType.Cache
220 self.model.nodes{ind}.setResultHitProb(hitprob(ind,:));
221 self.model.nodes{ind}.setResultMissProb(missprob(ind,:));
222 end
223 end
224 %self.model.refreshChains();
225 self.model.refreshStruct(true);
226 else % ordinary queueing network
227 switch method
228 case {'aba.upper', 'aba.lower', 'bjb.upper', 'bjb.lower', 'pb.upper', 'pb.lower', 'gb.upper', 'gb.lower', 'sb.upper', 'sb.lower'}
229 line_debug(options, 'Using bound method: %s', method);
230 [QN,UN,RN,TN,CN,XN,lG,runtime,lastiter] = solver_mva_bound_analyzer(sn, options);
231 otherwise
232 if ~isempty(sn.lldscaling) || ~isempty(sn.cdscaling)
233 line_debug(options, 'Load-dependent scaling detected (lldscaling=%d, cdscaling=%d), routing to mvald_analyzer', ~isempty(sn.lldscaling), ~isempty(sn.cdscaling));
234 [QN,UN,RN,TN,CN,XN,lG,runtime,lastiter,actualmethod] = solver_mvald_analyzer(sn, options);
235 else
236 line_debug(options, 'Standard queueing network, routing to mva_analyzer (method=%s)', method);
237 [QN,UN,RN,TN,CN,XN,lG,runtime,lastiter,actualmethod] = solver_mva_analyzer(sn, options);
238 end
239 end
240 end
241 end
242 if self.model.hasFork
243 line_debug(options, 'Fork-join post-processing: method=%s, computing sync delays', options.config.fork_join);
244 nonfjstruct = sn;
245 sn = self.getStruct;
246 % Pre-compute linked routing matrix once (loop-invariant)
247 switch options.config.fork_join
248 case {'mmt', 'default', 'fjt'}
249 Pcs = cell2mat(nonfjmodel.getLinkedRoutingMatrix);
250 end
251 for f=find(sn.nodetype == NodeType.Fork)'
252 switch options.config.fork_join
253 case {'mmt', 'default', 'fjt'}
254 TNfork = zeros(1,sn.nclasses);
255 for c=1:sn.nchains
256 inchain = find(sn.chains(c,:));
257 for r=inchain(:)'
258 TNfork(r) = (sn.nodevisits{c}(parent_forks(f),r) / sum(sn.visits{c}(sn.stationToStateful(sn.refstat(r)),inchain))) * sum(TN(sn.refstat(r),inchain));
259 end
260 end
261 % find join associated to fork f
262 joinIdx = find(sn.fj(f,:));
263 forkauxclasses = find(fjforkmap==f);
264 for s=forkauxclasses(:)'
265 r = fjclassmap(s); % original class associated to auxiliary class s
266 if isempty(joinIdx)
267 forkLambda(s) = mean([forkLambda(s); TNfork(r)],1);
268 else
269 joinStat = sn.nodeToStation(joinIdx);
270 TN(sn.nodeToStation(joinIdx),r) = TN(sn.nodeToStation(joinIdx),r) + sum(TN(sn.nodeToStation(joinIdx), find(fjclassmap == r))) - TN(sn.nodeToStation(joinIdx), s);
271 forkLambda(s) = mean([forkLambda(s); TN(sn.nodeToStation(joinIdx),r)],1);
272 end
273 if isempty(joinIdx) || ~outer_forks(f, r)
274 % No join nodes for this fork, no synchronisation delay
275 continue;
276 end
277 % Find the parallel paths coming out of the fork
278 ri = ModelAdapter.findPathsCS(sn, Pcs, f, joinIdx, r, [r,s], QN, TN, 0, fjclassmap, fjforkmap, nonfjmodel);
279 if isempty(ri)
280 % No routing from fork for this class - set sync delay to 0 (Immediate)
281 % Matches JAR behavior where empty Matrix gives syncDelay = 0
282 syncDelay = 0;
283 else
284 lambdai = 1./ri;
285 d0 = 0;
286 parallel_branches = length(ri);
287 for pow=0:(parallel_branches - 1)
288 current_sum = sum(1./sum(nchoosek(lambdai, pow + 1),2));
289 d0 = d0 + (-1)^pow * current_sum;
290 end
291 syncDelay = d0*sn.nodeparam{f}.fanOut - mean(ri);
292 end
293 % Set the synchronisation delays
294 nonfjmodel.nodes{joinIdx}.setService(nonfjmodel.classes{s}, Exp.fitMean(syncDelay));
295 if outer_forks(f, r)
296 nonfjmodel.nodes{joinIdx}.setService(nonfjmodel.classes{r}, Exp.fitMean(syncDelay));
297 end
298 end
299 case {'heidelberger-trivedi', 'ht'}
300 joinIdx = find(sn.fj(f,:));
301 for c=1:sn.nchains
302 inchain = find(sn.chains(c,:));
303 for r=inchain(:)'
304 if sn.nodevisits{c}(f,r) == 0
305 continue;
306 end
307 % Obtain the response times on the parallel branches
308 ri = RN(:, find(fjclassmap == r));
309 ri(isnan(ri) | isinf(ri)) = 0;
310 ri = sum(ri, 1, "omitnan") - RN(nonfjstruct.nodeToStation(fj_auxiliary_delays{joinIdx}), find(fjclassmap == r)) - RN(nonfjstruct.nodeToStation(joinIdx), find(fjclassmap == r));
311 lambdai = 1./ri;
312 d0 = 0;
313 parallel_branches = length(self.model.nodes{f}.output.outputStrategy{r}{3});
314 for pow=0:(parallel_branches - 1)
315 current_sum = sum(1./sum(nchoosek(lambdai, pow + 1),2));
316 d0 = d0 + (-1)^pow * current_sum;
317 end
318 di = d0*sn.nodeparam{f}.fanOut - ri;
319 r0 = sum(RN(:, inchain), 2);
320 r0(isnan(r0) | isinf(r0)) = 0;
321 r0 = sum(r0, 1, "omitnan") - RN(nonfjstruct.nodeToStation(joinIdx), r);
322 % Update the delays at the join node and at the auxiliary delay
323 nonfjmodel.nodes{joinIdx}.setService(nonfjmodel.classes{r}, Exp.fitMean(d0*sn.nodeparam{f}.fanOut));
324 idx = 1;
325 for s=find(fjclassmap == r)
326 nonfjmodel.nodes{joinIdx}.setService(nonfjmodel.classes{s}, Exp.fitMean(di(idx)));
327 idx = idx + 1;
328 nonfjmodel.nodes{fj_auxiliary_delays{joinIdx}}.setService(nonfjmodel.classes{s}, Exp.fitMean(r0));
329 end
330
331 end
332 end
333 end
334 end
335 % Batch refreshRates after all sync delay updates (moved out of inner loops for performance)
336 switch options.config.fork_join
337 case {'mmt', 'default', 'fjt'}
338 nonfjmodel.refreshRates();
339 end
340 switch options.config.fork_join
341 case {'heidelberger-trivedi', 'ht'}
342 nonfjmodel.refreshStruct();
343 % Delete the queue lengths, response times, throughputs and utilizations of the original classes at the join nodes
344 QN(nonfjstruct.nodeToStation(find(sn.nodetype == NodeType.Join)), nonzeros(fjclassmap)) = 0;
345 RN(nonfjstruct.nodeToStation(find(sn.nodetype == NodeType.Join)), nonzeros(fjclassmap)) = 0;
346 % Save the throughputs of the original classes at the join node
347 TN_orig = TN(nonfjstruct.nodeToStation(find(sn.nodetype == NodeType.Join)), nonzeros(fjclassmap));
348 TN(nonfjstruct.nodeToStation(find(sn.nodetype == NodeType.Join)), nonzeros(fjclassmap)) = 0;
349 UN(nonfjstruct.nodeToStation(find(sn.nodetype == NodeType.Join)), nonzeros(fjclassmap)) = 0;
350
351 % Remove the times at the auxiliary delay
352 QN(nonfjstruct.nodeToStation(cell2mat(fj_auxiliary_delays)),:) = [];
353 UN(nonfjstruct.nodeToStation(cell2mat(fj_auxiliary_delays)),:) = [];
354 RN(nonfjstruct.nodeToStation(cell2mat(fj_auxiliary_delays)),:) = [];
355 TN(nonfjstruct.nodeToStation(cell2mat(fj_auxiliary_delays)),:) = [];
356 % merge back artificial classes into their original classes
357 for r=1:length(fjclassmap)
358 s = fjclassmap(r);
359 if s>0
360 QN(:,s) = QN(:,s) + QN(:,r);
361 UN(:,s) = UN(:,s) + UN(:,r);
362 % Add all throughputs of the auxiliary classes to facilitate the computation of the response times
363 TN(:,s) = TN(:,s) + TN(:,r);
364 RN(:,s) = QN(:,s) ./ TN(:,s);
365 end
366 end
367 % Re-set the throughputs for the original classes
368 TN(nonfjstruct.nodeToStation(find(sn.nodetype == NodeType.Join)), nonzeros(fjclassmap)) = TN_orig;
369 case {'mmt', 'default', 'fjt'}
370 TN_orig = TN([nonfjstruct.nodeToStation(find(sn.nodetype == NodeType.Join)), nonfjstruct.nodeToStation(find(sn.nodetype == NodeType.Source))], nonzeros(fjclassmap));
371 % merge back artificial classes into their original classes
372 for r=1:length(fjclassmap)
373 s = fjclassmap(r);
374 if s>0
375 QN(:,s) = QN(:,s) + QN(:,r);
376 UN(:,s) = UN(:,s) + UN(:,r);
377 TN(:,s) = TN(:,s) + TN(:,r);
378 %RN(:,s) = RN(:,s) + RN(:,r);
379 % for i=find(snorig.nodetype == NodeType.Delay | snorig.nodetype == NodeType.Queue)'
380 % TN(snorig.nodeToStation(i),s) = TN(snorig.nodeToStation(i),s) + TN(snorig.nodeToStation(i),r);
381 % end
382 RN(:,s) = QN(:,s) ./ TN(:,s);
383 %CN(:,s) = CN(:,s) + CN(:,r);
384 %XN(:,s) = XN(:,s) + XN(:,r);
385 end
386 end
387 TN([nonfjstruct.nodeToStation(find(sn.nodetype == NodeType.Join)), nonfjstruct.nodeToStation(find(sn.nodetype == NodeType.Source))], nonzeros(fjclassmap)) = TN_orig;
388 end
389 QN(:,fjclassmap>0) = [];
390 UN(:,fjclassmap>0) = [];
391 RN(:,fjclassmap>0) = [];
392 TN(:,fjclassmap>0) = [];
393 CN(:,fjclassmap>0) = [];
394 XN(:,fjclassmap>0) = [];
395 end
396 iter = iter + lastiter;
397 % Cap accumulated iterations for stability (Python parity)
398 if iter > 10000
399 iter = 10000;
400 break; % Exit forkLoop early
401 end
402 end
403
404 sn = self.model.getStruct();
405
406 % Compute average residence time at steady-state
407 AN = sn_get_arvr_from_tput(sn, TN, self.getAvgTputHandles());
408 WN = sn_get_residt_from_respt(sn, RN, self.getAvgResidTHandles());
409 if strcmp(method,'default') && exist('actualmethod','var')
410 self.setAvgResults(QN,UN,RN,TN,AN,WN,CN,XN,runtime,['default/' actualmethod],iter);
411 else
412 self.setAvgResults(QN,UN,RN,TN,AN,WN,CN,XN,runtime,method,iter);
413 end
414 self.result.Prob.logNormConstAggr = lG;
415end
416end
417
418
Definition mmt.m:124