LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
Signal.m
1classdef Signal < JobClass
2 % Signal Job class representing a signal (e.g., negative customer in G-networks)
3 %
4 % Signal is a placeholder class that automatically resolves to OpenSignal
5 % or ClosedSignal based on the network structure. Users can simply use
6 % Signal in both open and closed networks - the resolution happens when
7 % the model is finalized (during getStruct/refreshStruct).
8 %
9 % @brief Job class for modeling signals in G-networks and related models
10 %
11 % Key characteristics:
12 % - Automatically resolves to OpenSignal or ClosedSignal
13 % - Supports different signal types (NEGATIVE, REPLY, CATASTROPHE)
14 % - NEGATIVE signals remove jobs from destination queues
15 % - CATASTROPHE signals reset the state of queues
16 % - Used in G-networks (Gelenbe networks)
17 %
18 % Signal types:
19 % - SignalType.NEGATIVE: Removes a job from the destination queue
20 % - SignalType.REPLY: Triggers a reply action
21 % - SignalType.CATASTROPHE: Resets destination queue to empty state
22 %
23 % Example (Open Network):
24 % @code
25 % model = Network('GNetwork');
26 % source = Source(model, 'Source');
27 % sink = Sink(model, 'Sink');
28 % queue = Queue(model, 'Queue', SchedStrategy.FCFS);
29 % posClass = OpenClass(model, 'Positive'); % Normal customers
30 % negClass = Signal(model, 'Negative', SignalType.NEGATIVE); % Resolves to OpenSignal
31 % source.setArrival(posClass, Exp(1.0));
32 % source.setArrival(negClass, Exp(0.3));
33 % @endcode
34 %
35 % Example (Closed Network):
36 % @code
37 % model = Network('ClosedGNetwork');
38 % delay = Delay(model, 'Think');
39 % queue = Queue(model, 'Queue', SchedStrategy.FCFS);
40 % jobClass = ClosedClass(model, 'Job', 5, delay);
41 % replySignal = Signal(model, 'Reply', SignalType.REPLY).forJobClass(jobClass); % Resolves to ClosedSignal
42 % @endcode
43 %
44 % Reference: Gelenbe, E. (1991). "Product-form queueing networks with
45 % negative and positive customers", Journal of Applied Probability
46 %
47 % Copyright (c) 2012-2026, Imperial College London
48 % All rights reserved.
49
50 properties
51 signalType % SignalType constant (NEGATIVE, REPLY, CATASTROPHE)
52 targetJobClass % JobClass that this signal is associated with (for REPLY: the class to unblock)
53 removalDistribution % DiscreteDistribution for number of removals (empty = remove exactly 1)
54 removalPolicy % RemovalPolicy constant (RANDOM, FCFS, LCFS)
55 model % Reference to the Network model
56 end
57
58 methods
59
60 %Constructor
61 function self = Signal(model, name, signalType, prio, removalDistribution, removalPolicy)
62 % SIGNAL Create a signal class instance
63 %
64 % @brief Creates a Signal class for G-network modeling
65 % @param model Network model to add the signal class to
66 % @param name String identifier for the signal class
67 % @param signalType SignalType constant (REQUIRED: NEGATIVE, REPLY, or CATASTROPHE)
68 % @param prio Optional priority level (default: 0)
69 % @param removalDistribution Optional discrete distribution for batch removals (default: [])
70 % @param removalPolicy Optional RemovalPolicy constant (default: RemovalPolicy.RANDOM)
71 % @return self Signal instance ready for arrival specification
72
73 if nargin < 3 || isempty(signalType)
74 line_error(mfilename, 'signalType is required. Use SignalType.NEGATIVE, SignalType.REPLY, or SignalType.CATASTROPHE.');
75 end
76 if nargin < 6 || isempty(removalPolicy)
77 removalPolicy = RemovalPolicy.RANDOM;
78 end
79 if nargin < 5
80 removalDistribution = [];
81 end
82 if nargin < 4 || isempty(prio)
83 prio = 0;
84 end
85
86 % Initialize as JobClass (type will be determined during resolution)
87 self@JobClass(JobClassType.OPEN, name); % Default to OPEN, resolved later
88 self.priority = prio;
89 self.signalType = signalType;
90 self.targetJobClass = [];
91 self.removalDistribution = removalDistribution;
92 self.removalPolicy = removalPolicy;
93 self.model = model;
94
95 % Register with the model
96 model.addJobClass(self);
97
98 % Set default routing for this class at all nodes
99 for i = 1:length(model.nodes)
100 if isa(model.nodes{i}, 'Join')
101 model.nodes{i}.setStrategy(self, JoinStrategy.STD);
102 model.nodes{i}.setRequired(self, -1);
103 end
104 if ~isempty(model.nodes{i})
105 model.nodes{i}.setRouting(self, RoutingStrategy.RAND);
106 end
107 end
108
109 % Java interop is handled during resolution
110 end
111
112 function concrete = resolve(self, isOpen, refstat)
113 % RESOLVE Resolve this Signal placeholder to OpenSignal or ClosedSignal
114 %
115 % @param isOpen true if the network is open (has Source node)
116 % @param refstat Reference station for closed networks (ignored for open)
117 % @return concrete OpenSignal or ClosedSignal instance
118
119 % Save properties before replacing the placeholder
120 savedIndex = self.index;
121 savedName = self.name;
122 savedTargetJobClass = self.targetJobClass;
123
124 % Everything a node holds per class, outputStrategy above all, is
125 % stored by class index and is not renumbered when a class moves.
126 % Resolving a signal at a new index therefore reassigns another
127 % class's routing: with two signals the second one's routes were
128 % overwritten by the first's, leaving its station unreachable and
129 % its reply lost. So snapshot the routing, put the concrete signal
130 % back in the placeholder's slot, and restore the snapshot: the
131 % index it occupies never changes.
132 savedOutputStrategy = cell(1, length(self.model.nodes));
133 for n = 1:length(self.model.nodes)
134 node = self.model.nodes{n};
135 if ~isempty(node.output) && isprop(node.output, 'outputStrategy')
136 savedOutputStrategy{n} = node.output.outputStrategy;
137 end
138 end
139
140 % The placeholder must go before the concrete signal is created,
141 % since addJobClass rejects a duplicate name.
142 placeholderIdx = find(cellfun(@(c) c == self, self.model.classes), 1);
143 if isempty(placeholderIdx)
144 placeholderIdx = savedIndex;
145 else
146 self.model.classes(placeholderIdx) = [];
147 end
148
149 % Create concrete signal (constructor will add it to model.classes)
150 if isOpen
151 concrete = OpenSignal(self.model, savedName, self.signalType, self.priority);
152 else
153 concrete = ClosedSignal(self.model, savedName, self.signalType, refstat, ...
154 self.priority, self.removalDistribution, self.removalPolicy);
155 end
156
157 appendedIdx = find(cellfun(@(c) c == concrete, self.model.classes), 1);
158 if ~isempty(appendedIdx)
159 self.model.classes(appendedIdx) = [];
160 end
161 isColumn = size(self.model.classes, 2) == 1;
162 cls = self.model.classes(:).';
163 cls = [cls(1:placeholderIdx-1), {concrete}, cls(placeholderIdx:end)];
164 if isColumn
165 cls = cls.';
166 end
167 self.model.classes = cls;
168 for c = 1:length(self.model.classes)
169 self.model.classes{c}.index = c;
170 end
171
172 for n = 1:length(self.model.nodes)
173 if ~isempty(savedOutputStrategy{n})
174 self.model.nodes{n}.output.outputStrategy = savedOutputStrategy{n};
175 end
176 end
177
178 % Copy over targetJobClass association
179 if ~isempty(savedTargetJobClass)
180 concrete.forJobClass(savedTargetJobClass);
181 end
182
183 % Copy removal configuration (both OpenSignal and ClosedSignal have these now)
184 concrete.removalDistribution = self.removalDistribution;
185 concrete.removalPolicy = self.removalPolicy;
186 end
187
188 function type = getSignalType(self)
189 % GETSIGNALTYPE Get the signal type
190 %
191 % @return type The SignalType of this signal class
192 type = self.signalType;
193 end
194
195 function self = forJobClass(self, jobClass)
196 % FORJOBCLASS Associate this signal with a job class
197 %
198 % self = FORJOBCLASS(self, jobClass) associates this signal with
199 % the specified job class. For REPLY signals, this specifies which
200 % job class's servers will be unblocked when this signal arrives.
201 %
202 % @param jobClass The JobClass to associate with this signal
203 % @return self The modified Signal instance (for chaining)
204 %
205 % Example:
206 % replySignal = Signal(model, 'Reply', SignalType.REPLY).forJobClass(reqClass);
207
208 self.targetJobClass = jobClass;
209
210 % Only a REPLY signal establishes the synchronous-call link:
211 % for a NEGATIVE or CATASTROPHE signal forJobClass merely names the
212 % victim class, and setting replySignalClass there made
213 % sn.syncreply >= 0, so the state layer reserved a held-server
214 % counter and rejected every non-FCFS station.
215 if ~isempty(jobClass) && self.signalType == SignalType.REPLY
216 jobClass.replySignalClass = self;
217 end
218 end
219
220 function jobClass = getTargetJobClass(self)
221 % GETTARGETJOBCLASS Get the associated job class
222 %
223 % @return jobClass The JobClass associated with this signal
224 jobClass = self.targetJobClass;
225 end
226
227 function idx = getTargetJobClassIndex(self)
228 % GETTARGETJOBCLASSINDEX Get the index of the associated job class
229 %
230 % @return idx Index of the associated JobClass, or -1 if none
231 if isempty(self.targetJobClass)
232 idx = -1;
233 else
234 idx = self.targetJobClass.index;
235 end
236 end
237
238 function dist = getRemovalDistribution(self)
239 % GETREMOVALDISTRIBUTION Get the removal distribution
240 %
241 % @return dist The discrete distribution for batch removals
242 dist = self.removalDistribution;
243 end
244
245 function self = setRemovalDistribution(self, dist)
246 % SETREMOVALDISTRIBUTION Set the removal distribution
247 %
248 % @param dist DiscreteDistribution for number of removals
249 self.removalDistribution = dist;
250 end
251
252 function policy = getRemovalPolicy(self)
253 % GETREMOVALPOLICY Get the removal policy
254 %
255 % @return policy The RemovalPolicy constant
256 policy = self.removalPolicy;
257 end
258
259 function self = setRemovalPolicy(self, policy)
260 % SETREMOVALPOLICY Set the removal policy
261 %
262 % @param policy RemovalPolicy constant (RANDOM, FCFS, LCFS)
263 self.removalPolicy = policy;
264 end
265
266 function b = isCatastrophe(self)
267 % ISCATASTROPHE Check if this is a catastrophe signal
268 %
269 % @return b true if signalType is SignalType.CATASTROPHE
270 b = (self.signalType == SignalType.CATASTROPHE);
271 end
272
273 end
274
275end
Definition fjtag.m:157
Definition Station.m:245