LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
fes_compute_throughputs.m
1%{ @file fes_compute_throughputs.m
2 % @brief Computes throughputs for all population states for FES scaling table
3 %
4 % @author LINE Development Team
5%}
6
7%{
8 % @brief Computes throughputs for all population states
9 %
10 % @details
11 % Enumerates all population states (n1, n2, ..., nK) up to the specified
12 % cutoffs and solves the isolated subnetwork with MVA to get per-class throughputs.
13 % These throughputs are stored in a linearized scaling table for use as
14 % Limited Joint Dependence (LJD) service rates in the Flow-Equivalent Server.
15 %
16 % @par Syntax:
17 % @code
18 % scalingTable = fes_compute_throughputs(L, mi, isDelay, cutoffs, options)
19 % @endcode
20 %
21 % @par Parameters:
22 % <table>
23 % <tr><th>Name<th>Description
24 % <tr><td>L<td>Service demands matrix (M_sub x K) from fes_build_isolated
25 % <tr><td>mi<td>Number of servers per station (1 x M_sub), Inf for Delay
26 % <tr><td>isDelay<td>Boolean array (1 x M_sub), true if station is a Delay
27 % <tr><td>cutoffs<td>Per-class population cutoffs [N1, N2, ..., NK]
28 % <tr><td>options<td>Options struct with field .verbose (default: false)
29 % </table>
30 %
31 % @par Returns:
32 % <table>
33 % <tr><th>Name<th>Description
34 % <tr><td>scalingTable<td>Cell array {class} of linearized throughput vectors
35 % </table>
36%}
37function scalingTable = fes_compute_throughputs(L, mi, isDelay, cutoffs, options)
38
39if nargin < 5
40 options = struct();
41end
42if ~isfield(options, 'verbose')
43 options.verbose = false;
44end
45
46% Get dimensions
47[M_sub, K] = size(L);
48
49% Separate Queue and Delay stations for MVA
50% Queue stations go into L_queue, Delay stations contribute to Z (think time)
51queueIdx = find(~isDelay);
52delayIdx = find(isDelay);
53
54M_queue = length(queueIdx);
55
56% Extract Queue station demands and servers
57if M_queue > 0
58 L_queue = L(queueIdx, :);
59 mi_queue = mi(queueIdx);
60else
61 % No Queue stations - all Delay
62 L_queue = zeros(0, K);
63 mi_queue = [];
64end
65
66% Compute think time Z from Delay stations
67% Z(k) = sum of service demands at Delay stations for class k
68if ~isempty(delayIdx)
69 Z = sum(L(delayIdx, :), 1);
70else
71 Z = zeros(1, K);
72end
73
74% Compute table size
75tableSize = prod(cutoffs + 1);
76
77% Initialize scaling tables (one per class)
78scalingTable = cell(1, K);
79for k = 1:K
80 scalingTable{k} = zeros(1, tableSize);
81end
82
83if options.verbose
84 fprintf('Computing FES throughputs for %d states (%d Queue, %d Delay stations)...\n', ...
85 tableSize, M_queue, length(delayIdx));
86end
87
88% Enumerate all states using BFS
89stateQueue = {zeros(1, K)}; % Start with zero population
90visited = containers.Map('KeyType', 'char', 'ValueType', 'logical');
91nStates = 0;
92
93while ~isempty(stateQueue)
94 nvec = stateQueue{1};
95 stateQueue(1) = [];
96
97 % Create key for this state
98 stateKey = mat2str(nvec);
99 if isKey(visited, stateKey)
100 continue;
101 end
102 visited(stateKey) = true;
103 nStates = nStates + 1;
104
105 % Compute throughput for this state
106 totalPop = sum(nvec);
107 idx = ljd_linearize(nvec, cutoffs);
108
109 if totalPop == 0
110 % Zero population: throughput is 0 for all classes
111 for k = 1:K
112 scalingTable{k}(idx) = 0;
113 end
114 else
115 % Solve with pfqn_mva
116 try
117 if M_queue > 0
118 % Call MVA with Queue stations and think times
119 [XN, ~, ~, ~] = pfqn_mva(L_queue, nvec, Z, mi_queue);
120 else
121 % Only Delay stations - throughput is N(k) / Z(k) for each class
122 XN = zeros(1, K);
123 for k = 1:K
124 if nvec(k) > 0 && Z(k) > 0
125 XN(k) = nvec(k) / Z(k);
126 end
127 end
128 end
129
130 % Store throughputs
131 for k = 1:K
132 if nvec(k) > 0
133 scalingTable{k}(idx) = XN(k);
134 else
135 scalingTable{k}(idx) = 0;
136 end
137 end
138 catch ME
139 % If solver fails, set throughput to 0
140 if options.verbose
141 fprintf('Warning: MVA failed for state %s: %s\n', stateKey, ME.message);
142 end
143 for k = 1:K
144 scalingTable{k}(idx) = 0;
145 end
146 end
147 end
148
149 % Add neighboring states to queue
150 for k = 1:K
151 if nvec(k) < cutoffs(k)
152 newState = nvec;
153 newState(k) = newState(k) + 1;
154 newKey = mat2str(newState);
155 if ~isKey(visited, newKey)
156 stateQueue{end+1} = newState;
157 end
158 end
159 end
160end
161
162if options.verbose
163 fprintf('Computed throughputs for %d states.\n', nStates);
164end
165
166end