### powerful function from quantecon
struct LSSMoments
lss::LSS
end
function Base.iterate(L::LSSMoments, state=(copy(L.lss.mu_0),
copy(L.lss.Sigma_0)))
A, C, G, H = L.lss.A, L.lss.C, L.lss.G, L.lss.H
mu_x, Sigma_x = state
mu_y, Sigma_y = G * mu_x, G * Sigma_x * G' + H * H'
# Update moments of x
mu_x2 = A * mu_x
Sigma_x2 = A * Sigma_x * A' + C * C'
return ((mu_x, mu_y, Sigma_x, Sigma_y), (mu_x2, Sigma_x2))
end
moment_sequence(lss::LSS) = LSSMoments(lss)
function stationary_distributions(lss::LSS; max_iter=200, tol=1e-5)
!is_stable(lss.A) ? error("Cannot compute stationary distribution because the system is not stable.") : nothing
# Initialize iteration
m = moment_sequence(lss)
mu_x, mu_y, Sigma_x, Sigma_y = first(m)
i = 0
err = tol + 1.0
for (mu_x1, mu_y, Sigma_x1, Sigma_y) in m
i > max_iter && error("Convergence failed after $i iterations")
i += 1
err_mu = maximum(abs, mu_x1 - mu_x)
err_Sigma = maximum(abs, Sigma_x1 - Sigma_x)
err = max(err_Sigma, err_mu)
mu_x, Sigma_x = mu_x1, Sigma_x1
if err < tol && i > 1
# return here because of how scoping works in loops.
return mu_x1, mu_y, Sigma_x1, Sigma_y
end
end
end
### begin exercise 4
μx, μy, Σx, Σy = stationary_distributions(uva)
T, I = 100, 80
rep_matrix = zeros(T, I)
σ = 0.1
A = [𝝓_1 𝝓_2 𝝓_3 𝝓_4
1 0 0 0
0 1 0 0
0 0 1 0]
G = [1.0 0.0 0.0 0.0]
stationary_uva = LSS(A, [σ 0.0 0.0 0.0]', G; mu_0 = μx)
for i in 1:I
res = simulate(stationary_uva, T)
rep_matrix[:,i] = res[2]
end
time_points = [10, 50, 75]
p1 = plot(rep_matrix,
label = "",
linealpha = 0.4,
linewidth = 1.2,
color_palette = :viridis,
grid = true,
xlabel = "Time",
ylabel = L"y_t",
title = ""
)
vline!(p1, time_points,
color = :black,
linewidth = 1.5,
label = ""
)
for t in time_points
x_vals = fill(t, I)
y_vals = rep_matrix[t, :]
scatter!(p1, x_vals, y_vals,
color = :black,
alpha = 0.6,
markersize = 4,
markerstrokewidth = 0,
label = ""
)
end
xticks!(p1, time_points, [L"T", L"T^\prime", L"T^{\prime\prime}"])
p2 = plot(layout = (1, 3), size = (900, 300), legend = nothing)
p2 = plot(title = "",
xlabel = "Value",
ylabel = "Density",
legend = :topright)
for t in time_points
data_slice = rep_matrix[t, :]
density!(p2, data_slice,
label = "t = $t",
linewidth = 2,
fill = (0, 0.1))
end
display(p1)
display(p2)