statespace_rep#
The representation of a linear Gaussian state space model (DK eq. 3.1):
with \(y_t\) of length p, \(\alpha_t\) of length m, \(\eta_t\) of length r, and t = 1, …, n, together with the distribution of \(\alpha_1\).
ssm_rep_t is plain data: its components are public, and the
algorithms of the other modules take it as an argument. Missing
observations are NaN in y and may be any subset of a period’s elements
(DK §4.10).
Example#
The local level model for the Nile data, with exact diffuse
initialization (from example/nile_local_level.f90):
type(ssm_rep_t) :: rep
type(filter_result_t) :: fres
integer :: info
rep = ssm_rep(y, m=1, r=1) ! y(1, n)
rep%Z = 1.0_dp
rep%T = 1.0_dp
rep%H = 15099.0_dp
rep%Q = 1469.1_dp
call rep%initialize_diffuse()
call kalman_filter(rep, fres, info)
ssm_rep_t#
type :: ssm_rep_t
integer :: k_endog, k_states, k_posdef, nobs ! p, m, r, n
real(dp), allocatable :: y(:, :) ! (p, n)
real(dp), allocatable :: Z(:, :, :), H(:, :, :) ! (p, m, 1|n), (p, p, 1|n)
real(dp), allocatable :: T(:, :, :), R(:, :, :) ! (m, m, 1|n), (m, r, 1|n)
real(dp), allocatable :: Q(:, :, :) ! (r, r, 1|n)
real(dp), allocatable :: c(:, :), d(:, :) ! (m, 1|n), (p, 1|n)
integer :: filter_method = FILTER_CONVENTIONAL
integer :: diffuse_method = DIFFUSE_UNIVARIATE
real(dp) :: tol_diffuse = 1.0e-10_dp
real(dp) :: tol_steady = 1.0e-15_dp
integer :: loglikelihood_burn = 0
logical :: marginal_likelihood = .false.
! initialization: blk_first, blk_last, blk_kind, a1, Pstar1, Pinf1
end type
A time dimension of 1 makes a matrix time-invariant; assigning an array
with time dimension n (rep%Z = Z_tv) makes it time-varying.
filter_methodFILTER_CONVENTIONALprocesses \(y_t\) as a vector (DK §4.3);FILTER_UNIVARIATEone element at a time (DK §6.4) in every period.diffuse_methodDIFFUSE_UNIVARIATE(default) filters the diffuse periods element by element (DK §5.2.5);DIFFUSE_MULTIVARIATEuses the multivariate exact initial filter (DK §5.2) where \(F_\infty\) is zero or nonsingular and the univariate step where it is singular but nonzero.tol_diffuseThreshold on \(F_\infty\) and \(\|P_\infty\|_F^2\) in the diffuse periods, as in statsmodels.
tol_steadyIn a time-invariant model the conventional filter holds P, F and K fixed once \(\|P_{t+1} - P_t\|_F \le\)
tol_steady\(\|P_{t+1}\|_F\) (DK §4.3.4), for as long as \(y_t\) is fully observed. A negative value turns this off. See The steady state.loglikelihood_burnNumber of leading periods left out of the log likelihood.
marginal_likelihoodReport the marginal log likelihood of Francke, Koopman and de Vos (2010) instead of the diffuse log likelihood (DK §7.2.6). The two differ by a term in Z, T and the diffuse directions only.
Constants#
Initialization kinds, for initialize_block: INIT_NONE (0),
INIT_KNOWN (1), INIT_APPROX_DIFFUSE (2), INIT_STATIONARY (3),
INIT_DIFFUSE (4), INIT_GENERAL (5).
Filter methods: FILTER_CONVENTIONAL (0), FILTER_UNIVARIATE (1).
Diffuse methods: DIFFUSE_UNIVARIATE (0), DIFFUSE_MULTIVARIATE (1).
ssm_rep#
function ssm_rep(y, m, r) result(rep)
real(dp), intent(in) :: y(:, :)
integer, intent(in) :: m, r
type(ssm_rep_t) :: rep
Create a time-invariant representation for data y(p, n) with m states
and r state disturbances. All system matrices start at zero except R, which
starts as the leading m × r identity. The initialization must be set before
filtering.
tidx#
pure integer function tidx(nt, t)
The slice of period t in an array whose time dimension has length nt:
min(t, nt).
Initialization#
The initial state is \(\alpha_1 = a + A\delta + R_0 \eta_0\) with \(\delta\) diffuse (DK eq. 5.2), that is \(\alpha_1 \sim N(a, P_* + \kappa P_\infty)\) with \(\kappa \to \infty\). It is set for the whole state vector, or block by block, for example a diffuse trend beside a stationary ARMA block (DK §5.6).
subroutine initialize_known(self, a1, P1)
subroutine initialize_approximate_diffuse(self, kappa, a1) ! both optional
subroutine initialize_stationary(self)
subroutine initialize_diffuse(self, a1) ! a1 optional
subroutine initialize_general(self, a1, Pstar, Pinf)
subroutine initialize_block(self, first, last, kind, a1, P1, kappa)
initialize_known\(\alpha_1 \sim N(a_1, P_1)\).
initialize_approximate_diffuse\(\alpha_1 \sim N(a_1, \kappa I)\), \(\kappa\) = 1e6 and \(a_1 = 0\) unless given.
initialize_stationaryThe unconditional distribution: \(a_1 = (I - T)^{-1} c\) and \(P_1 = T P_1 T' + R Q R'\), from the matrices at t = 1 and recomputed at each filter run, so it follows parameter updates.
initialize_diffuseExact diffuse: \(P_\infty = I\), \(P_* = 0\). The diffuse log likelihood (DK §7.2.2) accounts for the diffuse states, so
loglikelihood_burnshould be 0.initialize_generalDK §5.1 in full, with given \(a_1, P_*, P_\infty\).
initialize_blockStates
first..lastgetkind. Blocks must not overlap and must together cover the state vector. A stationary block must not depend on states outside it through T.
initial_state#
subroutine initial_state(self, a1, Pstar, Pinf, info)
real(dp), intent(out) :: a1(:), Pstar(:, :), Pinf(:, :)
integer, intent(out) :: info
The mean and the two variance parts of \(\alpha_1\) implied by the
initialization. info is SS_ERR_INIT if a state is not initialized
and SS_ERR_NOT_STATIONARY if a stationary block has a unit root.
k_diffuse#
integer function k_diffuse(self)
Number of diffuse elements of \(\alpha_1\), the rank of \(P_\infty\); counted as parameters in AIC and BIC (DK §7.4).
scale_by#
subroutine scale_by(self, s)
real(dp), intent(in) :: s
Multiply H, Q and \(P_*\) by s: puts a model whose scale was
concentrated out (loglike_concentrated) on the data’s scale.
\(P_\infty\) is not affected.
validate#
subroutine validate(self, info)
integer, intent(out) :: info
Check that the dimensions are consistent, that each time dimension is 1 or n, and that the model is initialized. The filters call it first.