Moving from bvartools 0.3.0 to 1.0.0

What this release is for

Version 0.3.0 is a transition release. It is the functionality of bvartools as it has been on CRAN, with a small number of correctness fixes, and it is the last version before 1.0.0 reorganises the package around a different set of functions.

Nothing in this release stops working. What it adds is a message: the first time in a session that you use a function which 1.0.0 does not have any more, bvartools says so and names what takes its place. Upgrading to this release is therefore a way to find out what a later upgrade to 1.0.0 will cost you, while everything still runs.

The messages are shown once per function per session. To switch them off:

options(bvartools.transition.messages = FALSE)

Renamed functions

These do the same thing under a new name. The arguments are unchanged.

0.3.0 1.0.0
gen_var() create_bvarmodel()
gen_vec() create_bvecmodel()
bvec_to_bvar() vec_to_var()
kalman_dk() kalman_durbin_koopman_2002()
stochvol_ksc1998() stochvol_ksc_1998()
stochvol_ocsn2007() stochvol_ocsn_2007()
stoch_vol() stochvol_ksc_1998()
bvs() post_bvs()

stoch_vol() was a wrapper for the algorithm of Kim, Shephard and Chib (1998), which stochvol_ksc_1998() implements directly, so the wrapper has no separate successor.

A changed workflow for posterior simulation

draw_posterior(), bvarpost() and bvecpost() are replaced by a sequence of functions, each of which adds one thing to the model object. Where 0.3.0 has

object <- gen_var(data, p = 2, deterministic = "const")
object <- add_priors(object)
object <- draw_posterior(object)

1.0.0 has

object <- create_bvarmodel(data, p = 2, deterministic = "const")
object <- add_priors(object)
object <- add_initial_values(object)
object <- add_posterior_coefficients(object)

with add_posterior_forecasts() and add_posterior_loglik() producing the forecasts and the log likelihood that draw_posterior() used to produce in the same call. Splitting them apart is what lets a model be estimated once and then have forecasts added, or the log likelihood recomputed, without repeating the simulation.

Removed without a successor

Dynamic factor models are removed from bvartools in 1.0.0 entirely. That covers dfm(), dfmpost() and gen_dfm(), the add_priors(), plot(), summary() and thin() methods for objects of class dfm, and the example data set bem_dfmdata. A data set cannot announce itself, so this is the only notice bem_dfmdata gets.

post_normal_covar_const() and post_normal_covar_tvp() are also removed with nothing taking their place.

Renamed classes, and the methods that follow them

The model classes are renamed in 1.0.0. The generics are the same, so code that calls plot(), summary(), predict() or thin() on a model object keeps working; what changes is the name of the class those methods are written for, which matters if you dispatch on it yourself or test for it with inherits().

0.3.0 1.0.0
bvar bvarmodel
bvec bvecmodel
bvarlist modellist

These do not produce a message, because the function you call is unchanged.

Same name, different input

These functions exist in 1.0.0 under the same name but do not take the same input, because they take the reorganised model object. They produce no message either, for the same reason: the name is still there. Read their documentation before assuming a call carries over.

add_priors(), bvar(), bvec(), irf(), fevd(), inclusion_prior(), minnesota_prior(), ssvs_prior().

Fixes in this release

Five defects in the CRAN sources are fixed here. Three of them change results.

  • Stochastic volatility with an observation far out in the tails. stochvol_ksc1998() and stochvol_ocsn2007() sampled the mixture indicator from weights formed as densities and normalised by their sum. Where an observation lies far enough out in the tails of every component, each density underflows to zero, the row sums to zero, the weights become NaN, and the indicator runs one past the last component – which ends the call with Mat::elem(): index out of bounds. The weights are now formed in logs and shifted by their row maximum before they are exponentiated. This is algebraically the same calculation, and draws from a given seed are unchanged: verified bit for bit against the previous implementation. Only the case that used to fail behaves differently, and it now returns a draw.

  • Argument checking in the same two functions. sigma, h_init and constant were indexed on trust, so a vector of the wrong length surfaced as Mat::elem(): index out of bounds rather than as a statement about the argument. Each is now checked against the number of columns of y and named in the error.

  • Impulse responses and variance decompositions of structural models. A structural model keeps its contemporaneous block separately, so its coefficient draws are the structural A_i and its covariance draws the covariance of the structural errors. The forecast error, orthogonalised and generalised recursions want the reduced form. Given the structural quantities they returned numbers that belong to no model at all – and the same numbers for all three types, since the structural error covariance makes the orthogonalisation degenerate. irf() with type of "feir", "oir" or "gir", and fevd() with "oir" or "gir", now refuse a structural model and say why. Use "sir" or "sgir", which are what a structural model is for and are unchanged, or estimate the model with structural = FALSE.

  • The structural variance decomposition ignored the variances of the structural shocks. fevd() with type = "sir" used A_0^-1 as the impulse matrix and A_0^-1 A_0^-1' as the forecast error covariance, leaving the covariance of the structural errors out of both. Every structural shock was then decomposed as if it had unit variance, which moves weight to whichever shock loads most heavily in A_0. Because the shares are normalised they still summed to one, so nothing in the output showed that anything was wrong. "sgir" already carried the covariance and is unchanged, as is every reduced form type.

  • Seasonal terms for data of frequency one. gen_vec() warned that no seasonal dummies are generated for a series of frequency one and then added them anyway, stopping with object 'seas' not found. It now does what the warning says. gen_var() was never affected.

Getting the messages out of a script

Beyond the option above, the messages are ordinary conditions, so suppressMessages() works on any single call:

object <- suppressMessages(gen_var(data, p = 2, deterministic = "const"))

They are messages rather than warnings deliberately: they will not become errors under options(warn = 2), and they will not fail a check that treats warnings as failures.