1classdef SolverNC < NetworkSolver
2 % SolverNC Normalizing Constant solver
for product-form networks
4 % SolverNC implements normalizing constant algorithms
for analyzing closed
5 % product-form queueing networks. It computes
the normalizing constant and
6 % associated performance measures efficiently without
explicitly enumerating
7 % all network states, making it suitable
for medium to large closed networks.
9 % @brief Normalizing constant solver
for efficient closed network analysis
11 % Key characteristics:
12 % - Normalizing constant computation
for product-form networks
13 % - Avoids
explicit state enumeration
14 % - Efficient algorithms
for closed networks
15 % - Multiple computational methods (exact, approximation)
16 % - State probability computation via normalization
19 % - Exact normalizing constant computation
20 % - IMCI (Improved Modular Computer Implementation)
21 % - Linearizer methods (LS, LE)
22 % - Interpolation methods (MMINT2, GLEINT)
23 % - Approximation methods (CA, Panacea)
25 % SolverNC
is ideal
for:
26 % - Closed product-form networks
27 % - Medium to large population networks
28 % - Systems requiring efficient exact solutions
29 % - Networks with complex routing patterns
30 % - Performance analysis requiring state probabilities
34 % solver = SolverNC(model,
'method',
'exact');
35 % solver.getProbAggr(); % State probabilities
36 % solver.getNormalizingConstant(); % Normalizing constant
39 % Copyright (c) 2012-2026, Imperial College London
40 % All rights reserved.
43 function self = SolverNC(model,varargin)
44 % SOLVERNC Create a Normalizing Constant solver instance
46 % @brief Creates an NC solver for product-form network analysis
47 % @param model Network model to be analyzed via normalizing constant methods
48 % @param varargin Optional parameters (method, tolerance, etc.)
49 % @return self SolverNC instance configured for NC analysis
51 self@NetworkSolver(model, mfilename);
52 self.setOptions(Solver.parseOptions(varargin, self.defaultOptions));
56 runtime = runAnalyzer(self, options)
57 Pnir = getProb(self, node, state)
58 Pnir = getProbAggr(self, node, state_a)
60 Pn = getProbSysAggr(self)
61 RD = getCdfRespT(self, R);
63 function [normConst,lNormConst] = getNormalizingConstant(self)
64 normConst = exp(getProbNormConstAggr(self));
65 lNormConst = getProbNormConstAggr(self);
68 [lNormConst] = getProbNormConstAggr(self)
70 function sn = getStruct(self)
73 % Get data structure summarizing
the model
74 sn = self.model.getStruct(
false); %no need
for initial state
77 function tf = supportsExactSensitivity(self) %#ok<MANU>
78 % TF = SUPPORTSEXACTSENSITIVITY()
79 % The normalizing-constant solver
is exact on
the same
80 % product-form class that pfqn_sens differentiates, so
81 % getSensitivityTable uses
the analytic branch.
85 function [allMethods] = listValidMethods(self)
86 % allMethods = LISTVALIDMETHODS()
87 % List valid methods
for this solver
88 sn = self.model.getStruct();
89 allMethods = {
'default',
'exact',
'erlangfp',
'mci',
'imci',
'ls',...
90 'le',
'mmint2',
'gleint',
'panacea',
'ca',...
91 'clw',
'kt',
'sampling',
'is',...
92 'propfair',
'comom',
'cub',...
93 'rd',
'nrp',
'nrl',
'gm',
'mem'};
96 function method = resolveMethod(self, options)
97 % Feature-driven resolution of options.method='default'. An open
98 % network with non-Markovian (any non-unit SCV) variability within
99 %
the MEM feature set
is solved by
the Maximum Entropy Method by
100 % default, since
the normalizing-constant path would silently
101 % exponentialize it; plain Markovian models keep
the exact
102 % product-form path. Mirrors
the dispatch in runAnalyzer.
103 method = options.method;
104 if strcmp(options.method,
'default')
105 sn = self.model.getStruct();
106 if solver_nc_mem_supports(sn)
107 scvv = sn.scv(isfinite(sn.scv));
108 if ~isempty(scvv) && any(abs(scvv - 1) > GlobalConstants.FineTol)
115 function featSupported = getMethodFeatureSet(self, method) %
#ok<INUSD>
116 % All NC methods share
the solver-level feature envelope.
118 % Defining this
is what lets NetworkSolver.supportsModelMethod name
119 %
the offending features: with no method feature set it falls back
120 % to the coarse supports(model) and returns an empty reason, so the
121 % gate could only report "features not supported" without saying
124 % A non-Network model (e.g. a LayeredNetwork) has no
125 % getUsedLangFeatures, so it keeps the coarse path and the
126 % structural checks/redirects that operate on such models.
127 if ~isa(self.model, 'Network')
131 featSupported = SolverNC.getFeatureSet();
134 function [bool, reason] = supportsModelMethod(self, method)
135 % MEM (Kouvatsos maximum entropy) has structural applicability
136 % rules beyond a flat feature set (open-only, no
class switching,
137 % non-priority scheduling); delegate to solver_nc_mem_supports,
138 % which returns a precise reason. All other NC methods inherit
the
139 % coarse product-form feature gate.
140 if strcmp(method, 'mem')
141 sn = self.model.getStruct();
142 [bool, reason] = solver_nc_mem_supports(sn);
144 % The structural rules say nothing about
the language
145 % features, so a model that
is structurally admissible
for
146 % mem still has to clear
the feature gate. Without
this the
147 % gate passed and
the model was rejected further down by
the
148 % coarse supports() test, which names no feature.
149 [
bool, reason] = supportsModelMethod@NetworkSolver(self, method);
152 [
bool, reason] = supportsModelMethod@NetworkSolver(self, method);
154 % Finite station/class capacity has no registry feature name, so
155 %
the coarse feature gate cannot see it. NC
is a product-form
156 % solver and has no representation of a finite buffer: without
157 % this gate it silently returns
the unconstrained answer (QLen=4
158 % instead of
the M/M/1/2 value 0.8525). Same defect as BUG-39 on
159 %
the MVA side. NC has no BAS/'sqd' method, so unlike SolverMVA it
160 % grants no Blocking-After-Service exemption.
161 if
bool && isa(self.model, 'Network')
162 [
bool, reason] = NetworkSolver.checkBindingCapacity(self.model, 'SolverNC');
166 function
bool = isStochasticMethod(self, method) %
#ok<INUSL>
167 % BOOL = ISSTOCHASTICMETHOD(METHOD)
168 % NC
is deterministic except
for the Monte Carlo integration
169 % methods (mci/imci), logistic sampling (ls),
the importance
170 % sampling method (
is), and
the sampling method, whose estimates
171 % depend on
the random seed. Method names are tokenized so that
172 % runtime-resolved names such as 'default/imci' and prefixed names
173 % such as 'nc.ls' classify correctly.
174 tokens = regexp(lower(method), '[./]', 'split');
175 bool = any(ismember(tokens, {
'mci',
'imci',
'ls',
'sampling',
'is'}));
181 function featSupported = getFeatureSet()
182 % FEATSUPPORTED = GETFEATURESET()
184 featSupported = SolverFeatureSet;
185 featSupported.setTrue({
'Sink',
'Source',...
186 'ClassSwitch',
'Delay',
'DelayStation',
'Queue',...
187 'APH',
'Coxian',
'Erlang',
'Det',
'Exp',
'HyperExp',...
188 'StatelessClassSwitcher',
'InfiniteServer',...
189 'SharedServer',
'Buffer',
'Dispatcher',...
190 'Server',
'JobSink',
'RandomSource',
'ServiceTunnel',...
191 'SchedStrategy_INF',
'SchedStrategy_PS',
'SchedStrategy_SIRO',...
192 'SchedStrategy_LCFS',
'SchedStrategy_LCFSPR',...
193 'RoutingStrategy_PROB',
'RoutingStrategy_RAND',...
194 'SchedStrategy_FCFS',
'SchedStrategy_OI',
'SchedStrategy_PAS',...
195 'ClosedClass',
'SelfLoopingClass',...
196 'Cache',
'CacheClassSwitcher',
'OpenClass', ...
197 'CacheRetrieval', ...
198 'ReplacementStrategy_RR',
'ReplacementStrategy_FIFO',...
199 'ReplacementStrategy_HLRU',...
200 'LoadDependence',
'ClassDependence'});
204 function [bool, featSupported] = supports(model)
205 % [BOOL, FEATSUPPORTED] = SUPPORTS(MODEL)
207 featUsed = model.getUsedLangFeatures();
208 featSupported = SolverNC.getFeatureSet();
209 bool = SolverFeatureSet.supports(featSupported, featUsed);
212 function options = defaultOptions()
213 % OPTIONS = DEFAULTOPTIONS()
214 options = SolverOptions('NC');
217 function libs = getLibrariesUsed(sn, options)
218 % GETLIBRARIESUSED Get list of external libraries used by NC solver
219 % NC uses internal normalizing constant algorithms, no external libraries needed