1function [W_red, state_map] = eliminate_immediate_matrix(W, sn, options)
2% [W_RED, STATE_MAP] = ELIMINATE_IMMEDIATE_MATRIX(W, SN, OPTIONS)
4% Eliminate immediate states from infinitesimal generator matrix W
7% W: [n_states x n_states] infinitesimal generator matrix
9% options: Solver options
12% W_red: Reduced generator matrix
13% state_map: Mapping from reduced to original state indices
15% Copyright (c) 2012-2026, Imperial College London
18% Get immediate detection threshold
19if isfield(options.config,
'immediate_tol')
20 imm_tol = options.config.immediate_tol;
22 imm_tol = GlobalConstants.Immediate / 10; % Default: 1e7
25% Identify immediate states (those with very high outgoing rates)
26max_rate_per_state = max(abs(W), [], 2);
27imm_states = find(max_rate_per_state >= imm_tol);
29% If no immediate states, return unchanged
32 state_map = 1:size(W, 1);
36% Identify timed states
37timed_states = setdiff(1:size(W,1), imm_states);
39% Check that we have enough timed states remaining
40if isempty(timed_states) || length(timed_states) <= 1
41 % Too few timed states - elimination would produce a trivial system.
42 % Fall back to the original system without elimination.
44 state_map = 1:size(W, 1);
49 % Apply stochastic complement
50 [W_red, ~, ~, ~, Q22, ~] = ctmc_stochcomp(W, timed_states);
52 % Validate result: singular Q22 produces NaN/Inf in W_red
53 if any(~isfinite(W_red(:)))
54 warning('LINE:Fluid:SingularElimination', ...
55 'Stochastic complementation produced non-finite values. Using original system.');
57 state_map = 1:size(W, 1);
61 state_map = timed_states;
64 if isfield(options, 'verbose') && options.verbose > 0
65 reduction_pct = 100 * (1 - length(timed_states)/size(W,1));
66 line_printf(sprintf('State space reduced from %d to %d states (%.1f%% reduction)\n', ...
67 size(W,1), length(timed_states), reduction_pct));
71 % Elimination failed - fall back to original
72 warning('LINE:Fluid:EliminationFailed', ...
73 'Immediate transition elimination failed: %s. Using original system.', ME.message);
75 state_map = 1:size(W, 1);
78end % eliminate_immediate_matrix