LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
refreshStruct.m
1function refreshStruct(self, hardRefresh)
2% REFRESHSTRUCT()
3%
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6
7sanitize(self);
8if nargin<2
9 hardRefresh = true;
10end
11
12%% store invariant information
13if self.hasStruct && ~hardRefresh
14 rtorig = self.sn.rtorig; % this must be destroyed with resetNetwork
15end
16
17if self.hasStruct && ~hardRefresh
18 nodetypes = sn.nodetypes;
19 classnames = sn.classnames;
20 nodenames = sn.nodenames;
21 refstat = sn.refstat;
22else
23 nodetypes = getNodeTypes(self);
24 classnames = getClassNames(self);
25 nodenames = getNodeNames(self);
26 refstat = getReferenceStations(self);
27
28 % Append FCR names and types to node lists (only when refreshing)
29 for f = 1:length(self.regions)
30 fcr = self.regions{f};
31 nodenames{end+1} = fcr.getName();
32 nodetypes(end+1) = NodeType.FiniteCapacityRegion;
33 end
34end
35conn = self.getConnectionMatrix;
36njobs = getNumberOfJobs(self);
37numservers = getStationServers(self);
38lldscaling = getLimitedLoadDependence(self);
39cdscaling = getLimitedClassDependence(self);
40
41%% init minimal structure
42sn = NetworkStruct(); % create in self to ensure propagation
43if isempty(self.sn)
44 sn.rtorig = {};
45 sn.reward = {};
46else
47 sn.rtorig = self.sn.rtorig;
48 if isfield(self.sn, 'reward')
49 sn.reward = self.sn.reward; % preserve reward definitions
50 else
51 sn.reward = {};
52 end
53end
54% sn.nnodes counts physical nodes only; FCRs are virtual nodes appended to nodenames/nodetypes
55sn.nnodes = numel(self.nodes);
56sn.nclasses = length(classnames);
57
58%% get routing strategies
59routing = zeros(sn.nnodes, sn.nclasses);
60for ind=1:sn.nnodes
61 for r=1:sn.nclasses
62 if isempty(self.nodes{ind}.output.outputStrategy{r})
63 routing(ind,r) = RoutingStrategy.DISABLED;
64 else
65 routing(ind,r) = RoutingStrategy.fromText(self.nodes{ind}.output.outputStrategy{r}{2});
66 end
67 end
68end
69sn.isslc = false(sn.nclasses,1);
70for r=1:sn.nclasses
71 if isa(self.classes{r},'SelfLoopingClass')
72 sn.isslc(r) = true;
73 end
74end
75sn.issignal = false(sn.nclasses,1);
76sn.signaltype = cell(sn.nclasses,1);
77for r=1:sn.nclasses
78 sn.signaltype{r} = NaN;
79end
80% Detect Signal classes and populate issignal/signaltype
81for r=1:sn.nclasses
82 if isa(self.classes{r},'Signal')
83 sn.issignal(r) = true;
84 sn.signaltype{r} = self.classes{r}.signalType;
85 end
86end
87sn.nclosedjobs = sum(njobs(isfinite(njobs)));
88sn.nservers = numservers;
89sn.isstation = (nodetypes == NodeType.Source | nodetypes == NodeType.Delay | nodetypes == NodeType.Queue | nodetypes == NodeType.Join | nodetypes == NodeType.Place);
90sn.nstations = sum(sn.isstation);
91sn.scv = ones(sn.nstations,sn.nclasses);
92sn.njobs = njobs(:)';
93sn.refstat = refstat;
94sn.space = cell(sn.nstations,1);
95sn.routing = routing;
96sn.chains = [];
97sn.lst = {};
98sn.lldscaling = lldscaling;
99sn.cdscaling = cdscaling;
100sn.nodetype = nodetypes;
101sn.nstations = sum(sn.isstation);
102sn.isstateful = (nodetypes == NodeType.Source | nodetypes == NodeType.Delay | nodetypes == NodeType.Queue | nodetypes == NodeType.Cache | nodetypes == NodeType.Join | nodetypes == NodeType.Router | nodetypes == NodeType.Place | nodetypes == NodeType.Transition);
103sn.isstatedep = false(sn.nnodes,3); % col 1: buffer, col 2: srv, col 3: routing
104sn.isfunction = [];
105for ind = 1:sn.nstations
106 if isa(self.stations{ind},'Queue')
107 sn.isfunction(ind) = ~isempty(self.stations{ind}.setupTime);
108 end
109end
110for ind=1:sn.nnodes
111 switch sn.nodetype(ind)
112 case NodeType.Cache
113 sn.isstatedep(ind,2) = true; % state dependent service
114 % case NodeType.Place
115 % self.nodes{ind}.init();
116 % case NodeType.Transition
117 % self.nodes{ind}.init(); % this erases enablingConditions
118 end
119
120 for r=1:sn.nclasses
121 switch sn.routing(ind,r)
122 case {RoutingStrategy.RROBIN, RoutingStrategy.WRROBIN, RoutingStrategy.JSQ, RoutingStrategy.RL, RoutingStrategy.KCHOICES}
123 sn.isstatedep(ind,3) = true; % state dependent routing
124 end
125 end
126end
127
128sn.nstateful = sum(sn.isstateful);
129sn.state = cell(sn.nstations,1);
130for i=1:sn.nstateful
131 sn.state{i} = [];
132end
133sn.nodenames = nodenames;
134sn.classnames = classnames;
135sn.connmatrix = conn;
136
137sn.nodeToStateful =[];
138sn.nodeToStation =[];
139sn.stationToNode =[];
140sn.stationToStateful =[];
141sn.statefulToNode =[];
142sn.statefulToStation =[];
143for ind=1:sn.nnodes
144 sn.nodeToStateful(ind) = nd2sf(sn,ind);
145 sn.nodeToStation(ind) = nd2st(sn,ind);
146end
147for ist=1:sn.nstations
148 sn.stationToNode(ist) = st2nd(sn,ist);
149 sn.stationToStateful(ist) = st2sf(sn,ist);
150end
151for isf=1:sn.nstateful
152 sn.statefulToNode(isf) = sf2nd(sn,isf);
153 sn.statefulToStation(isf) = sf2st(sn,isf);
154end
155sn.fj = self.getForkJoins();
156self.sn = sn;
157refreshPriorities(self);
158refreshProcesses(self);
159
160% Check if priorities are specified but no priority-aware scheduling policy is used
161sn = self.sn;
162if any(sn.classprio(:) > 0)
163 % Priority classes exist, check if any station uses priority-aware scheduling
164 prioScheds = [SchedStrategy.PSPRIO, SchedStrategy.DPSPRIO, SchedStrategy.GPSPRIO, ...
165 SchedStrategy.HOL, SchedStrategy.FCFSPRIO, SchedStrategy.LCFSPRIO, ...
166 SchedStrategy.LCFSPRPRIO, SchedStrategy.LCFSPIPRIO];
167 if ~any(ismember(sn.sched, prioScheds))
168 line_warning(mfilename, 'Priority classes are specified but no priority-aware scheduling policy (PSPRIO, DPSPRIO, GPSPRIO, HOL, FCFSPRIO, LCFSPRIO, LCFSPRPRIO, LCFSPIPRIO) is used in the model. Priorities will be ignored.\n');
169 end
170end
171
172if any(nodetypes == NodeType.Cache)
173 % this also refreshes the routing matrix and the visits
174 refreshChains(self, false); % wantVisits
175else
176 % this also refreshes the routing matrix and the visits
177 refreshChains(self, true); % wantVisits
178end
179sn = self.sn;
180refclasses = getReferenceClasses(self);
181refclass = zeros(1,sn.nchains);
182for c=1:sn.nchains
183 isect = intersect(sn.inchain{c},find(refclasses));
184 if any(isect)
185 refclass(c) = isect;
186 end
187end
188sn.refclass = refclass;
189self.sn = sn;
190refreshLocalVars(self); % depends on chains (rtnodes)
191refreshPetriNetNodes(self);
192refreshSync(self); % this assumes that refreshChain is called before
193refreshGlobalSync(self);
194
195sn = self.sn;
196self.hasStruct = true;
197
198if any(sn.fj(:)) % if there are forks
199 % try to recompute visits after mixed-model transformation:
200 % we obtain the visits of auxiliary class from the transformed model
201 % then we sum them to the original classes
202 %try
203 [nonfjmodel, fjclassmap, forkmap, fanOut] = ModelAdapter.mmt(self);
204 if any(fanOut==1)
205 % in this case, one of the forks is degenerate with a single
206 % outgoing link so no visit correction is needed
207 line_warning(mfilename,'The specified fork-join topology has partial support, only SolverJMT simulation results may be reliable.\n');
208 % return;
209 end
210 fsn = nonfjmodel.getStruct();
211 for new_chain=(sn.nchains+1):fsn.nchains
212 anyAuxClass = fsn.inchain{new_chain}(1);
213 origFork = forkmap(anyAuxClass);
214 origChain = find(sn.chains(:,fjclassmap(anyAuxClass))); % original chain of the class
215 fsn.nodevisits{new_chain}(fsn.nodetype == NodeType.Source | fsn.nodetype == NodeType.Sink | fsn.nodetype == NodeType.Fork,:) = 0;
216 Vaux = fsn.nodevisits{new_chain}(:,fsn.inchain{new_chain});
217 if fsn.nnodes > sn.nnodes % if source-sink were added
218 Vaux(fsn.nodetype == NodeType.Source | fsn.nodetype == NodeType.Sink,:) = [];
219 end
220 X = sn.nodevisits{origChain};
221 for jaux=1:length(fsn.inchain{new_chain})
222 j = sn.inchain{origChain}(jaux); % class in the original chain
223 self.sn.nodevisits{origChain}(:,j) = sn.nodeparam{origFork}.fanOut*(X(:,j) + Vaux(:,jaux));
224 end
225 end
226end
227
228sn = refreshRegions(self);
229self.sn = sn;
230end
231
232function stat_idx = nd2st(sn, node_idx)
233% STAT_IDX = ND2ST(NODE_IDX)
234
235if sn.isstation(node_idx)
236 stat_idx = at(cumsum(sn.isstation),node_idx);
237else
238 stat_idx = NaN;
239end
240end
241
242function node_idx = st2nd(sn,stat_idx)
243% NODE_IDX = ST2ND(SELF,STAT_IDX)
244
245v = cumsum(sn.isstation) == stat_idx;
246if any(v)
247 node_idx = find(v, 1);
248else
249 node_idx = NaN;
250end
251end
252
253function sful_idx = st2sf(sn,stat_idx)
254% SFUL_IDX = ST2SF(SELF,STAT_IDX)
255
256sful_idx = nd2sf(sn,st2nd(sn,stat_idx));
257end
258
259function sful_idx = nd2sf(sn, node_idx)
260% SFUL_IDX = ND2SF(NODE_IDX)
261
262if sn.isstateful(node_idx)
263 sful_idx = at(cumsum(sn.isstateful),node_idx);
264else
265 sful_idx = NaN;
266end
267end
268
269function node_idx = sf2nd(sn,stat_idx)
270% NODE_IDX = SF2ND(SELF,STAT_IDX)
271
272v = cumsum(sn.isstateful) == stat_idx;
273if any(v)
274 node_idx = find(v, 1);
275else
276 node_idx = NaN;
277end
278end
279
280function stat_idx = sf2st(sn,sful_idx)
281% STAT_IDX = SF2ST(SELF,SFUL_IDX)
282
283stat_idx = nd2st(sn,sf2nd(sn,sful_idx));
284end
Definition mmt.m:92