1classdef Solver < handle
2 % Abstract base
class for all LINE model solution algorithms
4 % Provides common
interface and infrastructure for queueing network analysis.
6 % Copyright (c) 2012-2026, Imperial College London
15 properties (Hidden, Access =
public)
19 properties (Access = public)
20 options; % Data structure with solver options
22 model; % Model to be solved
29 function self = Solver(model, name, options)
30 % SELF = SOLVER(MODEL, NAME, OPTIONS)
31 if nargin<3 %~exist('options','var')
32 options = self.defaultOptions;
34 self.model = model; % passed by reference for cache update
36 self.options = options;
37 self.enableChecks = true;
41 methods (Abstract) % implemented with errors for Octave compatibility
43 runtime = runAnalyzer(self, options)% generic method to run
the solver
44 bool = supports(self,model);
49 function model = getModel(self)
53 function self = setChecks(self,
bool)
54 self.enableChecks =
bool;
56 function out = getName(self)
61 function results = getResults(self)
62 % RESULTS = GETRESULTS()
63 % Return results data structure
64 results = self.result;
67 function
bool = hasResults(self)
69 % Check if
the model has been solved
70 bool = ~isempty(self.result);
73 function
bool = isStochastic(self)
74 % BOOL = ISSTOCHASTIC()
75 % True if
the solver, with its currently configured method,
76 % returns stochastic estimates (i.e., results depend on
the
77 % random seed, as in simulation or Monte Carlo integration).
78 % A solver run with method 'default' may resolve
the actual
79 % method only at runtime; once results are available,
the
80 % classification therefore uses
the method recorded in
81 % result.Avg.method (e.g. 'default/imci' when
the NC default
82 % path resolved to Monte Carlo integration).
83 method = self.options.method;
84 if ~isempty(self.result) && isfield(self.result,'Avg') && ...
85 isfield(self.result.Avg,'method') && ~isempty(self.result.Avg.method) && ...
86 ischar(self.result.Avg.method)
87 method = self.result.Avg.method;
89 bool = self.isStochasticMethod(method);
92 function
bool = isStochasticMethod(self, method) %
#ok<INUSD>
93 % BOOL = ISSTOCHASTICMETHOD(METHOD)
94 % Classify a (possibly runtime-resolved) method name of
this
95 % solver as stochastic. Deterministic by
default; subclasses
96 % with simulation-based or sampling-based methods
override this.
100 function options = getOptions(self)
101 % OPTIONS = GETOPTIONS()
102 % Return options data structure
103 options = self.options;
108 % Dispose previously stored results
110 Solver.resetRandomGeneratorSeed(self.options.seed);
113 function self = setOptions(self, options)
114 % SELF = SETOPTIONS(OPTIONS)
115 % Set a
new options data structure
116 self.options = options;
123 function resetRandomGeneratorSeed(seed)
124 % RESETRANDOMGENERATORSEED(SEED)
125 % Assign a
new seed to
the random number generator
126 warning(
'off',
'MATLAB:RandStream:ActivatingLegacyGenerators');
127 warning(
'off',
'MATLAB:RandStream:ReadingInactiveLegacyGeneratorState');
131 function
bool = isJavaAvailable()
132 % BOOL = ISJAVAAVAILABLE()
133 % Check
if Java dependencies are available
for the solver
136 [~,ret] = dos(
'java -version');
137 if strfind(ret,
'not recognized') %#ok<STRIFCND>
141 [~,ret] = unix(
'java -version');
142 if strfind(ret,
'command not found') %#ok<STRIFCND>
148 function [optList, allOpt] = listValidOptions()
149 % OPTLIST = LISTVALIDOPTIONS()
150 % List valid fields
for options data structure
151 optList = {
'cache',
'cutoff',
'force',
'init_sol',
'iter_max',
'iter_tol',
'lang',
'tol', ...
152 'keep',
'method',
'odesolvers',
'samples',
'seed',
'stiff',
'timespan',
'timestep',
'timeout',
'verbose',
'config.multiserver',
'config.fork_join',
'fork_join',
'confint',
'level'};
153 %,
'amva.aql',
'aql',
'amva.qdaql',
'qdaql',
'mom',
'brute',
'jmva.ls',
'jmt.jmva.ls'
154 allOpt = {
'cache',
'cutoff',
'force',
'init_sol',
'iter_max',
'iter_tol',
'lang',
'tol', ...
155 'keep',
'method',
'odesolvers',
'samples',
'seed',
'stiff',
'timespan',
'timestep',
'timeout',
'verbose',
'config.multiserver',
'config.fork_join',
'fork_join',
'confint',
'level', ...
156 'default',
'exact',
'auto',
'ctmc',
'ctmc.gpu',
'gpu',
'mva',
'mva.exact',
'mva.amva',
'mva.qna',
'sqni',
'mva.sqni',...
157 'amva',
'amva.bs',
'amva.qd',
'bs',
'qd',
'amva.qli',
'qli',
'amva.fli',
'fli',
'amva.lin',
'lin',
'amva.qdlin',
'qdlin',...
158 'ssa',
'ssa.parallel',
'serial',
'parallel',
'nrm',...
159 'jmt',
'jsim',
'replication',
'jmva',
'jmva.amva',
'jmva.mva',
'jmva.recal',
'jmva.mom',
'jmva.comom',
'jmva.chow',
'jmva.bs',
'jmva.aql',
'jmva.lin',
'jmva.dmlin',
'jmt.jsim',...
160 'jmt.jmva',
'jmt.jmva.mva',
'jmt.jmva.amva',
'jmt.jmva.recal',
'jmt.jmva.comom',
'jmt.jmva.chow',
'jmt.jmva.bs',
'jmt.jmva.aql',
'jmt.jmva.lin',
'jmt.jmva.dmlin',...
161 'ca',
'comom',
'comomld',
'gm',
'propfair',
'recal',
'kt',
'rd',
'nrp',
'nrl', ...
162 'nc.brute',
'nc.ca',
'nc.comom',
'nc.comomld',
'nc.gm',
'nc.mom',
'nc.propfair',
'nc.recal',
'nc.kt',
'nc.rd',
'nc.nr.probit',
'nc.nr.logit', ...
163 'fluid',
'matrix',
'softmin',
'statedep',
'closing',
'diffusion',
'fluid.softmin',
'fluid.statedep',
'fluid.closing',
'fluid.matrix',
'fluid.diffusion',...
164 'nc',
'nc.exact',
'nc.imci',
'ls',
'nc.ls',
'nc.cub',
'cub',
'le',
'nc.le',
'nc.panacea',
'panacea',
'nc.mmint2',
'mmint2',
'nc.gleint',
'gleint',
'mam',
'dec.source',
'dec.mmap',...
165 'mmk',
'gigk',
'gigk.kingman_approx', ...
166 'mm1',
'mg1',
'gm1',
'gig1',
'gim1',
'gig1.kingman',
'gig1.gelenbe',
'gig1.heyman',
'gig1.kimura',
'gig1.allen',
'gig1.kobayashi',
'gig1.klb',
'gig1.marchal',...
167 'aba.upper',
'aba.lower',
'gb.upper',
'gb.lower',
'sb.upper',
'sb.lower',
'bjb.upper',
'bjb.lower',
'pb.upper',
'pb.lower',
'mwba.upper',
'mwba.lower', ...
168 'pbh.upper',
'pbh.lower',
'pbk.upper',
'pbk.lower',
'bjbk.upper',
'bjbk.lower',
'cub.upper',
'cub.lower'};
171 function
bool = isValidOption(optName)
172 % BOOL = ISVALIDOPTION(OPTNAME)
173 % Check
if the given option exists
for the solver
174 [~,allOpts] = Solver.listValidOptions();
175 bool = any(cell2mat(findstring(optName, allOpts))==1);
178 function options = defaultOptions()
179 % OPTIONS = DEFAULTOPTIONS()
180 % Return
default options
181 options = lineDefaults;
184 function [enabled, level] = parseConfInt(confint)
185 % [ENABLED, LEVEL] = PARSECONFINT(CONFINT)
186 % Parse confidence interval option value
187 % Returns enabled (
true/
false) and confidence level (0.0-1.0)
188 if islogical(confint)
190 level = 0.95; % default 95% confidence
191 elseif isnumeric(confint) && confint > 0 && confint < 1
194 elseif isnumeric(confint) && confint == 0
203 function options = parseOptions(varargin, defaultOptions)
204 % OPTIONS = PARSEOPTIONS(VARARGIN, DEFAULTOPTIONS)
205 % Parse option parameters into options data structure
207 options = defaultOptions;
208 elseif isstruct(varargin{1})
209 options = varargin{1};
210 elseif ischar(varargin{1})
211 if length(varargin)>1 && isstruct(varargin{2}) % options
struct after method field
212 options = varargin{2};
214 elseif isscalar(varargin)
215 options = defaultOptions;
216 options.method = varargin{1};
218 options = defaultOptions;
220 [optList, allOpt] = Solver.listValidOptions();
221 allMethodsList = setdiff(allOpt, optList);
222 while ~isempty(varargin)
223 if Solver.isValidOption(varargin{1}) || startsWith(varargin{1},
'config.')
226 options.method = varargin{1};
230 case 'config.eventcache'
231 options.config.eventcache = varargin{2};
232 case 'config.warmupfrac'
233 options.config.warmupfrac = varargin{2};
234 case 'config.highvar'
235 options.config.highvar = varargin{2};
236 case 'config.multiserver'
237 options.config.multiserver = varargin{2};
238 case 'config.np_priority'
239 options.config.np_priority = varargin{2};
240 case 'config.fork_join'
241 options.config.fork_join = varargin{2};
243 options.config.fork_join = varargin{2};
245 % Convert
string verbose level to VerboseLevel constant
246 if ischar(varargin{2}) || isstring(varargin{2})
247 switch upper(
char(varargin{2}))
249 options.verbose = VerboseLevel.SILENT;
251 options.verbose = VerboseLevel.STD;
253 options.verbose = VerboseLevel.DEBUG;
255 options.verbose = varargin{2};
258 options.verbose = varargin{2};
261 options.(varargin{1}) = varargin{2};
267 %line_warning(mfilename,sprintf(
'Option "%s" does not exist. Ignoring.',varargin{1}));
272 line_error(mfilename,
'Invalid parameter.');