Repository: statsmodels/statsmodels

Issue:
BUG: Time-varying state space design matrix in constructor.
Hi -- I'm trying to initialize a state space representation with a time varying design matrix. For example:

import numpy as np
import statsmodels.api as sm

nobs = 100
k_endog = 1
k_states = 2
endog = np.random.normal(0,1,size=(nobs,))
dsn = np.random.normal(0,1,size=(k_endog,k_states,nobs))
sm.tsa.statespace.MLEModel(endog,k_states,design=dsn)

This gives the following error:

ValueError: Invalid dimensions for time-varying design matrix. Requires shape (*,*,0), got (1, 2, 100)

The documentation on the other hand suggests that the design matrix should be k_endog x k_states x nobs. Apologies if I'm missing something obvious. 


Discussion:
Hey, thanks for reporting this bug!  In the meantime, the workaround for this is to set the time-varying matrix after the object is already constructed:

```python
nobs = 100
k_endog = 1
k_states = 2
endog = np.random.normal(0,1,size=(nobs,))
dsn = np.random.normal(0,1,size=(k_endog,k_states,nobs))
mod = sm.tsa.statespace.MLEModel(endog,k_states)
mod['design'] = dsn
```

Resolving patch:
diff --git a/statsmodels/tsa/statespace/mlemodel.py b/statsmodels/tsa/statespace/mlemodel.py
--- a/statsmodels/tsa/statespace/mlemodel.py
+++ b/statsmodels/tsa/statespace/mlemodel.py
@@ -158,7 +158,8 @@ def initialize_statespace(self, **kwargs):
         endog = self.endog.T
 
         # Instantiate the state space object
-        self.ssm = SimulationSmoother(endog.shape[0], self.k_states, **kwargs)
+        self.ssm = SimulationSmoother(endog.shape[0], self.k_states,
+                                      nobs=endog.shape[1], **kwargs)
         # Bind the data to the model
         self.ssm.bind(endog)
 


Test patch:
diff --git a/statsmodels/tsa/statespace/tests/test_mlemodel.py b/statsmodels/tsa/statespace/tests/test_mlemodel.py
--- a/statsmodels/tsa/statespace/tests/test_mlemodel.py
+++ b/statsmodels/tsa/statespace/tests/test_mlemodel.py
@@ -57,6 +57,79 @@ def get_dummy_mod(fit=True, pandas=False):
     return mod, res
 
 
+def test_init_matrices_time_invariant():
+    # Test setting state space system matrices in __init__, with time-invariant
+    # matrices
+    k_endog = 2
+    k_states = 3
+    k_posdef = 1
+
+    endog = np.zeros((10, 2))
+    obs_intercept = np.arange(k_endog) * 1.0
+    design = np.reshape(
+        np.arange(k_endog * k_states) * 1.0, (k_endog, k_states))
+    obs_cov = np.reshape(np.arange(k_endog**2) * 1.0, (k_endog, k_endog))
+    state_intercept = np.arange(k_states) * 1.0
+    transition = np.reshape(np.arange(k_states**2) * 1.0, (k_states, k_states))
+    selection = np.reshape(
+        np.arange(k_states * k_posdef) * 1.0, (k_states, k_posdef))
+    state_cov = np.reshape(np.arange(k_posdef**2) * 1.0, (k_posdef, k_posdef))
+
+    mod = MLEModel(endog, k_states=k_states, k_posdef=k_posdef,
+                   obs_intercept=obs_intercept, design=design,
+                   obs_cov=obs_cov, state_intercept=state_intercept,
+                   transition=transition, selection=selection,
+                   state_cov=state_cov)
+
+    assert_allclose(mod['obs_intercept'], obs_intercept)
+    assert_allclose(mod['design'], design)
+    assert_allclose(mod['obs_cov'], obs_cov)
+    assert_allclose(mod['state_intercept'], state_intercept)
+    assert_allclose(mod['transition'], transition)
+    assert_allclose(mod['selection'], selection)
+    assert_allclose(mod['state_cov'], state_cov)
+
+
+def test_init_matrices_time_varying():
+    # Test setting state space system matrices in __init__, with time-varying
+    # matrices
+    nobs = 10
+    k_endog = 2
+    k_states = 3
+    k_posdef = 1
+
+    endog = np.zeros((10, 2))
+    obs_intercept = np.reshape(np.arange(k_endog * nobs) * 1.0,
+                               (k_endog, nobs))
+    design = np.reshape(
+        np.arange(k_endog * k_states * nobs) * 1.0, (k_endog, k_states, nobs))
+    obs_cov = np.reshape(
+        np.arange(k_endog**2 * nobs) * 1.0, (k_endog, k_endog, nobs))
+    state_intercept = np.reshape(
+        np.arange(k_states * nobs) * 1.0, (k_states, nobs))
+    transition = np.reshape(
+        np.arange(k_states**2 * nobs) * 1.0, (k_states, k_states, nobs))
+    selection = np.reshape(
+        np.arange(k_states * k_posdef * nobs) * 1.0,
+        (k_states, k_posdef, nobs))
+    state_cov = np.reshape(
+        np.arange(k_posdef**2 * nobs) * 1.0, (k_posdef, k_posdef, nobs))
+
+    mod = MLEModel(endog, k_states=k_states, k_posdef=k_posdef,
+                   obs_intercept=obs_intercept, design=design,
+                   obs_cov=obs_cov, state_intercept=state_intercept,
+                   transition=transition, selection=selection,
+                   state_cov=state_cov)
+
+    assert_allclose(mod['obs_intercept'], obs_intercept)
+    assert_allclose(mod['design'], design)
+    assert_allclose(mod['obs_cov'], obs_cov)
+    assert_allclose(mod['state_intercept'], state_intercept)
+    assert_allclose(mod['transition'], transition)
+    assert_allclose(mod['selection'], selection)
+    assert_allclose(mod['state_cov'], state_cov)
+
+
 def test_wrapping():
     # Test the wrapping of various Representation / KalmanFilter /
     # KalmanSmoother methods / attributes
diff --git a/statsmodels/tsa/statespace/tests/test_representation.py b/statsmodels/tsa/statespace/tests/test_representation.py
--- a/statsmodels/tsa/statespace/tests/test_representation.py
+++ b/statsmodels/tsa/statespace/tests/test_representation.py
@@ -691,6 +691,79 @@ def test_initialization():
         mod.initialize_known(initial_state, initial_state_cov)
 
 
+def test_init_matrices_time_invariant():
+    # Test setting state space system matrices in __init__, with time-invariant
+    # matrices
+    k_endog = 2
+    k_states = 3
+    k_posdef = 1
+
+    endog = np.zeros((10, 2))
+    obs_intercept = np.arange(k_endog) * 1.0
+    design = np.reshape(
+        np.arange(k_endog * k_states) * 1.0, (k_endog, k_states))
+    obs_cov = np.reshape(np.arange(k_endog**2) * 1.0, (k_endog, k_endog))
+    state_intercept = np.arange(k_states) * 1.0
+    transition = np.reshape(np.arange(k_states**2) * 1.0, (k_states, k_states))
+    selection = np.reshape(
+        np.arange(k_states * k_posdef) * 1.0, (k_states, k_posdef))
+    state_cov = np.reshape(np.arange(k_posdef**2) * 1.0, (k_posdef, k_posdef))
+
+    mod = Representation(endog, k_states=k_states, k_posdef=k_posdef,
+                         obs_intercept=obs_intercept, design=design,
+                         obs_cov=obs_cov, state_intercept=state_intercept,
+                         transition=transition, selection=selection,
+                         state_cov=state_cov)
+
+    assert_allclose(mod['obs_intercept'], obs_intercept)
+    assert_allclose(mod['design'], design)
+    assert_allclose(mod['obs_cov'], obs_cov)
+    assert_allclose(mod['state_intercept'], state_intercept)
+    assert_allclose(mod['transition'], transition)
+    assert_allclose(mod['selection'], selection)
+    assert_allclose(mod['state_cov'], state_cov)
+
+
+def test_init_matrices_time_varying():
+    # Test setting state space system matrices in __init__, with time-varying
+    # matrices
+    nobs = 10
+    k_endog = 2
+    k_states = 3
+    k_posdef = 1
+
+    endog = np.zeros((10, 2))
+    obs_intercept = np.reshape(np.arange(k_endog * nobs) * 1.0,
+                               (k_endog, nobs))
+    design = np.reshape(
+        np.arange(k_endog * k_states * nobs) * 1.0, (k_endog, k_states, nobs))
+    obs_cov = np.reshape(
+        np.arange(k_endog**2 * nobs) * 1.0, (k_endog, k_endog, nobs))
+    state_intercept = np.reshape(
+        np.arange(k_states * nobs) * 1.0, (k_states, nobs))
+    transition = np.reshape(
+        np.arange(k_states**2 * nobs) * 1.0, (k_states, k_states, nobs))
+    selection = np.reshape(
+        np.arange(k_states * k_posdef * nobs) * 1.0,
+        (k_states, k_posdef, nobs))
+    state_cov = np.reshape(
+        np.arange(k_posdef**2 * nobs) * 1.0, (k_posdef, k_posdef, nobs))
+
+    mod = Representation(endog, k_states=k_states, k_posdef=k_posdef,
+                         obs_intercept=obs_intercept, design=design,
+                         obs_cov=obs_cov, state_intercept=state_intercept,
+                         transition=transition, selection=selection,
+                         state_cov=state_cov)
+
+    assert_allclose(mod['obs_intercept'], obs_intercept)
+    assert_allclose(mod['design'], design)
+    assert_allclose(mod['obs_cov'], obs_cov)
+    assert_allclose(mod['state_intercept'], state_intercept)
+    assert_allclose(mod['transition'], transition)
+    assert_allclose(mod['selection'], selection)
+    assert_allclose(mod['state_cov'], state_cov)
+
+
 def test_no_endog():
     # Test for RuntimeError when no endog is provided by the time filtering
     # is initialized.