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 jmodel = LINE2JLINE(self.model);
34 %M = jmodel.getNumberOfStatefulNodes;
35 M = jmodel.getNumberOfStations;
36 R = jmodel.getNumberOfClasses;
37 switch options.method
38 case {'default', 'closing', 'matrix'}
39 jsolver = JLINE.SolverFluid(jmodel, options);
40 otherwise
41 line_warning(mfilename,'This solver does not support the specified method. Setting to default.\n');
42 options.method = 'default';
43 jsolver = JLINE.SolverFluid(jmodel, options);
44 end
45 [QN,UN,RN,WN,AN,TN] = JLINE.arrayListToResults(jsolver.getAvgTable);
46 runtime = toc(T0);
47 CN = [];
48 XN = [];
49 QN = reshape(QN',R,M)';
50 UN = reshape(UN',R,M)';
51 RN = reshape(RN',R,M)';
52 WN = reshape(WN',R,M)';
53 AN = reshape(AN',R,M)';
54 TN = reshape(TN',R,M)';
55 lG = NaN;
56 lastiter = NaN;
57 self.setAvgResults(QN,UN,RN,TN,AN,WN,CN,XN,runtime,options.method,lastiter);
58 self.result.Prob.logNormConstAggr = lG;
59 self.result.solverSpecific.sn = JLINE.from_jline_struct(jmodel);
60 self.result.solverSpecific.odeStateVec = JLINE.from_jline_matrix(jsolver.result.odeStateVec);
61 return
62 case 'matlab'
63 switch options.method
64 case {'matrix','pnorm'}
65 % Matrix method now supports mixed/open models per Ruuskanen et al., PEVA 151 (2021)
66 if sn_has_dps(sn)
67 line_error(mfilename,'The matrix solver does not support DPS scheduling. Use options.method=''closing'' instead.');
68 end
69 case {'closing'}
70 options.method = 'closing';
71 case {'default'}
72 % Use matrix method as default unless DPS is present
73 if sn_has_dps(sn)
74 options.method = 'closing';
75 else
76 options.method = 'matrix';
77 end
78 case {'statedep','softmin'}
79 % do nothing
80 case {'diffusion','fluid.diffusion'}
81 % Diffusion approximation - validated in solver_fluid_diffusion
82 % do nothing here, validation happens in the solver itself
83 case {'mfq','fluid.mfq','butools'}
84 % Markovian fluid queue method using BUTools for single-queue analysis
85 % Validation and fallback happens in solver_fluid_analyzer
86 otherwise
87 line_error(mfilename,sprintf('The ''%s'' method is unsupported by this solver.',options.method));
88 end
89end
90
91if isinf(options.timespan(1))
92 if options.verbose == 2
93 line_warning(mfilename,'%s requires options.timespan(1) to be finite. Setting it to 0.\n',mfilename);
94 end
95 options.timespan(1) = 0;
96end
97
98if options.timespan(1) == options.timespan(2)
99 line_warning(mfilename,'%s: timespan is a single point, unsupported. Setting options.timespace(1) to 0.\n',mfilename);
100 options.timespan(1) = 0;
101end
102
103if self.enableChecks && ~self.supports(self.model)
104 line_error(mfilename,'This model contains features not supported by the solver.');
105end
106
107self.setOptions(options);
108
109M = sn.nstations;
110K = sn.nclasses;
111
112%%
113lastSol= [];
114Q = zeros(M,K); R = zeros(M,K); T = zeros(M,K);
115U = zeros(M,K); C = zeros(1,K); X = zeros(1,K);
116Qt=[];
117s0 = sn.space;
118s0prior = sn.stateprior;
119s0_sz = cellfun(@(x) size(x,1), s0)';
120s0_id = pprod(s0_sz-1);
121cur_state = sn.state;
122while s0_id>=0 % for all possible initial states
123 s0prior_val = 1;
124 for ind=1:sn.nnodes
125 if sn.isstateful(ind)
126 isf = sn.nodeToStateful(ind);
127 s0prior_val = s0prior_val * s0prior{isf}(1+s0_id(isf)); % update prior
128 %sn.state{isf} = s0{isf}(1+s0_id(isf),:); % assign initial state to network
129 self.model.nodes{ind}.setState(s0{isf}(1+s0_id(isf),:));
130 end
131 end
132 sn = self.model.getStruct;
133 sn = sn_nonmarkov_toph(sn, options); % Re-apply conversion after fresh struct
134 if s0prior_val > 0
135 %useJLine = false;
136 %if useJLine
137 % [Qfull, Ufull, Rfull, Tfull, Cfull, Xfull, t, Qfull_t, Ufull_t, Tfull_t, lastSol] = JLINE.runFluidAnalyzer(self.model, options);
138 %else
139 [Qfull, Ufull, Rfull, Tfull, Cfull, Xfull, t, Qfull_t, Ufull_t, Tfull_t, lastSol, iter, aoiResults] = solver_fluid_analyzer(sn, options);
140 %end
141
142 [t,uniqueIdx] = unique(t);
143 if isempty(lastSol) % if solution fails
144 Q = NaN*ones(M,K); R = NaN*ones(M,K);
145 T = NaN*ones(M,K); U = NaN*ones(M,K);
146 C = NaN*ones(1,K); X = NaN*ones(1,K);
147 Qt = cell(M,K); Ut = cell(M,K); Tt = cell(M,K);
148 for ist=1:M
149 for r=1:K
150 Qt{ist,r} = [NaN,NaN];
151 Ut{ist,r} = [NaN,NaN];
152 Tt{ist,r} = [NaN,NaN];
153 end
154 end
155 else
156 if isempty(self.result) && max(size(Qt))==0 %~exist('Qt','var')
157 Q = Qfull*s0prior_val;
158 R = Rfull*s0prior_val;
159 T = Tfull*s0prior_val;
160 U = Ufull*s0prior_val;
161 C = Cfull*s0prior_val;
162 X = Xfull*s0prior_val;
163 Qt = cell(M,K);
164 Ut = cell(M,K);
165 Tt = cell(M,K);
166 for ist=1:M
167 for r=1:K
168 Qfull_t{ist,r} = Qfull_t{ist,r}(uniqueIdx);
169 Ufull_t{ist,r} = Ufull_t{ist,r}(uniqueIdx);
170 Tfull_t{ist,r} = Tfull_t{ist,r}(uniqueIdx);
171 Qt{ist,r} = [Qfull_t{ist,r} * s0prior_val,t];
172 Ut{ist,r} = [Ufull_t{ist,r} * s0prior_val,t];
173 Tt{ist,r} = [Tfull_t{ist,r} * s0prior_val,t];
174 end
175 end
176 else
177 Q = Q + Qfull*s0prior_val;
178 R = R + Rfull*s0prior_val;
179 T = T + Tfull*s0prior_val;
180 U = U + Ufull*s0prior_val;
181 C = C + Cfull*s0prior_val;
182 X = X + Xfull*s0prior_val;
183 for ist=1:M
184 for r=1:K
185 [t,uniqueIdx] = unique(t);
186 Qfull_t{ist,r} = Qfull_t{ist,r}(uniqueIdx);
187 Ufull_t{ist,r} = Ufull_t{ist,r}(uniqueIdx);
188 % Tfull_t{i,r} = Tfull_t{i,r}(uniqueIdx);
189
190 tunion = union(Qt{ist,r}(:,2), t);
191 dataOld = interp1(Qt{ist,r}(:,2),Qt{ist,r}(:,1),tunion);
192 dataNew = interp1(t,Qfull_t{ist,r},tunion);
193 Qt{ist,r} = [dataOld + s0prior_val * dataNew, tunion];
194
195 dataOld = interp1(Ut{ist,r}(:,2),Ut{ist,r}(:,1),tunion);
196 dataNew = interp1(t,Ufull_t{ist,r},tunion);
197 Ut{ist,r} = [dataOld + s0prior_val * dataNew, tunion];
198
199 % dataOld = interp1(Tt{i,r}(:,2),Tt{i,r}(:,1),tunion);
200 % dataNew = interp1(t,Tfull_t{i,r},tunion);
201 % Tt{i,r} = [dataOld + s0prior_val * dataNew, tunion];
202 end
203 end
204 end
205 end
206 end
207 s0_id=pprod(s0_id,s0_sz-1); % update initial state
208end
209% Now we restore the original state
210for ind=1:sn.nnodes
211 if sn.isstateful(ind)
212 isf = sn.nodeToStateful(ind);
213 self.model.nodes{ind}.setState(cur_state{isf});
214 end
215end
216runtime = toc(T0);
217self.result.solverSpecific = lastSol;
218% Store AoI results if available
219if exist('aoiResults', 'var') && ~isempty(aoiResults)
220 self.result.solverSpecific.aoiResults = aoiResults;
221end
222QN = Q; UN=U; RN=R; TN=T; CN=C; XN=X;
223% Compute average arrival rate at steady-state
224AN = sn_get_arvr_from_tput(sn, TN, self.getAvgTputHandles());
225if strcmp(orig_method,'default') && ~strcmp(options.method,'default')
226 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,['default/',options.method],iter);
227else
228 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,options.method,iter);
229end
230Rt={}; Xt={}; Ct={};
231self.setTranAvgResults(Qt,Ut,Rt,Tt,Ct,Xt,runtime);
232end