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;
6
7if nargin<2
8 options = self.getOptions;
9end
10
11if ~isinf(options.timespan(1)) && (options.timespan(1) == options.timespan(2))
12 line_warning(mfilename,'%s: timespan is a single point, spacing by options.tol (%e).\n',mfilename, options.tol);
13 options.timespan(2) = options.timespan(1) + options.tol;
14end
15
16
17self.runAnalyzerChecks(options);
18Solver.resetRandomGeneratorSeed(options.seed);
19
20% Show library attribution if verbose and not yet shown
21if options.verbose ~= VerboseLevel.SILENT && ~GlobalConstants.isLibraryAttributionShown()
22 libs = SolverCTMC.getLibrariesUsed([], options);
23 if ~isempty(libs)
24 line_printf('The solver will leverage %s.\n', strjoin(libs, ', '));
25 GlobalConstants.setLibraryAttributionShown(true);
26 end
27end
28
29if self.enableChecks && ~self.supports(self.model)
30 % Tier B redirects: detect common families of unsupported models and
31 % point the user at the right alternative solver instead of failing
32 % with a generic message.
33 sn = self.model.getStruct();
34 if any(sn.nodetype == NodeType.Fork) || any(sn.nodetype == NodeType.Join)
35 line_error(mfilename,['This model uses Fork/Join nodes which are not ', ...
36 'supported by SolverCTMC. Use SolverMVA (product-form fork-join via ', ...
37 'MMT decomposition) or SolverSSA (general).\n']);
38 elseif isa(self.model,'LayeredNetwork')
39 line_error(mfilename,['This model is a LayeredNetwork. Use SolverLN ', ...
40 '(iterative) or SolverLQNS (external LQNS) instead of SolverCTMC.\n']);
41 else
42 line_error(mfilename,'This model contains features not supported by the solver.\n');
43 end
44end
45
46% Inform user about reducible routing handling
47if self.enableChecks
48 [isErg, ergInfo] = self.model.isRoutingErgodic();
49 if ~isErg && ~isempty(ergInfo.absorbingStations)
50 absNames = strjoin(ergInfo.absorbingStations, ', ');
51 line_printf([...
52 'Note: Model has reducible routing with absorbing stations: %s\n' ...
53 ' Results represent limiting/absorption probabilities.\n' ...
54 ' Use model.getReducibilityInfo() for detailed analysis.\n'], ...
55 absNames);
56 end
57end
58
59sn = getStruct(self);
60line_debug(options, 'CTMC: using lang=matlab');
61
62% Convert non-Markovian distributions to PH
63sn = sn_nonmarkov_toph(sn, options);
64line_debug(options, 'CTMC: converted non-Markovian distributions to PH (nstations=%d, nclasses=%d)', sn.nstations, sn.nclasses);
65
66M = sn.nstations;
67K = sn.nclasses;
68NK = sn.njobs;
69sizeEstimator = 0;
70for k=1:K
71 sizeEstimator = sizeEstimator + gammaln(1+NK(k)+M-1) - gammaln(1+M-1) - gammaln(1+NK(k)); % worst-case estimate of the state space
72end
73
74if any(isinf(sn.njobs))
75 if isinf(options.cutoff)
76 line_warning(mfilename,sprintf('The model has open chains, it is recommended to specify a finite cutoff value, e.g., SolverCTMC(model,''cutoff'',1).\n'));
77 self.options.cutoff= ceil(6000^(1/(M*K)));
78 options.cutoff= ceil(6000^(1/(M*K)));
79 line_debug(options, 'Open/mixed model: auto-setting cutoff=%d for %d stations, %d classes', options.cutoff, M, K);
80 line_warning(mfilename,sprintf('Setting cutoff=%d.\n',self.options.cutoff));
81 end
82 % Mandatory truncation warning for open/mixed models
83 line_printf('CTMC solver using state space cutoff = %d for open/mixed model.\n', options.cutoff);
84 line_warning(mfilename,'State space truncation may cause inaccurate results. Consider varying cutoff to assess sensitivity.\n');
85end
86
87if sizeEstimator > 6
88 line_debug(options, 'State space size estimate: exp(%f), may be too large', sizeEstimator);
89 if ~isfield(options,'force') || options.force == false
90 % line_error(mfilename,'CTMC size may be too large to solve. Stopping SolverCTMC. Set options.force=true to bypass this control.');
91 line_error(mfilename,'CTMC size may be too large to solve. Stopping SolverCTMC. Set options.force=true or use SolverCTMC(...,''force'',true) to bypass this control.\n');
92 return
93 end
94end
95
96% we compute all metrics anyway because CTMC has essentially
97% the same cost
98if isinf(options.timespan(1))
99 if startsWith(options.method, 'qrf')
100 line_debug(options, 'Using QRF method for steady-state CTMC analysis');
101 [QN,UN,RN,TN,CN,XN,~] = solver_ctmc_qrf_analyzer(sn, options);
102 runtime = toc(T0);
103 T = getAvgTputHandles(self);
104 AN = sn_get_arvr_from_tput(sn, TN, T);
105 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,options.method);
106 else
107 line_debug(options, 'Using standard CTMC method for steady-state analysis');
108 s0 = sn.state;
109 s0prior = sn.stateprior;
110 for ind=1:sn.nnodes
111 if sn.isstateful(ind)
112 isf = sn.nodeToStateful(ind);
113 sn.state{isf} = s0{isf}(maxpos(s0prior{1}),:); % pick one particular initial state
114 end
115 end
116 [QN,UN,RN,TN,CN,XN,Q,SS,SSq,Dfilt,~,~,sn] = solver_ctmc_analyzer(sn, options);
117 % update initial state if this has been corrected by the state space
118 % generator
119 for isf=1:sn.nstateful
120 ind = sn.statefulToNode(isf);
121 self.model.nodes{ind}.setState(sn.state{isf});
122 switch class(self.model.nodes{sn.statefulToNode(isf)})
123 case 'Cache'
124 self.model.nodes{sn.statefulToNode(isf)}.setResultHitProb(sn.nodeparam{ind}.actualhitprob);
125 self.model.nodes{sn.statefulToNode(isf)}.setResultMissProb(sn.nodeparam{ind}.actualmissprob);
126 self.model.refreshChains();
127 end
128 end
129 %sn.space = SS;
130 self.result.infGen = Q;
131 self.result.space = SS;
132 self.result.spaceAggr = SSq;
133 self.result.nodeSpace = sn.space;
134 self.result.eventFilt = Dfilt;
135 runtime = toc(T0);
136 sn.space = {};
137 T = getAvgTputHandles(self);
138 AN=sn_get_arvr_from_tput(sn, TN, T);
139 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,options.method);
140 end % if startsWith(options.method, 'qrf')
141else
142 line_debug(options, 'Transient analysis: timespan=[%f,%f]', options.timespan(1), options.timespan(2));
143 lastSol= [];
144 s0 = sn.space;
145 s0prior = sn.stateprior;
146
147 s0_sz = cellfun(@(x) size(x,1), s0)';
148 s0_id = pprod(s0_sz-1);
149 cur_state = sn.state;
150 while s0_id>=0 % for all possible initial states
151 s0prior_val = 1;
152 for ind=1:sn.nnodes
153 if sn.isstateful(ind)
154 isf = sn.nodeToStateful(ind);
155 s0prior_val = s0prior_val * s0prior{isf}(1+s0_id(isf)); % update prior
156 sn.state{isf} = s0{isf}(1+s0_id(isf),:); % assign initial state to network
157 end
158 end
159 if s0prior_val > 0
160 [t,pit,QNt,UNt,~,TNt,~,~,Q,SS,SSq,Dfilt,runtime_t] = solver_ctmc_transient_analyzer(sn, options);
161 self.result.space = SS;
162 self.result.spaceAggr = SSq;
163 self.result.infGen = Q;
164 self.result.eventFilt = Dfilt;
165 %sn.space = SS;
166 setTranProb(self,t,pit,SS,runtime_t);
167 if isempty(self.result) || ~isfield(self.result,'Tran') || ~isfield(self.result.Tran,'Avg') || ~isfield(self.result.Tran.Avg,'Q')
168 self.result.Tran.Avg.Q = cell(M,K);
169 self.result.Tran.Avg.U = cell(M,K);
170 self.result.Tran.Avg.T = cell(M,K);
171 for ist=1:M
172 for r=1:K
173 self.result.Tran.Avg.Q{ist,r} = [QNt{ist,r} * s0prior_val,t];
174 self.result.Tran.Avg.U{ist,r} = [UNt{ist,r} * s0prior_val,t];
175 self.result.Tran.Avg.T{ist,r} = [TNt{ist,r} * s0prior_val,t];
176 end
177 end
178 else
179 for ist=1:M
180 for r=1:K
181 tunion = union(self.result.Tran.Avg.Q{ist,r}(:,2), t);
182 dataOld = interp1(self.result.Tran.Avg.Q{ist,r}(:,2),self.result.Tran.Avg.Q{ist,r}(:,1),tunion);
183 dataNew = interp1(t,QNt{ist,r},tunion);
184 self.result.Tran.Avg.Q{ist,r} = [dataOld+s0prior_val*dataNew,tunion];
185 dataOld = interp1(self.result.Tran.Avg.U{ist,r}(:,2),self.result.Tran.Avg.U{ist,r}(:,1),tunion);
186 dataNew = interp1(t,UNt{ist,r},tunion);
187 self.result.Tran.Avg.U{ist,r} = [dataOld+s0prior_val*dataNew,tunion];
188
189 dataOld = interp1(self.result.Tran.Avg.T{ist,r}(:,2),self.result.Tran.Avg.T{ist,r}(:,1),tunion);
190 dataNew = interp1(t,TNt{ist,r},tunion);
191 self.result.Tran.Avg.T{ist,r} = [dataOld+s0prior_val*dataNew,tunion];
192 end
193 end
194 end
195 end
196 s0_id=pprod(s0_id,s0_sz-1); % update initial state
197 end
198 % Now we restore the original state
199 for ind=1:sn.nnodes
200 if sn.isstateful(ind)
201 isf = sn.nodeToStateful(ind);
202 self.model.nodes{ind}.setState(cur_state{isf});
203 end
204 end
205
206 runtime = toc(T0);
207 sn.space = {};
208 self.result.('solver') = getName(self);
209 self.result.runtime = runtime;
210 self.result.solverSpecific = lastSol;
211end
212end
Definition mmt.m:124