LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
solver_ctmc_analyzer.m
1function [QN,UN,RN,TN,CN,XN,InfGen,StateSpace,StateSpaceAggr,EventFiltration,runtime,fname,sncopy] = solver_ctmc_analyzer(sn, options)
2% [QN,UN,RN,TN,CN,XN,INFGEN,STATESPACE,STATESPACEAGGR,EVENTFILTRATION,RUNTIME,FNAME,sn] = SOLVER_CTMC_ANALYZER(sn, OPTIONS)
3%
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6
7%if options.remote
8% sn.rtfun = {};
9% sn.lst = {};
10% qn_json = jsonencode(sn);
11% sn = NetworkStruct.fromJSON(qn_json)
12%return
13%end
14
15M = sn.nstations; %number of stations
16K = sn.nclasses; %number of classes
17S = sn.nservers;
18NK = sn.njobs'; % initial population per class
19sched = sn.sched;
20
21Tstart = tic;
22PH = sn.proc;
23
24line_debug('CTMC analyzer starting: nstations=%d, nclasses=%d, njobs=%s', M, K, mat2str(NK));
25
26% Note: hide_immediate now selectively preserves Cache immediate transitions
27% in solver_ctmc.m, so we no longer need to disable it entirely for Cache nodes
28
29line_debug('Building state space and infinitesimal generator via solver_ctmc');
30[InfGen,StateSpace,StateSpaceAggr,EventFiltration,arvRates,depRates,sn] = solver_ctmc(sn, options); % sn is updated with the state space
31
32% if the initial state does not reflect the final size of the state
33% vectors, attempt to correct it
34for isf=1:sn.nstateful
35 if size(sn.state{isf},2) < size(sn.space{isf},2)
36 sn.state{isf} = [zeros(1,size(sn.space{isf},2)-size(sn.state{isf},2)),sn.state{isf}];
37 end
38end
39sncopy = sn;
40
41if options.keep
42 line_debug('Saving CTMC data to file (options.keep=true)');
43 fname = lineTempName;
44 save([fname,'.mat'],'InfGen','StateSpace','StateSpaceAggr','EventFiltration')
45 line_printf('CTMC infinitesimal generator and state space saved in: ');
46 line_printf(strrep(sprintf('%s.mat\n',fname),'\','\\'))
47else
48 fname = '';
49end
50
51wset = 1:length(InfGen);
52
53line_debug('State space built: %d states, solving CTMC', length(InfGen));
54
55use_ctmc_solve_stable = true;
56if use_ctmc_solve_stable
57 % stable version
58 % Note: solver_ctmc now selectively preserves Cache immediate transitions
59 % to enable hit/miss rate computation while hiding other immediate transitions
60 [probSysState, ~, nConnComp, connComp] = ctmc_solve(InfGen, options);
61
62 if nConnComp > 1
63 line_debug('CTMC is reducible: %d connected components', nConnComp);
64 % the matrix was reducible
65 initState = matchrow(StateSpace, cell2mat(sn.state'));
66 if initState <= 0
67 % Initial state may have been removed by stochcomp (e.g., SPN with
68 % immediate ENABLE states). Use the largest connected component.
69 compSizes = accumarray(connComp(:), 1);
70 [~, largestComp] = max(compSizes);
71 wset = find(connComp == largestComp);
72 else
73 % determine the weakly connected component associated to the initial state
74 wset = find(connComp == connComp(initState));
75 end
76 if initState > 0
77 line_debug('Using component %d with %d states (from initial state)', connComp(initState), length(wset));
78 else
79 line_debug('Using largest component with %d states (initial state removed by stochcomp)', length(wset));
80 end
81 probSysState = ctmc_solve(InfGen(wset, wset), options);
82 InfGen = InfGen(wset, wset);
83 StateSpace = StateSpace(wset,:);
84 else
85 line_debug('CTMC is irreducible, using full state space');
86 end
87else
88 % development version
89
90 % we now find the initial state and then solver the CTMC allowing for the
91 % case where it is reducible
92 initState = matchrow(StateSpace, cell2mat(sn.state'));
93 pi0 = zeros(1,length(InfGen)); pi0(initState) = 1.0;
94 [pi,pis,~,scc,~] = ctmc_solve_reducible(InfGen, pi0, options);
95
96 if size(pis,1)==1
97 probSysState = pi;
98 else
99 wset = scc == scc(initState);
100 InfGen = InfGen(wset, wset);
101 StateSpace = StateSpace(wset,:);
102 probSysState = pis(scc(initState),scc == scc(initState));
103 end
104end
105probSysState(probSysState<GlobalConstants.Zero)=0;
106probSysState = probSysState/sum(probSysState);
107
108XN = NaN*zeros(1,K);
109UN = NaN*zeros(M,K);
110QN = NaN*zeros(M,K);
111RN = NaN*zeros(M,K);
112TN = NaN*zeros(M,K);
113CN = NaN*zeros(1,K);
114
115istSpaceShift = zeros(1,M);
116for ist=1:M
117 if ist==1
118 istSpaceShift(ist) = 0;
119 else
120 istSpaceShift(ist) = istSpaceShift(ist-1) + size(sn.space{ist-1},2);
121 end
122end
123
124for k=1:K
125 refsf = sn.stationToStateful(sn.refstat(k));
126 XN(k) = probSysState*arvRates(wset,refsf,k);
127end
128
129for ist=1:M
130 isf = sn.stationToStateful(ist);
131 ind = sn.stationToNode(ist);
132 for k=1:K
133 TN(ist,k) = probSysState*depRates(wset,isf,k);
134 QN(ist,k) = probSysState*StateSpaceAggr(wset,(ist-1)*K+k);
135 end
136 if sn.nodetype(ind) ~= NodeType.Source
137 switch sched(ist)
138 case SchedStrategy.INF
139 for k=1:K
140 UN(ist,k) = QN(ist,k);
141 end
142 case {SchedStrategy.PS, SchedStrategy.DPS, SchedStrategy.GPS, SchedStrategy.LPS}
143 if isempty(sn.lldscaling) && isempty(sn.cdscaling) && ~sn_has_joint_dependence(sn)
144 for k=1:K
145 if ~isempty(PH{ist}{k})
146 % There are cases where due to remove of
147 % immediate transitions or due to cutoff the
148 % utilization estimator based on arrivals or
149 % departures can be under-estimated. E.g.:
150 % UNarv_ik doesn't work well with example_stateDependentRouting_3
151 % UNdep_ik doesn't work well with test_OQN_JMT_6
152 % Therefore, we take the maximum of the two
153 % Note: the two estimators are normally
154 % identical.
155 UNarv_ik = probSysState*arvRates(wset,isf,k)*map_mean(PH{ist}{k})/S(ist);
156 UNdep_ik = TN(ist,k)*map_mean(PH{ist}{k})/S(ist); % this is valid because CS in LINE is in a separate node
157 UN(ist,k) = max(UNarv_ik,UNdep_ik);
158 end
159 end
160 else % lld/cd/ljd cases
161 ind = sn.stationToNode(ist);
162 UN(ist,1:K) = 0;
163 for st = wset
164 [ni,nir] = State.toMarginal(sn, ind, StateSpace(st,(istSpaceShift(ist)+1):(istSpaceShift(ist)+size(sn.space{ist},2))));
165 if ni>0
166 for k=1:K
167 UN(ist,k) = UN(ist,k) + probSysState(st)*nir(k)*sn.schedparam(ist,k)/(nir*sn.schedparam(ist,:)');
168 end
169 end
170 end
171 end
172 otherwise
173 if isempty(sn.lldscaling) && isempty(sn.cdscaling) && ~sn_has_joint_dependence(sn)
174 for k=1:K
175 if ~isempty(PH{ist}{k})
176 % There are cases where due to remove of
177 % immediate transitions or due to cutoff the
178 % utilization estimator based on arrivals or
179 % departures can be under-estimated. E.g.:
180 % UNarv_ik doesn't work well with example_stateDependentRouting_3
181 % UNdep_ik doesn't work well with test_OQN_JMT_6
182 % Therefore, we take the maximum of the two
183 % Note: the two estimators are normally
184 % identical.
185 UNarv_ik = probSysState*arvRates(wset,isf,k)*map_mean(PH{ist}{k})/S(ist);
186 UNdep_ik = TN(ist,k)*map_mean(PH{ist}{k})/S(ist); % this is valid because CS in LINE is in a separate node
187 UN(ist,k) = max(UNarv_ik,UNdep_ik);
188 end
189 end
190 else % lld/cd/ljd cases
191 ind = sn.stationToNode(ist);
192 UN(ist,1:K) = 0;
193 for st = wset
194 [ni,~,sir] = State.toMarginal(sn, ind, StateSpace(st,(istSpaceShift(ist)+1):(istSpaceShift(ist)+size(sn.space{ist},2))));
195 if ni>0
196 for k=1:K
197 UN(ist,k) = UN(ist,k) + probSysState(st)*sir(k)/S(ist);
198 end
199 end
200 end
201 end
202 end
203 end
204end
205
206for k=1:K
207 for ist=1:M
208 if TN(ist,k)>0
209 RN(ist,k) = QN(ist,k)./TN(ist,k);
210 else
211 RN(ist,k)=0;
212 end
213 end
214 CN(k) = NK(k)./XN(k);
215end
216
217QN(isnan(QN))=0;
218CN(isnan(CN))=0;
219RN(isnan(RN))=0;
220UN(isnan(UN))=0;
221XN(isnan(XN))=0;
222TN(isnan(TN))=0;
223
224runtime = toc(Tstart);
225
226% now update the routing probabilities in nodes with state-dependent routing
227TNcache = zeros(sn.nstateful,K);
228for k=1:K
229 for isf=1:sn.nstateful
230 ind = sncopy.statefulToNode(isf);
231 if sncopy.nodetype(ind) == NodeType.Cache
232 TNcache(isf,k) = probSysState*depRates(wset,isf,k);
233 end
234 end
235end
236
237% updates cache actual hit and miss data
238for k=1:K
239 for isf=1:sncopy.nstateful
240 ind = sncopy.statefulToNode(isf);
241 if sncopy.nodetype(ind) == NodeType.Cache
242 if length(sncopy.nodeparam{ind}.hitclass)>=k
243 h = sncopy.nodeparam{ind}.hitclass(k);
244 m = sncopy.nodeparam{ind}.missclass(k);
245 if h> 0 && m > 0
246 sncopy.nodeparam{ind}.actualhitprob(k) = TNcache(isf,h)/sum(TNcache(isf,[h,m]));
247 sncopy.nodeparam{ind}.actualmissprob(k) = TNcache(isf,m)/sum(TNcache(isf,[h,m]));
248 end
249 end
250 end
251 end
252end
253end
Definition mmt.m:124