1function tf = arrivalIsLost(sn, ist,
class)
2% TF = ARRIVALISLOST(SN, IST, CLASS)
4% True when an arrival of CLASS that finds no room at station IST
is LOST, and
5%
false when it must BLOCK
the upstream instead. This
is the single predicate
6% that decides
the refusal semantics; every refusal path must branch on it.
8% The rule
is the CLASS TYPE, not
the drop rule:
10% OPEN
class -> LOST. The external arrival stream
is memoryless, so a job
11% that finds
the station full simply never enters. The caller
12% must then leave
the state UNCHANGED (a self-loop):
the
13% arrival event still fires, so
the offered rate reaches
the
14% arrival-rate statistic and
the loss shows up as
15% ArvR - Tput. A self-loop cancels on
the generator diagonal
16% and therefore cannot perturb
the stationary distribution,
17% so QLen/Util/Tput are unaffected.
18% CLOSED class -> BLOCKED. A closed network
's N jobs have nowhere to go;
19% population conservation is a defining invariant, so a
20% closed job can never be dropped. The caller must return an
21% EMPTY outspace, which disables the upstream departure until
24% An explicit blocking drop rule (BAS/BBS/RSRD) also asks for blocking, for any
25% class: the user has said the job must wait rather than be lost.
27% This is the same open/closed predicate as the CTMC analyzer's canDropClass
28% and
the BUG-12 utilization guard. Note
the conventions are complementary, not
29% contradictory:
the arrival rate counts
the OFFERED job (this predicate lets
30%
the event fire), while Util/QLen/Tput
count only
the CARRIED one.
32% Copyright (c) 2012-2026, Imperial College London
35if ~isempty(sn.droprule) && size(sn.droprule,1) >= ist && size(sn.droprule,2) >= class
36 dr = sn.droprule(ist,class);
37 if dr == DropStrategy.BAS || dr == DropStrategy.BBS || dr == DropStrategy.RSRD
42% Open -> lost (self-loop), closed -> blocked. This decides only what happens
43% once
the arrival has already been refused (
the state was not placed). The
44% physical-vs-cutoff distinction
is NOT made here: an open arrival always
45% self-loops when refused, exactly as
the pre-change producer did (a refused
46% WAITQ arrival was left unchanged). What DID change with
the physical cap
is
47% WHERE
the refusal happens --
the hasRoom gate in afterEventStation stops
48% placing
the job at a physical cap so that it reaches
this self-loop, whereas
49% a cutoff-only
class is still placed and truncated by
the en_o filter. So
the
50% cutoff
case never relies on
this branch, and open self-looping here
is the
51% pre-change behaviour it must preserve.
52tf = isinf(sn.njobs(
class)); % open -> lost, closed -> blocked