pymc-extras 0.6.0__py3-none-any.whl → 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. pymc_extras/distributions/timeseries.py +10 -10
  2. pymc_extras/inference/dadvi/dadvi.py +14 -83
  3. pymc_extras/inference/laplace_approx/laplace.py +187 -159
  4. pymc_extras/inference/pathfinder/pathfinder.py +12 -7
  5. pymc_extras/inference/smc/sampling.py +2 -2
  6. pymc_extras/model/marginal/distributions.py +4 -2
  7. pymc_extras/model/marginal/marginal_model.py +12 -2
  8. pymc_extras/prior.py +3 -3
  9. pymc_extras/statespace/core/properties.py +276 -0
  10. pymc_extras/statespace/core/statespace.py +182 -45
  11. pymc_extras/statespace/filters/distributions.py +19 -34
  12. pymc_extras/statespace/filters/kalman_filter.py +13 -12
  13. pymc_extras/statespace/filters/kalman_smoother.py +2 -2
  14. pymc_extras/statespace/models/DFM.py +179 -168
  15. pymc_extras/statespace/models/ETS.py +177 -151
  16. pymc_extras/statespace/models/SARIMAX.py +149 -152
  17. pymc_extras/statespace/models/VARMAX.py +134 -145
  18. pymc_extras/statespace/models/__init__.py +8 -1
  19. pymc_extras/statespace/models/structural/__init__.py +30 -8
  20. pymc_extras/statespace/models/structural/components/autoregressive.py +87 -45
  21. pymc_extras/statespace/models/structural/components/cycle.py +119 -80
  22. pymc_extras/statespace/models/structural/components/level_trend.py +95 -42
  23. pymc_extras/statespace/models/structural/components/measurement_error.py +27 -17
  24. pymc_extras/statespace/models/structural/components/regression.py +105 -68
  25. pymc_extras/statespace/models/structural/components/seasonality.py +138 -100
  26. pymc_extras/statespace/models/structural/core.py +397 -286
  27. pymc_extras/statespace/models/utilities.py +5 -20
  28. {pymc_extras-0.6.0.dist-info → pymc_extras-0.8.0.dist-info}/METADATA +4 -4
  29. {pymc_extras-0.6.0.dist-info → pymc_extras-0.8.0.dist-info}/RECORD +31 -30
  30. {pymc_extras-0.6.0.dist-info → pymc_extras-0.8.0.dist-info}/WHEEL +0 -0
  31. {pymc_extras-0.6.0.dist-info → pymc_extras-0.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,15 +1,19 @@
1
- from collections.abc import Sequence
2
- from typing import Any
3
-
4
1
  import numpy as np
5
2
  import pytensor
6
3
  import pytensor.tensor as pt
7
4
 
8
5
  from pytensor.compile.mode import Mode
9
- from pytensor.tensor.slinalg import solve_discrete_lyapunov
10
-
6
+ from pytensor.tensor.linalg import solve_discrete_lyapunov
7
+
8
+ from pymc_extras.statespace.core.properties import (
9
+ Coord,
10
+ Data,
11
+ Parameter,
12
+ Shock,
13
+ State,
14
+ )
11
15
  from pymc_extras.statespace.core.statespace import PyMCStateSpace
12
- from pymc_extras.statespace.models.utilities import make_default_coords, validate_names
16
+ from pymc_extras.statespace.models.utilities import validate_names
13
17
  from pymc_extras.statespace.utils.constants import (
14
18
  ALL_STATE_AUX_DIM,
15
19
  ALL_STATE_DIM,
@@ -212,110 +216,96 @@ class BayesianVARMAX(PyMCStateSpace):
212
216
  "sigma_obs": k_endog * self.measurement_error,
213
217
  }
214
218
 
215
- @property
216
- def param_names(self):
217
- names = ["x0", "P0", "ar_params", "ma_params", "state_cov", "sigma_obs"]
218
- if self.stationary_initialization:
219
- names.remove("P0")
220
- names.remove("x0")
221
- if not self.measurement_error:
222
- names.remove("sigma_obs")
223
- if self.p == 0:
224
- names.remove("ar_params")
225
- if self.q == 0:
226
- names.remove("ma_params")
227
-
228
- # Add exogenous regression coefficents rather than remove, since we might have to handle
229
- # several (if self.exog_state_names is a dict)
230
- if isinstance(self.exog_state_names, list):
231
- names.append("beta_exog")
232
- elif isinstance(self.exog_state_names, dict):
233
- names.extend([f"beta_{name}" for name in self.exog_state_names.keys()])
219
+ def set_parameters(self) -> Parameter | tuple[Parameter, ...] | None:
220
+ k_endog = self.k_endog
221
+ k_states = self.k_states
222
+ k_posdef = self.k_posdef
234
223
 
235
- return names
236
-
237
- @property
238
- def param_info(self) -> dict[str, dict[str, Any]]:
239
- info = {
240
- "x0": {
241
- "shape": (self.k_states,),
242
- "constraints": None,
243
- },
244
- "P0": {
245
- "shape": (self.k_states, self.k_states),
246
- "constraints": "Positive Semi-definite",
247
- },
248
- "sigma_obs": {
249
- "shape": (self.k_endog, self.k_endog),
250
- "constraints": "Positive Semi-definite",
251
- },
252
- "state_cov": {
253
- "shape": (self.k_posdef, self.k_posdef),
254
- "constraints": "Positive Semi-definite",
255
- },
256
- "ar_params": {
257
- "shape": (self.k_endog, self.p, self.k_endog),
258
- "constraints": "None",
259
- },
260
- "ma_params": {
261
- "shape": (self.k_endog, self.q, self.k_endog),
262
- "constraints": "None",
263
- },
264
- }
224
+ parameters = []
265
225
 
266
- if isinstance(self.exog_state_names, list):
267
- k_exog = len(self.exog_state_names)
268
- info["beta_exog"] = {
269
- "shape": (self.k_endog, k_exog),
270
- "constraints": "None",
271
- }
226
+ if not self.stationary_initialization:
227
+ parameters.append(
228
+ Parameter(
229
+ name="x0",
230
+ shape=(k_states,),
231
+ dims=(ALL_STATE_DIM,),
232
+ constraints=None,
233
+ )
234
+ )
235
+ parameters.append(
236
+ Parameter(
237
+ name="P0",
238
+ shape=(k_states, k_states),
239
+ dims=(ALL_STATE_DIM, ALL_STATE_AUX_DIM),
240
+ constraints="Positive Semi-definite",
241
+ )
242
+ )
272
243
 
273
- elif isinstance(self.exog_state_names, dict):
274
- for name, exog_names in self.exog_state_names.items():
275
- k_exog = len(exog_names)
276
- info[f"beta_{name}"] = {
277
- "shape": (k_exog,),
278
- "constraints": "None",
279
- }
244
+ if self.p > 0:
245
+ parameters.append(
246
+ Parameter(
247
+ name="ar_params",
248
+ shape=(k_endog, self.p, k_endog),
249
+ dims=(OBS_STATE_DIM, AR_PARAM_DIM, OBS_STATE_AUX_DIM),
250
+ constraints=None,
251
+ )
252
+ )
280
253
 
281
- for name in self.param_names:
282
- info[name]["dims"] = self.param_dims[name]
254
+ if self.q > 0:
255
+ parameters.append(
256
+ Parameter(
257
+ name="ma_params",
258
+ shape=(k_endog, self.q, k_endog),
259
+ dims=(OBS_STATE_DIM, MA_PARAM_DIM, OBS_STATE_AUX_DIM),
260
+ constraints=None,
261
+ )
262
+ )
283
263
 
284
- return {name: info[name] for name in self.param_names}
264
+ parameters.append(
265
+ Parameter(
266
+ name="state_cov",
267
+ shape=(k_posdef, k_posdef),
268
+ dims=(SHOCK_DIM, SHOCK_AUX_DIM),
269
+ constraints="Positive Semi-definite",
270
+ )
271
+ )
285
272
 
286
- @property
287
- def data_info(self) -> dict[str, dict[str, Any]]:
288
- info = {}
273
+ if self.measurement_error:
274
+ parameters.append(
275
+ Parameter(
276
+ name="sigma_obs",
277
+ shape=(k_endog,),
278
+ dims=(OBS_STATE_DIM,),
279
+ constraints="Positive",
280
+ )
281
+ )
289
282
 
283
+ # Handle exogenous parameters
290
284
  if isinstance(self.exog_state_names, list):
291
- info = {
292
- "exogenous_data": {
293
- "dims": (TIME_DIM, EXOG_STATE_DIM),
294
- "shape": (None, self.k_exog),
295
- }
296
- }
297
-
285
+ k_exog = len(self.exog_state_names)
286
+ parameters.append(
287
+ Parameter(
288
+ name="beta_exog",
289
+ shape=(k_endog, k_exog),
290
+ dims=(OBS_STATE_DIM, EXOG_STATE_DIM),
291
+ constraints=None,
292
+ )
293
+ )
298
294
  elif isinstance(self.exog_state_names, dict):
299
- info = {
300
- f"{endog_state}_exogenous_data": {
301
- "dims": (TIME_DIM, f"{EXOG_STATE_DIM}_{endog_state}"),
302
- "shape": (None, len(exog_names)),
303
- }
304
- for endog_state, exog_names in self.exog_state_names.items()
305
- }
295
+ for name, exog_names in self.exog_state_names.items():
296
+ k_exog = len(exog_names)
297
+ parameters.append(
298
+ Parameter(
299
+ name=f"beta_{name}",
300
+ shape=(k_exog,),
301
+ dims=(f"{EXOG_STATE_DIM}_{name}",),
302
+ constraints=None,
303
+ )
304
+ )
306
305
 
307
- return info
306
+ return tuple(parameters)
308
307
 
309
- @property
310
- def data_names(self) -> list[str]:
311
- if isinstance(self.exog_state_names, list):
312
- return ["exogenous_data"]
313
- elif isinstance(self.exog_state_names, dict):
314
- return [f"{endog_state}_exogenous_data" for endog_state in self.exog_state_names.keys()]
315
- return []
316
-
317
- @property
318
- def state_names(self):
308
+ def set_states(self) -> State | tuple[State, ...] | None:
319
309
  state_names = self.endog_names.copy()
320
310
  state_names += [
321
311
  f"L{i + 1}_{state}" for i in range(self.p - 1) for state in self.endog_names
@@ -324,66 +314,65 @@ class BayesianVARMAX(PyMCStateSpace):
324
314
  f"L{i + 1}_{state}_innov" for i in range(self.q) for state in self.endog_names
325
315
  ]
326
316
 
327
- return state_names
317
+ hidden_states = [State(name=name, observed=False) for name in state_names]
328
318
 
329
- @property
330
- def observed_states(self):
331
- return self.endog_names
319
+ # The first k_endog states are observed
320
+ observed_states = [State(name=name, observed=True) for name in self.endog_names]
332
321
 
333
- @property
334
- def shock_names(self):
335
- return self.endog_names
322
+ return *hidden_states, *observed_states
336
323
 
337
- @property
338
- def default_priors(self):
339
- raise NotImplementedError
324
+ def set_shocks(self) -> Shock | tuple[Shock, ...] | None:
325
+ return tuple(Shock(name=name) for name in self.endog_names)
340
326
 
341
- @property
342
- def coords(self) -> dict[str, Sequence]:
343
- coords = make_default_coords(self)
344
- if self.p > 0:
345
- coords.update({AR_PARAM_DIM: list(range(1, self.p + 1))})
346
- if self.q > 0:
347
- coords.update({MA_PARAM_DIM: list(range(1, self.q + 1))})
327
+ def set_data_info(self) -> tuple[Data, ...] | None:
328
+ data = []
348
329
 
349
330
  if isinstance(self.exog_state_names, list):
350
- coords[EXOG_STATE_DIM] = self.exog_state_names
331
+ k_exog = len(self.exog_state_names)
332
+ data.append(
333
+ Data(
334
+ name="exogenous_data",
335
+ shape=(None, k_exog),
336
+ dims=(TIME_DIM, EXOG_STATE_DIM),
337
+ is_exogenous=True,
338
+ )
339
+ )
351
340
  elif isinstance(self.exog_state_names, dict):
352
- for name, exog_names in self.exog_state_names.items():
353
- coords[f"{EXOG_STATE_DIM}_{name}"] = exog_names
341
+ for endog_state, exog_names in self.exog_state_names.items():
342
+ k_exog = len(exog_names)
343
+ data.append(
344
+ Data(
345
+ name=f"{endog_state}_exogenous_data",
346
+ shape=(None, k_exog),
347
+ dims=(TIME_DIM, f"{EXOG_STATE_DIM}_{endog_state}"),
348
+ is_exogenous=True,
349
+ )
350
+ )
354
351
 
355
- return coords
352
+ return tuple(data)
356
353
 
357
- @property
358
- def param_dims(self):
359
- coord_map = {
360
- "x0": (ALL_STATE_DIM,),
361
- "P0": (ALL_STATE_DIM, ALL_STATE_AUX_DIM),
362
- "sigma_obs": (OBS_STATE_DIM,),
363
- "state_cov": (SHOCK_DIM, SHOCK_AUX_DIM),
364
- "ar_params": (OBS_STATE_DIM, AR_PARAM_DIM, OBS_STATE_AUX_DIM),
365
- "ma_params": (OBS_STATE_DIM, MA_PARAM_DIM, OBS_STATE_AUX_DIM),
366
- }
354
+ def set_coords(self) -> Coord | tuple[Coord, ...] | None:
355
+ coords = list(self.default_coords())
367
356
 
368
- if not self.measurement_error:
369
- del coord_map["sigma_obs"]
370
- if self.p == 0:
371
- del coord_map["ar_params"]
372
- if self.q == 0:
373
- del coord_map["ma_params"]
374
- if self.stationary_initialization:
375
- del coord_map["P0"]
376
- del coord_map["x0"]
357
+ # AR/MA param coords
358
+ if self.p > 0:
359
+ coords.append(Coord(dimension=AR_PARAM_DIM, labels=tuple(range(1, self.p + 1))))
360
+
361
+ if self.q > 0:
362
+ coords.append(Coord(dimension=MA_PARAM_DIM, labels=tuple(range(1, self.q + 1))))
377
363
 
364
+ # Exogenous coords
378
365
  if isinstance(self.exog_state_names, list):
379
- coord_map["beta_exog"] = (OBS_STATE_DIM, EXOG_STATE_DIM)
366
+ coords.append(Coord(dimension=EXOG_STATE_DIM, labels=tuple(self.exog_state_names)))
380
367
  elif isinstance(self.exog_state_names, dict):
381
- # If each state has its own exogenous variables, each parameter needs it own dim, since we expect the
382
- # dim labels to all be different (otherwise we'd be in the list case).
383
- for name in self.exog_state_names.keys():
384
- coord_map[f"beta_{name}"] = (f"{EXOG_STATE_DIM}_{name}",)
368
+ for name, exog_names in self.exog_state_names.items():
369
+ coords.append(Coord(dimension=f"{EXOG_STATE_DIM}_{name}", labels=tuple(exog_names)))
385
370
 
386
- return coord_map
371
+ return tuple(coords)
372
+
373
+ @property
374
+ def default_priors(self):
375
+ raise NotImplementedError
387
376
 
388
377
  def add_default_priors(self):
389
378
  raise NotImplementedError
@@ -1,6 +1,13 @@
1
1
  from pymc_extras.statespace.models import structural
2
+ from pymc_extras.statespace.models.DFM import BayesianDynamicFactor
2
3
  from pymc_extras.statespace.models.ETS import BayesianETS
3
4
  from pymc_extras.statespace.models.SARIMAX import BayesianSARIMAX
4
5
  from pymc_extras.statespace.models.VARMAX import BayesianVARMAX
5
6
 
6
- __all__ = ["BayesianSARIMAX", "BayesianVARMAX", "BayesianETS", "structural"]
7
+ __all__ = [
8
+ "BayesianSARIMAX",
9
+ "BayesianVARMAX",
10
+ "BayesianETS",
11
+ "BayesianDynamicFactor",
12
+ "structural",
13
+ ]
@@ -1,21 +1,43 @@
1
+ import warnings
2
+
1
3
  from pymc_extras.statespace.models.structural.components.autoregressive import (
2
- AutoregressiveComponent,
4
+ Autoregressive,
3
5
  )
4
- from pymc_extras.statespace.models.structural.components.cycle import CycleComponent
5
- from pymc_extras.statespace.models.structural.components.level_trend import LevelTrendComponent
6
+ from pymc_extras.statespace.models.structural.components.cycle import Cycle
7
+ from pymc_extras.statespace.models.structural.components.level_trend import LevelTrend
6
8
  from pymc_extras.statespace.models.structural.components.measurement_error import MeasurementError
7
- from pymc_extras.statespace.models.structural.components.regression import RegressionComponent
9
+ from pymc_extras.statespace.models.structural.components.regression import Regression
8
10
  from pymc_extras.statespace.models.structural.components.seasonality import (
9
11
  FrequencySeasonality,
10
12
  TimeSeasonality,
11
13
  )
12
14
 
15
+ _DEPRECATED_NAMES = {
16
+ "LevelTrendComponent": LevelTrend,
17
+ "CycleComponent": Cycle,
18
+ "RegressionComponent": Regression,
19
+ "AutoregressiveComponent": Autoregressive,
20
+ }
21
+
22
+
23
+ def __getattr__(name: str):
24
+ if name in _DEPRECATED_NAMES:
25
+ warnings.warn(
26
+ f"{name} is deprecated and will be removed in a future release. "
27
+ f"Use {_DEPRECATED_NAMES[name].__name__} instead.",
28
+ FutureWarning,
29
+ stacklevel=2,
30
+ )
31
+ return _DEPRECATED_NAMES[name]
32
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
33
+
34
+
13
35
  __all__ = [
14
- "AutoregressiveComponent",
15
- "CycleComponent",
36
+ "Autoregressive",
37
+ "Cycle",
16
38
  "FrequencySeasonality",
17
- "LevelTrendComponent",
39
+ "LevelTrend",
18
40
  "MeasurementError",
19
- "RegressionComponent",
41
+ "Regression",
20
42
  "TimeSeasonality",
21
43
  ]
@@ -1,12 +1,19 @@
1
+ import warnings
2
+
1
3
  import numpy as np
2
4
  import pytensor.tensor as pt
3
5
 
6
+ from pymc_extras.statespace.core.properties import (
7
+ Coord,
8
+ Parameter,
9
+ Shock,
10
+ State,
11
+ )
4
12
  from pymc_extras.statespace.models.structural.core import Component
5
13
  from pymc_extras.statespace.models.structural.utils import order_to_mask
6
- from pymc_extras.statespace.utils.constants import AR_PARAM_DIM
7
14
 
8
15
 
9
- class AutoregressiveComponent(Component):
16
+ class Autoregressive(Component):
10
17
  r"""
11
18
  Autoregressive timeseries component
12
19
 
@@ -58,8 +65,8 @@ class AutoregressiveComponent(Component):
58
65
  import pymc as pm
59
66
  import pytensor.tensor as pt
60
67
 
61
- trend = st.LevelTrendComponent(order=1, innovations_order=0)
62
- ar = st.AutoregressiveComponent(2)
68
+ trend = st.LevelTrend(order=1, innovations_order=0)
69
+ ar = st.Autoregressive(2)
63
70
  ss_mod = (trend + ar).build()
64
71
 
65
72
  with pm.Model(coords=ss_mod.coords) as model:
@@ -94,6 +101,8 @@ class AutoregressiveComponent(Component):
94
101
  self.order = order
95
102
  self.ar_lags = ar_lags
96
103
 
104
+ state_names = [f"L{i + 1}_{name}" for i in range(k_states)]
105
+
97
106
  super().__init__(
98
107
  name=name,
99
108
  k_endog=k_endog,
@@ -101,61 +110,82 @@ class AutoregressiveComponent(Component):
101
110
  k_posdef=k_posdef,
102
111
  measurement_error=True,
103
112
  combine_hidden_states=True,
104
- observed_state_names=observed_state_names,
113
+ base_observed_state_names=observed_state_names,
114
+ base_state_names=state_names,
105
115
  obs_state_idxs=np.tile(np.r_[[1.0], np.zeros(k_states - 1)], k_endog_effective),
106
116
  share_states=share_states,
107
117
  )
108
118
 
109
- def populate_component_properties(self):
110
- k_endog = self.k_endog
111
- k_endog_effective = 1 if self.share_states else k_endog
112
-
113
- k_states = self.k_states // k_endog_effective # this is also the number of AR lags
114
- base_names = [f"L{i + 1}_{self.name}" for i in range(k_states)]
119
+ def set_states(self) -> State | tuple[State, ...] | None:
120
+ base_names = self.base_state_names
121
+ observed_state_names = self.base_observed_state_names
115
122
 
116
123
  if self.share_states:
117
- self.state_names = [f"{name}[shared]" for name in base_names]
118
- self.shock_names = [f"{self.name}[shared]"]
124
+ state_names = [f"{name}[shared]" for name in base_names]
119
125
  else:
120
- self.state_names = [
126
+ state_names = [
121
127
  f"{name}[{state_name}]"
122
- for state_name in self.observed_state_names
128
+ for state_name in observed_state_names
123
129
  for name in base_names
124
130
  ]
125
- self.shock_names = [
126
- f"{self.name}[{obs_name}]" for obs_name in self.observed_state_names
127
- ]
128
131
 
129
- self.param_names = [f"params_{self.name}", f"sigma_{self.name}"]
130
- self.param_dims = {f"params_{self.name}": (f"lag_{self.name}",)}
131
- self.coords = {f"lag_{self.name}": self.ar_lags.tolist()}
132
+ hidden_states = [State(name=name, observed=False, shared=True) for name in state_names]
133
+ observed_states = [
134
+ State(name=name, observed=True, shared=False) for name in observed_state_names
135
+ ]
136
+ return *hidden_states, *observed_states
132
137
 
133
- if k_endog_effective > 1:
134
- self.param_dims[f"params_{self.name}"] = (
138
+ def set_parameters(self) -> Parameter | tuple[Parameter, ...] | None:
139
+ k_endog = self.k_endog
140
+ k_endog_effective = 1 if self.share_states else k_endog
141
+
142
+ k_states = self.k_states // k_endog_effective # this is also the number of AR lags
143
+
144
+ ar_param = Parameter(
145
+ name=f"params_{self.name}",
146
+ shape=(k_endog_effective, k_states) if k_endog_effective > 1 else (k_states,),
147
+ dims=(f"lag_{self.name}",)
148
+ if k_endog_effective == 1
149
+ else (
135
150
  f"endog_{self.name}",
136
151
  f"lag_{self.name}",
137
- )
138
- self.param_dims[f"sigma_{self.name}"] = (f"endog_{self.name}",)
139
-
140
- self.coords[f"endog_{self.name}"] = self.observed_state_names
141
-
142
- self.param_info = {
143
- f"params_{self.name}": {
144
- "shape": (k_endog_effective, k_states) if k_endog_effective > 1 else (k_states,),
145
- "constraints": None,
146
- "dims": (AR_PARAM_DIM,)
147
- if k_endog_effective == 1
148
- else (
149
- f"endog_{self.name}",
150
- f"lag_{self.name}",
151
- ),
152
- },
153
- f"sigma_{self.name}": {
154
- "shape": (k_endog_effective,) if k_endog_effective > 1 else (),
155
- "constraints": "Positive",
156
- "dims": (f"endog_{self.name}",) if k_endog_effective > 1 else None,
157
- },
158
- }
152
+ ),
153
+ constraints=None,
154
+ )
155
+
156
+ sigma_param = Parameter(
157
+ name=f"sigma_{self.name}",
158
+ shape=(k_endog_effective,) if k_endog_effective > 1 else (),
159
+ dims=(f"endog_{self.name}",) if k_endog_effective > 1 else None,
160
+ constraints="Positive",
161
+ )
162
+
163
+ return ar_param, sigma_param
164
+
165
+ def set_shocks(self) -> Shock | tuple[Shock, ...] | None:
166
+ observed_state_names = self.observed_state_names
167
+
168
+ if self.share_states:
169
+ shock_names = [f"{self.name}[shared]"]
170
+ else:
171
+ shock_names = [f"{self.name}[{obs_name}]" for obs_name in observed_state_names]
172
+
173
+ return tuple(Shock(name=name) for name in shock_names)
174
+
175
+ def set_coords(self) -> Coord | tuple[Coord, ...] | None:
176
+ k_endog = self.k_endog
177
+ k_endog_effective = 1 if self.share_states else k_endog
178
+ observed_state_names = self.observed_state_names
179
+
180
+ lag_coord = Coord(dimension=f"lag_{self.name}", labels=self.ar_lags.tolist())
181
+
182
+ coord_container = [lag_coord]
183
+
184
+ if k_endog_effective > 1:
185
+ endog_coord = Coord(dimension=f"endog_{self.name}", labels=observed_state_names)
186
+ coord_container.append(endog_coord)
187
+
188
+ return tuple(coord_container)
159
189
 
160
190
  def make_symbolic_graph(self) -> None:
161
191
  k_endog = self.k_endog
@@ -211,3 +241,15 @@ class AutoregressiveComponent(Component):
211
241
 
212
242
  cov_idx = ("state_cov", *np.diag_indices(k_posdef))
213
243
  self.ssm[cov_idx] = sigma_ar**2
244
+
245
+
246
+ def __getattr__(name: str):
247
+ if name == "AutoregressiveComponent":
248
+ warnings.warn(
249
+ "AutoregressiveComponent is deprecated and will be removed in a future release. "
250
+ "Use Autoregressive instead.",
251
+ FutureWarning,
252
+ stacklevel=2,
253
+ )
254
+ return Autoregressive
255
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")