LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
SolverNC.m
1classdef SolverNC < NetworkSolver
2 % SolverNC Normalizing Constant solver for product-form networks
3 %
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.
8 %
9 % @brief Normalizing constant solver for efficient closed network analysis
10 %
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
17 %
18 % NC solver methods:
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)
24 %
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
31 %
32 % Example:
33 % @code
34 % solver = SolverNC(model, 'method', 'exact');
35 % solver.getProbAggr(); % State probabilities
36 % solver.getNormalizingConstant(); % Normalizing constant
37 % @endcode
38 %
39 % Copyright (c) 2012-2026, Imperial College London
40 % All rights reserved.
41
42 methods
43 function self = SolverNC(model,varargin)
44 % SOLVERNC Create a Normalizing Constant solver instance
45 %
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
50
51 self@NetworkSolver(model, mfilename);
52 self.setOptions(Solver.parseOptions(varargin, self.defaultOptions));
53 self.setLang();
54 end
55
56 runtime = runAnalyzer(self, options)
57 Pnir = getProb(self, node, state)
58 Pnir = getProbAggr(self, node, state_a)
59 Pn = getProbSys(self)
60 Pn = getProbSysAggr(self)
61 RD = getCdfRespT(self, R);
62
63 function [normConst,lNormConst] = getNormalizingConstant(self)
64 normConst = exp(getProbNormConstAggr(self));
65 lNormConst = getProbNormConstAggr(self);
66 end
67
68 [lNormConst] = getProbNormConstAggr(self)
69
70 function sn = getStruct(self)
71 % QN = GETSTRUCT()
72
73 % Get data structure summarizing the model
74 sn = self.model.getStruct(false); %no need for initial state
75 end
76
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.
82 tf = true;
83 end
84
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'};
94 end
95
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)
109 method = 'mem';
110 end
111 end
112 end
113 end
114
115 function featSupported = getMethodFeatureSet(self, method) %#ok<INUSD>
116 % All NC methods share the solver-level feature envelope.
117 %
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
122 % which ones.
123 %
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')
128 featSupported = [];
129 return;
130 end
131 featSupported = SolverNC.getFeatureSet();
132 end
133
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 memblocking = false;
141 if strcmp(method, 'mem')
142 sn = self.model.getStruct();
143 [bool, reason, memblocking] = solver_nc_mem_supports(sn);
144 if bool
145 % a mem-admissible model still has to clear the feature gate;
146 % see _kb/06-solver-catalog.md (mem.blocking note)
147 [bool, reason] = supportsModelMethod@NetworkSolver(self, method);
148 end
149 else
150 [bool, reason] = supportsModelMethod@NetworkSolver(self, method);
151 end
152 % structural finite-capacity gate (no registry feature name); mem is
153 % the one exception (it represents the buffer as a GE/GE/c/0;N queue).
154 % see _kb/06-solver-catalog.md (finite capacity gate + mem.blocking)
155 if bool && isa(self.model, 'Network') && ~memblocking
156 % Single-station M/M/1/K with tail drop is handled exactly by the
157 % probability-based qsys_mm1k_loss branch in runAnalyzer; exempt
158 % it from the product-form capacity gate.
159 if ~sn_is_mm1k_loss(self.model.getStruct())
160 [bool, reason] = NetworkSolver.checkBindingCapacity(self.model, 'SolverNC');
161 end
162 end
163 end
164
165 function bool = isStochasticMethod(self, method) %#ok<INUSL>
166 % BOOL = ISSTOCHASTICMETHOD(METHOD)
167 % NC is deterministic except for the Monte Carlo integration
168 % methods (mci/imci), logistic sampling (ls), the importance
169 % sampling method (is), and the sampling method, whose estimates
170 % depend on the random seed. Method names are tokenized so that
171 % runtime-resolved names such as 'default/imci' and prefixed names
172 % such as 'nc.ls' classify correctly.
173 tokens = regexp(lower(method), '[./]', 'split');
174 bool = any(ismember(tokens, {'mci','imci','ls','sampling','is'}));
175 end
176 end
177
178 methods (Static)
179
180 function featSupported = getFeatureSet()
181 % FEATSUPPORTED = GETFEATURESET()
182
183 featSupported = SolverFeatureSet;
184 featSupported.setTrue({'Sink','Source',...
185 'ClassSwitch','Delay','DelayStation','Queue',...
186 'APH','Coxian','Erlang','Det','Exp','HyperExp',...
187 'StatelessClassSwitcher','InfiniteServer',...
188 'SharedServer','Buffer','Dispatcher',...
189 ... % Finite capacity regions: NC solves the OPEN single-Delay
190 ... % loss-network case exactly (Erlang fixed point,
191 ... % solver_nc_lossn_analyzer). It cannot do an FCR on queueing
192 ... % stations -- a boolean feature cannot express that split, so
193 ... % runAnalyzer keeps the imperative check for the queueing case,
194 ... % the same pattern as SolverMVA.supportsFiniteCapacity.
195 'Region', ...
196 'Server','JobSink','RandomSource','ServiceTunnel',...
197 'SchedStrategy_INF','SchedStrategy_PS','SchedStrategy_SIRO',...
198 'SchedStrategy_LCFS','SchedStrategy_LCFSPR',...
199 'RoutingStrategy_PROB','RoutingStrategy_RAND',...
200 'SchedStrategy_FCFS','SchedStrategy_OI','SchedStrategy_PAS',...
201 'Fork','Join','Forker','Joiner',... % fork-join via the MMT transformation (fjFixedPoint)
202 'ClosedClass','SelfLoopingClass',...
203 'Cache','CacheClassSwitcher','OpenClass', ...
204 'CacheRetrieval', ...
205 'ReplacementStrategy_RR', 'ReplacementStrategy_FIFO',...
206 'ReplacementStrategy_HLRU',...
207 'LoadDependence','ClassDependence','JointDependence'});
208 %'OpenClass',...
209 end
210
211 function [bool, featSupported] = supports(model)
212 % [BOOL, FEATSUPPORTED] = SUPPORTS(MODEL)
213
214 featUsed = model.getUsedLangFeatures();
215 featSupported = SolverNC.getFeatureSet();
216 bool = SolverFeatureSet.supports(featSupported, featUsed);
217 end
218
219 function options = defaultOptions()
220 % OPTIONS = DEFAULTOPTIONS()
221 options = SolverOptions('NC');
222 end
223
224 function libs = getLibrariesUsed(sn, options)
225 % GETLIBRARIESUSED Get list of external libraries used by NC solver
226 % NC uses internal normalizing constant algorithms, no external libraries needed
227 libs = {};
228 end
229 end
230end