LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
Station.m
1classdef Station < StatefulNode
2 % An abstract class for nodes where jobs station
3 %
4 % Copyright (c) 2012-2026, Imperial College London
5 % All rights reserved.
6
7 properties
8 numberOfServers;
9 cap;
10 dropRule;
11 classCap;
12 lldScaling; % limited load-dependence scaling factors
13 lcdScaling; % limited class-dependence scaling factors
14 stationIndex;
15 patienceDistributions; % per-class patience distributions (cell array indexed by class)
16 end
17
18 methods(Hidden)
19 %Constructor
20 function self = Station(name)
21 % SELF = STATION(NAME)
22
23 self@StatefulNode(name);
24 self.cap = Inf;
25 self.classCap = [];
26 self.lldScaling = [];
27 self.patienceDistributions = [];
28 end
29
30 % don't expose to avoid accidental call without checking the queue
31 % scheduling discipline
32 function setLimitedLoadDependence(self, alpha)
33 % SETLIMITEDLOADDEPENDENCE(self, alpha)
34 % alpha(ni) is the service rate scaling when there are ni>=1
35 % jobs in the system
36 self.lldScaling = alpha;
37 end
38
39 % don't expose to avoid accidental call without checking the queue
40 % scheduling discipline
41 function setLimitedClassDependence(self, gamma)
42 % SETLIMITEDCLASSDEPENDENCE(self, gamma)
43 %
44 % gamma(ni) is a function handle, where ni=[ni1,...,niR]
45 % is the service rate scaling when there are nir jobs at
46 % station i in class r
47 if isa(gamma,'function_handle')
48 self.lcdScaling = gamma;
49 else
50 line_error(mfilename, 'Class dependence must be specified through a function handle.');
51 end
52 end
53
54 end
55
56 methods
57
58 function self = setDropRule(self, class, drop)
59 % SELF = SETDROPRULE(CLASS, DROPRULE)
60
61 self.dropRule(class) = drop;
62 end
63
64
65 function setNumServers(self, value)
66 % SETNUMSERVERS(VALUE)
67
68 self.numberOfServers = value;
69 end
70
71 function setNumberOfServers(self, value)
72 % SETNUMBEROFSERVERS(VALUE)
73
74 self.numberOfServers = value;
75 end
76
77 function value = getNumServers(self)
78 % VALUE = GETNUMSERVERS()
79
80 value = self.numberOfServers;
81 end
82
83 function value = getNumberOfServers(self)
84 % VALUE = GETNUMBEROFSERVERS()
85
86 value = self.numberOfServers;
87 end
88
89 function setCapacity(self, value)
90 % SETCAPACITY(VALUE)
91
92 self.cap = value;
93 end
94
95 function setCap(self, value)
96 % SETCAP(VALUE)
97 % Alias for setCapacity() for backwards compatibility
98
99 self.setCapacity(value);
100 end
101
102 function setChainCapacity(self, values)
103 % SETCHAINCAPACITY(VALUES)
104
105 sn = self.model.getStruct;
106 if numel(values) ~= sn.nchains
107 line_error(mfilename,'The method requires in input a capacity value for each chain.');
108 end
109 for c = 1:sn.nchains
110 inchain = sn.inchain{c};
111 for r = inchain
112 if ~self.isServiceDisabled(r)
113 self.classCap(r) = values(c);
114 else
115 self.classCap(r) = Inf;
116 end
117 end
118 end
119 self.cap = min(sum(self.classCap(self.classCap>0)), self.cap);
120 end
121
122
123 function isD = isServiceDefined(self, class)
124 K = size(self.model.getClasses(),2);
125 isD = true(1, K);
126 switch self.server.className
127 case 'ServiceTunnel'
128 %noop
129 otherwise
130 for r=1:K
131 if isempty(self.server.serviceProcess{1,r})
132 isD(r) = false;
133 end
134 end
135 end
136 end
137
138 function isD = isServiceDisabled(self, class)
139 % ISD = ISSERVICEDISABLED(CLASS)
140 if nargin>=2
141 switch self.server.className
142 case 'ServiceTunnel'
143 isD = false;
144 otherwise
145 isD = self.server.serviceProcess{1,class}{end}.isDisabled();
146 end
147 else
148 K = size(self.model.getClasses(),2);
149 isD = false(1, K);
150 switch self.server.className
151 case 'ServiceTunnel'
152 %noop
153 otherwise
154 %isD = cellfun(@(sp) sp{end}.isDisabled, self.server.serviceProcess);
155 for r=1:K
156 isD(r) = self.server.serviceProcess{1,r}{end}.isDisabled();
157 end
158 end
159 end
160 end
161
162 function isI = isServiceImmediate(self, class)
163 % ISI = ISSERVICEIMMEDIATE(CLASS)
164
165 isI = self.server.serviceProcess{1,class}{end}.isImmediate();
166 end
167
168 function R = getNumberOfServiceClasses(self)
169 % R = GETNUMBEROFSERVICECLASSES()
170
171 R = size(self.server.serviceProcess,2);
172 end
173
174 function [p] = getSelfLoopProbabilities(self)
175 % [P] = GETSELFLOOPPROBABILITIES()
176
177 R = getNumberOfServiceClasses(self);
178 p = zeros(1,R);
179 for k=1:R
180 nOutLinks = length(self.output.outputStrategy{k}{end});
181 switch RoutingStrategy.toText(self.output.outputStrategy{k}{2})
182 case 'Random'
183 p(k) = 1 / nOutLinks;
184 case RoutingStrategy.PROB
185 for t=1:nOutLinks % for all outgoing links
186 if strcmp(self.output.outputStrategy{k}{end}{t}{1}.name, self.name)
187 p(k) = self.output.outputStrategy{k}{end}{t}{2};
188 break
189 end
190 end
191 end
192 end
193 end
194
195 function [map, mu, phi] = getSourceRates(self)
196 % [PH,MU,PHI] = GETSOURCERATES()
197
198 nclasses = size(self.input.sourceClasses,2);
199 map = cell(1,nclasses);
200 mu = cell(1,nclasses);
201 phi = cell(1,nclasses);
202 for r=1:nclasses
203 if isempty(self.input.sourceClasses{r})
204 self.input.sourceClasses{r} = {[],ServiceStrategy.LI,Disabled.getInstance()};
205 map{r} = {[NaN],[NaN]};
206 mu{r} = NaN;
207 phi{r} = NaN;
208 elseif ~self.input.sourceClasses{r}{end}.isDisabled()
209 switch class(self.input.sourceClasses{r}{end})
210 case {'Replayer', 'Trace'}
211 aph = self.input.sourceClasses{r}{end}.fitAPH;
212 map{r} = aph.getProcess();
213 mu{r} = aph.getMu;
214 phi{r} = aph.getPhi;
215 case {'Exp','Coxian','Erlang','HyperExp','Markovian','APH','PH'}
216 map{r} = self.input.sourceClasses{r}{end}.getProcess;
217 mu{r} = self.input.sourceClasses{r}{end}.getMu;
218 phi{r} = self.input.sourceClasses{r}{end}.getPhi;
219 case {'Det','Uniform','Pareto','Gamma','Lognormal','Weibull'}
220 map{r} = self.input.sourceClasses{r}{end}.getProcess();
221 mu{r} = [1/self.input.sourceClasses{r}{end}.getMean];
222 phi{r} = [1];
223 case 'MMPP2'
224 map{r} = self.input.sourceClasses{r}{end}.getProcess();
225 mu{r} = self.input.sourceClasses{r}{end}.getMu;
226 phi{r} = self.input.sourceClasses{r}{end}.getPhi;
227 case 'MAP'
228 map{r} = self.input.sourceClasses{r}{end}.getProcess();
229 mu{r} = self.input.sourceClasses{r}{end}.getMu;
230 phi{r} = self.input.sourceClasses{r}{end}.getPhi;
231 otherwise
232 % leave everything empty
233 end
234 else
235 map{r} = {[NaN],[NaN]};
236 mu{r} = NaN;
237 phi{r} = NaN;
238 end
239 end
240 end
241
242 function [map,mu,phi] = getServiceRates(self)
243 % [PH,MU,PHI] = GETSERVICERATES()
244
245 nclasses = size(self.server.serviceProcess,2);
246 map = cell(1,nclasses);
247 mu = cell(1,nclasses);
248 phi = cell(1,nclasses);
249 for r=1:nclasses
250 serviceProcess_r = self.server.serviceProcess{r};
251 if isempty(serviceProcess_r)
252 serviceProcess_r = {[],ServiceStrategy.LI,Disabled.getInstance()};
253 map{r} = {[NaN],[NaN]};
254 mu{r} = NaN;
255 phi{r} = NaN;
256 elseif serviceProcess_r{end}.isImmediate()
257 map{r} = {[-GlobalConstants.Immediate],[GlobalConstants.Immediate]};
258 mu{r} = [GlobalConstants.Immediate];
259 phi{r} = [1];
260 elseif ~serviceProcess_r{end}.isDisabled()
261 switch class(serviceProcess_r{end})
262 case {'Det','Uniform','Pareto','Gamma','Weibull','Lognormal'}
263 map{r} = serviceProcess_r{end}.getProcess();
264 mu{r} = [serviceProcess_r{end}.getRate];
265 phi{r} = [1];
266 case {'Replayer', 'Trace'}
267 aph = serviceProcess_r{end}.fitAPH;
268 map{r} = aph.getProcess();
269 mu{r} = aph.getMu;
270 phi{r} = aph.getPhi;
271 case {'Exp','Coxian','Erlang','HyperExp','Markovian','APH','MAP','PH'}
272 map{r} = serviceProcess_r{end}.getProcess();
273 mu{r} = serviceProcess_r{end}.getMu;
274 phi{r} = serviceProcess_r{end}.getPhi;
275 case 'MMPP2'
276 map{r} = serviceProcess_r{end}.getProcess();
277 mu{r} = serviceProcess_r{end}.getMu;
278 phi{r} = serviceProcess_r{end}.getPhi;
279 end
280 else
281 map{r} = {[NaN],[NaN]};
282 mu{r} = NaN;
283 phi{r} = NaN;
284 end
285 end
286 end
287
288 function summary(self)
289 % SUMMARY()
290
291 line_printf('\nNode: <strong>%s</strong>',self.getName);
292 line_printf('\nScheduling: %s',self.schedStrategy);
293 line_printf('\nNumber of Servers: %d',self.numberOfServers);
294 for r=1:length(self.output.outputStrategy)
295 classes = self.model.getClasses();
296 line_printf('\nRouting %s: %s',classes{r}.name,self.output.outputStrategy{r}{2});
297 end
298 % self.input.summary;
299 % self.server.summary;
300 % self.output.summary;
301 end
302
303 end
304end
Definition mmt.m:92