masbayes Rust modules
The Rust kernel powering masbayes is split into eight focused modules. Each section below is the module-level documentation extracted directly from the corresponding .rs file by _scripts/extract-rust-docs.R, so this page stays in sync with the source.
For per-function signatures and private-item details, build the full cargo doc HTML locally:
cd masbayes/src/rust && cargo doc --no-deps --document-private-items --openPackage overview
lib.rs
Computational backend for the masbayes R package: Bayesian genomic prediction models for biallelic SNP and multi-allelic microhaplotype markers. All numerically heavy work (MCMC, stochastic EM, design matrix construction) lives here; the R side is a thin extendr wrapper.
Module map
- [
matrix] — design-matrix construction:WMatrixBuilderimplements the Da (2015) \(W_{\alpha h}\) encoding for phased multi-allelic haplotype data, followed by a per-locus frequency-weighted row shrinkage.- Helper routines for biallelic SNP encoding (VanRaden) are exposed via the FFI wrappers in this file.
- [
bayesa] — BayesA Gibbs sampler. Per-marker variance follows a scaled inverse chi-squared prior, leading to a t-shrunk effect distribution. Supports binary traits via Albert–Chib data augmentation. - [
bayesr] — BayesR Gibbs sampler. Marker effects follow a four-component normal mixture (one spike at zero plus three slab components scaled relative to the genetic variance); mixture proportions are updated with a Dirichlet–Multinomial step. - [
bayesa_em] / [bayesr_em] — Stochastic EM variants of the two samplers. Faster but discard posterior uncertainty. - [
utils] — RNG helpers (inverse-gamma, Dirichlet, normal, tabulate) and R↔︎ndarrayconversion shims used across the kernels. - [
types] — POD result structs returned to R via the extendr wrappers.
Reproducibility
All samplers take a seed: u64 initialising a PCG64 RNG (rand_pcg). Given the same data, hyperparameters, and seed, the kernels reproduce posterior samples bit-for-bit on the same platform.
Reference
Da, Y. (2015). Multi-allelic haplotype model based on genetic partition for genomic prediction and variance component estimation using SNP markers. BMC Genetics, 16:144.
Module reference
matrix.rs
Design-matrix construction for multi-allelic microhaplotype markers.
Pipeline
- Per-block encoding — for each haplotype locus (block) and each non-baseline microhaplotype \(k\), the entry \(W_{i,k}\) for individual \(i\) is filled with the Da (2015) three-value coding rule (Eqs. 22–24): \(-2(1-p_k)\) when the individual is homozygous for \(k\), \(-(1-2p_k)\) when heterozygous, \(+2p_k\) when \(k\) is absent.
- Baseline drop — the most frequent microhaplotype per locus is used as the contrast reference and excluded from the columns; its effect is absorbed by the intercept \(\mu\) in downstream models.
- Frequency-weighted row shrinkage — see [
frequency_weighted_row_shrinkage]. Applied per locus after encoding; partially reduces the alignment between each individual row and the locus’s allele-frequency vector.
Equivalence with VanRaden
Da’s three-value rule can be written in closed form as \(W_{i,k} = 2 p_k - n_{i,k}\), where \(n_{i,k} \in \{0,1,2\}\) is the dosage of microhaplotype \(k\) in individual \(i\). This is the per-allele VanRaden centering with the sign flipped, stacked across all non-baseline microhaplotypes within the locus.
Train / test alignment
WMatrixBuilder accepts a ReferenceStructure for test-set encoding so that allele frequencies and the choice of baseline microhaplotype come from the training set, not the test set itself. Re-estimating \(p_k\) on test data would shift the centering and bias GEBVs — never do that.
Reference
Da, Y. (2015). Multi-allelic haplotype model based on genetic partition for genomic prediction and variance component estimation using SNP markers. BMC Genetics, 16:144.
bayesa.rs
BayesA Gibbs sampler.
Model
For a continuous trait,
y = 1·μ + X·α + W·β + ε, ε ~ N(0, σ²_e · I)
β_j | σ²_j ~ N(0, σ²_j)
σ²_j ~ InvChi2(ν, S²), S² = σ²_β / L (scaled)
σ²_e ~ InvGamma(a₀_e, b₀_e)
Marginalising the per-marker variance yields a \(t_\nu\)-shrunk effect distribution, which is the defining feature of BayesA relative to ridge regression / BayesC. The prior on σ²_j is informative (default ν = 4.5) so the posterior contracts toward small effects unless data demand otherwise.
Sampling steps (per Gibbs iteration)
- Update marker effects \(\beta_j\) one at a time from their full conditionals (Normal with mean and variance involving
wtw_diag[j],σ²_e,σ²_j, and the working residualyadj). - Update per-marker variances \(\sigma²_j\) from \(\mathrm{InvChi2}(\nu + 1, (\nu S² + \beta_j²) / (\nu + 1))\).
- Update residual variance \(\sigma²_e\) from \(\mathrm{InvGamma}(a_0 + n/2,\, b_0 + \|y - \hat{y}\|^2 / 2)\).
- Update intercept \(\mu\) from its normal full conditional given the residual mean.
- (Optional) Update fixed effects \(\alpha\) component-wise from normal full conditionals using
xtx_diag. - (Binary trait) Albert–Chib step: sample latent liabilities \(z\) from truncated normals consistent with the observed binary response.
State management
BayesARunner keeps a single working residual vector yadj = y - μ - X·α - W·β (or z - … for binary traits) updated incrementally after every coordinate move. This avoids recomputing the full \(W\beta\) product at each iteration, which is the main reason the kernel is fast.
Output
BayesARunner::run returns [BayesAResults] containing posterior samples (after burn-in / thinning) of all parameters, plus posterior means and derived quantities (sigma2_g, h2).
bayesa_em.rs
BayesA — stochastic EM variant.
Replaces the full Gibbs sweep of [crate::bayesa] with an EM-style coordinate-ascent update that uses posterior means (rather than draws) of the per-marker variances \(\sigma²_j\). Concretely, instead of sampling \(\sigma²_j\) each iteration, the E-step plugs in its conditional expectation and the M-step closes the loop by updating \(\beta\) and \(\sigma²_e\).
When to use
- Genome-wide screens or large runs where full posterior uncertainty is not needed and only point estimates of marker effects (\(\hat\beta\)) are reported.
- Cross-validation folds where many BayesA fits are needed and runtime is the bottleneck.
When not to use
- Reporting credible intervals, posterior distributions of variance components, or heritability uncertainty — these require the full MCMC in [
crate::bayesa]. - Datasets with strong multimodality in the marker-effect posterior; EM only finds a local mode.
Output
Reuses the [BayesAResults] struct so downstream R code does not need to branch on which estimator was used. Sample arrays in the result contain point estimates rather than MCMC traces.
bayesr.rs
BayesR Gibbs sampler.
Model
Marker effects follow a four-component mixture of normals (a spike at zero plus three slab components scaled relative to the total genetic variance):
y = 1·μ + X·α + W·β + ε, ε ~ N(0, σ²_e · I)
β_j | γ_j = c ~ N(0, vᶜ · σ²_g), vᶜ ∈ {0, 1e-4, 1e-3, 1e-2}
γ_j ~ Categorical(π), γ_j ∈ {1, 2, 3, 4}
π ~ Dirichlet(α₀)
σ²_e, σ²_g ~ InvGamma(·, ·)
Component 1 is the spike (vᶜ = 0, exactly zero effect); components 2–4 are slabs of increasing variance. Sparsity comes from the high prior mass on the spike under the Dirichlet, while large-effect markers escape into one of the slabs.
Sampling steps (per Gibbs iteration)
- For each marker \(j\), draw the mixture label \(\gamma_j\) from its full conditional categorical (probabilities proportional to the marginal likelihood under each component × \(\pi_c\)).
- Conditional on \(\gamma_j = c\), draw \(\beta_j\) from its normal full conditional (zero when
vᶜ = 0). - Update \(\pi\) via Dirichlet–Multinomial conjugacy: \(\pi \mid \gamma \sim \mathrm{Dirichlet}(\alpha_0 + n_c)\) with \(n_c\) tabulated by
tabulate(gamma, 4). - Update \(\sigma²_g\) and \(\sigma²_e\) from their inverse-gamma full conditionals.
- Update the intercept \(\mu\) and (optional) fixed effects \(\alpha\).
- (Binary trait) Albert–Chib augmentation step on latent liabilities.
State management
Identical strategy to BayesA: keep an incremental working residual yadj updated after every coordinate move so \(W\beta\) is never recomputed from scratch within a sweep.
Output
BayesRRunner::run returns [BayesRResults] with posterior samples of all parameters, mixture allocations \(\gamma\), mixture weights \(\pi\), and derived quantities (genetic variance, heritability).
bayesr_em.rs
BayesR — stochastic EM variant.
Replaces the full Gibbs sweep of [crate::bayesr] with an EM-style update where the mixture allocations \(\gamma_j\) are replaced by their posterior probabilities and the Dirichlet draws of \(\pi\) are replaced by their conditional expectation under the current allocation counts. Marker effects, variance components, and intercept retain closed-form coordinate updates.
When to use
- Same niche as [
crate::bayesa_em]: large screens where point estimates suffice and runtime per fit must be small. - Hybrid pipelines that first run EM to warm-start MCMC, then switch to the full [
crate::bayesr] sampler for posterior inference.
When not to use
- Reporting mixture-membership uncertainty (which markers belong to the spike vs. slab) — EM collapses this to soft probabilities at the mode and loses the underlying Bernoulli/Dirichlet posterior.
- Variance-component inference; same caveats as the BayesA EM variant.
Output
Returns a [BayesRResults] populated with EM point estimates in the sample fields so the R-side API is identical to the MCMC runner.
utils.rs
Shared utilities for the masbayes kernels.
Two unrelated groups of helpers live here:
- R ↔︎
ndarrayconversion —rmatrix_to_array2*copy an extendrRMatrixinto an ownedndarray::Array2so the MCMC loops can work with native Rust types without going through the R FFI on every cell access. Copy cost is paid once per kernel invocation. - Sampling primitives —
rnorm,rinvgamma,rdirichlet,tabulate. These wraprand_distrdistributions so the call sites inbayesa.rs/bayesr.rsstay close to the manuscript notation (e.g.sigma2 ~ InvGamma(a, b)reads asrinvgamma(rng, a, b)).
All sampling functions take an &mut R: Rng so that the caller controls the seed; this is what makes the full MCMC reproducible from a single Pcg64::seed_from_u64(seed) at the start of each runner.
types.rs
POD result structs returned by the BayesR and BayesA kernels.
These types are written by the MCMC / EM runners in bayesr.rs, bayesa.rs, bayesr_em.rs, bayesa_em.rs and then marshalled to R lists by the extendr wrappers in lib.rs. Field naming matches the manuscript notation:
beta_samples/beta_hat: marker (allele) effects.mu_samples/mu_hat: intercept (grand mean).sigma2_e_*: residual variance.sigma2_j_*(BayesA) andsigma2_{small,medium,large}_*(BayesR): per-marker / per-component variance components.gamma_samples/pi_samples(BayesR only): mixture allocations and their Dirichlet posterior weights.alpha_*: optional fixed-effect coefficients;Nonewhen no design matrixXwas supplied.z_hat: posterior mean of latent liabilities (Albert–Chib) for binary traits;Nonefor continuous traits.sigma2_g,h2: derived quantities — total additive variance and narrow-sense heritability computed from posterior means.