LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
afterEventStationPAS.m
1function [outspace, outrate, outprob, eventCache] = afterEventStationPAS(sn, ind, ist, inspace, event, class, isSimulation, eventCache, R, V, key) %#ok<INUSL>
2% [OUTSPACE, OUTRATE, OUTPROB, EVENTCACHE] = AFTEREVENTSTATIONPAS(...)
3%
4% Event handler for pass-and-swap (PAS) / order-independent (OI) stations.
5%
6% State layout (see State.fromMarginal): the local state is the full ordered
7% list of class indices c=(c1,...,cn), c1 the oldest job, stored left-aligned
8% in the first W = sn.cap(ist) columns and right zero-padded; the trailing V
9% columns hold routing local variables (carried through unchanged). There is
10% no server/buffer split: service is governed by the total rate function mu(c)
11% (sn.nodeparam{ind}.svcRateFun) and the swapping graph G
12% (sn.nodeparam{ind}.swapGraph), per Dorsman & Gardner (2024), Sect. 2.
13%
14% - ARV (passive): a class-`class` job joins at the back, c -> (c, class),
15% subject to capacity (lost when full).
16% - DEP (active): for each position p, the service token of position p fires at
17% rate Delta_mu(c1..cp) = mu(c1..cp) - mu(c1..c_{p-1}); the pass-and-swap
18% mechanism (State.passAndSwap) then determines the departing class. A DEP of
19% `class` collects all positions whose pass-and-swap ejects a class-`class`
20% job.
21% - PHASE: none (PAS service is exponential).
22%
23% Copyright (c) 2012-2026, Imperial College London
24% All rights reserved.
25
26outspace = [];
27outrate = [];
28outprob = [];
29
30muFun = sn.nodeparam{ind}.svcRateFun;
31G = sn.nodeparam{ind}.swapGraph;
32if isempty(muFun)
33 line_error(mfilename,'PAS station has no service rate function mu(c); set it via setService(@(c) ...).');
34end
35
36W = size(inspace,2) - V; % width of the ordered-list region
37list = inspace(:,1:W);
38varcols = inspace(:,(W+1):end); % routing local variables
39nrows = size(inspace,1);
40cap = sn.cap(ist);
41
42switch event
43 case EventType.ARV % passive: append the arriving job at the back of the list
44 for row=1:nrows
45 c = list(row, list(row,:)>0); % current ordered list (contiguous, left-aligned)
46 n = numel(c);
47 if n >= cap
48 continue; % buffer full: arrival is lost
49 end
50 newc = [c, class];
51 outspace = [outspace; newc, zeros(1, W-numel(newc)), varcols(row,:)]; %#ok<AGROW>
52 outrate = [outrate; -1]; % passive action, rate unspecified %#ok<AGROW>
53 outprob = [outprob; 1]; %#ok<AGROW>
54 end
55 case EventType.DEP % active: a class-`class` job departs via pass-and-swap
56 for row=1:nrows
57 c = list(row, list(row,:)>0);
58 n = numel(c);
59 if n == 0
60 continue;
61 end
62 muPrev = 0; % mu of the empty prefix = 0
63 for p=1:n
64 muCur = muFun(c(1:p));
65 ratep = muCur - muPrev; % Delta_mu(c1..cp): rate of position p
66 muPrev = muCur;
67 if ratep <= 0
68 continue; % position p receives no service
69 end
70 [cnew, depClass] = State.passAndSwap(c, p, G);
71 if depClass ~= class
72 continue; % a job of a different class departs
73 end
74 outspace = [outspace; cnew, zeros(1, W-numel(cnew)), varcols(row,:)]; %#ok<AGROW>
75 outrate = [outrate; ratep]; %#ok<AGROW>
76 outprob = [outprob; 1]; %#ok<AGROW>
77 end
78 end
79 case EventType.PHASE
80 % PAS service is exponential: no intra-service phase transitions.
81end
82
83if isSimulation
84 if ~isnan(key) && isobject(eventCache)
85 eventCache(key) = {outprob, outspace, outrate};
86 end
87 if size(outspace,1) > 1
88 if event == EventType.DEP
89 tot_rate = sum(outrate);
90 cum_rate = cumsum(outrate) / tot_rate;
91 firing_ctr = 1 + max([0, find(rand > cum_rate')]);
92 outspace = outspace(firing_ctr,:);
93 outrate = sum(outrate);
94 outprob = outprob(firing_ctr,:);
95 else % passive ARV
96 cum_prob = cumsum(outprob) / sum(outprob);
97 firing_ctr = 1 + max([0, find(rand > cum_prob')]);
98 outspace = outspace(firing_ctr,:);
99 outrate = -1;
100 outprob = 1;
101 end
102 end
103end
104end