LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
getUsedLangFeatures.m
1function used = getUsedLangFeatures(self)
2% USED = GETUSEDLANGFEATURES()
3
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6
7self.initUsedFeatures;
8if ~isempty(self.getIndexClosedClasses)
9 self.setUsedLangFeature('ClosedClass');
10end
11if ~isempty(self.getIndexOpenClasses)
12 self.setUsedLangFeature('OpenClass');
13end
14
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)
19 jobclass = self.classes{r};
20 if isa(jobclass,'Signal') || isa(jobclass,'OpenSignal') || isa(jobclass,'ClosedSignal')
21 if isa(jobclass,'ClosedSignal')
22 self.setUsedLangFeature('ClosedSignal');
23 elseif isa(jobclass,'OpenSignal')
24 self.setUsedLangFeature('OpenSignal');
25 else % unresolved placeholder: resolves by presence of a Source
26 if isempty(self.getIndexSourceNode)
27 self.setUsedLangFeature('ClosedSignal');
28 else
29 self.setUsedLangFeature('OpenSignal');
30 end
31 end
32 switch jobclass.signalType
33 case SignalType.NEGATIVE
34 self.setUsedLangFeature('SignalType_NEGATIVE');
35 case SignalType.REPLY
36 self.setUsedLangFeature('SignalType_REPLY');
37 case SignalType.CATASTROPHE
38 self.setUsedLangFeature('SignalType_CATASTROPHE');
39 end
40 % see _kb/04-networkstruct.md (node/process construction notes) for rationale
41 if ~isempty(jobclass.removalDistribution)
42 self.setUsedLangFeature('SignalBatchRemoval');
43 end
44 if ~isempty(jobclass.removalPolicy) && jobclass.removalPolicy ~= RemovalPolicy.RANDOM
45 self.setUsedLangFeature('SignalRemovalPolicy');
46 end
47 end
48end
49
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');
56end
57
58% Get attributes
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);
70 end
71 if self.nodes{i}.numberOfServers > 1
72 %self.setUsedLangFeature('MultiServer')
73 end
74 self.setUsedLangFeature(SchedStrategy.toFeature(self.nodes{i}.schedStrategy));
75 self.setUsedLangFeature(RoutingStrategy.toFeature(self.nodes{i}.output.outputStrategy{r}{2}));
76 end
77 case 'Router'
78 self.setUsedLangFeature(RoutingStrategy.toFeature(self.nodes{i}.output.outputStrategy{r}{2}));
79 case 'Source'
80 distName = self.nodes{i}.input.sourceClasses{r}{3}.name;
81 if ~strcmp(distName,'Immediate') && ~strcmp(distName,'Disabled')
82 self.setUsedLangFeature(distName);
83 end
84 self.setUsedLangFeature('Source');
85 case 'ClassSwitch'
86 self.setUsedLangFeature('StatelessClassSwitcher');
87 self.setUsedLangFeature('ClassSwitch');
88 case 'Fork'
89 self.setUsedLangFeature('Fork');
90 self.setUsedLangFeature('Forker');
91 case 'Join'
92 self.setUsedLangFeature('Join');
93 self.setUsedLangFeature('Joiner');
94 case 'Sink'
95 self.setUsedLangFeature('Sink');
96 case 'Cache'
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');
104 end
105 case 'Transition'
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');
116 break;
117 end
118 end
119 end
120 case 'Place'
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');
126 end
127 end
128 end
129 end
130end
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');
137 break
138 end
139end
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');
146 break
147 end
148end
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
151% it setup-free.
152for i=1:getNumberOfNodes(self)
153 if isa(self.nodes{i},'Queue') && ~isempty(self.nodes{i}.setupTime)
154 self.setUsedLangFeature('SetupDelayOff');
155 break
156 end
157end
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');
165 break
166 end
167 end
168 end
169end
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');
176 break
177 end
178 end
179 end
180end
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');
186 break
187 end
188end
189used = self.usedFeatures;
190end
Definition fjtag.m:161