@@ -73,7 +73,6 @@ function simulate(F::AbstractFactorProcess, S::Integer; rng::AbstractRNG = Xoshi
7373 else
7474 fs .= dynamics (F) * f[:, s - 1 ] + rand (rng, dist)
7575 end
76-
7776 end
7877
7978 return f
@@ -107,166 +106,256 @@ function simulate(ε::SpatialMovingAverage, S::Integer; rng::AbstractRNG = Xoshi
107106end
108107
109108"""
110- collapse (model) -> (A_low, Z_basis )
109+ state_space_init (model) -> (a1, P1 )
111110
112- Low-dimensional collapsing matrices for the dynamic factor model `model`
113- following the approach of Jungbacker and Koopman (2015).
111+ State space initial conditions of the state space form of the dynamic factor model `model`.
114112"""
115- function collapse (model:: DynamicFactorModel )
116- # active factors
117- active = [! all (iszero, λ) for λ in eachcol (loadings (model))]
118-
119- # collapsing matrix
120- H = cov (model)
121- if all (active)
122- C = (H \ loadings (model))' * loadings (model)
123- Z_basis = (C \ loadings (model)' )'
124- else
125- Z_basis = loadings (model)[:, active]
126- end
127- A_low = (H \ Z_basis)'
113+ function state_space_init (model:: DynamicFactorModel )
114+ T = eltype (data (model))
115+ R = nfactors (model)
116+ a1 = zeros (T, R)
117+ P1 = Matrix {T} (I, R, R)
128118
129- return (A_low, Z_basis )
119+ return (a1, P1 )
130120end
131121
132122"""
133- state_space (model) -> (y_low, Z_low, d_low , H_low, a1, P1 )
123+ collapse (model; objective = false ) -> (y_low, d_low, Z_low , H_low[, M] )
134124
135- State space form of the collapsed dynamic factor model `model` following the
136- approach of Jungbacker and Koopman (2015).
125+ Collapsed system components for the collapsed state space form of the dynamic factor model
126+ `model` following the approach of Jungbacker and Koopman (2015). Optional `objective`
127+ boolean indicating whether the collapsed system components are used for objective function
128+ (log-likelihood) computation, in which case additionally the annihilator matrix is returned.
137129"""
138- function state_space (model:: DynamicFactorModel )
139- R = size (process (model))
140- Ty = eltype (data (model))
141-
142- # active factors
143- active = [! all (iszero, λ) for λ in eachcol (loadings (model))]
144-
145- # collapsing matrix
146- if any (active)
147- (A_low, _) = collapse (model)
148- else
130+ function collapse (model:: DynamicFactorModel ; objective:: Bool = false )
131+ # linearly independent columns
132+ F = qr (loadings (model), ColumnNorm ())
133+ ic = isapprox .(diag (F. R), 0.0 , atol = 1e-8 )
134+
135+ # collapsing matrices
136+ Z_basis = Z[:, .! ic]
137+ if all (ic)
149138 A_low = I
139+ else
140+ A_low = (cov (model) \ Z_basis)'
150141 end
151142
152- # collapsing
153- y_low = A_low * data (model)
143+ # collapsed system
144+ y_low = [ A_low * yt for yt in eachcol ( data (model))]
154145 Z_low = A_low * loadings (model)
155146 if mean (model) isa ZeroMean
156- d_low = Zeros (mean (model). type, size (y_low))
147+ d_low = [ Zeros (mean (model). type, nfactors (model)) for _ in 1 : nobs (model)]
157148 elseif mean (model) isa Exogenous
158- d_low = A_low * mean (mean (model))
149+ d_low = [ A_low * μt for μt in eachcol ( mean (mean (model)))]
159150 end
160151 H_low = A_low * cov (model) * A_low'
161152
162- # initial conditions
163- a1 = zeros (Ty, R)
164- P1 = Matrix {Ty} (I, R, R)
153+ # annihilator matrix for log-likelihood
154+ if objective
155+ if all (ic)
156+ M = Zeros (eltype (data (model)), size (data (model), 1 ))
157+ else
158+ M = I - Z_basis * (H_low \ A_low)
159+ end
165160
166- return (y_low, Z_low, d_low, H_low, a1, P1)
161+ return (y_low, d_low, Z_low, H_low, M)
162+ else
163+ return (y_low, d_low, Z_low, H_low)
164+ end
167165end
168166
169167"""
170- _filter(y, Z, d, H, T, Q, a1, P1 ) -> (a, P, v, F, K )
168+ filter(model; predict = false ) -> (a, P, v, F)
171169
172- Kalman filter for the state space system `y`, `Z`, `d`, `H`, `T`, `Q`, `a1`,
173- and `P1`.
170+ Collapsed Kalman filter for the dynamic factor model `model`. Returns the filtered state `a`
171+ , covariance `P`, forecast error `v`, and forecast error variance `F`. If `predict` is
172+ `true` the filter reports the one-step ahead out-of-sample prediction.
174173"""
175- function _filter (y, Z, d, H, T, Q, a1, P1)
174+ function filter (model:: DynamicFactorModel ; predict:: Bool = false )
175+ # collapsed state space system
176+ (y, d, Z, H) = collapse (model)
177+ T = dynamics (model)
178+ Q = cov (process (model))
179+ (a1, P1) = state_space_init (model)
180+
176181 # initialize filter output
177- n = size (y, 2 )
178- a = Vector {typeof(a1)} (undef, n)
179- P = Vector {typeof(P1)} (undef, n)
180- v = Vector {typeof(a1)} (undef, n)
181- F = Vector {typeof(P1)} (undef, n)
182- K = Vector {typeof(P1)} (undef, n)
182+ n = length (y) + (predict ? 1 : 0 )
183+ a = similar (y, typeof (a1), n)
184+ P = similar (y, typeof (P1), n)
185+ v = similar (y)
186+ F = similar (y, typeof (P1))
187+
188+ # initialize storage
189+ ZtFinv = similar (P1)
190+ att = similar (a1)
191+ Ptt = similar (P1)
183192
184193 # initialize filter
185194 a[1 ] = a1
186195 P[1 ] = P1
187196
188197 # filter
189- for (t, yt) in pairs ( eachcol (y) )
198+ for t in eachindex (y )
190199 # forecast error
191- v[t] = yt - Z * a [t] - view (d, :, t)
200+ v[t] = y[t] - d [t] - Z * a[t]
192201 F[t] = Z * P[t] * Z' + H
193202
194- # Kalman gain
195- K[t] = T * P[t] * (F[t] \ Z)'
203+ # update
204+ ZtFinv .= (F[t] \ Z)'
205+ att .= a[t] + P[t] * ZtFinv * v[t]
206+ Ptt .= P[t] - P[t] * ZtFinv * Z * P[t]
196207
197208 # prediction
198- if t < n
199- a[t + 1 ] = T * a[t] + K[t] * v[t]
200- P[t + 1 ] = T * P[t] * (T - K[t] * Z)' + Q
209+ if predict || t < length (y)
210+ a[t + 1 ] = T * att
211+ P[t + 1 ] = T * Ptt * T' + Q
212+ # enforce symmetry for numerical stability
213+ P[t + 1 ] = 0.5 * (P[t + 1 ] + P[t + 1 ]' )
201214 end
202215 end
203216
204- return (a, P, v, F, K )
217+ return (a, P, v, F)
205218end
206219
207220"""
208- filter(model ) -> (a, P, v, F, K )
221+ _filter_smoother(y, d, Z, H, T, Q, a1, P1 ) -> (a, P, v, ZtFinv )
209222
210- Collapsed Kalman filter for the dynamic factor model `model`. Returns the
211- filtered state `a`, covariance `P`, forecast error `v`, forecast error variance
212- `F`, and Kalman gain `K`.
223+ Collapsed Kalman filter for the dynamic factor model used internally by the `smoother`
224+ routine to avoid duplicate expensive computation of state space system matrices.
213225"""
214- function filter (model:: DynamicFactorModel )
215- # collapsed state space system
216- (y, Z, d, H, a1, P1) = state_space (model)
217- T = dynamics (model)
218- Q = cov (process (model))
226+ function _filter_smoother (y, d, Z, H, T, Q, a1, P1)
227+ # initialize filter output
228+ a = similar (y, typeof (a1))
229+ P = similar (y, typeof (P1))
230+ v = similar (y)
231+ ZtFinv = similar (y, typeof (P1))
232+
233+ # initialize storage
234+ F = similar (P1)
235+ att = similar (a1)
236+ Ptt = similar (P1)
237+
238+ # initialize filter
239+ a[1 ] = a1
240+ P[1 ] = P1
241+
242+ # filter
243+ for t in eachindex (y)
244+ # forecast error
245+ v[t] = y[t] - d[t] - Z * a[t]
246+ F .= Z * P[t] * Z' + H
247+
248+ # update
249+ ZtFinv[t] = (F \ Z)'
250+ att .= a[t] + P[t] * ZtFinv[t] * v[t]
251+ Ptt .= P[t] - P[t] * ZtFinv[t] * Z * P[t]
252+
253+ # prediction
254+ if t < length (y)
255+ a[t + 1 ] = T * att
256+ P[t + 1 ] = T * Ptt * T' + Q
257+ # enforce symmetry for numerical stability
258+ P[t + 1 ] = 0.5 * (P[t + 1 ] + P[t + 1 ]' )
259+ end
260+ end
261+
262+ return (a, P, v, ZtFinv)
263+ end
264+
265+ """
266+ _filter_likelihood(y, d, Z, H, T, Q, a1, P1) -> (v, F, fac)
267+
268+ Collapsed Kalman filter for the dynamic factor model used internally by the `loglikelihood`
269+ routine to avoid duplicate expensive computation of collapsing components and state space
270+ system matrices.
271+ """
272+ function _filter_likelihood (y, d, Z, H, T, Q, a1, P1)
273+ # initialize filter output
274+ v = similar (y)
275+ F = similar (y, typeof (P1))
276+
277+ # initialize storage
278+ ZtFinv = similar (P1)
279+ att = similar (a1)
280+ Ptt = similar (P1)
281+
282+ # initialize filter
283+ a = copy (a1)
284+ P = copy (P1)
285+
286+ # filter
287+ for t in eachindex (y)
288+ # forecast error
289+ v[t] = y[t] - d[t] - Z * a
290+ F[t] = Z * P * Z' + H
219291
220- return _filter (y, Z, d, H, T, Q, a1, P1)
292+ # update
293+ ZtFinv .= (F[t] \ Z)'
294+ att .= a + P * ZtFinv * v[t]
295+ Ptt .= P - P * ZtFinv * Z * P
296+
297+ # prediction
298+ if t < length (y)
299+ a .= T * att
300+ P = T * Ptt * T' + Q
301+ # enforce symmetry for numerical stability
302+ P = 0.5 * (P + P' )
303+ end
304+ end
305+
306+ return (v, F)
221307end
222308
223309"""
224- smoother(model) -> (α̂ , V, Γ)
310+ smoother(model) -> (α , V, Γ)
225311
226- Collapsed Kalman smoother for the dynamic factor model `model`. Returns the
227- smoothed state `α̂ `, covariance `V`, and autocovariance `Γ`.
312+ Collapsed Kalman smoother for the dynamic factor model `model`. Returns the smoothed state
313+ `α `, covariance `V`, and autocovariance `Γ`.
228314"""
229- function smoother (model:: DynamicFactorModel )
315+ function smoother (model:: DynamicTensorAutoregression )
230316 # collapsed state space system
231- (y, Z, d, H, a1, P1 ) = state_space (model)
317+ (y, d, Z, H ) = collapse (model)
232318 T = dynamics (model)
233319 Q = cov (process (model))
320+ (a1, P1) = state_space_init (model)
234321
235322 # filter
236- (a, P, v, F, K ) = _filter (y, Z, d , H, T, Q, a1, P1)
323+ (a, P, v, ZtFinv ) = _filter_smoother (y, d, Z , H, T, Q, a1, P1)
237324
238325 # initialize smoother output
239- α̂ = similar (a)
326+ α = similar (a)
240327 V = similar (P)
241- Γ = similar (P, length (a ) - 1 )
328+ Γ = similar (P, length (y ) - 1 )
242329
243330 # initialize smoother
244- r = zero (a1 )
245- N = zero (P1 )
246- L = similar (P1 )
331+ r = zero (a[ 1 ] )
332+ N = zero (P[ 1 ] )
333+ L = similar (P[ 1 ] )
247334
248335 # smoother
249- for t in reverse (eachindex (a ))
250- L .= T - K [t] * Z
336+ for t in reverse (eachindex (y ))
337+ L .= T - T * P[t] * ZtFinv [t] * Z
251338
252339 # backward recursion
253- r .= (F [t] \ Z) ' * v[t] + L' * r
254- N .= (F [t] \ Z) ' * Z + L' * N * L
340+ r .= ZtFinv [t] * v[t] + L' * r
341+ N .= ZtFinv [t] * Z[t] + L' * N * L
255342
256343 # smoothing
257- α̂ [t] = a[t] + P[t] * r
344+ α [t] = a[t] + P[t] * r
258345 V[t] = P[t] - P[t] * N * P[t]
259346 t > 1 && (Γ[t - 1 ] = I - P[t] * N)
260- t < length (a ) && (Γ[t] *= L * P[t])
347+ t < length (y ) && (Γ[t] *= L * P[t])
261348 end
262349
263- return (α̂ , V, Γ)
350+ return (α , V, Γ)
264351end
265352
266353"""
267354 forecasts(μ, periods) -> forecasts
268355
269356Forecast the mean model `μ` `periods` ahead.
270357"""
271- forecast (μ:: AbstractMeanSpecification , periods:: Integer ) = error (" forecast for $(Base. typename (typeof (μ)). wrapper) not implemented." )
358+ function forecast (μ:: AbstractMeanSpecification , periods:: Integer )
359+ error (" forecast for $(Base. typename (typeof (μ)). wrapper) not implemented." )
360+ end
272361forecast (μ:: ZeroMean , periods:: Integer ) = Zeros (μ. type, μ. n, periods)
0 commit comments