prior_random() defines priors and policies for formula random effects. Random-effect formulas own the grouping variables, slopes, intercepts, and covariance structure. prior_random() supplies priors and monitoring policy for the already parsed random-effect blocks. Random-effect grouping expressions must be grouping variables, explicit : interactions, or explicit / nesting. Derived grouping variables should be materialized as columns in data before they are referenced by a formula.

prior_random(
  ...,
  sd = NULL,
  covariance = NULL,
  cor = NULL,
  monitor = random_monitor(),
  new_levels = random_new_levels(),
  allocation = NULL,
  parameterization = "noncentered"
)

random_block(
  sd = NULL,
  covariance = NULL,
  cor = NULL,
  monitor = NULL,
  new_levels = NULL,
  terms = NULL,
  contrasts = NULL,
  sd_source = NULL,
  parameterization = NULL
)

random_variance_allocation(
  name,
  terms = NULL,
  sd = NULL,
  weights = NULL,
  parent = NULL,
  target = c("block", "sd_component"),
  scale = c("total_variance", "mean_variance"),
  sd_source = NULL,
  inclusion = NULL,
  display_name = name,
  component_names = NULL
)

allocation_ref(allocation_name, component)

random_covariance(
  structure = NULL,
  sd = NULL,
  cor = NULL,
  eta = NULL,
  cor_scale = c("fisher_z", "cor", "logit")
)

prior_lkj(eta = 1, include_correlation = TRUE, include_primitives = FALSE)

random_monitor(
  latent = TRUE,
  coefficients = FALSE,
  correlation = TRUE,
  lkj_primitives = FALSE
)

random_new_levels(method = c("error", "zero", "sample"))

Arguments

...

named random_block() specifications and, optionally, top-level random_variance_allocation() specifications.

sd

prior distribution for random-effect standard deviations. In random_block(), it is the default for the terms that terms does not override, and may be omitted when terms covers every SD of the block (see the standard-deviation priors section).

covariance

optional random_covariance() specification.

cor

optional correlation prior. Use prior_lkj() for unstructured correlation matrices and an ordinary scalar prior for structured correlation models.

monitor

random_monitor() object.

new_levels

random_new_levels() object controlling prediction for previously unseen grouping levels.

allocation

optional random_variance_allocation() specification, or a list of such specifications, defining aggregate-SD plus Dirichlet variance allocation across named random-effect blocks.

parameterization

requested sampled random-effect parameterization: "noncentered", "centered", or "auto". The top-level value is inherited by blocks without an explicit random_block() override. A named block can additionally request "mean_centered"; see details.

terms

for random_block(), an optional named list of term-specific SD overrides. Each entry must be either a prior object or random_block(sd = ...), and names must match resolved model terms such as "intercept" or a slope term label (the index term for HCS and HAR). Terms not listed use sd; when every term is listed, sd may be omitted. For random_variance_allocation(), optional random-effect block names targeted by the shared allocation. If NULL, the allocation targets all remaining unallocated random-effect blocks at resolution time.

contrasts

for random_block(), an optional named character vector mapping factor predictors in that block to contrast families. Accepted values are "treatment" (also spelled "dummy"), "independent", "orthonormal", "meandif", "cumulative", and "cumulative_levels" (with or without the contr. prefix). Random-block contrasts are resolved independently of the fixed-effect design. Correlation structures with a structure-defined level basis do not accept this argument.

sd_source

for random_block(), optional external random-effect SD source created with random_sd_source(). A block-local sd_source replaces inherited top-level SD priors and inherited covariance SD priors, but conflicts with block-local sd, block-local covariance$sd, and term-specific SD overrides. For random_variance_allocation(), root allocations must specify exactly one of sd or sd_source; child allocations inherit their SD budget from parent.

name

required stable allocation identifier used by the backend and by allocation_ref().

weights

optional Dirichlet simplex prior over allocation weights.

parent

optional allocation_ref() object selecting a component of an earlier named allocation. Child allocations inherit that component's SD budget and must not specify sd or sd_source.

target

allocation target type. "block" allocates across named random-effect blocks or symbolic intermediate components. "sd_component" expands one selected heterogeneous block to its resolved SD components (one per exchangeable unit of a mean-difference or orthonormal factor term).

scale

variance normalization. "total_variance" uses sd_child = sd_parent * sqrt(w). "mean_variance" uses sd_child = sd_parent * sqrt(K * w) and is intended for target = "sd_component" heterogeneity tests. Summaries report the realized, gate-adjusted variance proportion for "total_variance" and K * w as a variance multiplier to the average SD-component variance for "mean_variance".

inclusion

optional named list of scalar probability priors, keyed by allocation component label. For target = "block", each listed component receives an independent Bernoulli gate and its SD contribution is multiplied by that gate. Public total-variance aggregates include these zero branches, while variance proportions condition on at least one active component. Gate names must match resolved allocation component labels. A block allocation with exactly one term is permitted only as a gate-only allocation: weights must be NULL and inclusion must name that term. Conditioning a gated total on presence uses the binding-factor (parent) gates that define a positive realized source, not every nested component gate; a total whose components all have inclusion gates and which also has parent gates cannot be conditioned (see parameter_mixed_posterior()). inclusion is not supported with target = "sd_component".

display_name

public semantic owner used as the parameter-name prefix. It defaults to name; use "" when a single model component needs no disambiguating prefix.

component_names

optional public names for the allocation components, in the same order as terms. Internal component identifiers remain the (sanitized) names of terms. A sole "" suppresses the redundant public component argument for a one-component allocation.

allocation_name

allocation name referenced by allocation_ref().

component

component label inside the referenced allocation. Named terms supply component labels; unnamed terms use sanitized term names.

structure

covariance structure label. Accepted labels are "ID", "DIAG", "CS", "HCS", "AR" / "AR1", "HAR", "CAR", and "UN" / "US"; matching is case-insensitive.

eta

LKJ concentration parameter used when cor is omitted for unstructured covariance. Values above one regularize correlations toward zero; eta = 1 is uniform over correlation matrices.

cor_scale

scale for an explicitly supplied scalar correlation prior. "fisher_z" is the default, "logit" uses a logit transform of the valid raw-correlation interval, and "cor" uses the raw correlation parameter. Coordinates beyond about 19 (Fisher-z) or 36.7 (logit) in absolute value map to a correlation of exactly +-1 in double precision (see prior_random()). For multi-column scalar-correlation structures, omitted cor resolves to a uniform prior on the raw correlation scale; explicitly requesting another scale without supplying cor is an error. US/UN structures use an LKJ prior instead. ID/DIAG structures and single-column blocks have no applicable scalar correlation.

include_correlation

whether to monitor the correlation matrix for prior_lkj().

include_primitives

whether to retain LKJ primitive beta coordinates for backend inspection. They remain internal and are not added to the public semantic parameter catalog.

latent

whether to monitor standardized latent random effects. Required for bridge sampling and coefficient reconstruction.

coefficients

whether to monitor realized group-level coefficients. This is convenient for inspection but can be memory intensive.

correlation

whether correlation matrices are part of the semantic monitored output. Scalar CS/HCS/AR1/HAR/CAR backends retain only an internal rho coordinate during sampling and derive the requested matrix afterward; this avoids a quadratic JAGS graph without changing the public cor target.

lkj_primitives

whether to retain LKJ primitive beta coordinates for backend inspection. They remain internal rather than semantic catalog quantities. For formula us random effects, raw LKJ primitive u coordinates are always retained internally because bridge sampling evaluates the LKJ prior on those coordinates.

method

new-level prediction method: "error" disallows new levels, "zero" fixes their random-effect contribution at zero, and "sample" treats them as draws from the fitted random-effect distribution.

Value

A list-like S3 object describing random-effect priors, covariance settings, allocation settings, and monitoring policy.

Details

Formula random effects in JAGS_formula() and JAGS_fit() require an explicit prior_random() object. The top-level arguments are defaults used by every random-effect block unless a named random_block() override is supplied in .... A top-level cor prior applies only to blocks whose resolved structure and dimension have a correlation parameter; it is not applied to id(), diag(), or single-column blocks. A block override with no covariance subcall inherits the shared covariance. A supplied random_covariance() or cor shorthand replaces the whole covariance object and uses its constructor defaults for omitted fields. In particular, random_covariance(cor = NULL) resets its correlation prior and scale to the formula defaults. A replacement also removes any shared covariance SD; if that was the only SD, supply a local or top-level SD prior. A block SD supplied through either sd or covariance = random_covariance(sd = ...) replaces the top-level SD supplied through either argument.

Each override name must match a stable random-effect block label generated from the formula parser or supplied by the user through named random terms. This keeps prior specification separate from formula syntax. For example, if the formula contains a block named "study", then prior_random(study = random_block(...)) overrides only that block.

Standard-deviation priors

sd must be a BayesTools prior object with nonnegative support, such as a truncated normal, gamma, point prior at zero, or mixture prior. When a structure needs multiple marginal standard deviations, a single sd prior is replicated over those SD components unless random_block(terms = ...) overrides the prior of individual terms; sd remains the default for the terms that are not overridden. A block with one SD per term (DIAG, US/UN, HCS, and HAR) may omit sd, both in the block and at the top level, when terms supplies a prior for every resolved term: the coefficient columns such as "intercept" or a slope label, or the index term whose per-level SDs HCS and HAR share one prior. Coverage is checked when the formula is resolved, and uncovered terms are named in the error. Structures with one shared SD (ID, diag(..., hom = TRUE), CS, AR1, and CAR) take no term overrides and always require sd. Non-point multivariate (vector) SD priors are unsupported; use nonnegative scalar SD priors. Deterministic nonnegative point vectors and supported independent factor priors retain their usual behavior.

For ordinary estimation, use continuous positive SD priors. Use point or mixture priors at zero only when a random-effect component is intentionally fixed or model-averaged.

Covariance structures

random_covariance() stores structure-specific covariance settings. The formula owns the structure and its design. ID, DIAG, and US/UN operate on generated random-coefficient columns; CS/HCS, AR1/HAR, and CAR operate on structure-owned indices. Supported structure labels are:

  • "ID": independent columns with one shared SD.

  • "DIAG": independent columns with one SD per generated column (one per exchangeable unit of a mean-difference or orthonormal factor term).

  • "CS" / "HCS": compound symmetry over one or more index variables, with one scalar correlation; "HCS" has one SD per index level. Multiple index variables in cs(index1 + index2 | group) are combined with interaction(..., drop = TRUE).

  • "AR" / "AR1" / "HAR": discrete autoregressive structure over a single ordered index variable, with one scalar correlation; "HAR" has one SD per index level.

  • "CAR": continuous-time AR(1), currently for car(time | group), using cor ^ abs(t_i - t_j) with 0 <= cor < 1.

  • "UN" / "US": unstructured covariance with SD priors and prior_lkj().

ID/DIAG/US formulas use random-intercept controls on their left side. Factor coding is resolved separately and can be set explicitly with random_block(contrasts = ...). The structured index families reject that contrast override and reject explicit 1, 0, or -1 terms. HCS is not an alias for US: HCS has one common pairwise correlation, whereas US estimates an unrestricted correlation matrix among coefficient columns.

A mean-difference or orthonormal factor term (also f:x, and f:g when every factor is so coded) is one exchangeable unit in a DIAG or US/UN block: its contrast columns form an arbitrary basis of the level deviations, so they share one SD (reported as sd(f), with one scalar prior) and are uncorrelated, which makes the model of the level deviations independent of the basis. A term that crosses such a factor with a treatment, independent, or ordered factor has one unit per column of that partner (e.g., sd(f:h[b])). Under US/UN a unit keeps its correlations with the other columns: the LKJ prior is restricted to an identity unit block (density det(R)^(eta - 1)), and the summaries report the correlation with each level of the factor, cor(x, f[a]), and the multiple correlation with the whole term, cor_total(x, f), instead of correlations of contrast columns. A US/UN block with more than one such term of three or more levels is refused (class BayesTools_random_effects_exchangeable_units_unavailable, reason "several_correlated_units"), as is a factor or vector SD prior on a unit (reason "unit_sd_prior"); a US/UN block that is one such term is its diagonal block, and a two-level factor has one column and is an ordinary column of the LKJ prior. Use treatment or independent contrasts for one SD per level.

The formula parser owns the actual structure used by a block. Supplying a conflicting structure in random_covariance() is rejected when the formula is resolved.

Correlation priors

Use prior_lkj(eta = ...) for full unstructured correlation matrices. When cor is omitted, an unstructured block receives prior_lkj(eta = 1) after its dimension is known. LKJ priors use the BayesTools compiled JAGS module.

Use an ordinary scalar prior in cor for scalar-correlation structures ("CS", "HCS", "AR", "HAR", and "CAR"). When cor is omitted, BayesTools places a uniform prior directly on the complete valid raw-correlation interval: (-1 / (K - 1), 1) for CS/HCS, (-1, 1) for AR/HAR, and [0, 1) for CAR. Here K is the resolved number of index levels. The CS/HCS lower bound -1/(K-1) is a singular kernel point and is open; the stored default Uniform parameters name the closed JAGS dunif hull. Uniform as a family is not an open-interval distribution. User-supplied Uniforms that include the CS bound are retained, and density there remains -Inf / a native error. AR/HAR |rho| = 1 is likewise a kernel singularity, not a Uniform policy. CAR includes rho = 0. Thus the default does not silently exclude negative correlations wherever the structure permits them. cor_scale controls the scale of an explicitly supplied scalar cor prior:

  • "fisher_z" places the prior on atanh(cor) and is the default for an explicit scalar cor prior. A point prior at zero corresponds to independence. For one-sided structures such as "CAR", the Fisher-z prior is truncated to the valid raw-correlation interval.

  • "logit" places the prior on a logit transform of the valid raw-correlation interval.

  • "cor" places the prior directly on the raw correlation; the prior is truncated to the structure-specific valid interval.

In double precision, Fisher-z coordinates beyond about 19 in absolute value (logit coordinates beyond about 36.7) map to a correlation of exactly \(\pm 1\). A scalar correlation prior with mass there gives draws on the boundary of the support: centered fits stop in JAGS with "Invalid parent values" and noncentered draws are refused when the correlation is reconstructed. A "CAR" correlation prior whose whole support lies there is refused when the model is built. A prior with less mass beyond these coordinates avoids the problem.

Variance allocation

random_variance_allocation() expresses one aggregate SD source plus a Dirichlet prior over variance proportions. A one-component block allocation is also supported when it supplies only an inclusion gate; this multiplies the component SD by the Bernoulli indicator without creating an artificial allocation weight. Root allocations must specify exactly one of a prior-owned sd prior or sd_source = random_sd_source(...). sd_source can reference an already-defined JAGS node such as scalar tau or row-shaped tau without creating a prior for that node. Multiple named allocations can be supplied in prior_random(); child allocations can inherit one component of an earlier allocation through parent = allocation_ref(...).

With scale = "total_variance", the ungated allocation preserves summed component variance. With optional independent component gates, the realized component SD and total variance are $$\sigma_j = I_j\sigma_{\mathrm{slab}}\sqrt{w_j}, \quad \sigma_{\mathrm{total}}^2 = \sigma_{\mathrm{slab}}^2 \sum_j I_j w_j, \quad w \sim \mathrm{Dirichlet}(\alpha).$$ Its public aggregate names sd_total and var_total refer to the realized gated total. var_prop(j) is the realized share \(I_j w_j / \sum_k I_k w_k\), conditional on positive realized total variance. It is undefined on all-off draws, which are omitted when the variance proportions are summarized. The positive slab scale and raw Dirichlet weights remain internal coordinates.

With scale = "mean_variance", the aggregate SD preserves mean component variance: $$\sigma_j = \sigma_{\mathrm{common}}\sqrt{K w_j}, \quad w \sim \mathrm{Dirichlet}(\alpha).$$ Its public aggregate names are sd_common and var_common, and its components are exposed as var_mult(...) and sd_mult(...), where var_mult(j) = K * w[j] and sd_mult(j) = sqrt(K * w[j]). Thus sd_common is the shared variance-scale anchor before the component multipliers are applied; it is not a sum of SDs.

The fitted parameter_map() links concrete parameter_coordinates() to the public random-effect quantities in parameter_catalog(). Canonical names use (formula) owner: quantity(arguments), with owner: omitted for exactly one random block and retained when multiple blocks require disambiguation. Parentheses contain coefficient or parameter names and square brackets contain factor or index levels. Public correlations use cor; compact scalar rho and LKJ construction coordinates remain internal backend dependencies. Downstream packages can opt into centrally generated simplified aliases. A sole intercept argument is then omitted (sd(intercept) becomes sd), and an owner-free shorthand is accepted only when it resolves uniquely. A non-intercept argument such as sd(x) is retained.

Allocation name is a required stable backend identifier. display_name independently controls an allocation-specific public owner, and component_names controls the public component arguments. An unnamed local SD-component allocation inherits its enclosing block's public owner under the same one-block/multiple-block rule. Total-variance allocations expose realized sd_total, var_total, and var_prop(...); mean-variance allocations expose sd_common, var_common, var_mult(...), and sd_mult(...).

This is useful for nested or crossed random intercepts when the prior should control total heterogeneity separately from how that heterogeneity is allocated across components. The allocation targets named random-effect blocks through terms. If terms = NULL, a single root block allocation targets all random-effect blocks at resolution time and must resolve to at least two blocks. Generated JAGS syntax supports allocated blocks with one SD component (such as a block that is one mean-difference or orthonormal factor term, an exchangeable unit with one SD), homogeneous structures where one SD controls the block, and explicit target = "sd_component" allocations that split the resolved SD components of one heterogeneous block. Row-shaped external sources are applied inside the observation-level random-effect contribution, including child allocations and SD-component allocations; they do not create scalar SD summary parameters. Prediction and bridge-sampling reconstruction for these sources require standardized latent random-effect monitors, row-source values from either posterior columns or a parameter_source(..., values = ...) callback, and any required Dirichlet allocation coordinates. Use scale = "total_variance" to preserve summed variance and scale = "mean_variance" to preserve average variance inside a heterogeneous block.

Monitoring and prediction

random_monitor() controls which random-effect quantities are saved from JAGS. The default monitors standardized latent random effects because they are required for bridge sampling and for reconstructing group-level coefficients in prediction. Turning latent = FALSE can reduce memory use, but bridge sampling and conditional prediction may require refitting.

random_new_levels() controls prediction for grouping levels that were not observed when the model was fitted. The default method = "error" disallows new levels. method = "zero" assigns zero random-effect contribution to new levels and method = "sample" draws new group-level coefficients from the fitted random-effect distribution during draw-valued prediction or integrates them through the block covariance for covariance-valued prediction. A level declared in a single grouping factor (for example, an unused factor level) but without rows in the fitting data remains a fitted group whose coefficients are informed only by the random-effect distribution; prediction treats it as a new level. Blocks with a known group covariance (random_group_covariance()) are the exception: the kernel links declared levels to the observed ones, so their declared levels are predicted from the fitted coefficients, and new levels are unsupported. Groupings of several variables contain only observed combinations.

Parameterization

parameterization controls how sampled random-effect blocks are represented by the computational backend. "noncentered" retains standardized latent effects, "centered" samples realized group-level coefficients, and "auto" lets the backend choose a supported representation from the resolved block design. Its deterministic heuristic uses within-group replication and design conditioning; it does not inspect outcome-specific likelihood curvature. The resolved choice, reason, and tuning thresholds are stored in fitted random-effect metadata; those thresholds are computational tuning defaults, not statistical assumptions. The choice does not change the SD, allocation, or correlation priors. Block-specific values supplied through random_block() override the top-level default. Explicit "centered" compilation requires strictly positive backend-owned SD coordinates and therefore rejects point-mass-at-zero scales, inclusion-gated variance allocations, and external or row-indexed SD sources. A centered CAR block additionally requires one block-owned SD prior whose support is bounded away from zero and infinity, and a known between-group covariance with several random-effect columns is compiled only noncentered. "auto" falls back to "noncentered" when those contracts or its design-information checks do not support centering.

An explicitly named random_block() may request "mean_centered" for a sampled block. It samples the group effects around the compiled contribution of the fixed terms the block absorbs, preserving the original effect, SD, allocation, and correlation priors (hierarchical centering). A block absorbs every fixed term whose design columns its random-effect design spans (such as the intercept and the slope of x for (1 + x | g), or the intercept and a factor term for us(0 + f | g)), every term constant within its groups when it has a random intercept (such as a group-level moderator), and the group locations of a mean-centered block whose groups contain its groups (nested blocks, such as (1 | g/h) with both blocks mean-centered). Each term is absorbed by the first block that can absorb it, coarser groupings first; other terms, including terms only partly spanned by a block design, remain in the predictor. The fixed effects need not have Normal priors; multipliers and a compiled log(intercept) contribution are also supported. A block that would absorb nothing and a rank-deficient block design are rejected. This mode requires the positive-SD contract above and excludes known between-group covariance and CAR structures. Selection-model callers must additionally require that the translated block is retained in the selection normalizer. Semantic random coefficients remain zero-mean deviations; prediction and bridge sampling retain their existing coefficient and standardized-latent conventions. Mean centering usually mixes better when the data inform the group effects well, and noncentering when they do not.

Examples

sd_prior <- prior(
  "normal", list(mean = 0, sd = 0.5),
  truncation = list(lower = 0, upper = Inf)
)
cor_prior <- prior("normal", list(mean = 0, sd = 0.5))

# One SD prior used for every random-effect block.
prior_random(sd = sd_prior)
#> defaults
#>   sigma ~ Normal(0, 0.5)[0, Inf]

# Override a named block while keeping a global default.
prior_random(
  sd = sd_prior,
  study = random_block(sd = prior("gamma", list(shape = 2, rate = 2)))
)
#> defaults
#>   sigma ~ Normal(0, 0.5)[0, Inf]
#> block: study
#>   sigma ~ Gamma(2, 2)

# Unstructured covariance: omitted correlation resolves to LKJ(1).
prior_random(
  study = random_block(sd = sd_prior)
)
#> block: study
#>   sigma ~ Normal(0, 0.5)[0, Inf]

# Scalar-correlation structure with a Fisher-z prior.
prior_random(
  study_time = random_block(
    covariance = random_covariance(
      structure = "AR",
      sd = sd_prior,
      cor = cor_prior,
      cor_scale = "fisher_z"
    )
  )
)
#> block: study_time (AR1)
#>   sigma ~ Normal(0, 0.5)[0, Inf]
#>   cor ~ Normal(0, 0.5)
#>   cor_scale: fisher_z

# Total heterogeneity plus Dirichlet variance allocation. The allocation
# has an internal name but no redundant public owner: sd_total,
# var_prop(study), and var_prop(outcome).
prior_random(
  random_variance_allocation(
    name = "heterogeneity",
    display_name = "",
    terms = c(study = "study", outcome = "outcome"),
    sd = sd_prior,
    weights = prior("dirichlet", list(alpha = c(1, 1)))
  )
)
#> allocation: heterogeneity
#>   sigma_total ~ Normal(0, 0.5)[0, Inf]
#>   w ~ Dirichlet(1, 1)
#>   sigma_study = sigma_total * sqrt(w[1])
#>   sigma_outcome = sigma_total * sqrt(w[2])

# Allocate a block SD across its coefficient components. This exposes
# study_components: sd_common, study_components: var_mult(intercept), and
# study_components: sd_mult(intercept), with analogous names for slopes.
prior_random(
  random_variance_allocation(
    name = "study_components",
    terms = "study",
    target = "sd_component",
    scale = "mean_variance",
    sd = sd_prior,
    weights = prior("dirichlet", list(alpha = c(1, 1)))
  )
)
#> allocation: study_components
#>   sigma_common ~ Normal(0, 0.5)[0, Inf]
#>   w ~ Dirichlet(1, 1)
#>   sigma_study[1] = sigma_common * sqrt(2 * w[1])
#>   sigma_study[2] = sigma_common * sqrt(2 * w[2])
#>   scale: mean_variance

# A child allocation can split one inherited variance budget.
prior_random(
  random_variance_allocation(
    name = "total_re",
    terms = c(nested = "nested", simple = "study"),
    sd = sd_prior,
    weights = prior("dirichlet", list(alpha = c(1, 1)))
  ),
  random_variance_allocation(
    name = "nested_split",
    parent = allocation_ref("total_re", "nested"),
    terms = c("paper", "country"),
    weights = prior("dirichlet", list(alpha = c(3, 1)))
  )
)
#> allocation: total_re
#>   sigma_total ~ Normal(0, 0.5)[0, Inf]
#>   w ~ Dirichlet(1, 1)
#>   sigma_nested = sigma_total * sqrt(w[1])
#>   sigma_simple = sigma_total * sqrt(w[2])
#> allocation: nested_split
#>   w ~ Dirichlet(3, 1)
#>   sigma_paper = sigma_nested * sqrt(w[1])
#>   sigma_country = sigma_nested * sqrt(w[2])