Core C++ engine for 'glmbayes': envelope-based iid linear and
generalized linear model samplers, prior-family routing, and optional
'OpenCL' acceleration. Sampling for supported non-conjugate models uses
accept-reject methods based on likelihood subgradients as in Nygren and
Nygren (2006)
glmbayesCore is the compiled sampling engine that powers the glmbayes ecosystem. It holds the C++/OpenCL envelope samplers, the family-function infrastructure, and the R-level prior and simulation interfaces that downstream packages depend on. End users should install glmbayes rather than this package directly.
The relationship to the broader ecosystem parallels how StanHeaders /
rstan serve as the compiled backbone for rstanarm: glmbayesCore is
the infrastructure layer; glmbayes and the in-development lmebayes
are the user-facing packages built on top of it.
Current staging note. This tree currently ships the iid GLM/LM envelope engine used by glmbayes. Mixed-model (LMM/GLMM / two-block) engines are still part of the long-term glmbayesCore API and are under active development in the temporary lmebayesCore fork (consumed by lmebayes). Think of lmebayesCore as a development holding package: features return here gradually once the iid backend is stable (CRAN / glmbayes re-import path).
Target architecture (after mixed-model reintegration):
┌─────────────────────────────────────────┐
│ End-user packages │
│ glmbayes · lmebayes · (others) │
└──────────────────┬──────────────────────┘
│ Imports / LinkingTo
┌──────────────────▼──────────────────────┐
│ glmbayesCore │
│ iid GLM/LM · LMM/GLMM · OpenCL │
│ pfamily · simfunctions · rglmb/rlmb │
└──────────────────┬──────────────────────┘
│ Imports
┌──────────────────▼──────────────────────┐
│ opencltools · nmathopencl │
│ Rcpp · RcppArmadillo · RcppParallel │
└─────────────────────────────────────────┘
Temporary staging (today): glmbayes → glmbayesCore (iid); lmebayes → lmebayesCore (full fork including mixed-model stack). The fork collapses back into glmbayesCore as features are merged.
glmbayes adds the formula interface (glmb(), lmb()), MCMC diagnostics,
and the full suite of S3 methods that mirror base-R's lm() / glm().
lmebayes (in development) extends the engine to linear / generalized
linear mixed-effects models (lmerb(), glmerb()).
src/)The core is organized under the glmbayes:: namespace:
| Sub-namespace | Key files | Role |
|---|---|---|
glmbayes::fam |
famfuncs.h, famfuncs_*.cpp |
Negative log-posterior (f2) and gradient (f3) for gaussian, poisson, binomial, Gamma |
glmbayes::env |
EnvelopeBuild*.cpp, EnvelopeEval.cpp, EnvelopeSort.cpp, EnvelopeSize.cpp, Set_Grid.cpp, Set_LogP.cpp |
Piecewise-exponential envelope construction (Nygren & Nygren, 2006) |
glmbayes::sim |
rNormalGLM.cpp, rIndepNormalGammaReg.cpp, rNormalGammaReg.cpp, rNormalReg.cpp, rGammaGamma.cpp, rGammaGaussian.cpp |
Posterior samplers |
glmbayes::rng |
rng_utils.cpp |
Thread-safe RNG wrappers for parallel sampling |
glmbayes::progress |
progress_utils.cpp |
Optional progress bar support |
Export wrappers in export_wrappers.cpp and kernel_wrappers.cpp expose
selected entry points to R via Rcpp.
inst/cl/)For systems with an OpenCL-capable device, envelope construction can be
offloaded to the GPU. The inst/cl/ tree contains family/link f2/f3
kernels, an OpenCL port of R Mathlib probability functions, and shim headers.
Kernel loading for exploration uses opencltools; runtime GPU assembly uses
kernel_loader.cpp and kernel_runners.cpp.
R/)| File | Role |
|---|---|
pfamily.R |
Prior-family constructors (dNormal, dNormal_Gamma, dIndependent_Normal_Gamma, dGamma, dBeta) and the pfamily() generic |
prior.R |
Prior_Setup(), Prior_Check(), and helper utilities for default hyperparameters |
simfunction.R |
Low-level simulation functions (rNormal_reg, rNormalGamma_reg, rindepNormalGamma_reg, rGamma_reg, …) and the simfunction() introspection generic |
simulationpipeline.R |
glmbfamfunc(), envelope R exports, standardized samplers |
rglmb.R / rlmb.R |
Matrix-input samplers — the primary R-level interface for glmbayes |
envelopeorchestrator.R |
R orchestration of multi-step envelope building and optional GPU dispatch |
compute_gaussian_prior.R |
Gaussian-specific prior calibration utilities |
A pfamily object is a self-contained prior specification. Every constructor
bundles the hyperparameters into a prior_list and embeds a simfun
function pointer. When rglmb() draws samples, it calls
pfamily$simfun(y, x, prior_list, family, ...) — there is no internal
switch on prior type.
rglmb(y, x, pfamily = dNormal(...), family = poisson())
│
└─► pfamily$simfun ──► rNormal_reg()
│
family == gaussian?
├── Yes ──► conjugate multivariate normal draw
└── No ──► envelope sampling (Nygren & Nygren, 2006)
│
└──► rNormalGLM (C++)
| pfamily constructor | Embedded simfun |
Posterior path |
|---|---|---|
dNormal() |
rNormal_reg() |
Conjugate MVN draw (Gaussian); subgradient envelope sampling (other families) |
dNormal_Gamma() |
rNormalGamma_reg() |
Conjugate Normal-Gamma draw (Gaussian only) |
dIndependent_Normal_Gamma() |
rindepNormalGamma_reg() |
Joint coefficient + dispersion envelope (Gaussian; non-conjugate) |
dGamma(Inv_Dispersion = TRUE) |
rGamma_reg() |
Gamma prior on inverse dispersion |
dGamma(Inv_Dispersion = FALSE) |
rGamma_Conjugate_reg() |
Conjugate Gamma–Poisson or Gamma–Gamma (intercept-only, identity link) |
dBeta() |
rBeta_reg() |
Conjugate Beta–Binomial (intercept-only, identity link) |
Prior_Setup() fits an auxiliary GLM and returns calibrated hyperparameters
on the same scale as the design matrix.
rNormal_reg()rNormal_reg(y, x, prior_list, family, ...)
│
family$family == "gaussian"?
├── Yes ──► direct MVN draw via backsolve / Cholesky
└── No ──► EnvelopeOrchestrator (R)
├── EnvelopeBuild (C++)
└── rNormalGLM (C++) [accept-reject; optional OpenCL envelope]
rindepNormalGamma_reg()rindepNormalGamma_reg(y, x, prior_list, ...)
│
└──► rIndepNormalGammaReg (C++)
├── EnvelopeBuild_Ind_Normal_Gamma per dispersion grid point
└── joint accept-reject over (beta, dispersion)
rGamma_reg()rGamma_reg(y, x, prior_list, family, ...)
│
family$family == "gaussian"?
├── Yes ──► rGammaGaussian (C++)
└── No ──► rGammaGamma (C++)
rglmb() Orchestrates a Drawrglmb() validates the family × pfamily combination and delegates sampling
to the simfun embedded in the pfamily object. In glmbayes, glmb() and
lmb() wrap rglmb() / rlmb() with formula parsing.
rglmb(y, x, family = poisson(), pfamily = dNormal(mu, Sigma), n = 1000)
│
├─ 1. Resolve family
├─ 2. Unpack pfamily (okfamilies, plinks, prior_list, simfun)
├─ 3. Validate combination
├─ 4. outlist ← simfun(...)
└─ 5. Post-process → class c("rglmb", "glmb", "glm", "lm")
Adding a new prior family requires a new pfamily constructor and simulation
function — not changes to rglmb() itself.
Symbols below are exported from glmbayesCore today (iid path). End users typically load glmbayes (or lmebayes for mixed models). Mixed-model exports temporarily ship from lmebayesCore and will return here.
| Function | Role |
|---|---|
Prior_Setup(), Prior_Check() |
Default prior calibration and prior predictive checks |
pfamily(), dNormal(), dNormal_Gamma(), dIndependent_Normal_Gamma(), dGamma(), dBeta() |
Prior-family constructors |
multi_prior_setup(), multi_rlmb() |
Multi-response Gaussian prior setup / LM sampler |
rglmb(), rlmb() |
Matrix-level Bayesian GLM / LM samplers |
diagnose_glmbayes() |
OpenCL / GPU diagnostic report |
| Function | Role |
|---|---|
compute_gaussian_prior() |
Internal Gaussian calibration used inside Prior_Setup() |
simfunction(), glmbfamfunc() |
Simulation registry and GLM family pipeline helpers |
rNormal_reg(), rNormalGamma_reg(), rindepNormalGamma_reg(), rGamma_reg(), rBeta_reg(), … |
Low-level simfunction samplers |
rNormalGLM_std(), rIndepNormalGammaReg_std(), glmb.wfit(), glmb_Standardize_Model() |
Standardized envelope path and fitter hooks |
EnvelopeBuild(), EnvelopeOrchestrator(), EnvelopeSize(), … |
Accept–reject envelope machinery |
pnorm_ct(), rnorm_ct(), pinvgamma_ct(), rgamma_ct(), … |
Truncated-distribution C++ callbacks |
These are part of the long-term glmbayesCore surface for lmebayes. They are not exported from this tree today.
| Area | Examples |
|---|---|
| Setup | model_setup(), Prior_Setup_lmebayes(), pfamily_list() |
| Matrix drivers | rlmerb(), rglmerb() |
| Two-block / sweep | rGLMM_reg*, rLMM_reg*, rGLMM_sweep(), two_block_*, plot_sweep_history_diag() |
| Block helpers | build_mu_all(), ICM helpers, block_rNormalReg() / block_rNormalGLM() |
Typical lmebayes workflow (via lmebayesCore for now):
model_setup() → Prior_Setup_lmebayes() → pfamily_list(ps) →
lmerb() / glmerb().
LinkingTo)#include "glmbayesCore/famfuncs.h"
#include "glmbayesCore/Envelopefuncs.h"
#include "glmbayesCore/simfuncs.h"
#include "glmbayesCore/R_interface.h"
library(glmbayesCore)
fit <- rindepNormalGamma_reg(
y = y, x = X, n = 2000,
prior_list = dIndependent_Normal_Gamma(mu, Sigma, shape, rate)$prior_list,
family = gaussian()
)
rglmb() / rlmb() with pfamily objectsps <- Prior_Setup(y, X, family = poisson())
fit <- rglmb(y = y, x = X, n = 1000,
pfamily = dNormal(mu = ps$mu, Sigma = ps$Sigma),
family = poisson())
GitHub / R-Universe (recommended for developers):
install.packages("glmbayesCore",
repos = c("https://cloud.r-project.org",
"https://knygren.r-universe.dev"))
From source (required for OpenCL GPU support):
install.packages("glmbayesCore", type = "source",
repos = "https://knygren.r-universe.dev")
See Chapter 16 — Large models: GPU acceleration using OpenCL for system-level setup instructions.
Dependencies that must be installed first:
install.packages(c("Rcpp", "RcppArmadillo", "RcppParallel", "MASS", "Rdpack"))
install.packages(c("opencltools", "nmathopencl"),
repos = "https://knygren.r-universe.dev")
See inst/ADDING_PFAMILY.md. In summary:
pfamily.R that builds prior_list and sets simfun.simfunction.R.src/, register via
Rcpp::compileAttributes(), and expose it through export_wrappers.cpp.f2/f3 OpenCL kernel under
inst/cl/src/ and register it in kernel_loader.cpp.The orchestrator pattern is intentionally generic: validate a model
specification, unpack a routing object, call the embedded simfun,
post-process. Mixed-effects drivers in lmebayes (lmerb(), glmerb())
build on two-block Gibbs engines that will return to this package. While
those engines are staged in lmebayesCore, architecture notes
(ergodicity, rGLMM_sweep / Block~1–Block~2 call chains, C++ migration
plans) live there and will move back with the code.
A complete bibliography is in inst/REFERENCES.bib.
model_setup, Prior_Setup_lmebayes,
pfamily_list), matrix drivers (rlmerb / rglmerb), and two-block /
block-ING engines back into glmbayesCore, then point lmebayes at
this package again and retire lmebayesCore.sweep_history on all two-block paths:
Mixed-model sampling should use a sweep-outer loop (all chains
complete inner sweep m, then m+1, …) on every route, for consistency
with rGLMM_sweep() / rGLMM_reg_*. Each stored draw should attach
sweep_history (class two_block_sweep_history) so print() and
plot_sweep_history_diag() can diagnose inner-Gibbs convergence.
Sweep-outer R drivers and ING pilot/main paths already capture history in
the lmebayesCore fork; gaps remain on some Gaussian fixed-τ² / fixed-σ²
routes that still use a chain-outer C++ driver without per-sweep
cross-chain stats.src/*.cpp drivers.
Parallelism should be within-block, across chains at fixed inner
sweep m (not parallel inner sweeps): Block~1 random-effect updates
over replicate chains first (higher priority); Block~2 fixed-effect
/ hyperparameter updates over chains where safe (ideal follow-on).
Use native threading (e.g. RcppParallel) so large n does not pay full
R-loop overhead.LinkingTo: opencltools, thin
manifest-based loader.GPL-2. See the LICENSE file and inst/COPYRIGHTS for attribution of
incorporated R Mathlib sources.