1%{ @file fes_compute_throughputs.m
2 % @brief Computes throughputs
for all population states
for FES scaling table
4 % @author LINE Development Team
8 % @brief Computes throughputs
for all population states
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.
18 % scalingTable = fes_compute_throughputs(L, mi, isDelay, cutoffs, options)
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)
33 % <tr><th>Name<th>Description
34 % <tr><td>scalingTable<td>Cell array {
class} of linearized throughput vectors
37function scalingTable = fes_compute_throughputs(L, mi, isDelay, cutoffs, options)
42if ~isfield(options,
'verbose')
43 options.verbose = false;
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);
54M_queue = length(queueIdx);
56% Extract Queue station demands and servers
58 L_queue = L(queueIdx, :);
59 mi_queue = mi(queueIdx);
61 % No Queue stations - all Delay
62 L_queue = zeros(0, K);
66% Compute think time Z from Delay stations
67% Z(k) = sum of service demands at Delay stations for class k
69 Z = sum(L(delayIdx, :), 1);
75tableSize = prod(cutoffs + 1);
77% Initialize scaling tables (one per class)
78scalingTable = cell(1, K);
80 scalingTable{k} = zeros(1, tableSize);
84 fprintf(
'Computing FES throughputs for %d states (%d Queue, %d Delay stations)...\n', ...
85 tableSize, M_queue, length(delayIdx));
88% Enumerate all states
using BFS
89stateQueue = {zeros(1, K)}; % Start with zero population
90visited = containers.Map(
'KeyType',
'char',
'ValueType',
'logical');
93while ~isempty(stateQueue)
97 % Create key
for this state
98 stateKey = mat2str(nvec);
99 if isKey(visited, stateKey)
102 visited(stateKey) =
true;
103 nStates = nStates + 1;
105 % Compute throughput
for this state
106 totalPop = sum(nvec);
107 idx = ljd_linearize(nvec, cutoffs);
110 % Zero population: throughput
is 0
for all
classes
112 scalingTable{k}(idx) = 0;
115 % Solve with pfqn_mva
118 % Call MVA with Queue stations and think times
119 [XN, ~, ~, ~] = pfqn_mva(L_queue, nvec, Z, mi_queue);
121 % Only Delay stations - throughput
is N(k) / Z(k) for each class
124 if nvec(k) > 0 && Z(k) > 0
125 XN(k) = nvec(k) / Z(k);
133 scalingTable{k}(idx) = XN(k);
135 scalingTable{k}(idx) = 0;
139 % If solver fails, set throughput to 0
141 fprintf(
'Warning: MVA failed for state %s: %s\n', stateKey, ME.message);
144 scalingTable{k}(idx) = 0;
149 % Add neighboring states to queue
151 if nvec(k) < cutoffs(k)
153 newState(k) = newState(k) + 1;
154 newKey = mat2str(newState);
155 if ~isKey(visited, newKey)
156 stateQueue{end+1} = newState;
163 fprintf(
'Computed throughputs for %d states.\n', nStates);