1function [supported, reason, blocking] = solver_nc_mem_supports(sn)
2% [SUPPORTED, REASON, BLOCKING] = SOLVER_NC_MEM_SUPPORTS(SN)
4% Checks whether the Maximum Entropy Method (Kouvatsos 1994) supports the
5% model described by the network structure SN. Returns SUPPORTED=
true and
6% an empty REASON when the model
is a plain open queueing network
7% (Section 3.2: Source, Queue, Delay and Sink
nodes; GE/GE/1, GE/GE/c and
8% GE/GE/inf building blocks), a plain closed queueing network
9% (Section 3.3: Queue and Delay
nodes; G/G/1 and G/G/inf building blocks
10% only, so finite multiserver stations are rejected), or a mixed
11% open/closed network (composition of the two algorithms; single-server
12% and IS stations only), in all cases without
class switching and with
13% non-priority scheduling disciplines only; otherwise SUPPORTED=
false and
14% REASON explains the first unsupported feature found.
16% An open model with finite station buffers
is also supported, provided it
17%
is single
class: it
is then solved by the censored GE/GE/c/0;N building
18% block of Section 4.1, under loss (drop rule DROP) or transfer blocking
19% (drop rule BAS, holding-node expansion of Tahilramani, Manjunath and
20% Bose 1999). BLOCKING returns
true for such a model, so the caller can
21% route it to ME_OQN_BLK instead of ME_OQN. The GE distribution
is only
22% defined
for scv >= 1, so a finite-buffer model with a hypo-exponential
23% service or arrival process
is rejected rather than approximated.
25% Copyright (c) 2012-2026, Imperial College London
32isopen = sn_is_open_model(sn);
33isclosed = sn_is_closed_model(sn);
34ismixed = ~isopen && ~isclosed;
38% Node types: open models are Source/Queue/Delay/Sink networks, closed
39% models are Queue/Delay networks
41 switch sn.nodetype(ind)
42 case {NodeType.Queue, NodeType.Delay}
44 case {NodeType.Source, NodeType.Sink}
46 reason =
'MEM supports only Queue and Delay nodes in closed models.';
50 reason =
'MEM supports only Source, Queue, Delay and Sink nodes.';
55% Class switching
is not part of the Kouvatsos (1994) network model
56if any(any(sn.csmask & ~eye(R)))
57 reason = 'MEM does not support class switching.';
61% Absorbing self-loops (p_ii=1) make the routing reducible and the
62% geometric feedback transform 1/(1-p_ii) degenerate
63for ist = 1:sn.nstations
64 ind = sn.stationToNode(ist);
66 if sn.rtnodes((ind-1)*R + r, (ind-1)*R + r) >= 1 - 1e-9
67 reason = 'MEM does not support absorbing self-loop routing (reducible network).';
73% Only non-priority disciplines are supported; the PR/HOL constraint
74% formulae are not given in Kouvatsos (1994)
75for ist = 1:sn.nstations
77 case {SchedStrategy.EXT, SchedStrategy.INF, SchedStrategy.FCFS, ...
78 SchedStrategy.PS, SchedStrategy.SIRO, SchedStrategy.LCFS, ...
82 reason = sprintf(
'MEM does not support the %s scheduling strategy.', SchedStrategy.toText(sn.sched(ist)));
88 % A Source node must be present
for the external arrival extraction
91 if sn.nodetype(ind) == NodeType.Source
97 reason =
'MEM requires a Source node when open classes are present.';
101if isclosed || ismixed
102 % Closed classes build on G/G/1 and G/G/inf queues only (Section 3.3)
103 for ist = 1:sn.nstations
104 if isfinite(sn.nservers(ist)) && sn.nservers(ist) > 1
105 reason =
'MEM does not support multiserver stations in closed or mixed models.';
111% Finite buffers admissible only in a single-
class open model (the GE/GE/c/0;N
112% building block
is single
class); see _kb/06-solver-catalog.md (mem.blocking note)
113capped =
false(sn.nstations, 1);
114for ist = 1:sn.nstations
115 if sn.sched(ist) == SchedStrategy.EXT
118 if isfinite(sn_get_buffer_size(sn, ist))
124 reason =
'MEM supports finite station buffers only in open models.';
128 reason =
'MEM supports finite station buffers only in single-class models: the censored GE/GE/c/0;N building block is single class.';
131 for ist = 1:sn.nstations
135 if ~isfinite(sn.nservers(ist)) || sn.nservers(ist) < 1
136 reason = sprintf(
'MEM cannot apply a finite buffer to the infinite-server station %d.', ist);
139 if sn.sched(ist) ~= SchedStrategy.FCFS
140 reason = sprintf(
'MEM supports finite station buffers only under FCFS scheduling; station %d uses %s.', ist, SchedStrategy.toText(sn.sched(ist)));
143 dr = DropStrategy.DROP;
144 if ~isempty(sn.droprule) && size(sn.droprule, 1) >= ist
145 dr = sn.droprule(ist, 1);
147 if dr ~= DropStrategy.DROP && dr ~= DropStrategy.BAS
148 reason = sprintf(
'MEM supports the DROP and BAS drop rules at a finite buffer; station %d uses %s.', ist, DropStrategy.toText(dr));
151 if isfinite(sn.scv(ist, 1)) && sn.scv(ist, 1) < 1 - 1e-12
152 reason = sprintf(
'MEM with finite buffers needs a service scv of at least 1 at station %d: the GE distribution is not defined below 1.', ist);
156 for ist = 1:sn.nstations
157 if sn.sched(ist) == SchedStrategy.EXT && isfinite(sn.scv(ist, 1)) && sn.scv(ist, 1) < 1 - 1e-12
158 reason =
'MEM with finite buffers needs an external interarrival scv of at least 1: the GE distribution is not defined below 1.';