LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
afterEvent.m
1function [outspace, outrate, outprob, eventCache] = afterEvent(sn, ind, inspace, event, class, isSimulation, eventCache)
2% [OUTSPACE, OUTRATE, OUTPROB] = AFTEREVENT(QN, IND, INSPACE, EVENT, CLASS, ISSIMULATION, EVENTCACHE)
3
4% Copyright (c) 2012-2026, Imperial College London
5% All rights reserved.
6
7% Event cache for faster simulation
8if isSimulation && nargin >= 7 && isobject(eventCache)
9 vector = [ind, event, class, inspace];
10 key = mat2str(vector);
11 if eventCache.isKey(key)
12 cachedResult = eventCache(key);
13 outprob = cachedResult{1};
14 outspace = cachedResult{2};
15 outrate = cachedResult{3};
16 if size(outspace,1) > 1
17 tot_rate = sum(outrate);
18 cum_rate = cumsum(outrate) / tot_rate;
19 firing_ctr = 1 + max([0,find( rand > cum_rate' )]); % select action
20 outspace = outspace(firing_ctr,:);
21 outrate = sum(outrate);
22 outprob = outprob(firing_ctr,:);
23 end
24 return
25 end
26else
27 key = NaN;
28 eventCache = [];
29end
30% Else continue to main body below
31M = sn.nstations;
32R = sn.nclasses;
33S = sn.nservers;
34phasessz = sn.phasessz;
35phaseshift = sn.phaseshift;
36pie = sn.pie;
37
38% ind: node index
39isf = sn.nodeToStateful(ind);
40
41if sn.isstation(ind)
42 ismkvmod = any(sn.procid(sn.nodeToStation(ind),:)==ProcessType.MAP | sn.procid(sn.nodeToStation(ind),:)==ProcessType.MMPP2);
43 ismkvmodclass = zeros(R,1);
44 for r=1:R
45 ismkvmodclass(r) = any(sn.procid(sn.nodeToStation(ind),r)==ProcessType.MAP | sn.procid(sn.nodeToStation(ind),r)==ProcessType.MMPP2);
46 end
47end
48
49lldscaling = sn.lldscaling;
50if isempty(lldscaling)
51 lldlimit = max(sum(sn.nclosedjobs),1);
52 lldscaling = ones(M,lldlimit);
53else
54 lldlimit = size(lldscaling,2);
55end
56
57cdscaling = sn.cdscaling;
58if isempty(cdscaling)
59 cdscaling = cell(M,1);
60 cdscaling{1} = @(ni) 1;
61 for i=2:M % faster this way
62 cdscaling{i} = cdscaling{1};
63 end
64end
65
66hasOnlyExp = false; % true if all service processes are exponential
67if sn.isstation(ind)
68 ist = sn.nodeToStation(ind);
69 K = phasessz(ist,:);
70 Ks = phaseshift(ist,:);
71 if max(K)==1
72 hasOnlyExp = true;
73 end
74 mu = sn.mu;
75 phi = sn.phi;
76 proc = sn.proc;
77 capacity = sn.cap;
78 classcap = sn.classcap;
79 if K(class) == 0 % if this class is not accepted at the resource
80 eventCache(key) = {outprob, outspace,outrate};
81 return
82 end
83 V = sum(sn.nvars(ind,:));
84 % Place nodes: state format is [buffer(R), server(sum(K))] after ARV
85 if sn.nodetype(ind) == NodeType.Place
86 space_var = zeros(size(inspace,1), 0); % proper dimensions for concatenation
87 state_len = size(inspace, 2);
88 expected_len = R + sum(K);
89 if state_len == expected_len
90 % State already has [buffer, server] format
91 space_buf = inspace(:, 1:R);
92 space_srv = inspace(:, (R+1):end);
93 elseif state_len == R
94 % Initial state: just buffer counts
95 space_buf = inspace;
96 space_srv = zeros(size(inspace,1), sum(K));
97 else
98 % Fallback for unexpected formats
99 space_buf = inspace;
100 space_srv = zeros(size(inspace,1), sum(K));
101 end
102 else
103 space_var = inspace(:,(end-V+1):end); % local state variables
104 space_srv = inspace(:,(end-sum(K)-V+1):(end-V)); % server state
105 space_buf = inspace(:,1:(end-sum(K)-V)); % buffer state
106 end
107elseif sn.isstateful(ind)
108 V = sum(sn.nvars(ind,:));
109 % in this case service is always immediate so sum(K)=1
110 space_var = inspace(:,(end-V+1):end); % local state variables
111 if sn.nodetype(ind) == NodeType.Transition
112 K = sn.nodeparam{ind}.firingphases;
113 nmodes = sn.nodeparam{ind}.nmodes;
114 % Handle NaN firingphases (non-phase-type distributions like Pareto)
115 % Infer phase count from D0 matrix size
116 if any(isnan(K))
117 K = zeros(1, nmodes);
118 for m = 1:nmodes
119 if iscell(sn.nodeparam{ind}.firingproc) && ~isempty(sn.nodeparam{ind}.firingproc{m})
120 K(m) = size(sn.nodeparam{ind}.firingproc{m}{1}, 1);
121 else
122 K(m) = 1;
123 end
124 end
125 end
126 Ks = [0,cumsum(K,2)];
127 space_buf = inspace(:,1:nmodes); % idle servers count put in buf
128 space_srv = inspace(:,(nmodes+1):(nmodes+sum(K))); % enabled servers' phases
129 % Handle both state formats: with and without fired component
130 expected_len_with_fired = 2*nmodes + sum(K);
131 expected_len_without_fired = nmodes + sum(K);
132 if size(inspace, 2) >= expected_len_with_fired
133 space_fired = inspace(:,(nmodes+sum(K)+1):(2*nmodes+sum(K))); % servers that just fired
134 elseif size(inspace, 2) == expected_len_without_fired
135 % Legacy format without fired component - initialize to zeros
136 space_fired = zeros(size(inspace,1), nmodes);
137 else
138 line_error(mfilename, 'Unexpected state vector length for Transition node');
139 end
140 else
141 space_buf = []; % buffer state
142 space_srv = inspace(:,(end-R-V+1):(end-V)); % server state
143 space_fired = []; % only for Transition nodes
144 end
145else % stateless node
146 space_var = [];
147 space_srv = [];
148 space_buf = [];
149end
150
151if sn.isstation(ind)
152 [outspace, outrate, outprob, eventCache] = State.afterEventStation(sn, ind, inspace, event, class, isSimulation, eventCache, ...
153 M, R, S, phasessz, phaseshift, pie, isf, ismkvmod, ismkvmodclass, lldscaling, lldlimit, cdscaling, ...
154 hasOnlyExp, ist, K, Ks, mu, phi, proc, capacity, classcap, V, space_buf, space_srv, space_var, key);
155elseif sn.isstateful(ind)
156 switch sn.nodetype(ind)
157 case NodeType.Router
158 [outspace, outrate, outprob, eventCache] = State.afterEventRouter(sn, ind, event, class, isSimulation, eventCache, space_buf, space_srv, space_var, key);
159 case NodeType.Cache
160 [outspace, outrate, outprob, eventCache] = State.afterEventCache(sn, ind, event, class, isSimulation, eventCache, R, space_buf, space_srv, space_var, key);
161 case NodeType.Transition
162 [outspace, outrate, outprob, eventCache] = State.afterEventTransition(sn, ind, inspace, K, Ks, event, class, isSimulation, eventCache, R, space_buf, space_srv, space_fired, space_var, key);
163 end % switch nodeType
164end
165end
Definition mmt.m:92