// Test for aalphahat0 computation in smoother_redux with ilagged static variables.
//
// Model:
//   k = alpha * k(-1) + beta * x(-1) + e_k   (dynamic: predetermined, persistent)
//   x = e_x                                    (dynamic: predetermined via x(-1), iid)
//   c = x(-1)                                  (static: depends on lagged x only)
//   y = c + k                                  (static: observed)
//
// Key property: x has no persistence (ghx_x = [0,0]), so the reduced transition
// matrix in smoother_redux is
//   T = [alpha, beta; 0, 0]
// which is rank-deficient. This means pinv(T)*T ≠ I, causing ilagged=true for
// both static variables c and y in DsgeSmoother's reconstruction logic.
//
// When d=0 (stationary model, lik_init=1) and smoother_redux is enabled, the
// smoother computes aalphahat0 at t=1 via a two-step backward recursion (DK 2012,
// eq. 4.35 applied at t=0). DsgeSmoother then uses aalphahat0 to reconstruct the
// ilagged static updated variables at t = d+1 = 1 via:
//   ahat(static_ilagged, 1) = Tstar(ilagged,:) * aalphahat0 + Rstar(ilagged,:) * eehat(:,1)
//
// This test verifies that smoother_redux correctly replicates the full
// (non-redux) smoother output for all variables, including updated variables
// at the critical first period where aalphahat0 is the only available "lagged state".

var y c k x;
varexo e_k e_x;

parameters alpha beta;

alpha = 0.5;
beta = 0.3;

model(linear);
  k = alpha * k(-1) + beta * x(-1) + e_k;
  x = e_x;
  c = x(-1);
  y = c + k;
end;

initval;
  y = 0;
  c = 0;
  k = 0;
  x = 0;
end;

steady(nocheck);

shocks;
  var e_k; stderr 0.1;
  var e_x; stderr 0.2;
end;

varobs y;

// Generate simulated data with fixed seed for reproducibility
set_dynare_seed(42);
stoch_simul(periods=200, irf=0, noprint, nograph);
datatomfile('smoother_redux_a0g0_data', {'y'});


// =========================================================================
// Run 1: full smoother (no smoother_redux) — baseline
// =========================================================================
calib_smoother(datafile=smoother_redux_a0g0_data, filtered_vars, filter_covariance, smoothed_state_uncertainty, updated_covariance, smoothed_shock_variance) y c k x;
oo0 = oo_;

// =========================================================================
// Run 2: smoother_redux with kalman_algo=1 (multivariate)
// =========================================================================
calib_smoother(datafile=smoother_redux_a0g0_data, filtered_vars, filter_covariance, smoothed_state_uncertainty, smoother_redux, updated_covariance, smoothed_shock_variance) y c k x;
oo1 = oo_;

// =========================================================================
// Run 3: smoother_redux with kalman_algo=2 (univariate)
// =========================================================================
calib_smoother(datafile=smoother_redux_a0g0_data, filtered_vars, filter_covariance, smoothed_state_uncertainty, smoother_redux, updated_covariance, smoothed_shock_variance, kalman_algo=2) y c k x;
oo2 = oo_;


// =========================================================================
// Verify that ilagged is actually triggered (diagnostic)
// =========================================================================
// In the reduced state space, T = [alpha, beta; 0, 0] is rank-deficient.
// This forces the DsgeSmoother reconstruction for static variables to use
// both alphahat_0g1 (at t=1) and alphahat_tm1gt (at t>1) instead of C*ahat+D*eta_tgt.
T_reduced = oo1.dr.ghx(oo1.dr.restrict_var_list, :);
if rank(T_reduced) == size(T_reduced, 1)
    error('Test design error: reduced T should be rank-deficient to trigger ilagged.')
end
fprintf('Reduced T has rank %d (size %d x %d) — ilagged path is active.\n', ...
    rank(T_reduced), size(T_reduced, 1), size(T_reduced, 2));


// =========================================================================
// Consistency checks: smoother_redux (kalman_algo=1) vs full baseline
// =========================================================================

// --- Smoothed shocks ---
for k=1:M_.exo_nbr
    mserr(k) = max(abs(oo0.SmoothedShocks.(M_.exo_names{k}) - oo1.SmoothedShocks.(M_.exo_names{k})));
end
if max(mserr) > 1e-12
    error('smoother_redux (kalman_algo=1) does not replicate smoothed shocks! max diff = %e', max(mserr))
end

// --- Smoothed variables ---
for k=1:M_.endo_nbr
    merr(k) = max(abs(oo0.SmoothedVariables.(M_.endo_names{k}) - oo1.SmoothedVariables.(M_.endo_names{k})));
end
if max(merr) > 1e-12
    error('smoother_redux (kalman_algo=1) does not replicate smoothed variables! max diff = %e', max(merr))
end

// --- Updated variables (critical: tests alphahat_0g1 at t=1 for ilagged statics) ---
for k=1:M_.endo_nbr
    merrU(k) = max(abs(oo0.UpdatedVariables.(M_.endo_names{k}) - oo1.UpdatedVariables.(M_.endo_names{k})));
end
if max(merrU) > 1e-12
    error('smoother_redux (kalman_algo=1) does not replicate updated variables! max diff = %e (aalphahat0 may be incorrect)', max(merrU))
end

// --- Extra: check updated variables at t=1 specifically (direct aalphahat0 test) ---
for k=1:M_.endo_nbr
    merrU1(k) = abs(oo0.UpdatedVariables.(M_.endo_names{k})(1) - oo1.UpdatedVariables.(M_.endo_names{k})(1));
end
if max(merrU1) > 1e-12
    error('smoother_redux (kalman_algo=1) fails at t=1 updated variables! max diff = %e — aalphahat0 is likely wrong', max(merrU1))
end

// --- Filtered variables ---
for k=1:M_.endo_nbr
    merrF(k) = max(abs(oo0.FilteredVariables.(M_.endo_names{k}) - oo1.FilteredVariables.(M_.endo_names{k})));
end
if max(merrF) > 1e-12
    error('smoother_redux (kalman_algo=1) does not replicate filtered variables! max diff = %e', max(merrF))
end

// --- Filter covariance (P_{t|t-1}) ---
verr = max(max(max(abs(oo0.Smoother.Variance - oo1.Smoother.Variance))));
if verr > 1e-10
    error('smoother_redux (kalman_algo=1) does not replicate filter covariance! max diff = %e', verr)
end

// --- State uncertainty (V_{t|T}) ---
verrS = max(max(max(abs(oo0.Smoother.State_uncertainty - oo1.Smoother.State_uncertainty))));
if verrS > 1e-10
    error('smoother_redux (kalman_algo=1) does not replicate state uncertainty! max diff = %e', verrS)
end

// --- Updated covariance (P_{t|t}) ---
verrU = max(max(max(abs(oo0.Smoother.UpdatedVariance - oo1.Smoother.UpdatedVariance))));
if verrU > 1e-10
    error('smoother_redux (kalman_algo=1) does not replicate updated covariance! max diff = %e', verrU)
end

// --- Smoothed shock variance (V_eta) ---
verrV = max(max(max(abs(oo0.Smoother.Shock_variance - oo1.Smoother.Shock_variance))));
if verrV > 1e-10
    error('smoother_redux (kalman_algo=1) does not replicate shock variance! max diff = %e', verrV)
end

fprintf('All smoother_redux (kalman_algo=1, multivariate) checks PASSED.\n');


// =========================================================================
// Consistency checks: smoother_redux (kalman_algo=2) vs full baseline
// =========================================================================

// --- Smoothed shocks ---
for k=1:M_.exo_nbr
    mserr2(k) = max(abs(oo0.SmoothedShocks.(M_.exo_names{k}) - oo2.SmoothedShocks.(M_.exo_names{k})));
end
if max(mserr2) > 1e-12
    error('smoother_redux (kalman_algo=2) does not replicate smoothed shocks! max diff = %e', max(mserr2))
end

// --- Smoothed variables ---
for k=1:M_.endo_nbr
    merr2(k) = max(abs(oo0.SmoothedVariables.(M_.endo_names{k}) - oo2.SmoothedVariables.(M_.endo_names{k})));
end
if max(merr2) > 1e-12
    error('smoother_redux (kalman_algo=2) does not replicate smoothed variables! max diff = %e', max(merr2))
end

// --- Updated variables (critical: tests alphahat_0g1 at t=1 for ilagged statics) ---
for k=1:M_.endo_nbr
    merrU2(k) = max(abs(oo0.UpdatedVariables.(M_.endo_names{k}) - oo2.UpdatedVariables.(M_.endo_names{k})));
end
if max(merrU2) > 1e-12
    error('smoother_redux (kalman_algo=2) does not replicate updated variables! max diff = %e (aalphahat0 may be incorrect)', max(merrU2))
end

// --- Extra: check updated variables at t=1 specifically ---
for k=1:M_.endo_nbr
    merrU1_2(k) = abs(oo0.UpdatedVariables.(M_.endo_names{k})(1) - oo2.UpdatedVariables.(M_.endo_names{k})(1));
end
if max(merrU1_2) > 1e-12
    error('smoother_redux (kalman_algo=2) fails at t=1 updated variables! max diff = %e — aalphahat0 is likely wrong', max(merrU1_2))
end

// --- Filtered variables ---
for k=1:M_.endo_nbr
    merrF2(k) = max(abs(oo0.FilteredVariables.(M_.endo_names{k}) - oo2.FilteredVariables.(M_.endo_names{k})));
end
if max(merrF2) > 1e-12
    error('smoother_redux (kalman_algo=2) does not replicate filtered variables! max diff = %e', max(merrF2))
end

// --- Filter covariance ---
verr2 = max(max(max(abs(oo0.Smoother.Variance - oo2.Smoother.Variance))));
if verr2 > 1e-10
    error('smoother_redux (kalman_algo=2) does not replicate filter covariance! max diff = %e', verr2)
end

// --- State uncertainty ---
verrS2 = max(max(max(abs(oo0.Smoother.State_uncertainty - oo2.Smoother.State_uncertainty))));
if verrS2 > 1e-10
    error('smoother_redux (kalman_algo=2) does not replicate state uncertainty! max diff = %e', verrS2)
end

// --- Updated covariance ---
verrU2 = max(max(max(abs(oo0.Smoother.UpdatedVariance - oo2.Smoother.UpdatedVariance))));
if verrU2 > 1e-10
    error('smoother_redux (kalman_algo=2) does not replicate updated covariance! max diff = %e', verrU2)
end

// --- Smoothed shock variance ---
verrV2 = max(max(max(abs(oo0.Smoother.Shock_variance - oo2.Smoother.Shock_variance))));
if verrV2 > 1e-10
    error('smoother_redux (kalman_algo=2) does not replicate shock variance! max diff = %e', verrV2)
end

fprintf('All smoother_redux (kalman_algo=2, univariate) checks PASSED.\n');


// =========================================================================
// Cross-check: kalman_algo=1 vs kalman_algo=2 smoother_redux
// =========================================================================

// --- Updated variables ---
for k=1:M_.endo_nbr
    merr_cross(k) = max(abs(oo1.UpdatedVariables.(M_.endo_names{k}) - oo2.UpdatedVariables.(M_.endo_names{k})));
end
if max(merr_cross) > 1e-12
    error('Cross-check: kalman_algo=1 vs 2 disagree on updated variables! max diff = %e', max(merr_cross))
end

// --- Smoothed variables ---
for k=1:M_.endo_nbr
    merr_cross_s(k) = max(abs(oo1.SmoothedVariables.(M_.endo_names{k}) - oo2.SmoothedVariables.(M_.endo_names{k})));
end
if max(merr_cross_s) > 1e-12
    error('Cross-check: kalman_algo=1 vs 2 disagree on smoothed variables! max diff = %e', max(merr_cross_s))
end

fprintf('Cross-check (kalman_algo=1 vs 2, smoother_redux) PASSED.\n');


fprintf('\n=== All aalphahat0 smoother_redux tests PASSED. ===\n');
