LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
afterFJEvent.m
1function [outGlobalStates, outrate, outprob] = afterFJEvent(sn, fjentry, glspace, isSimulation)
2% [OUTGLOBALSTATES, OUTRATE, OUTPROB] = AFTERFJEVENT(SN, FJENTRY, GLSPACE, ISSIMULATION)
3%
4% Fire a fork synchronization (one entry of sn.fjsync, built by
5% ModelAdapter.fjtag) on the global state GLSPACE, a cell array with the
6% local state of every stateful node. The firing atomically consumes one
7% parent job of class r held at the (stateful) Fork node and emits one
8% sibling per branch, in the auxiliary classes of the entry's tag, at the
9% branch head nodes.
10%
11% Enabling condition (evaluated on the global state):
12% 1. the Fork holds at least one class-r parent job;
13% 2. the entry's tag is the LOWEST free tag for this (fork, class):
14% a tag is free iff its auxiliary classes have zero occupancy
15% network-wide. Canonical lowest-free-tag allocation ensures exactly
16% one fjsync entry per (fork, class) is enabled in any state.
17%
18% Outputs: OUTGLOBALSTATES is a cell array of successor global states
19% (full glspace cells); OUTRATE the firing rate (immediate) and OUTPROB
20% the probability of each outcome (phase-entry mixtures of the sibling
21% service processes at the branch heads). When ISSIMULATION is true a
22% single outcome is returned, sampled internally.
23
24% Copyright (c) 2012-2026, Imperial College London
25% All rights reserved.
26
27outGlobalStates = {};
28outrate = [];
29outprob = [];
30
31R = sn.nclasses;
32f = fjentry.fork;
33r = fjentry.class;
34isf_f = sn.nodeToStateful(f);
35
36% 1. parent job held at the fork
37forkstate = glspace{isf_f};
38if forkstate(end-R+r) < 1
39 return
40end
41
42% 2. lowest-free-tag test: occupancy of each tag's auxiliary classes,
43% scanned across all stateful nodes
44auxall = fjentry.auxall; % B x T auxiliary class indices
45T = size(auxall,2);
46t = fjentry.tag;
47nglobal = zeros(1,R);
48for isf=1:sn.nstateful
49 [~, nir] = State.toMarginalAggr(sn, sn.statefulToNode(isf), glspace{isf});
50 nglobal = nglobal + nir(1,1:R);
51end
52occ = sum(reshape(nglobal(auxall), size(auxall,1), T), 1);
53if occ(t) > 0
54 return % tag in use
55end
56if any(occ(1:t-1) == 0)
57 return % a lower tag is free: that entry fires instead
58end
59
60% consume the parent job at the fork
61newgl = glspace;
62newgl{isf_f}(end-R+r) = newgl{isf_f}(end-R+r) - 1;
63
64% emit fjentry.weight (tasksPerLink) siblings per branch: sequential
65% application over the partial outcome list handles branches sharing the
66% same head node, repeated emissions on the same branch, and expands
67% phase-entry mixtures of non-exponential sibling services
68partials = {newgl};
69partprob = 1;
70B = length(fjentry.branchheads);
71emissions = repmat(1:B, 1, fjentry.weight);
72for b=emissions
73 bh = fjentry.branchheads(b);
74 isf_b = sn.nodeToStateful(bh);
75 a = fjentry.auxclasses(b);
76 newpartials = {};
77 newpartprob = [];
78 for pp=1:length(partials)
79 curgl = partials{pp};
80 [arvspace, ~, arvprob] = State.afterEvent(sn, bh, curgl{isf_b}, EventType.ARV, a, isSimulation, []);
81 if isempty(arvspace)
82 % sibling arrival blocked (cannot occur under the per-tag
83 % auxiliary class capacity invariant); disable the firing
84 outGlobalStates = {};
85 outrate = [];
86 outprob = [];
87 return
88 end
89 for io=1:size(arvspace,1)
90 nextgl = curgl;
91 nextgl{isf_b} = arvspace(io,:);
92 newpartials{end+1,1} = nextgl; %#ok<AGROW>
93 if length(arvprob) >= io
94 newpartprob(end+1,1) = partprob(pp)*arvprob(io); %#ok<AGROW>
95 else
96 newpartprob(end+1,1) = partprob(pp); %#ok<AGROW>
97 end
98 end
99 end
100 partials = newpartials;
101 partprob = newpartprob;
102end
103
104outGlobalStates = partials;
105outprob = partprob(:) * fjentry.prob;
106outrate = GlobalConstants.Immediate * ones(length(partials),1);
107
108if isSimulation
109 if length(partials) > 1
110 % sample one outcome (afterEvent already samples per-node mixtures
111 % when isSimulation is true, so this is defensive)
112 cum_prob = cumsum(outprob) / sum(outprob);
113 firing_ctr = 1 + max([0,find( rand > cum_prob' )]);
114 outGlobalStates = outGlobalStates(firing_ctr);
115 outrate = outrate(firing_ctr);
116 end
117 % the phase-entry choice has already been sampled inside afterEvent,
118 % so the firing competes at the full immediate rate
119 outprob = 1;
120end
121
122end
Definition Station.m:245