LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
getAvg.m
1function [QNclass,UNclass,RNclass,TNclass,ANclass,WNclass] = getAvg(self,Q,U,R,T,A,W)
2% [QNCLASS,UNCLASS,RNCLASS,TNCLASS,ANCLASS,WNCLASS] = GETAVG(SELF,Q,U,R,T,A,W)
3%
4% Compute steady-state average metrics (queue length, utilization, response time,
5% throughput, arrival rate, residence time) for all stations and job classes.
6%
7% Copyright (c) 2012-2026, Imperial College London
8% All rights reserved.
9
10sn = self.model.getStruct();
11
12if strcmp(self.options.lang,'java') && ~strcmp(self.name,'SolverLDES')
13 T0=tic;
14 M = sn.nstations;
15 R = sn.nclasses;
16 % Force fresh Java model conversion each time to ensure current state
17 % Only re-create the Java model if the model is not already Java-native
18 if ~self.model.isJavaNative()
19 self.model.obj = [];
20 self.setLang();
21 end
22 self.obj.getOptions.verbose = jline.VerboseLevel.STD;
23 SolverResult = self.obj.getAvg();
24 QN = JLINE.from_jline_matrix(SolverResult.QN);
25 UN = JLINE.from_jline_matrix(SolverResult.UN);
26 RN = JLINE.from_jline_matrix(SolverResult.RN);
27 TN = JLINE.from_jline_matrix(SolverResult.TN);
28 AN = JLINE.from_jline_matrix(SolverResult.AN);
29 WN = JLINE.from_jline_matrix(SolverResult.WN);
30 runtime=SolverResult.runtime;
31 method=SolverResult.method;
32 % Extract cache hit/miss probabilities from Java model
33 for ind = 1:sn.nnodes
34 if sn.nodetype(ind) == NodeType.Cache
35 jnode = self.model.obj.getNodeByIndex(ind-1);
36 hitRatioVec = JLINE.from_jline_matrix(jnode.getHitRatio());
37 missRatioVec = JLINE.from_jline_matrix(jnode.getMissRatio());
38 % Store per-class hit/miss probabilities matching MATLAB format:
39 % only parent classes with hitClass>0 have non-zero entries
40 hitClass = self.model.nodes{ind}.getHitClass;
41 nk = length(hitClass);
42 hitprob = zeros(1, nk);
43 missprob = zeros(1, nk);
44 for k = 1:nk
45 if hitClass(k) > 0 && k <= length(hitRatioVec)
46 hitprob(k) = hitRatioVec(k);
47 missprob(k) = missRatioVec(k);
48 end
49 end
50 self.model.nodes{ind}.setResultHitProb(hitprob);
51 self.model.nodes{ind}.setResultMissProb(missprob);
52 % Retrieval-cache extras (delayed-hit ratio, per-list hit ratio and
53 % expected latency) copied raw from the Java cache so getAvgCacheTable
54 % matches the native path. Empty for plain caches.
55 self.model.nodes{ind}.setResultDelayedHitProb(JLINE.from_jline_matrix(jnode.getDelayedHitRatio()));
56 self.model.nodes{ind}.setResultHitProbList(JLINE.from_jline_matrix(jnode.getHitRatioByList()));
57 self.model.nodes{ind}.setResultItemProb(JLINE.from_jline_matrix(jnode.getItemProb()));
58 self.model.nodes{ind}.setResultResidT(JLINE.from_jline_matrix(jnode.getResidT()));
59 end
60 end
61 if any(sn.nodetype == NodeType.Cache)
62 self.model.refreshStruct(true);
63 end
64 self.setAvgResults(QN,UN,RN,TN,AN,WN,[],[],runtime,method,1);
65 QNclass = reshape(QN,M,R);
66 UNclass = reshape(UN,M,R);
67 RNclass = reshape(RN,M,R);
68 TNclass = reshape(TN,M,R);
69 ANclass = reshape(AN,M,R);
70 WNclass = reshape(WN,M,R);
71 return
72end
73
74%%
75if nargin == 1 % no parameter
76 if isempty(self.model.handles) || ~isfield(self.model.handles,'Q') || ...
77 ~isfield(self.model.handles,'U') || ~isfield(self.model.handles,'R') || ...
78 ~isfield(self.model.handles,'T') || ~isfield(self.model.handles,'A') || ...
79 ~isfield(self.model.handles,'W')
80 reset(self); % reset results in case there are partial results saved
81 end
82 [Q,U,R,T,A,W] = self.getAvgHandles;
83elseif nargin == 2
84 handlers = Q;
85 [Q,U,R,T,A,W] = deal(handlers{:}); % set Q=handlers{1}, U=handlers{2}, ...
86end
87
88if isfield(self.options,'timespan')
89 if isfinite(self.options.timespan(2))
90 line_error(mfilename,'The getAvg method does not support the timespan option, use the getTranAvg method instead.');
91 end
92else
93 self.options.timespan = [0,Inf];
94end
95
96if ~self.hasAvgResults() || ~self.options.cache
97 runAnalyzer(self);
98 % the next line is required because getAvg can alter the chain
99 % structure in the presence of caches so we need to reload sn
100 sn = self.model.getStruct;
101 if ~self.hasAvgResults
102 line_error(mfilename,'Unable to return results for this model.');
103 end
104end % else return cached value
105
106
107M = sn.nstations;
108K = sn.nclasses;
109
110% Check if this is an SPN model (Places don't have response times)
111hasSPN = any(sn.nodetype == NodeType.Place) || any(sn.nodetype == NodeType.Transition);
112
113if ~isempty(R)
114 RNclass = filterMetric(R, self.result.Avg.R, [], sn, K, M);
115else
116 RNclass = [];
117end
118
119if ~isempty(Q)
120 % For SPNs, don't zero Q based on R because Places don't have response times
121 if hasSPN
122 zeroMaskQ = [];
123 else
124 zeroMaskQ = RNclass < 10 * GlobalConstants.FineTol;
125 end
126 QNclass = filterMetric(Q, self.result.Avg.Q, zeroMaskQ, sn, K, M);
127else
128 QNclass = [];
129end
130
131if ~isempty(U)
132 % For SPNs, don't zero U based on R because Places don't have response times
133 if hasSPN
134 zeroMaskU = [];
135 else
136 zeroMaskU = RNclass < 10 * GlobalConstants.FineTol;
137 end
138 UNclass = filterMetric(U, self.result.Avg.U, zeroMaskU, sn, K, M);
139else
140 UNclass = [];
141end
142
143if ~isempty(T)
144 TNclass = filterMetric(T, self.result.Avg.T, [], sn, K, M);
145else
146 TNclass = [];
147end
148
149if ~isempty(A)
150 zeroMask = false(size(RNclass));
151 zeroMask(sn.nodeToStation(sn.nodetype==NodeType.Source),:) = true;
152 ANclass = filterMetric(A, self.result.Avg.A, zeroMask, sn, K, M);
153else
154 ANclass = [];
155end
156
157if ~isempty(W)
158 WNclass = sn_get_residt_from_respt(sn, RNclass, W);
159else
160 WNclass = [];
161end
162
163if ~isempty(UNclass)
164 unstableQueues = find(sum(UNclass,2)>0.99 * sn.nservers);
165 if any(unstableQueues) && any(isinf(sn.njobs))
166 line_warning(mfilename,'The model has unstable queues, performance metrics may grow unbounded.\n')
167 end
168end
169end
170
171function outData = filterMetric(handle, metric, zeroMask, sn, K, M)
172% post-process Avg measure
173outData = zeros(M, K);
174for k = 1:K
175 for i = 1:M
176 if ~handle{i,k}.disabled && ~isempty(metric)
177 outData(i,k) = metric(i,k);
178 else
179 outData(i,k) = NaN;
180 end
181 end
182end
183
184% NaN values indicate that a metric is disabled
185outData(isnan(outData)) = 0;
186% set to zero entries associated to immediate transitions
187outData(zeroMask) = 0;
188% round to zero numerical perturbations
189outData(outData < GlobalConstants.FineTol) = 0;
190
191% set to zero metrics for classes that are unreachable
192% but skip this check for fork-join models where the visits calculation
193% doesn't correctly capture the parent class visiting Join and downstream nodes
194% also skip when no chains are defined (routing not specified)
195% also skip for SPN models where Places don't have traditional visits
196hasForkJoin = any(sn.nodetype == NodeType.Fork) && any(sn.nodetype == NodeType.Join);
197hasSPN = any(sn.nodetype == NodeType.Place) || any(sn.nodetype == NodeType.Transition);
198
199if sn.nchains > 0 && ~hasSPN % Only check reachability if chains are defined and not SPN
200 for k = 1:K
201 c = sn.chains(:, k)>0;
202 if any(c) % Only check if class k belongs to a chain
203 for i = 1:M
204 if sn.visits{c}(i,k) == 0
205 % For fork-join models, don't zero out if the metric has a non-zero value
206 % from simulation - the visits calculation doesn't capture fork-join semantics
207 % where Join outputs the parent class
208 if hasForkJoin && ~isempty(metric) && metric(i,k) > GlobalConstants.FineTol
209 continue; % Trust the simulation result
210 end
211 outData(i,k) = 0;
212 end
213 end
214 end
215 end
216end
217end
Definition mmt.m:124