LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
Activity.m
1classdef Activity < LayeredNetworkElement
2 % A stage of service in a Task of a LayeredNetwork.
3 %
4 % Copyright (c) 2012-2026, Imperial College London
5 % All rights reserved.
6
7 properties
8 hostDemand;
9 hostDemandMean; %double
10 hostDemandSCV; %double
11 parent;
12 parentName; %string
13 boundToEntry; %string
14 callOrder; %string \in {'STOCHASTIC', 'DETERMINISTIC'}
15 syncCallDests = cell(0); %string array
16 syncCallMeans = []; %integer array
17 asyncCallDests = cell(0); %string array
18 asyncCallMeans = []; %integer array
19 scheduling = [];
20 thinkTime; %Distribution object
21 thinkTimeMean; %double
22 thinkTimeSCV; %double
23 phase = 1; %integer: phase number (1 or 2)
24 end
25
26 methods
27 %public methods, including constructor
28
29 %constructor
30 function obj = Activity(model, name, hostDemand, boundToEntry, callOrder)
31 % OBJ = ACTIVITY(MODEL, NAME, HOSTDEMAND, BOUNDTOENTRY, CALLORDER)
32 name = char(name);
33 if nargin<2 %~exist('name','var')
34 line_error(mfilename,'Constructor requires to specify at least a name.');
35 end
36 obj@LayeredNetworkElement(name);
37
38 if nargin<3 %~exist('hostDemand','var')
39 hostDemand = GlobalConstants.FineTol;
40 elseif isnumeric(hostDemand) && hostDemand == 0
41 hostDemand = GlobalConstants.FineTol;
42 end
43 if nargin<4 %~exist('boundToEntry','var')
44 boundToEntry = '';
45 end
46 if nargin<5 %~exist('callOrder','var')
47 callOrder = 'STOCHASTIC';
48 end
49
50 obj.setHostDemand(hostDemand);
51 obj.boundToEntry = boundToEntry;
52 obj.setCallOrder(callOrder);
53
54 % Initialize default think time
55 obj.thinkTime = Immediate.getInstance();
56 obj.thinkTimeMean = GlobalConstants.FineTol;
57 obj.thinkTimeSCV = GlobalConstants.FineTol;
58
59 if isa(model,'LayeredNetwork')
60 model.activities{end+1} = obj;
61 obj.model = model;
62 elseif isa(model,'JLayeredNetwork')
63 % JLayeredNetwork support would go here if it exists
64 obj.obj = jline.lang.layered.Activity(model.obj, name, hostDemand, boundToEntry, callOrder);
65 model.addActivity(obj);
66 end
67 end
68
69 function obj = setParent(obj, parent)
70 % OBJ = SETPARENT(OBJ, PARENT)
71
72 if isa(parent,'Entry') || isa(parent,'Task')
73 obj.parentName = parent.name;
74 obj.parent = parent;
75 else
76 obj.parentName = parent;
77 obj.parent = [];
78 end
79 end
80
81 function self = on(self, parent)
82 % OBJ = ON(OBJ, PARENT)
83 if ~isa(parent,'Task')
84 line_error(mfilename,'Invalid .on() argument: expected a task.')
85 end
86 if isempty(self.parent)
87 parent.addActivity(self);
88 self.parent = parent;
89 else
90 line_error(mfilename,'Parent task already defined.')
91 end
92 end
93
94 function obj = setHostDemand(obj, hostDemand)
95 % OBJ = SETHOSTDEMAND(OBJ, HOSTDEMAND)
96
97 if isnumeric(hostDemand)
98 if hostDemand <= GlobalConstants.FineTol
99 obj.hostDemand = Immediate.getInstance();
100 obj.hostDemandMean = GlobalConstants.FineTol;
101 obj.hostDemandSCV = GlobalConstants.FineTol;
102 else
103 obj.hostDemand = Exp(1/hostDemand);
104 obj.hostDemandMean = hostDemand;
105 obj.hostDemandSCV = 1.0;
106 end
107 elseif isa(hostDemand,'Distribution')
108 obj.hostDemand = hostDemand;
109 obj.hostDemandMean = hostDemand.getMean();
110 obj.hostDemandSCV = hostDemand.getSCV();
111 end
112 end
113
114 function obj = repliesTo(obj, entry)
115 % OBJ = REPLIESTO(OBJ, ENTRY)
116
117 if ~isempty(obj.parent)
118 switch SchedStrategy.fromText(obj.parent.scheduling)
119 case SchedStrategy.REF
120 line_error(mfilename,'Activities in reference tasks cannot reply.');
121 otherwise
122 entry.replyActivity{end+1} = obj.name;
123 end
124 else
125 entry.replyActivity{end+1} = obj.name;
126 end
127 end
128
129 function obj = boundTo(obj, entry)
130 % OBJ = BOUNDTO(OBJ, ENTRY)
131
132 if isa(entry,'Entry')
133 obj.boundToEntry = entry.name;
134 elseif ischar(entry)
135 obj.boundToEntry = entry;
136 else
137 line_error(mfilename,'Wrong entry parameter for boundTo method.');
138 end
139 end
140
141 function obj = setCallOrder(obj, callOrder)
142 % OBJ = SETCALLORDER(OBJ, CALLORDER)
143
144 if strcmpi(callOrder,'STOCHASTIC') || strcmpi(callOrder,'DETERMINISTIC')
145 obj.callOrder = upper(callOrder);
146 else
147 obj.callOrder = 'STOCHASTIC';
148 end
149 end
150
151 function obj = setThinkTime(obj, thinkTime)
152 % OBJ = SETTHINKTIME(OBJ, THINKTIME)
153
154 if isnumeric(thinkTime)
155 if thinkTime <= GlobalConstants.FineTol
156 obj.thinkTime = Immediate.getInstance();
157 obj.thinkTimeMean = GlobalConstants.FineTol;
158 obj.thinkTimeSCV = GlobalConstants.FineTol;
159 else
160 obj.thinkTime = Exp(1/thinkTime);
161 obj.thinkTimeMean = thinkTime;
162 obj.thinkTimeSCV = 1.0;
163 end
164 elseif isa(thinkTime,'Distribution')
165 obj.thinkTime = thinkTime;
166 obj.thinkTimeMean = thinkTime.getMean();
167 obj.thinkTimeSCV = thinkTime.getSCV();
168 end
169 end
170
171 function obj = setPhase(obj, phaseNum)
172 % OBJ = SETPHASE(OBJ, PHASENUM)
173 % Set the phase number for this activity.
174 % Phase 1: activities before the reply is sent
175 % Phase 2: activities after the reply is sent (post-reply processing)
176
177 if ~isnumeric(phaseNum) || phaseNum < 1 || phaseNum > 2
178 line_error(mfilename, 'Phase must be 1 or 2.');
179 end
180 obj.phase = phaseNum;
181 end
182
183 %synchCall
184
185 function obj = synchCall(obj, synchCallDest, synchCallMean)
186 % OBJ = SYNCHCALL(OBJ, SYNCHCALLDEST, SYNCHCALLMEAN)
187
188 if nargin<3 %~exist('synchCallMean','var')
189 synchCallMean = 1.0;
190 end
191
192 % Get the destination entry name
193 if ischar(synchCallDest)
194 destName = synchCallDest;
195 else % object
196 destName = synchCallDest.name;
197 end
198
199 % Check if this entry is already in the synchronous call destinations
200 if ~isempty(obj.syncCallDests)
201 for i = 1:length(obj.syncCallDests)
202 if strcmp(obj.syncCallDests{i}, destName)
203 error_msg = sprintf('Activity "%s" already has a synchronous call to entry "%s". ', ...
204 obj.name, destName);
205 error_msg = [error_msg, 'If you intend multiple calls, change the mean number of calls using synchCall(entry, mean_calls) or define an activity graph with explicit precedences.'];
206 line_error(mfilename, error_msg);
207 end
208 end
209 end
210
211 % Add the new call destination
212 obj.syncCallDests{length(obj.syncCallDests)+1} = destName;
213 obj.syncCallMeans = [obj.syncCallMeans; synchCallMean];
214 end
215
216 %asynchCall
217 function obj = asynchCall(obj, asynchCallDest, asynchCallMean)
218 % OBJ = ASYNCHCALL(OBJ, ASYNCHCALLDEST, ASYNCHCALLMEAN)
219
220 if nargin<3 %~exist('asynchCallMean','var')
221 asynchCallMean = 1.0;
222 end
223
224 % Get the destination entry name
225 if ischar(asynchCallDest)
226 destName = asynchCallDest;
227 else % object
228 destName = asynchCallDest.name;
229 end
230
231 % Check if this entry is already in the asynchronous call destinations
232 if ~isempty(obj.asyncCallDests)
233 for i = 1:length(obj.asyncCallDests)
234 if strcmp(obj.asyncCallDests{i}, destName)
235 error_msg = sprintf('Activity "%s" already has an asynchronous call to entry "%s". ', ...
236 obj.name, destName);
237 error_msg = [error_msg, 'If you intend multiple calls, change the mean number of calls using asynchCall(entry, mean_calls) or define an activity graph with explicit precedences.'];
238 line_error(mfilename, error_msg);
239 end
240 end
241 end
242
243 % Add the new call destination
244 obj.asyncCallDests{length(obj.asyncCallDests)+1} = destName;
245 obj.asyncCallMeans = [obj.asyncCallMeans; asynchCallMean];
246 end
247
248 % Getter methods for API consistency with Java/Python
249 function val = getHostDemand(obj)
250 % GETHOSTDEMAND Get the host demand distribution
251 val = obj.hostDemand;
252 end
253
254 function val = getHostDemandMean(obj)
255 % GETHOSTDEMANDMEAN Get the mean host demand
256 val = obj.hostDemandMean;
257 end
258
259 function val = getHostDemandSCV(obj)
260 % GETHOSTDEMANDSCV Get the SCV of host demand
261 val = obj.hostDemandSCV;
262 end
263
264 function val = getCallOrder(obj)
265 % GETCALLORDER Get the call order (STOCHASTIC or DETERMINISTIC)
266 val = obj.callOrder;
267 end
268
269 function val = getBoundToEntry(obj)
270 % GETBOUNDTOENTRY Get the entry this activity is bound to
271 val = obj.boundToEntry;
272 end
273
274 function val = getParent(obj)
275 % GETPARENT Get the parent task
276 val = obj.parent;
277 end
278
279 function val = getSyncCallDests(obj)
280 % GETSYNCCALLDESTS Get the synchronous call destinations
281 val = obj.syncCallDests;
282 end
283
284 function val = getSyncCallMeans(obj)
285 % GETSYNCCALLMEANS Get the synchronous call means
286 val = obj.syncCallMeans;
287 end
288
289 function val = getAsyncCallDests(obj)
290 % GETASYNCCALLDESTS Get the asynchronous call destinations
291 val = obj.asyncCallDests;
292 end
293
294 function val = getAsyncCallMeans(obj)
295 % GETASYNCCALLMEANS Get the asynchronous call means
296 val = obj.asyncCallMeans;
297 end
298
299 function val = getThinkTimeMean(obj)
300 % GETTHINKTIMEMEAN Get the mean think time
301 val = obj.thinkTimeMean;
302 end
303
304 function val = getPhase(obj)
305 % GETPHASE Get the phase number (1 or 2)
306 val = obj.phase;
307 end
308
309 end
310
311end