Getting Started

This tutorial walks through the core workflow of DifferenceEquations.jl: defining a linear state-space model, simulating it, and computing likelihoods.

Creating a Linear State Space Model

A LinearStateSpaceProblem represents a linear time-invariant state-space model:

\[u_{n+1} = A\, u_n + B\, w_{n+1}, \qquad z_n = C\, u_n + v_n\]

Define the model primitives, create a problem, and solve:

using DifferenceEquations, LinearAlgebra, Random
A = [0.95 6.2; 0.0 0.2]
B = [0.0; 0.01;;]  # 2×1 Matrix (Julia's ;; creates a column matrix)
C = [0.09 0.67; 1.00 0.00]
u0 = zeros(2)
T = 10

prob = LinearStateSpaceProblem(A, B, u0, (0, T); C)
sol = solve(prob)
sol.u[end]
2-element Vector{Float64}:
  0.044879388496239715
 -0.01200993769889138

Computing Likelihood

To compute log-likelihoods, provide observables (a Vector{Vector} of length T) and observables_noise (the observation noise covariance matrix — e.g., Diagonal(d) for diagonal noise or Symmetric(H * H') for a general covariance).

Timing convention

Observations correspond to $z_1, z_2, \ldots, z_T$ – that is, the states after the initial condition. Pass T observation vectors for a tspan of (0, T).

First, simulate some data to use as observables:

Random.seed!(123)
D = Diagonal([0.1, 0.1])  # diagonal observation noise covariance matrix
prob_sim = LinearStateSpaceProblem(A, B, u0, (0, T); C, observables_noise = D)
sol_sim = solve(prob_sim)

# Extract observations at times 1..T (skip the initial condition at t=0)
observables = sol_sim.z[2:end]
length(observables)  # should be T
10

Compute the joint log-likelihood given fixed noise using DirectIteration:

prob_lik = LinearStateSpaceProblem(A, B, u0, (0, length(observables)); C,
    observables = observables,
    observables_noise = D,
    noise = sol_sim.W)
sol_lik = solve(prob_lik)
sol_lik.logpdf  # joint log-likelihood
-0.2908180730779734

For the marginal log-likelihood (integrating out the latent noise), use a KalmanFilter by additionally providing a Gaussian prior on u0:

prob_kf = LinearStateSpaceProblem(A, B, u0, (0, length(observables)); C,
    observables = observables,
    observables_noise = D,
    u0_prior_mean = zeros(2),
    u0_prior_var = Matrix(1.0I, 2, 2))
sol_kf = solve(prob_kf)  # KalmanFilter is auto-selected
sol_kf.logpdf  # marginal log-likelihood
-5.285155583498729

DataFrame Conversion

Convert the state trajectory to a DataFrame for analysis. Column names come from syms if provided:

using DataFrames
prob_df = LinearStateSpaceProblem(A, B, u0, (0, T); C,
    syms = (:capital, :productivity))
sol_df = solve(prob_df)
DataFrame(sol_df)
11×3 DataFrame
Rowtimestampcapitalproductivity
Int64Float64Float64
100.00.0
210.0-0.0108822
32-0.06746950.00486115
43-0.0339570.00240549
54-0.01734510.00196485
65-0.004295760.0104891
760.06095150.00238549
870.07269390.00218506
980.0826066-0.0167342
109-0.02527570.00772098
11100.02385820.0130312

Next Steps