1
1
import logging
2
2
3
3
from collections .abc import Callable , Sequence
4
- from typing import Any
4
+ from typing import Any , Literal
5
5
6
6
import numpy as np
7
7
import pandas as pd
@@ -822,6 +822,7 @@ def build_statespace_graph(
822
822
mode : str | None = None ,
823
823
missing_fill_value : float | None = None ,
824
824
cov_jitter : float | None = JITTER_DEFAULT ,
825
+ mvn_method : Literal ["cholesky" , "eigh" , "svd" ] = "svd" ,
825
826
save_kalman_filter_outputs_in_idata : bool = False ,
826
827
) -> None :
827
828
"""
@@ -865,6 +866,14 @@ def build_statespace_graph(
865
866
866
867
- The Univariate Filter is more robust than other filters, and can tolerate a lower jitter value
867
868
869
+ mvn_method: str, default "svd"
870
+ Method used to invert the covariance matrix when calculating the pdf of a multivariate normal
871
+ (or when generating samples). One of "cholesky", "eigh", or "svd". "cholesky" is fastest, but least robust
872
+ to ill-conditioned matrices, while "svd" is slow but extremely robust.
873
+
874
+ In general, if your model has measurement error, "cholesky" will be safe to use. Otherwise, "svd" is
875
+ recommended. "eigh" can also be tried if sampling with "svd" is very slow, but it is not as robust as "svd".
876
+
868
877
save_kalman_filter_outputs_in_idata: bool, optional, default=False
869
878
If True, Kalman Filter outputs will be saved in the model as deterministics. Useful for debugging, but
870
879
should not be necessary for the majority of users.
@@ -915,6 +924,7 @@ def build_statespace_graph(
915
924
logp = logp ,
916
925
observed = data ,
917
926
dims = obs_dims ,
927
+ method = mvn_method ,
918
928
)
919
929
920
930
self ._fit_coords = pm_mod .coords .copy ()
@@ -1109,6 +1119,7 @@ def _sample_conditional(
1109
1119
group : str ,
1110
1120
random_seed : RandomState | None = None ,
1111
1121
data : pt .TensorLike | None = None ,
1122
+ mvn_method : Literal ["cholesky" , "eigh" , "svd" ] = "svd" ,
1112
1123
** kwargs ,
1113
1124
):
1114
1125
"""
@@ -1130,6 +1141,14 @@ def _sample_conditional(
1130
1141
Observed data on which to condition the model. If not provided, the function will use the data that was
1131
1142
provided when the model was built.
1132
1143
1144
+ mvn_method: str, default "svd"
1145
+ Method used to invert the covariance matrix when calculating the pdf of a multivariate normal
1146
+ (or when generating samples). One of "cholesky", "eigh", or "svd". "cholesky" is fastest, but least robust
1147
+ to ill-conditioned matrices, while "svd" is slow but extremely robust.
1148
+
1149
+ In general, if your model has measurement error, "cholesky" will be safe to use. Otherwise, "svd" is
1150
+ recommended. "eigh" can also be tried if sampling with "svd" is very slow, but it is not as robust as "svd".
1151
+
1133
1152
kwargs:
1134
1153
Additional keyword arguments are passed to pymc.sample_posterior_predictive
1135
1154
@@ -1181,6 +1200,7 @@ def _sample_conditional(
1181
1200
covs = cov ,
1182
1201
logp = dummy_ll ,
1183
1202
dims = state_dims ,
1203
+ method = mvn_method ,
1184
1204
)
1185
1205
1186
1206
obs_mu = (Z @ mu [..., None ]).squeeze (- 1 )
@@ -1192,6 +1212,7 @@ def _sample_conditional(
1192
1212
covs = obs_cov ,
1193
1213
logp = dummy_ll ,
1194
1214
dims = obs_dims ,
1215
+ method = mvn_method ,
1195
1216
)
1196
1217
1197
1218
# TODO: Remove this after pm.Flat initial values are fixed
@@ -1222,6 +1243,7 @@ def _sample_unconditional(
1222
1243
steps : int | None = None ,
1223
1244
use_data_time_dim : bool = False ,
1224
1245
random_seed : RandomState | None = None ,
1246
+ mvn_method : Literal ["cholesky" , "eigh" , "svd" ] = "svd" ,
1225
1247
** kwargs ,
1226
1248
):
1227
1249
"""
@@ -1251,6 +1273,14 @@ def _sample_unconditional(
1251
1273
random_seed : int, RandomState or Generator, optional
1252
1274
Seed for the random number generator.
1253
1275
1276
+ mvn_method: str, default "svd"
1277
+ Method used to invert the covariance matrix when calculating the pdf of a multivariate normal
1278
+ (or when generating samples). One of "cholesky", "eigh", or "svd". "cholesky" is fastest, but least robust
1279
+ to ill-conditioned matrices, while "svd" is slow but extremely robust.
1280
+
1281
+ In general, if your model has measurement error, "cholesky" will be safe to use. Otherwise, "svd" is
1282
+ recommended. "eigh" can also be tried if sampling with "svd" is very slow, but it is not as robust as "svd".
1283
+
1254
1284
kwargs:
1255
1285
Additional keyword arguments are passed to pymc.sample_posterior_predictive
1256
1286
@@ -1309,6 +1339,7 @@ def _sample_unconditional(
1309
1339
steps = steps ,
1310
1340
dims = dims ,
1311
1341
mode = self ._fit_mode ,
1342
+ method = mvn_method ,
1312
1343
sequence_names = self .kalman_filter .seq_names ,
1313
1344
k_endog = self .k_endog ,
1314
1345
)
@@ -1331,7 +1362,11 @@ def _sample_unconditional(
1331
1362
return idata_unconditional .posterior_predictive
1332
1363
1333
1364
def sample_conditional_prior (
1334
- self , idata : InferenceData , random_seed : RandomState | None = None , ** kwargs
1365
+ self ,
1366
+ idata : InferenceData ,
1367
+ random_seed : RandomState | None = None ,
1368
+ mvn_method : Literal ["cholesky" , "eigh" , "svd" ] = "svd" ,
1369
+ ** kwargs ,
1335
1370
) -> InferenceData :
1336
1371
"""
1337
1372
Sample from the conditional prior; that is, given parameter draws from the prior distribution,
@@ -1347,6 +1382,14 @@ def sample_conditional_prior(
1347
1382
random_seed : int, RandomState or Generator, optional
1348
1383
Seed for the random number generator.
1349
1384
1385
+ mvn_method: str, default "svd"
1386
+ Method used to invert the covariance matrix when calculating the pdf of a multivariate normal
1387
+ (or when generating samples). One of "cholesky", "eigh", or "svd". "cholesky" is fastest, but least robust
1388
+ to ill-conditioned matrices, while "svd" is slow but extremely robust.
1389
+
1390
+ In general, if your model has measurement error, "cholesky" will be safe to use. Otherwise, "svd" is
1391
+ recommended. "eigh" can also be tried if sampling with "svd" is very slow, but it is not as robust as "svd".
1392
+
1350
1393
kwargs:
1351
1394
Additional keyword arguments are passed to pymc.sample_posterior_predictive
1352
1395
@@ -1358,10 +1401,16 @@ def sample_conditional_prior(
1358
1401
"predicted_prior", and "smoothed_prior".
1359
1402
"""
1360
1403
1361
- return self ._sample_conditional (idata , "prior" , random_seed , ** kwargs )
1404
+ return self ._sample_conditional (
1405
+ idata = idata , group = "prior" , random_seed = random_seed , mvn_method = mvn_method , ** kwargs
1406
+ )
1362
1407
1363
1408
def sample_conditional_posterior (
1364
- self , idata : InferenceData , random_seed : RandomState | None = None , ** kwargs
1409
+ self ,
1410
+ idata : InferenceData ,
1411
+ random_seed : RandomState | None = None ,
1412
+ mvn_method : Literal ["cholesky" , "eigh" , "svd" ] = "svd" ,
1413
+ ** kwargs ,
1365
1414
):
1366
1415
"""
1367
1416
Sample from the conditional posterior; that is, given parameter draws from the posterior distribution,
@@ -1376,6 +1425,14 @@ def sample_conditional_posterior(
1376
1425
random_seed : int, RandomState or Generator, optional
1377
1426
Seed for the random number generator.
1378
1427
1428
+ mvn_method: str, default "svd"
1429
+ Method used to invert the covariance matrix when calculating the pdf of a multivariate normal
1430
+ (or when generating samples). One of "cholesky", "eigh", or "svd". "cholesky" is fastest, but least robust
1431
+ to ill-conditioned matrices, while "svd" is slow but extremely robust.
1432
+
1433
+ In general, if your model has measurement error, "cholesky" will be safe to use. Otherwise, "svd" is
1434
+ recommended. "eigh" can also be tried if sampling with "svd" is very slow, but it is not as robust as "svd".
1435
+
1379
1436
kwargs:
1380
1437
Additional keyword arguments are passed to pymc.sample_posterior_predictive
1381
1438
@@ -1387,14 +1444,17 @@ def sample_conditional_posterior(
1387
1444
"predicted_posterior", and "smoothed_posterior".
1388
1445
"""
1389
1446
1390
- return self ._sample_conditional (idata , "posterior" , random_seed , ** kwargs )
1447
+ return self ._sample_conditional (
1448
+ idata = idata , group = "posterior" , random_seed = random_seed , mvn_method = mvn_method , ** kwargs
1449
+ )
1391
1450
1392
1451
def sample_unconditional_prior (
1393
1452
self ,
1394
1453
idata : InferenceData ,
1395
1454
steps : int | None = None ,
1396
1455
use_data_time_dim : bool = False ,
1397
1456
random_seed : RandomState | None = None ,
1457
+ mvn_method : Literal ["cholesky" , "eigh" , "svd" ] = "svd" ,
1398
1458
** kwargs ,
1399
1459
) -> InferenceData :
1400
1460
"""
@@ -1423,6 +1483,14 @@ def sample_unconditional_prior(
1423
1483
random_seed : int, RandomState or Generator, optional
1424
1484
Seed for the random number generator.
1425
1485
1486
+ mvn_method: str, default "svd"
1487
+ Method used to invert the covariance matrix when calculating the pdf of a multivariate normal
1488
+ (or when generating samples). One of "cholesky", "eigh", or "svd". "cholesky" is fastest, but least robust
1489
+ to ill-conditioned matrices, while "svd" is slow but extremely robust.
1490
+
1491
+ In general, if your model has measurement error, "cholesky" will be safe to use. Otherwise, "svd" is
1492
+ recommended. "eigh" can also be tried if sampling with "svd" is very slow, but it is not as robust as "svd".
1493
+
1426
1494
kwargs:
1427
1495
Additional keyword arguments are passed to pymc.sample_posterior_predictive
1428
1496
@@ -1439,7 +1507,13 @@ def sample_unconditional_prior(
1439
1507
"""
1440
1508
1441
1509
return self ._sample_unconditional (
1442
- idata , "prior" , steps , use_data_time_dim , random_seed , ** kwargs
1510
+ idata = idata ,
1511
+ group = "prior" ,
1512
+ steps = steps ,
1513
+ use_data_time_dim = use_data_time_dim ,
1514
+ random_seed = random_seed ,
1515
+ mvn_method = mvn_method ,
1516
+ ** kwargs ,
1443
1517
)
1444
1518
1445
1519
def sample_unconditional_posterior (
@@ -1448,6 +1522,7 @@ def sample_unconditional_posterior(
1448
1522
steps : int | None = None ,
1449
1523
use_data_time_dim : bool = False ,
1450
1524
random_seed : RandomState | None = None ,
1525
+ mvn_method : Literal ["cholesky" , "eigh" , "svd" ] = "svd" ,
1451
1526
** kwargs ,
1452
1527
) -> InferenceData :
1453
1528
"""
@@ -1477,6 +1552,14 @@ def sample_unconditional_posterior(
1477
1552
random_seed : int, RandomState or Generator, optional
1478
1553
Seed for the random number generator.
1479
1554
1555
+ mvn_method: str, default "svd"
1556
+ Method used to invert the covariance matrix when calculating the pdf of a multivariate normal
1557
+ (or when generating samples). One of "cholesky", "eigh", or "svd". "cholesky" is fastest, but least robust
1558
+ to ill-conditioned matrices, while "svd" is slow but extremely robust.
1559
+
1560
+ In general, if your model has measurement error, "cholesky" will be safe to use. Otherwise, "svd" is
1561
+ recommended. "eigh" can also be tried if sampling with "svd" is very slow, but it is not as robust as "svd".
1562
+
1480
1563
Returns
1481
1564
-------
1482
1565
InferenceData
@@ -1490,7 +1573,13 @@ def sample_unconditional_posterior(
1490
1573
"""
1491
1574
1492
1575
return self ._sample_unconditional (
1493
- idata , "posterior" , steps , use_data_time_dim , random_seed , ** kwargs
1576
+ idata = idata ,
1577
+ group = "posterior" ,
1578
+ steps = steps ,
1579
+ use_data_time_dim = use_data_time_dim ,
1580
+ random_seed = random_seed ,
1581
+ mvn_method = mvn_method ,
1582
+ ** kwargs ,
1494
1583
)
1495
1584
1496
1585
def sample_statespace_matrices (
@@ -1933,6 +2022,7 @@ def forecast(
1933
2022
filter_output = "smoothed" ,
1934
2023
random_seed : RandomState | None = None ,
1935
2024
verbose : bool = True ,
2025
+ mvn_method : Literal ["cholesky" , "eigh" , "svd" ] = "svd" ,
1936
2026
** kwargs ,
1937
2027
) -> InferenceData :
1938
2028
"""
@@ -1989,6 +2079,14 @@ def forecast(
1989
2079
verbose: bool, default=True
1990
2080
Whether to print diagnostic information about forecasting.
1991
2081
2082
+ mvn_method: str, default "svd"
2083
+ Method used to invert the covariance matrix when calculating the pdf of a multivariate normal
2084
+ (or when generating samples). One of "cholesky", "eigh", or "svd". "cholesky" is fastest, but least robust
2085
+ to ill-conditioned matrices, while "svd" is slow but extremely robust.
2086
+
2087
+ In general, if your model has measurement error, "cholesky" will be safe to use. Otherwise, "svd" is
2088
+ recommended. "eigh" can also be tried if sampling with "svd" is very slow, but it is not as robust as "svd".
2089
+
1992
2090
kwargs:
1993
2091
Additional keyword arguments are passed to pymc.sample_posterior_predictive
1994
2092
@@ -2098,6 +2196,7 @@ def forecast(
2098
2196
sequence_names = self .kalman_filter .seq_names ,
2099
2197
k_endog = self .k_endog ,
2100
2198
append_x0 = False ,
2199
+ method = mvn_method ,
2101
2200
)
2102
2201
2103
2202
forecast_model .rvs_to_initial_values = {
@@ -2126,6 +2225,7 @@ def impulse_response_function(
2126
2225
shock_trajectory : np .ndarray | None = None ,
2127
2226
orthogonalize_shocks : bool = False ,
2128
2227
random_seed : RandomState | None = None ,
2228
+ mvn_method : Literal ["cholesky" , "eigh" , "svd" ] = "svd" ,
2129
2229
** kwargs ,
2130
2230
):
2131
2231
"""
@@ -2177,6 +2277,14 @@ def impulse_response_function(
2177
2277
random_seed : int, RandomState or Generator, optional
2178
2278
Seed for the random number generator.
2179
2279
2280
+ mvn_method: str, default "svd"
2281
+ Method used to invert the covariance matrix when calculating the pdf of a multivariate normal
2282
+ (or when generating samples). One of "cholesky", "eigh", or "svd". "cholesky" is fastest, but least robust
2283
+ to ill-conditioned matrices, while "svd" is slow but extremely robust.
2284
+
2285
+ In general, if your model has measurement error, "cholesky" will be safe to use. Otherwise, "svd" is
2286
+ recommended. "eigh" can also be tried if sampling with "svd" is very slow, but it is not as robust as "svd".
2287
+
2180
2288
kwargs:
2181
2289
Additional keyword arguments are passed to pymc.sample_posterior_predictive
2182
2290
@@ -2236,7 +2344,7 @@ def impulse_response_function(
2236
2344
shock_trajectory = pt .zeros ((n_steps , self .k_posdef ))
2237
2345
if Q is not None :
2238
2346
init_shock = pm .MvNormal (
2239
- "initial_shock" , mu = 0 , cov = Q , dims = [SHOCK_DIM ], method = "svd"
2347
+ "initial_shock" , mu = 0 , cov = Q , dims = [SHOCK_DIM ], method = mvn_method
2240
2348
)
2241
2349
else :
2242
2350
init_shock = pm .Deterministic (
0 commit comments