systems.builtin.stochastic.discrete.DiscreteVAR1
systems.builtin.stochastic.discrete.DiscreteVAR1(*args, **kwargs)Vector Autoregressive process of order 1 - multivariate time series model.
The fundamental model for systems of interrelated time series, combining multiple variables with dynamic cross-effects. This is the discrete-time analog of multivariate Ornstein-Uhlenbeck and the foundation for modern macroeconomic analysis.
Vector Difference Equation
Standard VAR(1) form: X[k] = A·X[k-1] + w[k]
With control: X[k] = A·X[k-1] + B·u[k] + w[k]
where: - X[k] ∈ ℝⁿ: State vector (n time series) - A ∈ ℝⁿˣⁿ: Coefficient matrix (VAR coefficients) - B ∈ ℝⁿˣᵖ: Control matrix (optional) - u[k] ∈ ℝᵖ: Exogenous inputs - w[k] ~ N(0, Σ_w): Vector white noise - Σ_w ∈ ℝⁿˣⁿ: Innovation covariance
Component Equations: X_i[k] = Σⱼ A_ij·X_j[k-1] + w_i[k]
Each variable depends on all lagged variables.
Physical Interpretation
Coefficient Matrix A:
Diagonal elements A_ii: - Own-lag effect (like univariate AR) - Persistence of variable i - Typical: 0.5-0.9 (positive persistence)
Off-diagonal elements A_ij (i ≠ j): - Cross-lag effect (variable j → variable i) - Spillover, contagion, transmission - Can be positive (co-movement) or negative (offset) - Zero: No direct effect (X_j doesn’t Granger-cause X_i)
Example (2D Macro Model): [GDP[k] ] = [a₁₁ a₁₂]·[GDP[k-1] ] + [w₁[k]] [Inflation[k]] [a₂₁ a₂₂] [Inflation[k-1]] [w₂[k]]
Interpretation: - a₁₁: GDP persistence (momentum) - a₁₂: Effect of past inflation on GDP (Phillips curve) - a₂₁: Effect of past GDP on inflation (demand-pull) - a₂₂: Inflation persistence (expectations)
Innovation Covariance Σ_w:
Diagonal elements (Σ_w)_ii: - Variance of idiosyncratic shock to variable i
Off-diagonal elements (Σ_w)_ij: - Contemporaneous correlation between shocks - Common factors affecting multiple variables - Non-zero typical (shocks correlated)
Key Features
Multivariate: n variables modeled jointly (not independently).
Cross-Effects: A_ij captures dynamic interaction (j → i).
Stationarity: All eigenvalues of A inside unit circle: |λ| < 1
Symmetry: A can be asymmetric (feedback loops possible).
Correlated Shocks: Σ_w typically non-diagonal (contemporaneous correlation).
Markov: Future depends only on X[k], not X[k-2], X[k-3], …
Gaussian: If w ~ N(0, Σ_w), then X is multivariate Gaussian.
Mathematical Properties
Eigenvalue Decomposition: A = V·Λ·V⁻¹
Eigenvalues λ_i determine: - Stability: All |λ_i| < 1 required - Time scales: τ_i = -1/ln|λ_i| periods - Oscillations: Im(λ_i) ≠ 0 → cycles
Stationary Covariance:
Discrete Lyapunov: Γ₀ = A·Γ₀·Aᵀ + Σ_w
Numerical solution via: - scipy.linalg.solve_discrete_lyapunov - Bartels-Stewart algorithm - Kronecker form: (I - A⊗A)·vec(Γ₀) = vec(Σ_w)
Impulse Response:
h-step response: Ψ_h = Aʰ
Trace shock propagation through system.
Physical Interpretation
Matrix A Structure:
Full (dense): - All variables interact - n² parameters - Flexible but many parameters
Diagonal: - No cross-effects (independent AR(1)s) - n parameters - Restrictive but parsimonious
Block diagonal: - Groups of interacting variables - Within-group coupling, no between-group - Intermediate complexity
Sparse: - Most A_ij = 0 (network structure) - Few interactions - Common in high-dimensional VARs
State Space
State: X ∈ ℝⁿ - Vector of n time series - Unbounded (Gaussian)
Control: u ∈ ℝᵖ (optional) - Exogenous inputs - Policy variables
Noise: w ∈ ℝⁿ - Vector white noise - Covariance Σ_w (can be correlated)
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| A | (np.ndarray or list, shape(n, n)) | VAR coefficient matrix - Diagonal: Own-lag effects - Off-diagonal: Cross-effects - Eigenvalues must satisfy |λ| < 1 | required |
| Sigma_w | (np.ndarray or list, shape(n, n)) | Innovation covariance matrix - Must be symmetric positive definite - Diagonal: Idiosyncratic variances - Off-diagonal: Contemporaneous correlations | required |
| B | (Optional[np.ndarray], shape(n, p)) | Control/exogenous input matrix | required |
| dt | float | Sampling period (time units) | 1.0 |
Stochastic Properties
- System Type: LINEAR (multivariate AR)
- Noise Type: ADDITIVE (vector white noise)
- Markov: Yes (one lag)
- Stationary: If all |λ(A)| < 1
- Gaussian: If w ~ N(0, Σ_w)
- Dimension: n (number of variables)
Applications
1. Macroeconomics: - GDP, inflation, interest rates - Unemployment, investment, consumption - Fiscal and monetary policy analysis
2. Finance: - Multi-asset portfolios - Volatility spillovers - Market contagion
3. International: - Multi-country models - Trade dynamics - Exchange rates
4. Energy: - Electricity, gas, oil prices - Demand forecasting - Renewable integration
5. Operations: - Multi-product demand - Supply chain dynamics - Inventory systems
Numerical Simulation
Direct Matrix Multiplication: X[k+1] = A @ X[k] + w[k]
Efficient: Use NumPy matrix operations.
Stability Check: Before long simulation, verify eigenvalues inside unit circle.
Granger Causality Testing
Implementation:
Test if X_j → X_i (j Granger-causes i): 1. Restricted model: X_i[k] = a_ii·X_i[k-1] + ε[k] 2. Unrestricted: X_i[k] = a_ii·X_i[k-1] + a_ij·X_j[k-1] + ε[k] 3. F-test: Is a_ij significantly non-zero?
Comparison with Scalar AR
Scalar AR(1): - 1 variable, 1 lag - 1 parameter (φ)
VAR(1): - n variables, 1 lag - n² parameters (A matrix) - Captures interactions
When VAR Essential: - Variables economically related - Spillovers/contagion - Joint forecasting better
Limitations
- Linear dynamics only
- Constant parameters
- Short memory (lag 1 only, extend to VAR(p))
- Many parameters (n² for n variables)
- Curse of dimensionality (high n)
Extensions
- VAR(p): Multiple lags
- VARMA: Add moving average
- SVAR: Structural identification
- BVAR: Bayesian shrinkage (Minnesota prior)
- Factor-Augmented VAR: Handle high dimension
See Also
DiscreteAR1 : Univariate version (n=1) MultivariateOrnsteinUhlenbeck : Continuous-time analog DiscreteARMA11 : Univariate with MA component
Methods
| Name | Description |
|---|---|
| compute_impulse_response | Compute impulse response function. |
| define_system | Define VAR(1) process dynamics. |
| get_eigenvalues | Get eigenvalues of A (determines stability and dynamics). |
| get_innovation_covariance | Get innovation covariance Σ_w. |
| get_stationary_covariance | Compute stationary covariance Γ₀. |
| get_var_matrix | Get VAR coefficient matrix A. |
| test_granger_causality | Test if variable j Granger-causes variable i. |
compute_impulse_response
systems.builtin.stochastic.discrete.DiscreteVAR1.compute_impulse_response(
horizon=20,
)Compute impulse response function.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| horizon | int | Number of periods ahead | 20 |
Returns
| Name | Type | Description |
|---|---|---|
| np.ndarray | IRF tensor (horizon+1, n, n) IRF[h, i, j] = response of variable i to shock in j after h periods |
Examples
>>> var = DiscreteVAR1(A=[[0.8, 0.2], [0.1, 0.7]], Sigma_w=np.eye(2)*0.01)
>>> irf = var.compute_impulse_response(horizon=10)
>>> print(f"Impact of shock to X₁ on X₂ after 5 periods: {irf[5, 1, 0]:.3f}")define_system
systems.builtin.stochastic.discrete.DiscreteVAR1.define_system(
A,
Sigma_w,
B=None,
dt=1.0,
)Define VAR(1) process dynamics.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| A | (np.ndarray or list, shape(n, n)) | VAR coefficient matrix - Diagonal: Own-lag effects (persistence) - Off-diagonal: Cross-lag effects (spillovers) - Must have eigenvalues |λ| < 1 for stationarity | required |
| Sigma_w | (np.ndarray or list, shape(n, n)) | Innovation covariance matrix - Must be symmetric positive definite - Diagonal: Shock variances - Off-diagonal: Shock correlations | required |
| B | (Optional[np.ndarray], shape(n, p)) | Control/exogenous input matrix | None |
| dt | float | Sampling period (e.g., daily, monthly, quarterly) | 1.0 |
Raises
| Name | Type | Description |
|---|---|---|
| ValueError | If dimensions incompatible or Σ_w not positive definite | |
| UserWarning | If eigenvalues of A outside unit circle (non-stationary) |
Notes
Stationarity: Check all eigenvalues of A: |λ_i| < 1
Parameter Count: - VAR coefficients: n² - Covariance: n(n+1)/2 - Total: n² + n(n+1)/2
Example: n=3 → 9 + 6 = 15 parameters!
Granger Causality: X_j Granger-causes X_i if A_ij ≠ 0. Test via F-test on individual coefficients.
Impulse Response: h-step response: Ψ_h = Aʰ Trace shock effects over time.
get_eigenvalues
systems.builtin.stochastic.discrete.DiscreteVAR1.get_eigenvalues()Get eigenvalues of A (determines stability and dynamics).
Returns
| Name | Type | Description |
|---|---|---|
| np.ndarray | Eigenvalues (may be complex) |
Examples
>>> var = DiscreteVAR1(A=[[0.8, 0.1], [0.1, 0.7]],
... Sigma_w=np.eye(2)*0.01)
>>> eigs = var.get_eigenvalues()
>>> print(f"Eigenvalues: {eigs}")get_innovation_covariance
systems.builtin.stochastic.discrete.DiscreteVAR1.get_innovation_covariance()Get innovation covariance Σ_w.
get_stationary_covariance
systems.builtin.stochastic.discrete.DiscreteVAR1.get_stationary_covariance() Compute stationary covariance Γ₀.
Solves: Γ₀ = A·Γ₀·Aᵀ + Σ_w
Returns
np.ndarray
Stationary covariance
Examples
>>> var = DiscreteVAR1(A=[[0.8, 0], [0, 0.7]], Sigma_w=np.eye(2)*0.01)
>>> Gamma = var.get_stationary_covariance()
>>> print(f"Stationary covariance:
{Gamma}“)
get_var_matrix
systems.builtin.stochastic.discrete.DiscreteVAR1.get_var_matrix()Get VAR coefficient matrix A.
test_granger_causality
systems.builtin.stochastic.discrete.DiscreteVAR1.test_granger_causality(i, j)Test if variable j Granger-causes variable i.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| i | int | Target variable index | required |
| j | int | Source variable index | required |
Returns
| Name | Type | Description |
|---|---|---|
| dict | {‘causes’: bool, ‘coefficient’: float} |
Notes
Simple test: Is A_ij ≠ 0?
For rigorous test, need F-statistic from data.
Examples
>>> var = DiscreteVAR1(A=[[0.8, 0.2], [0.0, 0.7]], Sigma_w=np.eye(2)*0.01)
>>> test = var.test_granger_causality(i=0, j=1)
>>> print(f"X₁ causes X₀: {test}") # True (A₀₁ = 0.2)