LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
solver_nc_mem_supports.m
1function [supported, reason, blocking] = solver_nc_mem_supports(sn)
2% [SUPPORTED, REASON, BLOCKING] = SOLVER_NC_MEM_SUPPORTS(SN)
3%
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.
15%
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.
24%
25% Copyright (c) 2012-2026, Imperial College London
26% All rights reserved.
27
28supported = false;
29reason = '';
30blocking = false;
31
32isopen = sn_is_open_model(sn);
33isclosed = sn_is_closed_model(sn);
34ismixed = ~isopen && ~isclosed;
35
36R = sn.nclasses;
37
38% Node types: open models are Source/Queue/Delay/Sink networks, closed
39% models are Queue/Delay networks
40for ind = 1:sn.nnodes
41 switch sn.nodetype(ind)
42 case {NodeType.Queue, NodeType.Delay}
43 % supported
44 case {NodeType.Source, NodeType.Sink}
45 if isclosed
46 reason = 'MEM supports only Queue and Delay nodes in closed models.';
47 return
48 end
49 otherwise
50 reason = 'MEM supports only Source, Queue, Delay and Sink nodes.';
51 return
52 end
53end
54
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.';
58 return
59end
60
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);
65 for r = 1:R
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).';
68 return
69 end
70 end
71end
72
73% Only non-priority disciplines are supported; the PR/HOL constraint
74% formulae are not given in Kouvatsos (1994)
75for ist = 1:sn.nstations
76 switch sn.sched(ist)
77 case {SchedStrategy.EXT, SchedStrategy.INF, SchedStrategy.FCFS, ...
78 SchedStrategy.PS, SchedStrategy.SIRO, SchedStrategy.LCFS, ...
79 SchedStrategy.LCFSPR}
80 % supported
81 otherwise
82 reason = sprintf('MEM does not support the %s scheduling strategy.', SchedStrategy.toText(sn.sched(ist)));
83 return
84 end
85end
86
87if isopen || ismixed
88 % A Source node must be present for the external arrival extraction
89 hasSource = false;
90 for ind = 1:sn.nnodes
91 if sn.nodetype(ind) == NodeType.Source
92 hasSource = true;
93 break;
94 end
95 end
96 if ~hasSource
97 reason = 'MEM requires a Source node when open classes are present.';
98 return
99 end
100end
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.';
106 return
107 end
108 end
109end
110
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
116 continue
117 end
118 if isfinite(sn_get_buffer_size(sn, ist))
119 capped(ist) = true;
120 end
121end
122if any(capped)
123 if ~isopen
124 reason = 'MEM supports finite station buffers only in open models.';
125 return
126 end
127 if R > 1
128 reason = 'MEM supports finite station buffers only in single-class models: the censored GE/GE/c/0;N building block is single class.';
129 return
130 end
131 for ist = 1:sn.nstations
132 if ~capped(ist)
133 continue
134 end
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);
137 return
138 end
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)));
141 return
142 end
143 dr = DropStrategy.DROP;
144 if ~isempty(sn.droprule) && size(sn.droprule, 1) >= ist
145 dr = sn.droprule(ist, 1);
146 end
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));
149 return
150 end
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);
153 return
154 end
155 end
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.';
159 return
160 end
161 end
162 blocking = true;
163end
164
165supported = true;
166end
Definition fjtag.m:161