@@ -684,4 +684,86 @@ function reinstantiate(model::UnobservedComponents, y::Vector{Fl}, X::Matrix{Fl}
684
684
trend = model. trend,
685
685
seasonal = model. seasonal,
686
686
cycle = model. cycle)
687
+ end
688
+
689
+
690
+ # UnobservedComponents with explanatory requires a custom simulation
691
+
692
+ function simulate_scenarios (
693
+ model:: UnobservedComponents ,
694
+ steps_ahead:: Int ,
695
+ n_scenarios:: Int ,
696
+ new_exogenous:: Matrix{Fl} ;
697
+ filter:: KalmanFilter = default_filter (model),
698
+ ) where Fl
699
+ @assert steps_ahead == size (new_exogenous, 1 ) " new_exogenous must have the same dimension as steps_ahead"
700
+ # Query the type of model elements
701
+ fo = kalman_filter (model)
702
+ last_state = fo. a[end ]
703
+ num_series = size (model. system. y, 2 )
704
+
705
+ scenarios = Array {Fl,3} (undef, steps_ahead, num_series, n_scenarios)
706
+ for s in 1 : n_scenarios
707
+ scenarios[:, :, s] = simulate (model, last_state, steps_ahead, new_exogenous)
708
+ end
709
+ return scenarios
710
+ end
711
+
712
+ function simulate_scenarios (
713
+ model:: UnobservedComponents ,
714
+ steps_ahead:: Int ,
715
+ n_scenarios:: Int ,
716
+ new_exogenous:: Array{Fl, 3} ;
717
+ filter:: KalmanFilter = default_filter (model),
718
+ ) where Fl
719
+ @assert steps_ahead == size (new_exogenous, 1 ) " new_exogenous must have the same dimension of steps_ahead"
720
+ @assert n_scenarios == size (new_exogenous, 3 ) " new_exogenous must have the same number of scenarios of n_scenarios"
721
+ # Query the type of model elements
722
+ fo = kalman_filter (model)
723
+ last_state = fo. a[end ]
724
+ num_series = size (model. system. y, 2 )
725
+
726
+ scenarios = Array {Fl,3} (undef, steps_ahead, num_series, n_scenarios)
727
+ for s in 1 : n_scenarios
728
+ scenarios[:, :, s] = simulate (model, last_state, steps_ahead, new_exogenous[:, :, s])
729
+ end
730
+ return scenarios
731
+ end
732
+
733
+ function simulate (
734
+ model:: UnobservedComponents ,
735
+ initial_state:: Vector{Fl} ,
736
+ n:: Int ,
737
+ new_exogenous:: Matrix{Fl} ;
738
+ return_simulated_states:: Bool = false ,
739
+ ) where Fl
740
+ sys = model. system
741
+ m = size (sys. T[1 ], 1 )
742
+ y = Vector {Fl} (undef, n)
743
+ alpha = Matrix {Fl} (undef, n + 1 , m)
744
+ # Sampling errors
745
+ chol_H = sqrt (sys. H[1 ])
746
+ chol_Q = cholesky_decomposition (sys. Q[1 ])
747
+ standard_ε = randn (n)
748
+ standard_η = randn (n + 1 , size (sys. Q[1 ], 1 ))
749
+
750
+ num_exogenous = size (model. exogenous, 2 )
751
+ @assert num_exogenous == size (new_exogenous, 2 ) " You must have the same number of exogenous variables of the model."
752
+
753
+ # The first state of the simulation is the update of a_0
754
+ alpha[1 , :] .= initial_state
755
+ sys. Z[1 ][end - num_exogenous+ 1 : end ] .= new_exogenous[1 , :]
756
+ y[1 ] = dot (sys. Z[1 ], initial_state) + sys. d[1 ] + chol_H * standard_ε[1 ]
757
+ alpha[2 , :] = sys. T[1 ] * initial_state + sys. c[1 ] + sys. R[1 ] * chol_Q. L * standard_η[1 , :]
758
+ # Simulate scenarios
759
+ for t in 2 : n
760
+ sys. Z[t][end - num_exogenous+ 1 : end ] .= new_exogenous[t, :]
761
+ y[t] = dot (sys. Z[t], alpha[t, :]) + sys. d[t] + chol_H * standard_ε[t]
762
+ alpha[t + 1 , :] = sys. T[t] * alpha[t, :] + sys. c[t] + sys. R[t] * chol_Q. L * standard_η[t, :]
763
+ end
764
+
765
+ if return_simulated_states
766
+ return y, alpha[1 : n, :]
767
+ end
768
+ return y
687
769
end
0 commit comments