| Title: | Transmission Channel Analysis in Structural VAR Models |
|---|---|
| Description: | Implements Transmission Channel Analysis (TCA) for structural vector autoregressive (SVAR) models following the methodology of Wegner, Lieb, Smeekes and Wilms (2025) <doi:10.48550/arXiv.2405.18987>. TCA decomposes impulse response functions (IRFs) into contributions from distinct transmission channels using a systems form representation and directed acyclic graph (DAG) path analysis. Supports overlapping channels, exhaustive 3-way and 4-way decompositions via inclusion-exclusion principle. This is a parallel R implementation of the 'tca-matlab-toolbox' (<https://github.com/enweg/tca-matlab-toolbox>). |
| Authors: | Muhammad Alkhalaf [aut, cre] (ORCID: <https://orcid.org/0009-0002-2677-9246>), Enrico Wegner [ctb] (Author of the MATLAB TCA toolbox the package is ported from; co-author of the original methodology), Lenard Lieb [ctb] (Original methodology), Stephan Smeekes [ctb] (Original methodology), Ines Wilms [ctb] (Original methodology) |
| Maintainer: | Muhammad Alkhalaf <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.0.3 |
| Built: | 2026-11-01 08:30:31 UTC |
| Source: | https://github.com/muhammedalkhalaf/svartca |
The SVARtca package implements Transmission Channel Analysis (TCA) for decomposing impulse response functions in structural vector autoregressive (SVAR) models. The package follows the methodology presented in Wegner, Lieb, Smeekes and Wilms (2025).
TCA enables researchers to decompose the total impulse response to a shock into contributions from different transmission channels. Supported channels include effects passing through specific intermediate variables, allowing analysts to distinguish direct effects from indirect effects that operate through identified transmission mechanisms.
Key features:
Multiple decomposition modes: overlapping, exhaustive 3-way, and exhaustive 4-way.
Support for VAR and SVAR models via integration with the vars package.
Visualization of channel contributions using ggplot2.
Diagnostic tools for validating decomposition accuracy.
tca_systems_formBuild the systems form representation (B and Omega matrices) from VAR coefficients and structural impact matrix.
tca_analyzeRun the main TCA analysis with specified decomposition mode.
tca_decompose_binaryDecompose IRF into "through" and "not_through" components for a single variable.
tca_validate_additivityValidate that the binary decomposition satisfies exact additivity.
tca_from_varConvenience wrapper to run TCA directly from a fitted VAR model object.
plot_tcaCreate publication-quality visualizations of channel contributions.
The package supports two identification schemes:
Cholesky: Lower-triangular Cholesky decomposition of the
residual covariance matrix. Set Phi0 = t(chol(Sigma)).
Manual: User-supplied structural impact matrix for alternative identifications (e.g., sign restrictions, zero restrictions).
If you use the SVARtca package in your research, please cite the original methodology paper:
Wegner, E., Lieb, L., Smeekes, S. and Wilms, I. (2025). Transmission Channel Analysis in Dynamic Models. arXiv:2405.18987, doi:10.48550/arXiv.2405.18987. https://github.com/enweg/tca-matlab-toolbox
Muhammad Alkhalaf
Wegner, E., Lieb, L., Smeekes, S. and Wilms, I. (2025). Transmission Channel Analysis in Dynamic Models. arXiv:2405.18987, doi:10.48550/arXiv.2405.18987.
Creates a stacked bar chart (for exhaustive modes) or a line chart (for overlapping mode) showing channel contributions over horizons.
plot_tca(x, target = NULL, type = NULL, title = NULL, colors = NULL)plot_tca(x, target = NULL, type = NULL, title = NULL, colors = NULL)
x |
A |
target |
Integer index of the response variable to plot (default: first variable after shock). |
type |
Plot type: |
title |
Custom plot title (optional). |
colors |
Named character vector of colours for channels (optional). |
A ggplot object.
K <- 4 A1 <- matrix(c(0.7,-0.1,0.05,-0.05, -0.3,0.6,0.10,-0.10, -0.2,0.1,0.70,0.05, -0.1,0.2,0.05,0.65), K, K, byrow=TRUE) Sigma <- matrix(c(1,0.3,0.2,0.1, 0.3,1.5,0.25,0.15, 0.2,0.25,0.8,0.1, 0.1,0.15,0.1,0.6), K, K, byrow=TRUE) Phi0 <- t(chol(Sigma)) sf <- tca_systems_form(Phi0, list(A1), h = 20) res <- tca_analyze(from = 1, B = sf$B, Omega = sf$Omega, intermediates = c(2, 4), K = K, h = 20, order = 1:K, mode = "exhaustive_4way", var_names = c("IntRate","GDP","Inflation","Wages")) plot_tca(res, target = 3)K <- 4 A1 <- matrix(c(0.7,-0.1,0.05,-0.05, -0.3,0.6,0.10,-0.10, -0.2,0.1,0.70,0.05, -0.1,0.2,0.05,0.65), K, K, byrow=TRUE) Sigma <- matrix(c(1,0.3,0.2,0.1, 0.3,1.5,0.25,0.15, 0.2,0.25,0.8,0.1, 0.1,0.15,0.1,0.6), K, K, byrow=TRUE) Phi0 <- t(chol(Sigma)) sf <- tca_systems_form(Phi0, list(A1), h = 20) res <- tca_analyze(from = 1, B = sf$B, Omega = sf$Omega, intermediates = c(2, 4), K = K, h = 20, order = 1:K, mode = "exhaustive_4way", var_names = c("IntRate","GDP","Inflation","Wages")) plot_tca(res, target = 3)
S3 print method for tca_result objects. Displays a formatted
table of transmission channel contributions across horizons.
## S3 method for class 'tca_result' print(x, target = NULL, ...)## S3 method for class 'tca_result' print(x, target = NULL, ...)
x |
A |
target |
Integer index (original ordering) of the response variable
to display. Default |
... |
Additional arguments (ignored). |
Invisibly returns x.
Decomposes impulse response functions into transmission channel contributions using the methodology of Wegner, Lieb, Smeekes and Wilms (2025), doi:10.48550/arXiv.2405.18987.
Three decomposition modes are supported:
"overlapping"Each channel is through(j) = total - not_through(j). Channels may overlap, so their sum may differ from the total.
"exhaustive_3way"(2 intermediates only) Non-overlapping: (1) through var1 inclusive, (2) through var2 only, (3) direct. Sum equals total.
"exhaustive_4way"(2 intermediates only) Full inclusion-exclusion: (1) var1 only, (2) var2 only, (3) both, (4) direct. Sum equals total.
tca_analyze(from, B, Omega, intermediates, K, h, order, mode = "overlapping", var_names = NULL)tca_analyze(from, B, Omega, intermediates, K, h, order, mode = "overlapping", var_names = NULL)
from |
Shock variable number (1-based). |
B |
Systems form B matrix (from |
Omega |
Systems form Omega matrix. |
intermediates |
Integer vector of intermediate variable numbers (1-based, original ordering). |
K |
Number of variables. |
h |
Maximum horizon. |
order |
Transmission ordering vector. |
mode |
Decomposition mode: |
var_names |
Character vector of variable names (optional). |
A list of class "tca_result" with components:
Matrix (h+1) x K of total IRFs.
Named list of channel IRF matrices, each (h+1) x K.
Character vector of channel names.
Decomposition mode used.
Shock variable number.
Number of variables.
Maximum horizon.
Transmission ordering.
Variable names.
Wegner, E., Lieb, L., Smeekes, S. and Wilms, I. (2025). Transmission Channel Analysis in Dynamic Models. arXiv:2405.18987, doi:10.48550/arXiv.2405.18987.
# Monetary policy model K <- 4 A1 <- matrix(c(0.7,-0.1,0.05,-0.05, -0.3,0.6,0.10,-0.10, -0.2,0.1,0.70,0.05, -0.1,0.2,0.05,0.65), K, K, byrow=TRUE) Sigma <- matrix(c(1,0.3,0.2,0.1, 0.3,1.5,0.25,0.15, 0.2,0.25,0.8,0.1, 0.1,0.15,0.1,0.6), K, K, byrow=TRUE) Phi0 <- t(chol(Sigma)) sf <- tca_systems_form(Phi0, list(A1), h = 20) result <- tca_analyze(from = 1, B = sf$B, Omega = sf$Omega, intermediates = c(2, 4), K = K, h = 20, order = 1:K, mode = "exhaustive_4way", var_names = c("IntRate","GDP","Inflation","Wages")) print(result)# Monetary policy model K <- 4 A1 <- matrix(c(0.7,-0.1,0.05,-0.05, -0.3,0.6,0.10,-0.10, -0.2,0.1,0.70,0.05, -0.1,0.2,0.05,0.65), K, K, byrow=TRUE) Sigma <- matrix(c(1,0.3,0.2,0.1, 0.3,1.5,0.25,0.15, 0.2,0.25,0.8,0.1, 0.1,0.15,0.1,0.6), K, K, byrow=TRUE) Phi0 <- t(chol(Sigma)) sf <- tca_systems_form(Phi0, list(A1), h = 20) result <- tca_analyze(from = 1, B = sf$B, Omega = sf$Omega, intermediates = c(2, 4), K = K, h = 20, order = 1:K, mode = "exhaustive_4way", var_names = c("IntRate","GDP","Inflation","Wages")) print(result)
Decomposes the total IRF into the effect passing through a variable
and the effect not passing through it. The not-through effect is
obtained by blocking every node of the variable (NOT condition) and the
through effect is defined as total - not_through, so the three
matrices satisfy total = through + not_through by construction.
Use tca_validate_additivity to check the decomposition
against an independent computation of the through effect.
tca_decompose_binary(from, B, Omega, var_idx, K, h, order)tca_decompose_binary(from, B, Omega, var_idx, K, h, order)
from |
Shock variable (1-based). |
B |
Systems form B matrix. |
Omega |
Systems form Omega matrix. |
var_idx |
Variable to decompose through (1-based). |
K |
Number of variables. |
h |
Maximum horizon. |
order |
Transmission ordering. |
A list with matrices total, through,
not_through (each (h+1) x K).
Extracts coefficient matrices and residual covariance from a fitted VAR model (from the vars package) and runs TCA.
tca_from_var(var_model, from, intermediates, h = 20, order = NULL, mode = "overlapping", identification = "cholesky", Phi0 = NULL)tca_from_var(var_model, from, intermediates, h = 20, order = NULL, mode = "overlapping", identification = "cholesky", Phi0 = NULL)
var_model |
A fitted VAR model object from |
from |
Shock variable (integer or name). |
intermediates |
Integer vector or character vector of intermediate variable names. |
h |
Maximum horizon (default: 20). |
order |
Transmission ordering (default: variable ordering in the VAR). |
mode |
Decomposition mode: |
identification |
Identification scheme: |
Phi0 |
Manual impact matrix. Required if |
A tca_result object (see tca_analyze).
library(vars) data(Canada) var_est <- VAR(Canada, p = 2, type = "const") result <- tca_from_var(var_est, from = "e", intermediates = c("prod", "rw"), h = 20, mode = "exhaustive_4way") plot_tca(result, target = "U")library(vars) data(Canada) var_est <- VAR(Canada, p = 2, type = "const") result <- tca_from_var(var_est, from = "e", intermediates = c("prod", "rw"), h = 20, mode = "exhaustive_4way") plot_tca(result, target = "U")
Constructs both B and Omega matrices for the systems form representation x = Bx + Omega*epsilon, following the methodology of Wegner, Lieb, Smeekes and Wilms (2025).
tca_systems_form(Phi0, As, h, order = NULL, Psis = NULL)tca_systems_form(Phi0, As, h, order = NULL, Psis = NULL)
Phi0 |
Structural impact matrix (K x K). For Cholesky
identification, use |
As |
List of VAR coefficient matrices (A_1, A_2, ..., A_p). |
h |
Maximum IRF horizon. |
order |
Transmission ordering vector (default: |
Psis |
Optional list of reduced-form MA coefficient matrices
(Psi_1, ..., Psi_q), each K x K, for VARMA or DSGE models. See
Details. Default |
Note on Psis. For a pure VAR or SVAR model leave
Psis at its default (NULL, treated as an empty list): the
moving-average dynamics are generated by (I - B)^{-1}. Only
VARMA or DSGE models with a moving-average component pass Psis.
The matrices in Psis must be the reduced-form MA
coefficient matrices, that is, the coefficients on the lagged
reduced-form errors u_t = Phi0 %*% epsilon_t in
y_t = A_1 y_{t-1} + ... + u_t + Psi_1 u_{t-1} + .... If the model
is written with structural MA matrices on the structural shocks,
y_t = ... + Phi0 %*% (epsilon_t + Psi^s_1 epsilon_{t-1} + ...),
convert them first: Psi_j = Phi0 %*% Psi^s_j %*% solve(Phi0).
Passing the structural matrices directly gives wrong impulse responses
at horizons 1 and above, because makeOmega_systems multiplies
each Psi_j by Phi0 on the right, so that
Psi_j %*% Phi0 is the horizon-j structural MA coefficient.
A list with components:
Systems form B matrix (K*(h+1) x K*(h+1)).
Systems form Omega matrix (K*(h+1) x K*(h+1)).
Wegner, E., Lieb, L., Smeekes, S. and Wilms, I. (2025). Transmission Channel Analysis in Dynamic Models. arXiv:2405.18987, doi:10.48550/arXiv.2405.18987. https://github.com/enweg/tca-matlab-toolbox
# 2-variable VAR(1) Phi0 <- matrix(c(1, 0.3, 0, 0.95), 2, 2) As <- list(matrix(c(0.5, -0.1, 0.2, 0.4), 2, 2)) sf <- tca_systems_form(Phi0, As, h = 10) dim(sf$B) # 22 x 22# 2-variable VAR(1) Phi0 <- matrix(c(1, 0.3, 0, 0.95), 2, 2) As <- list(matrix(c(0.5, -0.1, 0.2, 0.4), 2, 2)) sf <- tca_systems_form(Phi0, As, h = 10) dim(sf$B) # 22 x 22
Checks Theorem 2(ii) of Wegner, Lieb, Smeekes and Wilms (2025): the
effects of disjoint transmission channels sum to the total effect.
For every variable j, the effect of the paths passing through
j (at any horizon) is computed independently of the identity
through = total - not_through, by partitioning those paths by the
first node of j they visit and summing the AND-conditioned
effects of the parts (see tca_analyze for the AND and NOT
conditions). This independent through effect plus the NOT-conditioned
not-through effect is then compared with the total effect. The residual
is evaluated at all response variables other than j itself,
because the AND condition sets the effect on the conditioning node to
zero while the effect on j counts entirely as "through j"
in the total - not_through convention.
If pair is given, the inclusion-exclusion identity used by the
"exhaustive_4way" mode of tca_analyze,
through(v1 and v2) = through(v1) + through(v2) - through(v1 or v2),
is also checked: the left-hand side is computed directly with AND
conditions on both variables (a double first-passage sum of
(h+1)^2 linear solves, so keep h moderate), the right-hand
side from the independent single-variable through effects and
total - not_through(v1, v2). The residual is evaluated at all
response variables other than v1 and v2.
The function also reports whether B is strictly lower triangular
(entries on and above the diagonal at most 1e-12 times the
largest absolute entry), which the systems form requires for the graph
to be acyclic. Before
version 1.0.3 the residual was computed as
total - ((total - not_through) + not_through), which is zero by
construction and could not detect any error.
tca_validate_additivity(from, B, Omega, K, h, order, var_names = NULL, verbose = TRUE, pair = NULL, tol = 1e-10)tca_validate_additivity(from, B, Omega, K, h, order, var_names = NULL, verbose = TRUE, pair = NULL, tol = 1e-10)
from |
Shock variable (1-based). |
B |
Systems form B matrix. |
Omega |
Systems form Omega matrix. |
K |
Number of variables. |
h |
Maximum horizon. |
order |
Transmission ordering. |
var_names |
Character vector of variable names (optional). |
verbose |
Logical; print results? Default |
pair |
Optional integer vector of two distinct variable numbers (1-based) for which the inclusion-exclusion identity is checked. |
tol |
Tolerance for the maximum absolute residual. Default
|
Invisibly returns a logical, TRUE if B is strictly
lower triangular and every residual is below tol, with
attributes residuals (named numeric vector, the maximum absolute
additivity residual for each variable), pair_residual (the
maximum absolute inclusion-exclusion residual, or NA if
pair is NULL), max_residual (the largest of these)
and lower_triangular (logical).
Wegner, E., Lieb, L., Smeekes, S. and Wilms, I. (2025). Transmission Channel Analysis in Dynamic Models. arXiv:2405.18987, doi:10.48550/arXiv.2405.18987.
Phi0 <- matrix(c(1, 0.3, 0, 0.95), 2, 2) As <- list(matrix(c(0.5, -0.1, 0.2, 0.4), 2, 2)) sf <- tca_systems_form(Phi0, As, h = 5) ok <- tca_validate_additivity(1, sf$B, sf$Omega, K = 2, h = 5, order = 1:2, pair = c(1, 2)) attr(ok, "max_residual") # A backward edge breaks the acyclic structure and is detected Bc <- sf$B; Bc[1, 4] <- 0.2 tca_validate_additivity(1, Bc, sf$Omega, K = 2, h = 5, order = 1:2)Phi0 <- matrix(c(1, 0.3, 0, 0.95), 2, 2) As <- list(matrix(c(0.5, -0.1, 0.2, 0.4), 2, 2)) sf <- tca_systems_form(Phi0, As, h = 5) ok <- tca_validate_additivity(1, sf$B, sf$Omega, K = 2, h = 5, order = 1:2, pair = c(1, 2)) attr(ok, "max_residual") # A backward edge breaks the acyclic structure and is detected Bc <- sf$B; Bc[1, 4] <- 0.2 tca_validate_additivity(1, Bc, sf$Omega, K = 2, h = 5, order = 1:2)