1515def test_autoregressive_model (order , rng ):
1616 ar = st .AutoregressiveComponent (order = order ).build (verbose = False )
1717
18- # Check coords
1918 _assert_basic_coords_correct (ar )
2019
2120 lags = np .arange (len (order ) if isinstance (order , list ) else order , dtype = "int" ) + 1
@@ -25,34 +24,34 @@ def test_autoregressive_model(order, rng):
2524
2625
2726def test_autoregressive_multiple_observed_build (rng ):
28- ar = st .AutoregressiveComponent (order = 3 , observed_state_names = ["data_1" , "data_2" ])
27+ ar = st .AutoregressiveComponent (order = 3 , name = "ar" , observed_state_names = ["data_1" , "data_2" ])
2928 mod = ar .build (verbose = False )
3029
3130 assert mod .k_endog == 2
3231 assert mod .k_states == 6
3332 assert mod .k_posdef == 2
3433
3534 assert mod .state_names == [
36- "L1 [data_1]" ,
37- "L2 [data_1]" ,
38- "L3 [data_1]" ,
39- "L1 [data_2]" ,
40- "L2 [data_2]" ,
41- "L3 [data_2]" ,
35+ "L1_ar [data_1]" ,
36+ "L2_ar [data_1]" ,
37+ "L3_ar [data_1]" ,
38+ "L1_ar [data_2]" ,
39+ "L2_ar [data_2]" ,
40+ "L3_ar [data_2]" ,
4241 ]
4342
44- assert mod .shock_names == ["auto_regressive [data_1]" , "auto_regressive [data_2]" ]
43+ assert mod .shock_names == ["ar [data_1]" , "ar [data_2]" ]
4544
4645 params = {
47- "params_auto_regressive " : np .full (
46+ "params_ar " : np .full (
4847 (
4948 2 ,
5049 sum (ar .order ),
5150 ),
5251 0.5 ,
5352 dtype = config .floatX ,
5453 ),
55- "sigma_auto_regressive " : np .array ([0.05 , 0.12 ]),
54+ "sigma_ar " : np .array ([0.05 , 0.12 ]),
5655 }
5756 _ , _ , _ , _ , T , Z , R , _ , Q = mod ._unpack_statespace_with_placeholders ()
5857 input_vars = explicit_graph_inputs ([T , Z , R , Q ])
@@ -89,6 +88,33 @@ def test_autoregressive_multiple_observed_build(rng):
8988 np .testing .assert_allclose (Q , np .diag ([0.05 ** 2 , 0.12 ** 2 ]))
9089
9190
91+ def test_autoregressive_multiple_observed_shared ():
92+ ar = st .AutoregressiveComponent (
93+ order = 1 ,
94+ name = "latent" ,
95+ observed_state_names = ["data_1" , "data_2" , "data_3" ],
96+ share_states = True ,
97+ )
98+ mod = ar .build (verbose = False )
99+
100+ assert mod .k_endog == 3
101+ assert mod .k_states == 1
102+ assert mod .k_posdef == 1
103+
104+ assert mod .state_names == ["L1_latent[shared]" ]
105+ assert mod .shock_names == ["latent[shared]" ]
106+ assert mod .coords ["lag_latent" ] == [1 ]
107+ assert "endog_latent" not in mod .coords
108+
109+ outputs = [mod .ssm ["transition" ], mod .ssm ["design" ]]
110+ params = {"params_latent" : np .array ([0.9 ])}
111+ T , Z = pytensor .function (list (explicit_graph_inputs (outputs )), outputs )(** params )
112+
113+ np .testing .assert_allclose (np .array ([[1.0 ], [1.0 ], [1.0 ]]), Z )
114+
115+ np .testing .assert_allclose (np .array ([[0.9 ]]), T )
116+
117+
92118def test_autoregressive_multiple_observed_data (rng ):
93119 ar = st .AutoregressiveComponent (order = 1 , observed_state_names = ["data_1" , "data_2" , "data_3" ])
94120 mod = ar .build (verbose = False )
@@ -112,21 +138,130 @@ def test_add_autoregressive_different_observed():
112138
113139 mod = (mod_1 + mod_2 ).build (verbose = False )
114140
115- print (mod .coords )
116-
117141 assert mod .k_endog == 2
118142 assert mod .k_states == 7
119143 assert mod .k_posdef == 2
120144 assert mod .state_names == [
121- "L1 [data_1]" ,
122- "L1 [data_2]" ,
123- "L2 [data_2]" ,
124- "L3 [data_2]" ,
125- "L4 [data_2]" ,
126- "L5 [data_2]" ,
127- "L6 [data_2]" ,
145+ f"L1_ { mod_1 . name } [data_1]" ,
146+ f"L1_ { mod_2 . name } [data_2]" ,
147+ f"L2_ { mod_2 . name } [data_2]" ,
148+ f"L3_ { mod_2 . name } [data_2]" ,
149+ f"L4_ { mod_2 . name } [data_2]" ,
150+ f"L5_ { mod_2 . name } [data_2]" ,
151+ f"L6_ { mod_2 . name } [data_2]" ,
128152 ]
129153
130154 assert mod .shock_names == ["ar1[data_1]" , "ar6[data_2]" ]
131155 assert mod .coords ["lag_ar1" ] == [1 ]
132156 assert mod .coords ["lag_ar6" ] == [1 , 2 , 3 , 4 , 5 , 6 ]
157+
158+
159+ def test_autoregressive_shared_and_not_shared ():
160+ shared = st .AutoregressiveComponent (
161+ order = 3 ,
162+ name = "shared_ar" ,
163+ observed_state_names = ["data_1" , "data_2" , "data_3" ],
164+ share_states = True ,
165+ )
166+ individual = st .AutoregressiveComponent (
167+ order = 3 ,
168+ name = "individual_ar" ,
169+ observed_state_names = ["data_1" , "data_2" , "data_3" ],
170+ share_states = False ,
171+ )
172+
173+ mod = (shared + individual ).build (verbose = False )
174+
175+ assert mod .k_endog == 3
176+ assert mod .k_states == 3 + 3 * 3
177+ assert mod .k_posdef == 4
178+
179+ assert mod .state_names == [
180+ "L1_shared_ar[shared]" ,
181+ "L2_shared_ar[shared]" ,
182+ "L3_shared_ar[shared]" ,
183+ "L1_individual_ar[data_1]" ,
184+ "L2_individual_ar[data_1]" ,
185+ "L3_individual_ar[data_1]" ,
186+ "L1_individual_ar[data_2]" ,
187+ "L2_individual_ar[data_2]" ,
188+ "L3_individual_ar[data_2]" ,
189+ "L1_individual_ar[data_3]" ,
190+ "L2_individual_ar[data_3]" ,
191+ "L3_individual_ar[data_3]" ,
192+ ]
193+
194+ assert mod .shock_names == [
195+ "shared_ar[shared]" ,
196+ "individual_ar[data_1]" ,
197+ "individual_ar[data_2]" ,
198+ "individual_ar[data_3]" ,
199+ ]
200+ assert mod .coords ["lag_shared_ar" ] == [1 , 2 , 3 ]
201+ assert mod .coords ["lag_individual_ar" ] == [1 , 2 , 3 ]
202+
203+ outputs = [mod .ssm ["transition" ], mod .ssm ["design" ], mod .ssm ["selection" ], mod .ssm ["state_cov" ]]
204+ T , Z , R , Q = pytensor .function (
205+ list (explicit_graph_inputs (outputs )),
206+ outputs ,
207+ )(
208+ ** {
209+ "params_shared_ar" : np .array ([0.9 , 0.8 , 0.7 ]),
210+ "params_individual_ar" : np .full ((3 , 3 ), 0.5 ),
211+ "sigma_shared_ar" : np .array (0.1 ),
212+ "sigma_individual_ar" : np .array ([0.05 , 0.12 , 0.22 ]),
213+ }
214+ )
215+
216+ np .testing .assert_allclose (
217+ T ,
218+ np .array (
219+ [
220+ [0.9 , 0.8 , 0.7 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ],
221+ [1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ],
222+ [0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ],
223+ [0.0 , 0.0 , 0.0 , 0.5 , 0.5 , 0.5 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ],
224+ [0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ],
225+ [0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ],
226+ [0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.5 , 0.5 , 0.5 , 0.0 , 0.0 , 0.0 ],
227+ [0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ],
228+ [0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 ],
229+ [0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.5 , 0.5 , 0.5 ],
230+ [0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 ],
231+ [0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 ],
232+ ]
233+ ),
234+ )
235+
236+ np .testing .assert_allclose (
237+ Z ,
238+ np .array (
239+ [
240+ [1.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ],
241+ [1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ],
242+ [1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 ],
243+ ]
244+ ),
245+ )
246+
247+ np .testing .assert_allclose (
248+ R ,
249+ np .array (
250+ [
251+ [1.0 , 0.0 , 0.0 , 0.0 ],
252+ [0.0 , 0.0 , 0.0 , 0.0 ],
253+ [0.0 , 0.0 , 0.0 , 0.0 ],
254+ [0.0 , 1.0 , 0.0 , 0.0 ],
255+ [0.0 , 0.0 , 0.0 , 0.0 ],
256+ [0.0 , 0.0 , 0.0 , 0.0 ],
257+ [0.0 , 0.0 , 1.0 , 0.0 ],
258+ [0.0 , 0.0 , 0.0 , 0.0 ],
259+ [0.0 , 0.0 , 0.0 , 0.0 ],
260+ [0.0 , 0.0 , 0.0 , 1.0 ],
261+ [0.0 , 0.0 , 0.0 , 0.0 ],
262+ [0.0 , 0.0 , 0.0 , 0.0 ],
263+ ]
264+ ),
265+ )
266+
267+ np .testing .assert_allclose (Q , np .diag ([0.1 , 0.05 , 0.12 , 0.22 ]) ** 2 )
0 commit comments