LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
spaceGeneratorNodes.m
1function [nodeStateSpace, sn, capacityc] = spaceGeneratorNodes(sn, cutoff, options)
2if nargin<3
3 options = Solver.defaultOptions;
4end
5N = sn.njobs';
6sn.space = {};
7capacityc = zeros(sn.nnodes, sn.nclasses);
8% Draft SPN support
9% for n=1:sn.nnodes
10% if isfield(sn.varsparam{n}, "capacityc")
11% capacityc(n) = sn.varsparam{n}.capacityc;
12% end
13% end
14for ind=1:sn.nnodes
15 % Cooperative wall-clock budget checkpoint (options.timeout)
16 if nargin>=3 && lineTimeoutExceeded(options)
17 line_error(mfilename,'State space generation exceeded the wall-clock time budget (options.timeout=%gs).', options.timeout);
18 end
19 if sn.isstation(ind) % place jobs across stations
20 ist = sn.nodeToStation(ind);
21 isf = sn.nodeToStateful(ind);
22 for r=1:sn.nclasses %cut-off open classes to finite capacity
23 c = find(sn.chains(:,r));
24 if ~isempty(sn.visits{c}) && sn.visits{c}(isf,r) == 0
25 capacityc(ind,r) = 0;
26 % Draft SPN support
27 %elseif isfield(sn.varsparam{ind}, 'capacityc')
28 % capacityc(ind,r) = min(cutoff(ist,r), sn.classcap(ist,r));
29 elseif sn.nodetype(ind) ~= NodeType.Place && ~isempty(sn.proc) && ~isempty(sn.proc{ist}{r}) && any(any(isnan(sn.proc{ist}{r}{1}))) % disabled (not Places - they hold tokens without service)
30 capacityc(ind,r) = 0;
31 else
32 if isinf(N(r))
33 capacityc(ind,r) = min(cutoff(ist,r), sn.classcap(ist,r));
34 else
35 % closed classes: enumerate up to the chain population, but never
36 % beyond the class capacity at this station (finite-buffer stations)
37 capacityc(ind,r) = min(sum(sn.njobs(sn.chains(c,:))), sn.classcap(ist,r));
38 end
39 end
40 % Finite-capacity region bound: a station in a DROP/WAITQ region can
41 % never hold more than the region's per-class cap (nor more than the
42 % region-global cap) of class r, so enumerating beyond it produces only
43 % states the region filter later discards. Bounding capacityc here keeps
44 % the generated space small (the auto-cutoff is region-blind and can be
45 % far larger than any reachable population), with an identical final
46 % result. -1 = unbounded. sn.region{f} is M x (K+1): cols 1..K per-class,
47 % col K+1 the region-global cap at each member station.
48 if isfield(sn,'nregions') && sn.nregions > 0 && capacityc(ind,r) > 0
49 for f=1:sn.nregions
50 regf = sn.region{f};
51 if ist <= size(regf,1)
52 rc = regf(ist, r);
53 gc = regf(ist, sn.nclasses+1);
54 if rc >= 0
55 capacityc(ind,r) = min(capacityc(ind,r), rc);
56 end
57 if gc >= 0
58 capacityc(ind,r) = min(capacityc(ind,r), gc);
59 end
60 end
61 end
62 end
63 end
64 if sn.isstation(ind)
65 % in this case, the local variables are produced within
66 % fromMarginalBounds, e.g., for RROBIN routing
67 sn.space{isf} = State.fromMarginalBounds(sn, ind, [], capacityc(ind,:), sn.cap(ist), options);
68 else
69 % this is the case for example of cache nodes
70 state_bufsrv = State.fromMarginalBounds(sn, ind, [], capacityc(ind,:), sn.cap(ist), options);
71 state_var = State.spaceLocalVars(sn, ind);
72 sn.space{isf} = State.cartesian(state_bufsrv,state_var); % generate all possible states for local variables
73 end
74 if isinf(sn.nservers(ist))
75 sn.nservers(ist) = sum(capacityc(ind,:));
76 end
77 elseif sn.isstateful(ind) % generate state space of other stateful nodes that are not stations
78 %ist = sn.nodeToStation(ind);
79 isf = sn.nodeToStateful(ind);
80 switch sn.nodetype(ind)
81 case NodeType.Cache
82 for r=1:sn.nclasses % restrict state space generation to immediate events
83 capacityc(ind,r) = 1;
84 end
85 case NodeType.Router
86 % For Router nodes, only allow capacity for classes that have
87 % non-zero nodevisits (classes that actually visit the Router)
88 for r=1:sn.nclasses
89 c = find(sn.chains(:,r));
90 if ~isempty(sn.nodevisits{c}) && sn.nodevisits{c}(ind,r) > 0
91 capacityc(ind,r) = 1;
92 else
93 capacityc(ind,r) = 0;
94 end
95 end
96 case NodeType.Transition
97 capacityc(ind,:) = 0; % Transitions don't hold class-based jobs
98 % Generate per-mode state space (bypass fromMarginalBounds)
99 nmodes = sn.nodeparam{ind}.nmodes;
100 firingphases = sn.nodeparam{ind}.firingphases;
101 if any(isnan(firingphases))
102 firingphases = zeros(1, nmodes);
103 for m = 1:nmodes
104 if iscell(sn.nodeparam{ind}.firingproc) && ~isempty(sn.nodeparam{ind}.firingproc{m})
105 firingphases(m) = size(sn.nodeparam{ind}.firingproc{m}{1}, 1);
106 else
107 firingphases(m) = 1;
108 end
109 end
110 end
111 fK = firingphases;
112 nmodeservers = sn.nodeparam{ind}.nmodeservers;
113 max_jobs = sum(sn.njobs(~isinf(sn.njobs)));
114 if any(isinf(sn.njobs))
115 max_jobs = max_jobs + sum(cutoff(1,:));
116 end
117 mode_spaces = cell(1, nmodes);
118 for m = 1:nmodes
119 max_srv_m = nmodeservers(m);
120 if isinf(max_srv_m)
121 max_srv_m = max_jobs;
122 end
123 max_srv_m = min(max_srv_m, max_jobs);
124 mode_states = [];
125 for total = 0:max_srv_m
126 phase_combs = multichoose(fK(m), total);
127 buf_m = nmodeservers(m);
128 if isinf(buf_m)
129 buf_m = GlobalConstants.MaxInt();
130 end
131 buf_m = buf_m - total;
132 mode_states = [mode_states; repmat(buf_m, size(phase_combs,1), 1), phase_combs]; %#ok<AGROW>
133 end
134 mode_spaces{m} = mode_states;
135 end
136 trans_space = mode_spaces{1};
137 for m = 2:nmodes
138 trans_space = State.cartesian(trans_space, mode_spaces{m});
139 end
140 % State.cartesian interleaves the columns as
141 % [idle_1, phases_1, idle_2, phases_2, ...]. Reorder to the
142 % contiguous layout [idle(nmodes), phases(sum fK), fired(nmodes)]
143 % expected by afterGlobalEvent.m (space_buf = 1:nmodes,
144 % space_srv = nmodes+(1:sum fK)) and produced by the native-Python
145 % builder. The interleaved layout made afterGlobalEvent read the
146 % idle/phase counts of every mode after the first from the wrong
147 % columns, which collapsed the state space of any transition with
148 % more than one mode.
149 idle_cols = zeros(1, nmodes);
150 phase_cols = [];
151 off = 0;
152 for m = 1:nmodes
153 idle_cols(m) = off + 1;
154 phase_cols = [phase_cols, (off+2):(off+1+fK(m))]; %#ok<AGROW>
155 off = off + 1 + fK(m);
156 end
157 trans_space = trans_space(:, [idle_cols, phase_cols]);
158 trans_space = [trans_space, zeros(size(trans_space,1), nmodes)]; % append fired counts
159 state_var = State.spaceLocalVars(sn, ind);
160 sn.space{isf} = State.cartesian(trans_space, state_var);
161 continue; % skip fromMarginalBounds below
162 otherwise
163 capacityc(ind,:) = 1; %
164 end
165 state_bufsrv = State.fromMarginalBounds(sn, ind, [], capacityc(ind,:), 1, options);
166 state_var = State.spaceLocalVars(sn, ind);
167 sn.space{isf} = State.cartesian(state_bufsrv,state_var); % generate all possible states for local variables
168
169 % Prune locally invalid cache states for retrieval-system caches. The
170 % unfiltered cartesian product enumerates states the dynamics can never
171 % reach -- an item simultaneously cached and being retrieved, more items
172 % in retrieval than the retrieval-system capacity, or more than one job
173 % in the cache server. Leaving them in pollutes the CTMC stationary
174 % distribution. The cross-node (cache <-> queue) consistency is enforced
175 % during global composition. Non-retrieval caches are left untouched.
176 if sn.nodetype(ind) == NodeType.Cache ...
177 && isfield(sn.nodeparam{ind},'retrievalSystemCapacity') ...
178 && sn.nodeparam{ind}.retrievalSystemCapacity > 0
179 np = sn.nodeparam{ind};
180 nItems = np.nitems;
181 tcc = np.totalCacheCapacity;
182 rsc = np.retrievalSystemCapacity;
183 lvs = size(state_bufsrv,2); % per-class server presence is columns 1..lvs
184 value = sn.space{isf};
185 keep = false(size(value,1),1);
186 for row = 1:size(value,1)
187 st = value(row,:);
188 % at most one class job may sit in the cache server/buffer
189 validRow = sum(st(1:lvs)) <= 1;
190 if validRow
191 nbits = 0;
192 cacheItems = st((lvs+1):(lvs+tcc));
193 for col = (lvs+tcc+1):size(st,2)
194 if st(col) == 0, continue; end
195 nbits = nbits + 1;
196 item = col - (lvs+tcc); % 1-based item id of the set bit
197 % a cached item cannot simultaneously be in the retrieval system
198 if any(cacheItems == item)
199 validRow = false; break;
200 end
201 end
202 % at most retrievalSystemCapacity items may be in retrieval at once
203 if validRow && nbits > rsc
204 validRow = false;
205 end
206 end
207 keep(row) = validRow;
208 end
209 sn.space{isf} = value(keep,:);
210 end
211 end
212end
213nodeStateSpace = sn.space;
214end
Definition fjtag.m:157
Definition Station.m:245