C++ Architecture

Warning

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.

Warning

Never hand-edit src/sources.mk. Run Rscript inst/generate_makevars_sources.R after adding or removing .cpp files.