|
| 1 | +# nSim = 1 method: Xdraws is (T + sample_t0) × n matrix |
| 2 | +@views function BackwardSampling!(Xdraws::AbstractMatrix, μ_filter, Σ_filter, |
| 3 | + μ_pred, Σ_pred, A, μ₀, Σ₀; sample_t0 = true) |
1 | 4 |
|
2 | | -@views function BackwardSampling!(Xdraws, μ_filter, Σ_filter, μ_pred, Σ_pred, A, μ₀, Σ₀, |
3 | | - nSim = 1; sample_t0 = true) |
| 5 | + T, n = size(μ_filter) |
| 6 | + x = zeros(n) |
| 7 | + μback = zeros(n) |
| 8 | + μ_zero = zeros(n) |
| 9 | + AS = zeros(n, n) |
| 10 | + G = zeros(n, n) |
| 11 | + |
| 12 | + rand!(MvNormal(μ_filter[T,:], Hermitian(Σ_filter[:,:,T])), x) |
| 13 | + Xdraws[T + sample_t0, :] .= x |
| 14 | + |
| 15 | + for t = (T-1):-1:1 |
| 16 | + mul!(AS, A, Σ_filter[:,:,t]) |
| 17 | + G .= (Σ_pred[:,:,t+1] \ AS)' |
| 18 | + Σback = Hermitian(Σ_filter[:,:,t] - G * AS) |
| 19 | + μback .= μ_filter[t,:] .+ G * (Xdraws[t+1+sample_t0,:] .- μ_pred[t+1,:]) |
| 20 | + if isposdef(Σback) |
| 21 | + rand!(MvNormal(μ_zero, Σback), x) |
| 22 | + Xdraws[t+sample_t0,:] .= μback .+ x |
| 23 | + else |
| 24 | + Xdraws[t+sample_t0,:] .= Xdraws[t+1+sample_t0,:] |
| 25 | + end |
| 26 | + end |
| 27 | + |
| 28 | + if sample_t0 |
| 29 | + Σ₀mat = Matrix(Σ₀) |
| 30 | + mul!(AS, A, Σ₀mat) |
| 31 | + G .= (Σ_pred[:,:,1] \ AS)' |
| 32 | + Σback = Hermitian(Σ₀mat - G * AS) |
| 33 | + μback .= μ₀ .+ G * (Xdraws[2,:] .- μ_pred[1,:]) |
| 34 | + if isposdef(Σback) |
| 35 | + rand!(MvNormal(μ_zero, Σback), x) |
| 36 | + Xdraws[1,:] .= μback .+ x |
| 37 | + else |
| 38 | + Xdraws[1,:] .= Xdraws[2,:] |
| 39 | + end |
| 40 | + end |
| 41 | +end |
| 42 | + |
| 43 | +# Thin wrapper: loop over sims and delegate to 2D |
| 44 | +# Not used, but may try it to avoid code duplication. |
| 45 | +function BackwardSamplingThin!(Xdraws::AbstractArray{<:Real,3}, μ_filter, Σ_filter, |
| 46 | + μ_pred, Σ_pred, A, μ₀, Σ₀, nSim = 1; sample_t0 = true) |
| 47 | + for i = 1:nSim |
| 48 | + BackwardSampling!(@view(Xdraws[:,:,i]), μ_filter, Σ_filter, μ_pred, Σ_pred, A, |
| 49 | + μ₀, Σ₀; sample_t0 = sample_t0) |
| 50 | + end |
| 51 | +end |
| 52 | + |
| 53 | +# nSim > 1 method: Xdraws is (T + sample_t0) × n × nSim array — dispatch on AbstractArray |
| 54 | +@views function BackwardSampling!(Xdraws::AbstractArray{<:Real,3}, μ_filter, Σ_filter, |
| 55 | + μ_pred, Σ_pred, A, μ₀, Σ₀; sample_t0 = true) |
| 56 | + |
4 | 57 | T, n = size(μ_filter) # T does not include t=0, n is the dim of state |
| 58 | + nSim = size(Xdraws, 3) # number of draws |
5 | 59 | X = zeros(n, nSim) # buffer, reused every t |
6 | 60 | μback = zeros(n, nSim) |
7 | 61 | μ_zero = zeros(n) # pre-allocated zero mean for MvNormal |
@@ -72,7 +126,7 @@ A, C, Σₑ and Σₙ can be deterministically time-varying by passing 3D arrays |
72 | 126 | Note: If nSim == 1, the returned Xdraws is matrix, otherwise it is a 3D array of size T×n×nSim. |
73 | 127 |
|
74 | 128 | """ |
75 | | -function FFBS!(Draws, U, Y, A, B, C, Σₑ, Σₙ, μ₀, Σ₀, nSim = 1; |
| 129 | +function FFBS!(Draws, U, Y, A, B, C, Σₑ, Σₙ, μ₀, Σ₀; |
76 | 130 | filter_output = false, sample_t0 = true) |
77 | 131 |
|
78 | 132 | T = length(Y) # Number of time steps |
@@ -106,7 +160,7 @@ function FFBS!(Draws, U, Y, A, B, C, Σₑ, Σₙ, μ₀, Σ₀, nSim = 1; |
106 | 160 | Σ_pred[:,:,t] .= Σ̄ |
107 | 161 | end |
108 | 162 |
|
109 | | - BackwardSampling!(Draws, μ_filter, Σ_filter, μ_pred, Σ_pred, A, μ₀, Σ₀, nSim; |
| 163 | + BackwardSampling!(Draws, μ_filter, Σ_filter, μ_pred, Σ_pred, A, μ₀, Σ₀; |
110 | 164 | sample_t0 = sample_t0) |
111 | 165 |
|
112 | 166 | if filter_output |
|
0 commit comments