| Type: | Package |
| Title: | Bayesian Structural VARs with Asymmetric Conjugate Priors |
| Version: | 0.2.0 |
| Description: | Implements Bayesian estimation of structural Vector Autoregressions in the asymmetric A-form of Chan (2022) <doi:10.3982/QE1381>, with an asymmetric Minnesota prior whose own-lag and cross-lag hyperparameters are selected by empirical Bayes via the closed-form marginal likelihood. Exact equation-by-equation posterior simulation in the structural form (independent Normal-Inverse-Gamma draws) provides posterior draws of the reduced-form parameters; structural identification through sign restrictions follows the algorithm of Rubio-Ramirez, Waggoner and Zha (2010) <doi:10.1111/j.1467-937X.2009.00578.x>. Impulse responses, posterior bands, and acceptance diagnostics are computed from the accepted draws. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| Depends: | R (≥ 4.0) |
| Imports: | stats, utils, graphics, grDevices |
| Suggests: | bsvarSIGNs, bsvars, knitr, rmarkdown, testthat (≥ 3.0.0) |
| Config/testthat/edition: | 3 |
| VignetteBuilder: | knitr |
| URL: | https://github.com/ursillofederica/acpbvar |
| BugReports: | https://github.com/ursillofederica/acpbvar/issues |
| Config/roxygen2/version: | 8.1.1 |
| NeedsCompilation: | no |
| Packaged: | 2026-10-20 13:43:47 UTC; federicaursillo |
| Author: | Federica Ursillo [aut, cre] |
| Maintainer: | Federica Ursillo <federica.ursillo@outlook.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-10-31 11:20:08 UTC |
Print, summary and plot methods for acpbvar objects
Description
post_sim() returns an object of class "acpbvar_post",
sign_restrict() an object of class "acpbvar_signs" and
collect_irfs() an object of class "acpbvar_irf". All three remain the
plain list or array documented in the respective function (subsetting an
"acpbvar_irf" with [ gives a plain array); the classes only add the
methods below.
Usage
## S3 method for class 'acpbvar_post'
print(x, ...)
## S3 method for class 'acpbvar_signs'
print(x, ...)
## S3 method for class 'acpbvar_irf'
print(x, ...)
## S3 method for class 'acpbvar_irf'
summary(
object,
horizons = NULL,
probs = c(0.16, 0.5, 0.84),
vars = NULL,
shocks = NULL,
...
)
## S3 method for class 'summary.acpbvar_irf'
print(x, digits = 3, ...)
## S3 method for class 'acpbvar_irf'
plot(x, vars = NULL, shocks = NULL, probs = c(0.16, 0.84), ...)
Arguments
x, object |
An object of the corresponding class. |
... |
For |
horizons |
Integer vector of horizons to summarise (default all). |
probs |
Quantiles to report (summary, default |
vars, shocks |
Variables and shocks to summarise or plot: integer
indices or names. Default |
digits |
Number of digits when printing a summary. |
Value
print methods return their argument invisibly. summary returns
an object of class "summary.acpbvar_irf": a list, one element per
selected shock, each a list of probs x horizons matrices, one per
selected variable. plot returns NULL invisibly.
Examples
sim <- simulate_var_example(T = 120, seed = 1)
mcmc <- post_sim(sim$Y, p = 1L, R = 200L, var_names = sim$var_names)
mcmc
S <- rbind(supply = c(1, -1, 0), demand = c(1, 1, 0), monetary = c(-1, -1, 1))
acc <- sign_restrict(mcmc, S, max_tries = 500L, verbose = FALSE)
acc
irfs <- collect_irfs(acc, n = 3L, p = 1L, H = 8L)
irfs
summary(irfs, vars = "output", shocks = "monetary", horizons = c(0, 4, 8))
plot(irfs, shocks = "monetary", mfrow = c(1, 3))
Build the asymmetric Minnesota prior in A-form
Description
Constructs the per-equation prior means and variances for the structural coefficients of an asymmetric Minnesota prior, as required by the A-form representation. Own-lag, cross-lag, and intercept components have separate tightness hyperparameters; lag decay is quadratic in the lag order.
Usage
build_prior_asym(
y_list,
p,
s2,
kappa1,
kappa2,
kappa3 = 100,
unit_root_mean = FALSE,
elicit = c("structural", "reduced")
)
Arguments
y_list, p, s2 |
As produced by |
kappa1 |
Own-lag tightness (positive scalar). Smaller values pull
own-lag coefficients toward zero (or toward one, under |
kappa2 |
Cross-lag tightness (positive scalar), typically much smaller
than |
kappa3 |
Intercept variance (positive scalar). Default |
unit_root_mean |
Logical; if |
elicit |
Where the Minnesota prior on the lag coefficients is
elicited: |
Value
A list with per-equation prior components:
m_alpha, V_alpha (contemporaneous coefficients),
m_beta, V_beta (intercept and lagged coefficients),
m, V (concatenations used by the conjugate sampler),
nu, S (Inverse-Gamma hyperparameters for the structural variances).
Estimate residual variances from univariate AR fits
Description
For each variable, fits an AR(ar.lags) with intercept by ordinary least
squares and returns the mean of the squared residuals, as in the
replication code of Chan (2022). The resulting variances enter the
asymmetric Minnesota prior as scaling factors. Series too short for the
fit (fewer than ar.lags + 3 observations) get their sample variance.
Usage
build_s2(y_list, ar.lags = 4)
Arguments
y_list |
A list of |
ar.lags |
Integer; order of the univariate autoregression. Default |
Value
A list with elements:
s2Numeric vector of length
n; residual variances.SDiagonal matrix
diag(s2).
Examples
sim <- simulate_var_example(T = 120, seed = 1)
dat <- build_yX(sim$Y, p = 1L)
s2 <- build_s2(dat$y_list)$s2
s2 # AR(4) residual variances, one per variable;
# they scale the Minnesota prior
Build response and regressor matrices for the A-form VAR
Description
Constructs the equation-by-equation response vectors and regressor matrices
required by the asymmetric A-form representation of a structural VAR. For
equation i, the regressors include the lagged values of all variables, an
intercept, and (for i > 1) the contemporaneous values of variables 1
through i - 1 entered with a negative sign, so that the impact matrix is
lower triangular by construction.
Usage
build_yX(Y, p)
Arguments
Y |
A |
p |
The VAR lag order (positive integer). |
Value
A list with the following elements:
y_listA list of length
n;y_list[[i]]is the post-lag response vector for equationi, of lengthTT = T - p.X_listA list of length
n;X_list[[i]]is the regressor matrix for equationi, withTTrows and(i - 1) + 1 + n * pcolumns (contemporaneous block, intercept, lagged variables).nNumber of endogenous variables.
pVAR lag order.
TTEffective sample size after lag truncation.
Examples
sim <- simulate_var_example(T = 120, seed = 1)
dat <- build_yX(sim$Y, p = 1L)
length(dat$y_list) # one response vector per equation
sapply(dat$X_list, ncol) # 4, 5, 6: intercept + n*p lags, plus the
# contemporaneous variables ordered before
# the equation (entered with a minus sign)
Verify a candidate impact matrix against a sign-restriction pattern
Description
Checks whether the column k of the candidate impact matrix satisfies the
sign pattern S[k, ], for k = 1, ..., n_id. Entries of S equal to +1,
-1, or 0 denote respectively a positive, negative, or unrestricted sign
for the corresponding variable response.
Usage
check_sign(impact, S, n_id, tol = 1e-12)
Arguments
impact |
The candidate |
S |
An |
n_id |
Integer; number of identified shocks (defaults to |
tol |
Numeric tolerance below which violations are ignored. |
Value
TRUE if the candidate satisfies the restrictions, otherwise
FALSE.
Collect impulse responses across accepted draws
Description
Loops compute_irf() over the list of accepted rotations returned by
sign_restrict() and stacks the resulting impulse-response arrays along a
fourth dimension indexing the draw.
Usage
collect_irfs(accepted, n, p, H)
Arguments
accepted |
The list of accepted draws returned by |
n, p, H |
As in |
Value
An object of class "acpbvar_irf": a four-dimensional array of
dimension n x (H + 1) x n x n_accepted (variable x horizon x shock x
draw), with variable and shock names as dimnames, and print,
summary and plot methods. Subsetting with [ returns a plain array.
Examples
sim <- simulate_var_example(T = 120, seed = 1)
mcmc <- post_sim(sim$Y, p = 1L, R = 200L)
S <- rbind(c(1, -1, 0), c(1, 1, 0), c(-1, -1, 1))
acc <- sign_restrict(mcmc, S, max_tries = 500L, verbose = FALSE)
irfs <- collect_irfs(acc, n = 3L, p = 1L, H = 8L)
dim(irfs) # variable x horizon x shock x accepted draw
# Posterior median and 68% band of variable 1 to shock 3, horizons 0..8
apply(irfs[1, , 3, ], 1, quantile, probs = c(0.16, 0.5, 0.84))
Compute structural impulse responses for a single draw
Description
Computes the structural impulse responses at horizons 0, ..., H for the
given impact matrix and reduced-form coefficient matrix, through the VMA
recursion on the n x n lag matrices.
Usage
compute_irf(impact, B_rf, n, p, H)
Arguments
impact |
The |
B_rf |
Reduced-form coefficient matrix as returned by |
n, p |
Number of variables and VAR lag order. |
H |
Maximum impulse-response horizon. |
Value
A three-dimensional array of dimension n x (H + 1) x n, indexed
by [variable, horizon, shock].
Examples
sim <- simulate_var_example(T = 120, seed = 1)
mcmc <- post_sim(sim$Y, p = 1L, R = 50L)
S <- rbind(c(1, -1, 0), c(1, 1, 0), c(-1, -1, 1))
acc <- sign_restrict(mcmc, S, max_tries = 500L, verbose = FALSE)
irf1 <- compute_irf(acc[[1]]$impact, acc[[1]]$B_rf, n = 3L, p = 1L, H = 8L)
dim(irf1) # variable x horizon (0..H) x shock
irf1[1, , 3] # response of variable 1 to shock 3 over horizons
Single-equation Normal-Inverse-Gamma posterior draw
Description
Draws one value of the structural variance and of the coefficient vector
of a single equation from their joint Normal-Inverse-Gamma posterior,
using the quantities precomputed by posterior_eq(): sigma^2 from its
marginal inverse-gamma posterior, then theta | sigma^2 from the
conditional normal through the stored Cholesky factor (no inversion).
Usage
draw(post)
Arguments
post |
The list returned by |
Value
A list with sigma2 and theta.
Equation-by-equation posterior draw
Description
Loops draw() across all equations and collects the per-equation posterior
draws into list/vector containers.
Usage
draw_all(post_list)
Arguments
post_list |
List with one element per equation, each produced by
|
Value
A list with sigma2 (numeric vector of length n) and theta
(list of length n of coefficient vectors).
Closed-form log marginal likelihood under the asymmetric Minnesota prior
Description
Returns the log marginal likelihood of the data under the asymmetric A-form prior, exploiting Normal-Inverse-Gamma conjugacy equation by equation. The computation reuses the Cholesky factor of the posterior precision matrix to avoid forming explicit matrix inverses, and accumulates the per-equation contributions into the joint log marginal likelihood.
Usage
log_mlik_asym(
y_list,
X_list,
p,
s2,
kappa1,
kappa2,
kappa3 = 100,
unit_root_mean = FALSE,
elicit = c("structural", "reduced")
)
Arguments
y_list, p, s2 |
As produced by |
X_list |
Per-equation regressor matrices as produced by |
kappa1 |
Own-lag tightness (positive scalar). Smaller values pull
own-lag coefficients toward zero (or toward one, under |
kappa2 |
Cross-lag tightness (positive scalar), typically much smaller
than |
kappa3 |
Intercept variance (positive scalar). Default |
unit_root_mean |
Logical; if |
elicit |
Where the Minnesota prior on the lag coefficients is
elicited: |
Value
Numeric scalar, the joint log marginal likelihood.
Empirical Bayes selection of Minnesota prior tightness
Description
Selects the own-lag and cross-lag tightness parameters
(\kappa_1, \kappa_2) by maximising the closed-form log marginal
likelihood. Optimisation is performed by Nelder-Mead in log-space, with the
transformation kappa = exp(log_kappa) ensuring positivity. The marginal
likelihood is evaluated under the prior selected by elicit, so that the
tightness is optimised for the prior actually used in estimation.
Usage
optim_hyper(
y_list,
X_list,
p,
s2,
kappa3 = 100,
unit_root_mean = FALSE,
elicit = c("structural", "reduced"),
init = c(0.04, 0.004)
)
Arguments
y_list, p, s2 |
As produced by |
X_list |
Per-equation regressor matrices as produced by |
kappa3 |
Intercept variance (positive scalar). Default |
unit_root_mean |
Logical; if |
elicit |
Where the Minnesota prior on the lag coefficients is
elicited: |
init |
Numeric vector of length 2; starting values for
|
Value
A list with kappa1, kappa2, the optimised log_ml, and the
convergence code returned by stats::optim().
Examples
sim <- simulate_var_example(T = 120, seed = 1)
dat <- build_yX(sim$Y, p = 1L)
s2 <- build_s2(dat$y_list)$s2
opt <- optim_hyper(dat$y_list, dat$X_list, p = 1L, s2 = s2)
opt$kappa1 # own-lag tightness (larger = looser)
opt$kappa2 # cross-lag tightness, usually much smaller
opt$convergence # 0 means the optimiser converged
Plot posterior impulse responses with credible bands
Description
Produces a grid of base-R plots displaying the posterior median impulse
response of each selected variable to each selected shock, together with a
shaded credible band defined by the quantiles in probs. A second set of
responses (ref), for example from another package or the true responses
of a simulated process, can be overlaid for comparison.
Usage
plot_irfs(
irfs,
vars = NULL,
shocks = NULL,
var_names = NULL,
shock_names = NULL,
probs = c(0.16, 0.84),
ref = NULL,
col_med = "black",
col_band = "steelblue",
col_ref = "black",
alpha_band = 0.3,
xlab = "",
ylab = "",
main_cex = 0.9,
mfrow = NULL
)
Arguments
irfs |
A four-dimensional array of impulse responses as returned by
|
vars, shocks |
Which variables and shocks to plot: integer indices or
names matching the dimnames of |
var_names |
Optional character vector of variable names of length
|
shock_names |
Optional character vector of shock names of length
|
probs |
Two-element numeric vector of quantiles for the credible
band. Default |
ref |
Optional responses to overlay (dashed median, dotted band at
the same |
col_med |
Colour of the posterior median line. Default |
col_band |
Colour of the credible band. Default |
col_ref |
Colour of the overlaid responses. Default |
alpha_band |
Transparency of the credible band. Default |
xlab, ylab |
Axis labels. Defaults |
main_cex |
Scaling factor for panel titles. Default |
mfrow |
Panel layout passed to |
Value
Called for its side effect (a grid of base-R plots). Invisibly
returns NULL.
Examples
sim <- simulate_var_example(T = 120, seed = 1)
mcmc <- post_sim(sim$Y, p = 1L, R = 200L)
S <- rbind(supply = c(1, -1, 0), demand = c(1, 1, 0), monetary = c(-1, -1, 1))
acc <- sign_restrict(mcmc, S, max_tries = 500L, verbose = FALSE)
irfs <- collect_irfs(acc, n = 3L, p = 1L, H = 8L)
plot_irfs(irfs, probs = c(0.16, 0.84)) # all panels, 68% band
plot_irfs(irfs, shocks = "monetary", mfrow = c(1, 3)) # one shock, one row
# overlay the true responses of the simulated process
irf_true <- compute_irf(sim$impact_true, cbind(sim$intercept_true, sim$B_true),
n = 3L, p = 1L, H = 8L)
plot_irfs(irfs, ref = array(irf_true, c(dim(irf_true), 1)))
Posterior simulation for the asymmetric A-form BVAR
Description
End-to-end wrapper: prepares the equation-by-equation responses and
regressors, fits univariate AR variance estimates, optimises the Minnesota
tightness via Empirical Bayes, constructs the asymmetric prior, and runs
draws R independent posterior samples, equation by equation.
Usage
post_sim(
Y,
p,
R,
kappa3 = 100,
unit_root_mean = FALSE,
elicit = c("structural", "reduced"),
var_names = NULL,
seed = NULL
)
Arguments
Y |
A |
p |
VAR lag order. |
R |
Number of posterior draws to retain. |
kappa3 |
Intercept prior variance, passed to |
unit_root_mean |
Logical; whether to centre the first own-lag prior
at one. Default |
elicit |
Where the Minnesota prior on the lag coefficients is
elicited: |
var_names |
Optional character vector of variable names of length
|
seed |
Optional integer seed passed to |
Value
An object of class "acpbvar_post" (a list with print method) with samples (the posterior draws of theta and
sigma2), spec (sampler configuration, optimised tightness, log
marginal likelihood, the convergence code returned by stats::optim()
for the hyperparameter search, residual variances, variable names), and dat
(the prepared response/regressor objects).
Examples
sim <- simulate_var_example(T = 120, seed = 1)
mcmc <- post_sim(sim$Y, p = 1L, R = 200L)
mcmc$spec$kappa # tightness chosen by Empirical Bayes
mcmc$spec$convergence # 0 = optimiser converged
dim(mcmc$samples$sigma2) # R draws x n equations
length(mcmc$samples$theta) # R draws, each a list of n coefficient vectors
Posterior quantities of one equation
Description
Computes, once per equation, everything the Normal-Inverse-Gamma posterior
needs: the Cholesky factor of the posterior precision, the posterior mean
of the coefficient vector, and the parameters of the inverse-gamma
posterior of the variance. None of these depends on the draw, so they are
computed once and reused by draw() for every posterior draw.
Usage
posterior_eq(y, X, nu, m, V, S)
Arguments
y |
Response vector for the equation. |
X |
Regressor matrix for the equation. |
nu |
Shape hyperparameter of the prior on |
m |
Prior mean of the structural coefficient vector. |
V |
Diagonal of the prior covariance of the structural coefficient vector (passed as a numeric vector of prior variances). |
S |
Scale hyperparameter of the prior on |
Value
A list with UK (upper Cholesky factor of the posterior
precision), theta_hat (posterior mean), S_post and nu_post
(inverse-gamma posterior parameters).
Recover reduced-form quantities from a structural A-form draw
Description
Given a posterior draw of the structural coefficients and variances,
reconstructs the contemporaneous impact matrix A, its inverse, the
reduced-form coefficient matrix B_rf = A^{-1} B_struct, and the reduced-
form innovation covariance Sigma_rf = A^{-1} diag(sigma2) A^{-1}'.
Usage
recover_rf(theta_draw, sigma2_draw)
Arguments
theta_draw |
A list of length |
sigma2_draw |
Numeric vector of length |
Value
A list with A, A_inv, B_struct, B_rf, and Sigma_rf.
Examples
sim <- simulate_var_example(T = 120, seed = 1)
mcmc <- post_sim(sim$Y, p = 1L, R = 50L)
rf <- recover_rf(mcmc$samples$theta[[1]], mcmc$samples$sigma2[1, ])
rf$A # lower triangular, ones on the diagonal
rf$B_rf # reduced-form intercept and lag coefficients
rf$Sigma_rf # reduced-form innovation covariance
Structural identification via sign restrictions (RRWZ algorithm)
Description
Implements the Rubio-Ramirez, Waggoner and Zha (2010, Theorem 9)
rotation algorithm for sign-restriction identification. For each retained
posterior draw of the reduced form, candidate rotations Q are drawn from
the Haar measure (via QR decomposition of a standard normal matrix, with
sign normalisation on the diagonal of R); for each candidate, all
2^n_id sign flips on the columns are checked against the restrictions,
and the first accepted rotation is stored.
Usage
sign_restrict(
mcmc,
S,
n_id = nrow(S),
horizons = 0L,
method = c("per_draw", "joint"),
max_tries = 10000,
verbose = TRUE
)
Arguments
mcmc |
A posterior object produced by |
S |
Sign restrictions, with entries |
n_id |
Number of identified shocks (defaults to |
horizons |
Non-negative integer. Sign restrictions are imposed on the
impulse responses at horizons |
method |
|
max_tries |
Maximum number of |
verbose |
Logical; print a progress bar and acceptance summary. |
Value
A list of length equal to the number of accepted draws; each entry
contains draw_id, impact, Q, B_rf, Sigma_rf.
The result carries two attributes: "n_tries", the number of Q
candidates needed for each accepted draw, and "failed_draws", the
indices of the posterior draws dropped after max_tries.
Examples
sim <- simulate_var_example(T = 120, seed = 1)
mcmc <- post_sim(sim$Y, p = 1L, R = 100L)
# Rows: identified shocks. Columns: variables (output, inflation, rate).
# +1 / -1 restrict the sign of the impact response, 0 leaves it free.
S <- rbind(supply = c( 1, -1, 0),
demand = c( 1, 1, 0),
monetary = c(-1, -1, 1))
acc <- sign_restrict(mcmc, S, max_tries = 500L, verbose = FALSE)
length(acc) # accepted draws (one rotation each)
acc[[1]]$impact # impact matrix of the first draw
summary(attr(acc, "n_tries")) # rotations screened per acceptance;
# compare the max with max_tries
attr(acc, "failed_draws") # draws dropped after max_tries
# Partial identification: two shocks, the third column is left free
S2 <- S[1:2, ]
acc2 <- sign_restrict(mcmc, S2, max_tries = 500L, verbose = FALSE)
# Same signs imposed on impact and on the next horizon (Uhlig 2005 uses
# several): more demanding, so more rotations are screened per draw
acc3 <- sign_restrict(mcmc, S, horizons = 1L, max_tries = 1000L, verbose = FALSE)
summary(attr(acc3, "n_tries"))
# Different signs at different horizons: one matrix per horizon
A <- array(0, c(3, 3, 3))
A[, , 1] <- S # impact: full pattern
A[3, 3, 2] <- 1 # h = 1: interest rate still up after a monetary shock
A[1, 1, 3] <- 1 # h = 2: output still up after a supply shock
accA <- sign_restrict(mcmc, A, horizons = 2L, max_tries = 2000L, verbose = FALSE)
Simulate a small structural VAR with known sign restrictions
Description
Generates a three-variable structural VAR(1) calibrated to deliver impulse responses with the canonical macroeconomic sign pattern: a positive supply shock raises output and lowers inflation; a positive demand shock raises both output and inflation; a positive monetary-policy shock lowers output and inflation while raising the interest rate. The function returns the simulated sample together with the true structural impact matrix and the true reduced-form coefficients, so that recovery can be validated against the data-generating process.
Usage
simulate_var_example(T = 200, seed = NULL)
Arguments
T |
Integer; number of post-burn-in observations to return.
Default |
seed |
Optional integer seed passed to |
Details
The simulation discards a burn-in of 100 observations to wash out the influence of the zero initial condition.
Value
A list with the following elements:
YT x 3matrix of simulated observations on output, inflation, and the interest rate.impact_trueThe
3 x 3structural impact matrix used in the DGP; columns index shocks (supply, demand, monetary).B_trueThe
3 x 3reduced-form coefficient matrix on the first lag.intercept_trueThe
3-vector of intercepts in the DGP.var_namesVariable names.
shock_namesShock names corresponding to the columns of
impact_true.
Examples
sim <- simulate_var_example(T = 200, seed = 42)
head(sim$Y)
sim$impact_true