1function [nodeStateSpace, sn, capacityc] = spaceGeneratorNodes(sn, cutoff, options)
3 options = Solver.defaultOptions;
7capacityc = zeros(sn.nnodes, sn.nclasses);
10% if isfield(sn.varsparam{n}, "capacityc")
11% capacityc(n) = sn.varsparam{n}.capacityc;
15 if sn.isstation(ind) % place jobs across stations
16 ist = sn.nodeToStation(ind);
17 isf = sn.nodeToStateful(ind);
18 for r=1:sn.nclasses %cut-off open classes to finite capacity
19 c = find(sn.chains(:,r));
20 if ~isempty(sn.visits{c}) && sn.visits{c}(isf,r) == 0
23 %elseif isfield(sn.varsparam{ind}, 'capacityc
')
24 % capacityc(ind,r) = min(cutoff(ist,r), sn.classcap(ist,r));
25 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)
29 capacityc(ind,r) = min(cutoff(ist,r), sn.classcap(ist,r));
31 capacityc(ind,r) = sum(sn.njobs(sn.chains(c,:)));
36 % in this case, the local variables are produced within
37 % fromMarginalBounds, e.g., for RROBIN routing
38 sn.space{isf} = State.fromMarginalBounds(sn, ind, [], capacityc(ind,:), sn.cap(ist), options);
40 % this is the case for example of cache nodes
41 state_bufsrv = State.fromMarginalBounds(sn, ind, [], capacityc(ind,:), sn.cap(ist), options);
42 state_var = State.spaceLocalVars(sn, ind);
43 sn.space{isf} = State.cartesian(state_bufsrv,state_var); % generate all possible states for local variables
45 if isinf(sn.nservers(ist))
46 sn.nservers(ist) = sum(capacityc(ind,:));
48 elseif sn.isstateful(ind) % generate state space of other stateful nodes that are not stations
49 %ist = sn.nodeToStation(ind);
50 isf = sn.nodeToStateful(ind);
51 switch sn.nodetype(ind)
53 for r=1:sn.nclasses % restrict state space generation to immediate events
54 if isnan(sn.nodeparam{ind}.pread{r})
55 capacityc(ind,r) = 1; %
57 capacityc(ind,r) = 1; %
61 % For Router nodes, only allow capacity for classes that have
62 % non-zero nodevisits (classes that actually visit the Router)
64 c = find(sn.chains(:,r));
65 if ~isempty(sn.nodevisits{c}) && sn.nodevisits{c}(ind,r) > 0
71 case NodeType.Transition
72 capacityc(ind,:) = 0; % Transitions don't hold
class-based jobs
73 % Generate per-mode state space (bypass fromMarginalBounds)
74 nmodes = sn.nodeparam{ind}.nmodes;
75 firingphases = sn.nodeparam{ind}.firingphases;
76 if any(isnan(firingphases))
77 firingphases = zeros(1, nmodes);
79 if iscell(sn.nodeparam{ind}.firingproc) && ~isempty(sn.nodeparam{ind}.firingproc{m})
80 firingphases(m) = size(sn.nodeparam{ind}.firingproc{m}{1}, 1);
87 nmodeservers = sn.nodeparam{ind}.nmodeservers;
88 max_jobs = sum(sn.njobs(~isinf(sn.njobs)));
89 if any(isinf(sn.njobs))
90 max_jobs = max_jobs + sum(cutoff(1,:));
92 mode_spaces = cell(1, nmodes);
94 max_srv_m = nmodeservers(m);
98 max_srv_m = min(max_srv_m, max_jobs);
100 for total = 0:max_srv_m
101 phase_combs = multichoose(fK(m), total);
102 buf_m = nmodeservers(m);
104 buf_m = GlobalConstants.MaxInt();
106 buf_m = buf_m - total;
107 mode_states = [mode_states; repmat(buf_m, size(phase_combs,1), 1), phase_combs]; %
#ok<AGROW>
109 mode_spaces{m} = mode_states;
111 trans_space = mode_spaces{1};
113 trans_space = State.cartesian(trans_space, mode_spaces{m});
115 trans_space = [trans_space, zeros(size(trans_space,1), nmodes)]; % append fired counts
116 state_var = State.spaceLocalVars(sn, ind);
117 sn.space{isf} = State.cartesian(trans_space, state_var);
118 continue; % skip fromMarginalBounds below
120 capacityc(ind,:) = 1; %
122 state_bufsrv = State.fromMarginalBounds(sn, ind, [], capacityc(ind,:), 1, options);
123 state_var = State.spaceLocalVars(sn, ind);
124 sn.space{isf} = State.cartesian(state_bufsrv,state_var); % generate all possible states
for local variables
127nodeStateSpace = sn.space;