LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
qsys_is_retrial.m
1%{ @file qsys_is_retrial.m
2 % @brief Checks if network is a valid BMAP/PH/N/N bufferless retrial queue
3 %
4 % @author LINE Development Team
5%}
6
7%{
8 % @brief Checks if network is a valid BMAP/PH/N/N bufferless retrial queue
9 %
10 % @details
11 % Validates that the network structure matches the requirements for
12 % the BMAP/PH/N/N retrial queue solver:
13 % - Single bufferless queue (capacity == number of servers)
14 % - Retrial drop strategy configured
15 % - BMAP/MAP arrival process at source
16 % - PH/Exp service at queue
17 % - Open class model
18 %
19 % Based on: Dudin et al., "Analysis of BMAP/PH/N-Type Queueing System with
20 % Flexible Retrials Admission Control", Mathematics 2025, 13(9), 1434.
21 %
22 % @par Syntax:
23 % @code
24 % [isRetrial, retInfo] = qsys_is_retrial(sn)
25 % @endcode
26 %
27 % @par Parameters:
28 % <table>
29 % <tr><th>Name<th>Description
30 % <tr><td>sn<td>Network structure
31 % </table>
32 %
33 % @par Returns:
34 % <table>
35 % <tr><th>Name<th>Description
36 % <tr><td>isRetrial<td>True if network is valid BMAP/PH/N/N retrial topology
37 % <tr><td>retInfo<td>Struct with parameters for the retrial solver
38 % </table>
39 %
40 % Copyright (c) 2012-2026, Imperial College London
41 % All rights reserved.
42%}
43function [isRetrial, retInfo] = qsys_is_retrial(sn)
44
45% Initialize output
46isRetrial = false;
47retInfo = struct();
48retInfo.stationIdx = [];
49retInfo.nodeIdx = [];
50retInfo.sourceIdx = [];
51retInfo.classIdx = [];
52retInfo.errorMsg = '';
53retInfo.N = []; % Number of servers
54retInfo.alpha = []; % Retrial rate
55retInfo.gamma = 0; % Orbit impatience (default 0)
56retInfo.p = 0; % Batch rejection prob (default 0)
57retInfo.R = []; % Admission threshold (from FCR or default N-1)
58
59% Check if model is open
60if ~sn_is_open_model(sn)
61 retInfo.errorMsg = 'BMAP/PH/N/N retrial solver requires open queueing model.';
62 return;
63end
64
65% Check for single class (current limitation)
66if sn.nclasses > 1
67 retInfo.errorMsg = 'BMAP/PH/N/N retrial solver currently supports single class only.';
68 return;
69end
70
71retInfo.classIdx = 1;
72
73% see _kb/03-api-layer.md (qsys/ family) for rationale
74bufferlessStations = [];
75for ist = 1:sn.nstations
76 if sn.nodetype(sn.stationToNode(ist)) ~= NodeType.Queue
77 continue
78 end
79 hasRetrialProc = isfield(sn,'retrialProc') && ~isempty(sn.retrialProc) ...
80 && size(sn.retrialProc,1) >= ist && any(~cellfun(@isempty, sn.retrialProc(ist,:)));
81 isBufferless = isfinite(sn.cap(ist)) && sn.cap(ist) == sn.nservers(ist);
82 if hasRetrialProc || isBufferless
83 bufferlessStations = [bufferlessStations, ist];
84 end
85end
86
87if isempty(bufferlessStations)
88 retInfo.errorMsg = 'No retrial queue found (configure setOrbit, or a bufferless station with setRetrial).';
89 return;
90end
91
92% Check retrial drop strategy
93retrialStation = [];
94for ist = bufferlessStations(:)'
95 if any(sn.droprule(ist,:) == DropStrategy.RETRIAL | ...
96 sn.droprule(ist,:) == DropStrategy.RETRIAL_WITH_LIMIT)
97 retrialStation = ist;
98 break;
99 end
100end
101
102if isempty(retrialStation)
103 retInfo.errorMsg = 'No retrial drop strategy configured on bufferless queue.';
104 return;
105end
106
107retInfo.stationIdx = retrialStation;
108retInfo.nodeIdx = sn.stationToNode(retrialStation);
109retInfo.N = sn.nservers(retrialStation);
110
111% Find source station
112sourceStation = [];
113for ist = 1:sn.nstations
114 if sn.nodetype(sn.stationToNode(ist)) == NodeType.Source
115 sourceStation = ist;
116 break;
117 end
118end
119
120if isempty(sourceStation)
121 retInfo.errorMsg = 'No Source node found.';
122 return;
123end
124
125retInfo.sourceIdx = sourceStation;
126
127% Validate arrival process (must be MAP/BMAP)
128% sn.proc{station}{class} contains PH representation
129arrivalProc = sn.proc{sourceStation}{retInfo.classIdx};
130if isempty(arrivalProc) || ~iscell(arrivalProc) || length(arrivalProc) < 2
131 retInfo.errorMsg = 'Invalid arrival process at source.';
132 return;
133end
134
135% Check if arrival is MAP/BMAP (has matrix structure)
136% For BMAP: proc is {D0, D1, D2, ...} or {alpha, A} for MAP
137% For Exp/PH at source: it's {1, -lambda} format
138if ~iscell(arrivalProc{1}) && size(arrivalProc{1}, 2) > 1
139 % This looks like a PH representation {alpha, A}, convert from arrival to MAP
140 % For now, we accept it - the solver_mam_retrial will handle conversion
141elseif iscell(arrivalProc{1})
142 % This might be BMAP format already
143end
144
145% Validate service process (must be PH/Exp)
146serviceProc = sn.proc{retrialStation}{retInfo.classIdx};
147if isempty(serviceProc) || ~iscell(serviceProc) || length(serviceProc) < 2
148 retInfo.errorMsg = 'Invalid service process at queue.';
149 return;
150end
151
152% Extract retrial rate alpha from retrial delay distribution
153% In sn struct, we need to check for retrial configuration
154% For now, use default if not found - the Network/getStruct needs to export this
155retInfo.alpha = 0.1; % Default, will be extracted from sn in solver
156
157% Check for FCR containing this queue and extract admission threshold
158retInfo.R = retInfo.N - 1; % Default: no admission control
159
160% Check if region field exists and is non-empty
161if isfield(sn, 'region') && ~isempty(sn.region) && isfield(sn, 'nregions') && sn.nregions > 0
162 for f = 1:sn.nregions
163 regionMatrix = sn.region{f};
164 % Check if this station is in the region with a global capacity
165 if size(regionMatrix, 1) >= retrialStation
166 globalCapCol = size(regionMatrix, 2); % Last column is typically global cap
167 if regionMatrix(retrialStation, globalCapCol) > 0
168 % Get the global max jobs for this region
169 R_fcr = regionMatrix(retrialStation, globalCapCol);
170 if R_fcr <= retInfo.N - 1
171 retInfo.R = R_fcr; % Use FCR threshold
172 end
173 break;
174 end
175 end
176 end
177end
178
179% All validations passed
180isRetrial = true;
181
182end