I was playing with using a horseshoe prior in brms and looking at the generated stan code -- it looks like there's a redundant/duplicated function call in the transformed parameters block to the horseshoe function. Is this intentional?
library(brms)
#> Loading required package: Rcpp
#> Loading 'brms' package (version 2.15.0). Useful instructions
#> can be found by typing help('brms'). A more detailed introduction
#> to the package is available through vignette('brms_overview').
#>
#> Attaching package: 'brms'
#> The following object is masked from 'package:stats':
#>
#> ar
n <- 100
y <- rpois(n, lambda = 1)
x <- rnorm(n)
d <- data.frame(x = x, y = y)
fit <- brm(y ~ x, data = d,
family = poisson,
prior = set_prior("horseshoe(1)"),
backend = "cmdstanr",
silent = 2, refresh = 0)
#> Running MCMC with 4 sequential chains...
#>
#> Chain 1 finished in 0.1 seconds.
#> Chain 2 finished in 0.2 seconds.
#> Chain 3 finished in 0.2 seconds.
#> Chain 4 finished in 0.2 seconds.
#>
#> All 4 chains finished successfully.
#> Mean chain execution time: 0.2 seconds.
#> Total execution time: 1.1 seconds.
#>
#> Warning: 718 of 4000 (18.0%) transitions ended with a divergence.
#> This may indicate insufficient exploration of the posterior distribution.
#> Possible remedies include:
#> * Increasing adapt_delta closer to 1 (default is 0.8)
#> * Reparameterizing the model (e.g. using a non-centered parameterization)
#> * Using informative or weakly informative prior distributions
brms::stancode(fit)
#> // generated with brms 2.15.0
#> functions {
#> /* Efficient computation of the horseshoe prior
#> * see Appendix C.1 in https://projecteuclid.org/euclid.ejs/1513306866
#> * Args:
#> * z: standardized population-level coefficients
#> * lambda: local shrinkage parameters
#> * tau: global shrinkage parameter
#> * c2: slap regularization parameter
#> * Returns:
#> * population-level coefficients following the horseshoe prior
#> */
#> vector horseshoe(vector z, vector lambda, real tau, real c2) {
#> int K = rows(z);
#> vector[K] lambda2 = square(lambda);
#> vector[K] lambda_tilde = sqrt(c2 * lambda2 ./ (c2 + tau^2 * lambda2));
#> return z .* lambda_tilde * tau;
#> }
#> }
#> data {
#> int<lower=1> N; // total number of observations
#> int Y[N]; // response variable
#> int<lower=1> K; // number of population-level effects
#> matrix[N, K] X; // population-level design matrix
#> // data for the horseshoe prior
#> real<lower=0> hs_df; // local degrees of freedom
#> real<lower=0> hs_df_global; // global degrees of freedom
#> real<lower=0> hs_df_slab; // slab degrees of freedom
#> real<lower=0> hs_scale_global; // global prior scale
#> real<lower=0> hs_scale_slab; // slab prior scale
#> int prior_only; // should the likelihood be ignored?
#> }
#> transformed data {
#> int Kc = K - 1;
#> matrix[N, Kc] Xc; // centered version of X without an intercept
#> vector[Kc] means_X; // column means of X before centering
#> for (i in 2:K) {
#> means_X[i - 1] = mean(X[, i]);
#> Xc[, i - 1] = X[, i] - means_X[i - 1];
#> }
#> }
#> parameters {
#> // local parameters for horseshoe prior
#> vector[Kc] zb;
#> vector<lower=0>[Kc] hs_local;
#> real Intercept; // temporary intercept for centered predictors
#> // horseshoe shrinkage parameters
#> real<lower=0> hs_global; // global shrinkage parameters
#> real<lower=0> hs_slab; // slab regularization parameter
#> }
#> transformed parameters {
#> vector[Kc] b; // population-level effects
#> // compute actual regression coefficients
#> b = horseshoe(zb, hs_local, hs_global, hs_scale_slab^2 * hs_slab);
#> // compute actual regression coefficients
#> b = horseshoe(zb, hs_local, hs_global, hs_scale_slab^2 * hs_slab);
#> }
#> model {
#> // likelihood including constants
#> if (!prior_only) {
#> target += poisson_log_glm_lpmf(Y | Xc, Intercept, b);
#> }
#> // priors including constants
#> target += std_normal_lpdf(zb);
#> target += student_t_lpdf(hs_local | hs_df, 0, 1)
#> - rows(hs_local) * log(0.5);
#> target += student_t_lpdf(Intercept | 3, 0, 2.5);
#> target += student_t_lpdf(hs_global | hs_df_global, 0, hs_scale_global)
#> - 1 * log(0.5);
#> target += inv_gamma_lpdf(hs_slab | 0.5 * hs_df_slab, 0.5 * hs_df_slab);
#> }
#> generated quantities {
#> // actual population-level intercept
#> real b_Intercept = Intercept - dot_product(means_X, b);
#> }
I was playing with using a horseshoe prior in brms and looking at the generated stan code -- it looks like there's a redundant/duplicated function call in the transformed parameters block to the
horseshoe
function. Is this intentional?Created on 2021-05-25 by the reprex package (v2.0.0)
Notice the duplicated line:
Here's my session info in case its useful: