1function used = getUsedLangFeatures(self)
2% USED = GETUSEDLANGFEATURES()
4% Copyright (c) 2012-2026, Imperial College London
8if ~isempty(self.getIndexClosedClasses)
9 self.setUsedLangFeature('ClosedClass');
11if ~isempty(self.getIndexOpenClasses)
12 self.setUsedLangFeature('OpenClass');
15% G-network signal classes. Signal
is an unresolved placeholder that becomes
16% OpenSignal or ClosedSignal at refreshStruct time, so all three names are
17% inspected here: getUsedLangFeatures may run before resolution.
18for r=1:getNumberOfClasses(self)
22 self.setUsedLangFeature('ClosedSignal');
24 self.setUsedLangFeature('OpenSignal');
25 else % unresolved placeholder: resolves by presence of a Source
26 if isempty(self.getIndexSourceNode)
27 self.setUsedLangFeature('ClosedSignal');
29 self.setUsedLangFeature('OpenSignal');
33 case SignalType.NEGATIVE
34 self.setUsedLangFeature('SignalType_NEGATIVE');
36 self.setUsedLangFeature('SignalType_REPLY');
37 case SignalType.CATASTROPHE
38 self.setUsedLangFeature('SignalType_CATASTROPHE');
40 % see _kb/04-networkstruct.md (node/process construction notes) for rationale
41 if ~isempty(
jobclass.removalDistribution)
42 self.setUsedLangFeature('SignalBatchRemoval');
44 if ~isempty(
jobclass.removalPolicy) &&
jobclass.removalPolicy ~= RemovalPolicy.RANDOM
45 self.setUsedLangFeature('SignalRemovalPolicy');
50% Finite capacity regions: solvers that ignore FCRs must be able to reject
51% them through the registry, not only through the imperative checks in their
52% own runAnalyzer. Trigger matches python get_used_lang_features exactly: at
53% least one region on the model.
54if ~isempty(self.regions)
55 self.setUsedLangFeature('Region');
59for i=1:getNumberOfNodes(self)
60 for r=1:getNumberOfClasses(self)
61 try % not all
nodes have all classes
62 switch class(self.
nodes{i})
63 case {
'Queue',
'QueueingStation',
'DelayStation',
'Delay'}
64 if ~isempty(self.nodes{i}.server.serviceProcess{r})
65 % Immediate/Disabled are internal placeholders, not
66 % user-facing distributions (same exclusion as JAR)
67 distName = self.nodes{i}.server.serviceProcess{r}{3}.name;
68 if ~strcmp(distName,
'Immediate') && ~strcmp(distName,
'Disabled')
69 self.setUsedLangFeature(distName);
71 if self.
nodes{i}.numberOfServers > 1
72 %self.setUsedLangFeature(
'MultiServer')
74 self.setUsedLangFeature(SchedStrategy.toFeature(self.nodes{i}.schedStrategy));
75 self.setUsedLangFeature(RoutingStrategy.toFeature(self.nodes{i}.output.outputStrategy{r}{2}));
78 self.setUsedLangFeature(RoutingStrategy.toFeature(self.nodes{i}.output.outputStrategy{r}{2}));
80 distName = self.nodes{i}.input.sourceClasses{r}{3}.name;
81 if ~strcmp(distName,
'Immediate') && ~strcmp(distName,
'Disabled')
82 self.setUsedLangFeature(distName);
84 self.setUsedLangFeature('Source');
86 self.setUsedLangFeature('StatelessClassSwitcher');
87 self.setUsedLangFeature('ClassSwitch');
89 self.setUsedLangFeature('Fork');
90 self.setUsedLangFeature('Forker');
92 self.setUsedLangFeature('Join');
93 self.setUsedLangFeature('Joiner');
95 self.setUsedLangFeature('Sink');
97 self.setUsedLangFeature('CacheClassSwitcher');
98 self.setUsedLangFeature('Cache');
99 self.setUsedLangFeature(ReplacementStrategy.toFeature(self.
nodes{i}.replacestrategy));
100 if ~isempty(self.nodes{i}.retrievalClassIndices)
101 % delayed-hit retrieval system (setRetrievalSystem):
102 % per-item retrieval classes; JMT cannot load these
103 self.setUsedLangFeature(
'CacheRetrieval');
106 self.setUsedLangFeature(
'Transition');
107 self.setUsedLangFeature(
'Enabling');
108 self.setUsedLangFeature(
'Timing');
109 self.setUsedLangFeature(
'Firing');
110 % Inhibitor arcs: flag only when a finite threshold
is set,
111 % so plain SPNs are not gated out of solvers lacking it.
112 if isprop(self.nodes{i},
'inhibitingConditions')
113 for m=1:numel(self.
nodes{i}.inhibitingConditions)
114 if any(isfinite(self.nodes{i}.inhibitingConditions{m}(:)))
115 self.setUsedLangFeature(
'Inhibiting');
121 self.setUsedLangFeature(
'Storage');
122 self.setUsedLangFeature(
'Linkage');
123 self.setUsedLangFeature(
'Place');
124 if isprop(self.nodes{i},
'queueing') && ~isempty(self.nodes{i}.queueing) && self.nodes{i}.queueing
125 self.setUsedLangFeature(
'QueueingPlace');
131% Class-dependent scaling (setLimitedClassDependence): registered so that
132% solvers ignoring the handle (e.g. JMT) reject the model instead of
133% silently solving it as if the scaling were absent.
134for i=1:getNumberOfNodes(self)
135 if isa(self.
nodes{i},
'Station') && ~isempty(self.
nodes{i}.lcdScaling)
136 self.setUsedLangFeature(
'ClassDependence');
140% Joint-dependent scaling (setJointDependence): the NON-product-
form eta_i(n)
141% case. Registered so that solvers not plumbing the handle reject the model
142% instead of silently solving it as if the scaling were absent.
143for i=1:getNumberOfNodes(self)
144 if isa(self.
nodes{i},
'Station') && ~isempty(self.
nodes{i}.ljdScaling)
145 self.setUsedLangFeature(
'JointDependence');
149% Setup/delay-off times (setDelayOff): registered so that solvers ignoring
150% them (CTMC, SSA, MVA, NC, FLD) reject the model instead of silently solving
152for i=1:getNumberOfNodes(self)
153 if isa(self.
nodes{i},
'Queue') && ~isempty(self.
nodes{i}.setupTime)
154 self.setUsedLangFeature(
'SetupDelayOff');
158% see _kb/04-networkstruct.md (node/process construction notes)
for rationale
159for i=1:getNumberOfNodes(self)
160 nodeObj = self.nodes{i};
161 if isa(nodeObj,
'Queue') && ~isempty(nodeObj.impatienceTypes)
162 for r=1:numel(nodeObj.impatienceTypes)
163 if ~isempty(nodeObj.impatienceTypes{r}) && nodeObj.impatienceTypes{r} == ImpatienceType.RENEGING
164 self.setUsedLangFeature(
'Reneging');
170for i=1:getNumberOfNodes(self)
171 nodeObj = self.nodes{i};
172 if isa(nodeObj,
'Queue') && ~isempty(nodeObj.balkingStrategies)
173 for r=1:numel(nodeObj.balkingStrategies)
174 if ~isempty(nodeObj.balkingStrategies{r})
175 self.setUsedLangFeature(
'Balking');
181% see _kb/04-networkstruct.md (node/process construction notes)
for rationale
182for i=1:getNumberOfNodes(self)
183 nodeObj = self.nodes{i};
184 if isa(nodeObj,
'Queue') && ~isempty(nodeObj.breakdownFailure) && ~isempty(nodeObj.breakdownRepair)
185 self.setUsedLangFeature('Breakdown');
189used = self.usedFeatures;