C++ Architecture
This page has not yet passed technical or readability review.
The bgms C++ backend is organized in five top-level directories under src/. Each directory has a distinct role, and dependencies flow downward: algorithms depend on math utilities but not on models, and the execution layer orchestrates everything.
Source layout
src/
├── mcmc/
│ ├── algorithms/ # Stateless: nuts_step(), hmc_step(), leapfrog()
│ ├── samplers/ # Stateful: NUTSSampler, HMCSampler, MetropolisSampler
│ └── execution/ # Orchestration: chain_runner, warmup_schedule, chain_result
├── models/
│ ├── base_model.h # Abstract interface (30+ virtual methods)
│ ├── ggm/ # GGMModel — precision matrix, Metropolis-only
│ ├── omrf/ # OMRFModel — ordinal MRF, gradient-based
│ └── mixed/ # MixedMRFModel — mixed discrete-continuous MRF
├── priors/
│ ├── edge_prior.h # BaseEdgePrior + Bernoulli, BetaBernoulli, SBM
│ ├── sbm_edge_prior.h # MFM-SBM Gibbs updates
│ └── sbm_edge_prior.cpp
├── math/
│ ├── cholupdate.h/cpp # Rank-1 Cholesky update/downdate (Givens/hyperbolic)
│ ├── cholesky_helpers.h # Log-determinant, Schur complement
│ ├── custom_explog.h/cpp # OpenLibM exp/log for cross-platform consistency
│ ├── custom_arma_explog.h # Armadillo wrappers for custom exp/log
│ └── explog_macros.h # Platform detection macros (MY_EXP, ARMA_MY_EXP)
├── utils/
│ ├── variable_helpers.h/cpp # Numerically stable MRF probabilities
│ ├── common_helpers.h # Enums (UpdateMethod, EdgePrior), counting helpers
│ ├── progress_manager.h/cpp # Multi-chain progress bar
│ └── print_mutex.h # Thread-safe printing
├── rng/
│ └── rng_utils.h # SafeRNG wrapper around dqrng::xoshiro256plusplus
├── bgmCompare/ # Group comparison sampler and helpers
│ ├── bgmCompare_sampler.h/cpp
│ ├── bgmCompare_helper.h/cpp
│ ├── bgmCompare_logp_and_grad.h/cpp
│ └── bgmCompare_output.h
└── [interface files] # Rcpp entry points: sample_ggm.cpp, sample_omrf.cpp, etc.
Layer separation
| Layer | Location | Responsibility |
|---|---|---|
| Algorithms | mcmc/algorithms/ |
Pure functions that perform one MCMC step. No state, no model knowledge. |
| Samplers | mcmc/samplers/ |
Stateful objects that own adaptation state and delegate to algorithms. |
| Execution | mcmc/execution/ |
Chain runner, warmup scheduling, sample storage. |
| Models | models/ |
Log-posterior, gradient, Metropolis proposals. Each model implements BaseModel. |
| Priors | priors/ |
Edge inclusion prior updates. Each prior implements BaseEdgePrior. |
| Math | math/ |
Numerical primitives: Cholesky updates, cross-platform exp/log. |
| Utilities | utils/ |
Shared helpers: stable probability computation, progress tracking, enums. |
Design principles
Separation of concerns. Algorithms know nothing about models. A nuts_step() call receives a function logp_and_gradient(vec) → (double, vec) and returns a StepResult. The model provides the function; the algorithm does the math.
Virtual dispatch for models. All models inherit from BaseModel and override a small set of virtual methods. The chain runner calls model.logp_and_gradient() without knowing whether it is sampling a GGM or an ordinal MRF. See Model Classes.
Cloning for parallelism. Both BaseModel and BaseEdgePrior expose a clone() method that produces an independent copy. The Rcpp entry point constructs a single model from R input and passes it to run_mcmc_sampler(). Inside C++, that prototype is cloned once per chain (each clone receiving its own RNG seed), and the clones are dispatched to TBB threads via RcppParallel::parallelFor(). R never interacts with the clones directly — parallelism is entirely C++-side. After all chains finish, the vector<ChainResult> is converted to an R list and returned. See Parallel Chains.
Header-only samplers. The sampler classes in mcmc/samplers/ are header-only. They are lightweight wrappers that hold adaptation state and call algorithm functions from mcmc/algorithms/.
Rcpp interface files. The top-level .cpp files in src/ (sample_ggm.cpp, sample_omrf.cpp, sample_mixed.cpp, bgmCompare_interface.cpp) are thin Rcpp entry points. They construct C++ objects from R lists and call run_mcmc_sampler().
Build system
src/Makevars.in (configured by configure/configure.win) sets compiler flags and links against RcppArmadillo, RcppParallel (TBB), and dqrng. The file src/sources.mk lists all .cpp translation units and is auto-generated by inst/generate_makevars_sources.R.
Never hand-edit src/sources.mk. Run Rscript inst/generate_makevars_sources.R after adding or removing .cpp files.