Skip to main content

rustmc

Bayesian inference powered by Rust, with a Python API.

Project status: alpha. rustmc is suitable for research, evaluation, and controlled internal workflows. Its supported modeling surface is useful but still intentionally smaller than mature probabilistic programming systems. Validate every model on representative data before using its output for consequential decisions.

rustmc is a practical, general-purpose Bayesian toolkit. It combines graph-based automatic differentiation and NUTS/HMC with reusable compiled models, exact conjugate inference, and specialized state-space algorithms. A generic sampler is available when a model needs one, while focused methods can be added when a research or production problem benefits from them.

rustmc complements PyMC and Stan rather than trying to replace them. Its practical distinction is native Rust execution and Rayon-powered parallelism across chains and repeated-model workloads. That foundation can support fast forecasting, regression, and domain-specific models in biomedical research, engineering, science, finance, and other fields. The project aims to keep those implementations understandable enough to inspect, adapt, and extend for real work.

Why rustmc

  • General and specialized inference in one runtime. The model builder uses reverse-mode automatic differentiation with NUTS or HMC. Local-level, seasonal, and trend models use FFBS/Gibbs, while Gaussian AR(p) uses an exact Normal-Inverse-Gamma posterior.
  • Compile once, bind many. ModelBuilder.compile() separates immutable model structure from validated datasets, including datasets with different row counts.
  • Native execution. Sampling, state-space operations, and chain coordination execute in Rust outside the Python hot path.
  • Deterministic parallelism. Chains and repeated-model workloads use Rayon with stable per-chain seed derivation and ordered results.
  • A focused scope. General inference and specialized model implementations share a native core, so domain methods can be added without pursuing feature parity with a mature probabilistic-programming language. The Python binding surface still needs the modularization described in the roadmap before that extension path is as simple as it should be.
  • Bayesian workflow support. Prior predictive checks, posterior predictive draws, pointwise log likelihood, convergence diagnostics, and ArviZ export are available for the generic inference path.
  • Coherent uncertainty. Specialized forecasting APIs retain complete (chain, draw, horizon) paths so derived totals and other nonlinear quantities can be calculated draw by draw.

These are implementation capabilities, not a universal speed or accuracy claim. Performance and statistical quality depend on the model, data, tuning, and hardware.

Installation

Install the latest published Python package with:

pip install rustmc

To build the current source instead of installing a published wheel:

git clone https://github.com/tbosier/rustmc.git
cd rustmc
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip maturin numpy
maturin develop --manifest-path python_bindings/Cargo.toml --release

Python 3.9 through 3.13 are covered by source-install and wheel-install CI. NumPy is the only required Python runtime dependency. ArviZ and Matplotlib are optional:

pip install "rustmc[viz]"

The Python extension is the supported public package today. rustmc_core contains the Rust implementation, but its public API should still be considered unstable.

Quick start

Version 0.12 adds custom expressions and future-data prediction, composable structural forecasts, and dynamic count, hurdle, and pooled Gaussian models. The forecasting workflow guide covers backtests, scores, named features, scenarios, storage, and updates.

This example fits a Bayesian linear regression with NUTS:

import numpy as np
import rustmc as rmc

rng = np.random.default_rng(42)
x = rng.normal(size=1_000)
y = 2.5 * x + rng.normal(size=1_000)

builder = rmc.ModelBuilder()
beta = builder.normal_prior("beta", mu=0.0, sigma=1.0)
builder.normal_likelihood(
    "obs",
    mu_expr=beta * "x",
    sigma=1.0,
    observed_key="y",
)

fit = rmc.sample(
    model_spec=builder.build(),
    data={"x": x, "y": y},
    chains=4,
    warmup=1_000,
    draws=1_000,
    seed=42,
)
print(fit.summary())

The same modeling surface supports scalar hierarchical priors, GLM-style expressions, and a vectorized beta @ "X" path backed by faer.

Reuse one model structure

When the structure is shared across datasets, compile it once and bind new data:

builder = rmc.ModelBuilder()
intercept = builder.normal_prior("intercept", mu=0.0, sigma=5.0)
slope = builder.normal_prior("slope", mu=0.0, sigma=2.0)
builder.normal_likelihood(
    "obs",
    mu_expr=intercept + slope * "x",
    sigma=1.0,
    observed_key="y",
)

compiled = builder.compile()
batch = compiled.sample_batch(
    [
        {"x": x_a, "y": y_a},
        {"x": x_b, "y": y_b},
    ],
    ids=["dataset-a", "dataset-b"],
    chains=4,
    warmup=500,
    draws=1_000,
    seed=42,
)

CompiledModel validates each binding against the same structural schema. The legacy sample() and batch_sample() entry points remain available.

Forecasting as an application

Forecasting is one application of rustmc's structure-aware inference rather than the definition of the library. Current specialized models include a joint hierarchical mean for ragged related series, Bayesian local level, seasonal local level, local linear trend, and directly observed Gaussian AR(p), plus fixed-parameter linear Gaussian state-space filtering, smoothing, and a sum-to-zero seasonal constructor.

For many short program series, fit one population → group → program posterior instead of independently batching models:

model = rmc.BayesianHierarchicalMean(
    group_variance_prior=rmc.InverseGammaPrior(3.0, 20.0),
    program_variance_prior=rmc.InverseGammaPrior(3.0, 10.0),
    observation_variance_prior=rmc.InverseGammaPrior(3.0, 25.0),
    population_mean_prior=100.0,
    population_variance_prior=400.0,
)
fit = model.fit(
    [program_a, program_b, program_c],       # unequal lengths are native
    group_index=[0, 0, 1],
    program_names=["a", "b", "c"],
    group_names=["division-a", "division-b"],
)
forecast = fit.forecast(steps=12)

# (chain, draw, program, step); chain/draw alignment preserves dependence.
company_draws = forecast.observation_samples.sum(axis=2)
division_draws = forecast.group_observation_samples

This MVP pools a static Gaussian intercept/mean; it is not a dynamic local-level model. Its conjugate Gibbs kernel samples the joint hierarchy directly and avoids requiring HMC to navigate a funnel. Centered Gibbs can still mix slowly near zero variance, so inspect fit.summary()/fit.diagnostics(); explicit priors remain important for sparse groups.

values = np.asarray(
    [101, 98, 103, 105, 102, 108, 111, 109, 114, 116, 113, 119,
     121, 118, 123, 126, 124, 129, 131, 128, 134, 136, 133, 139],
    dtype=float,
)

model = rmc.BayesianLocalLevel(
    process_variance_prior=rmc.InverseGammaPrior(shape=3.0, scale=20.0),
    observation_variance_prior=rmc.InverseGammaPrior(shape=3.0, scale=50.0),
    initial_mean=float(values[0]),
    initial_variance=100.0,
)
fit = model.fit(values, chains=4, warmup=500, draws=1_000, seed=42)
forecast = fit.forecast(steps=12, seed=43)

predictive_lower, predictive_upper = forecast.interval(0.95)
level_lower, level_upper = forecast.state_interval(0.95)

# Derived quantities are summarized after calculation within each joint draw.
six_period_totals = forecast.observation_samples[:, :, :6].sum(axis=2)
total_mean = six_period_totals.mean()
total_interval = np.quantile(six_period_totals, [0.025, 0.975])

The observation interval is posterior predictive; the latent-level interval is a credible interval for the expected level. Applications include demand, operations, sensor data, and financial series such as rebate accruals. Rebate payments are only an example: choose a model for settlement timing, zeros, contract drivers, and positive support, with priors matched to observation units.

The fitted Gaussian models support joint Bayesian regressors and Fourier calendar terms, including known future design rows. Calendar coefficients, structural states, and variance parameters remain aligned in posterior forecast paths. Native independent batches fit ragged cells with stable IDs, explicit worker limits, per-cell diagnostics, and collected errors. Annual seasonal models accept histories shorter than two full cycles under proper priors.

For sparse nonnegative amounts, BayesianHurdleLogNormal combines a learned zero probability with dynamic positive severity and bounded log variances. DirichletMultinomialRunoff models payment-event counts by cohort and lag, including unknown ultimate counts and an explicit unscheduled tail. Runoff count inputs represent events; currency amounts need an amount model.

Forecasting examples:

Implemented surface

Area Current support
Generic inference NUTS with configurable target_accept, fixed-trajectory HMC, transformed continuous parameters, parallel chains
Continuous priors Normal, Student-t, HalfNormal, Exponential, LogNormal, Gamma, Beta, Uniform
Likelihoods Normal, Bernoulli-logit, Poisson-log, Exponential, LogNormal, Negative Binomial
Model structure Joint ragged hierarchical means, scalar hierarchical priors, scalar/vector regression expressions, automatic non-centering for supported generic scalar hierarchies
Diagnostics Rank-normalized folded split R-hat, bulk/tail ESS, MCSE and HDIs on generic and specialized fits; sampler-specific divergence/acceptance metadata
Predictive workflow Prior predictive, posterior predictive, pointwise log likelihood, ArviZ export
Repeated models In-memory compile/bind reuse, generic batch sampling, and independent forecasting batches with stable cell IDs
Fixed state space Constant transitions and time-varying observation rows, Kalman filter, RTS smoother, missing observations, joint and cumulative conditional forecasts
Specialized inference Bayesian level/trend/seasonal regression, Fourier calendar features, Gaussian AR(p), sparse hurdle lognormal, and payment-count runoff

Bernoulli and Poisson are exposed for prior-predictive use, but discrete latent parameters are not suitable for the current gradient-based samplers. Fitted AR(p) coefficient draws are not constrained to the stationary region; explosive draws are possible and are not silently discarded.

Validation and benchmarks

The repository includes finite-difference autodiff checks, analytic and synthetic posterior recovery, state-space reference tests, cross-thread determinism checks, Python API tests, and clean-wheel verification.

Run the core verification with:

cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --release
python -m pytest -q

Run python examples/run_benchmarks.py --help for the benchmark harness. This README does not publish a numeric cross-engine result because the repository does not retain a complete raw output, environment, and revision for one. Use benchmarks/RESULTS_TEMPLATE.md when publishing a result, and report statistical quality together with wall time.

The separate demo-docs synthetic forecasting study retains its generated data, model-selection code, raw outputs, RustMC plots, comparison timings, and negative results. It is a diagnostic example, not a general product benchmark.

Tests establish behavior on their stated reference cases. They do not prove that a new model is appropriate for a user's data or that its intervals are calibrated under misspecification.

Current limitations

  • The expression and distribution surface is deliberately finite; arbitrary user-defined probability functions and broad tensor algebra are not yet supported.
  • Expressions support scalar and elementwise operations, matrix-vector regression, named dimensions, and group indexing; unrestricted tensor programs remain outside scope.
  • Generic compiled models and fits, structural models/fits, dynamic-family fits, and forecast draws have versioned persistence. These are prediction artifacts, not sampler checkpoints; they do not resume RNG/adaptation state.
  • Explicit unconstrained chain initialization is available. BFMI is not yet reported.
  • Structural AR coefficients, damping, and Student-t degrees of freedom are fixed. Dynamic GLM scales and negative-binomial dispersion are fixed inputs; coefficients and time states are inferred jointly. Learned scales for these GLMs need another kernel.
  • Singular predictive covariance systems are not supported by the structural FFBS solver.
  • Shared-factor dynamics, stochastic volatility, regime switching, and calendar-varying payment lag probabilities remain future extensions.
  • Performance has not been established on a representative, retained benchmark corpus.

See ROADMAP.md for the ordered engineering plan and differentiated capability ideas.

Contributing

See CONTRIBUTING.md for development and evidence requirements. Bug reports are most useful when they include a minimal model, seed, environment, diagnostics, and expected result.

License

MIT

Release files for rustmc 0.12.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rustmc 0.12.0
File Size Uploaded
rustmc-0.12.0.tar.gz 264.3 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for rustmc 0.12.0
File
rustmc-0.12.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
rustmc-0.12.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
rustmc-0.12.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details
rustmc-0.12.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
rustmc-0.12.0-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 9.7 MB

Release files / rustmc-0.12.0.tar.gz

Download URL rustmc-0.12.0.tar.gz
Size 264.3 kB
Tags Source
SHA-256 checksum
How to use checksums
1cae6d66a3a7e0790012dbdc8bc0a09b7ec8c931df3c4cc8e43961e1152ce591
BLAKE2b-256 checksum
How to use checksums
2e0d219ede3f5605887ab48cb5b9949fbadc6c83d65a9990ca5f05fda2d9a963
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / rustmc-0.12.0-cp39-abi3-win_amd64.whl

Download URL rustmc-0.12.0-cp39-abi3-win_amd64.whl
Size 1.7 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
0404bd5939919334df503179126c1ebf61c3a2630dbdd68b815da2138eae3953
BLAKE2b-256 checksum
How to use checksums
1d4fd4f97f046b574aa5130d616b363a236c67f9ec5f32f22c73f24d05d525ab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / rustmc-0.12.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL rustmc-0.12.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 2.0 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
181e1ca39b621d644f43b18b48666d22bbf5c1fa6b9eb3c33d5d1e4155df69b0
BLAKE2b-256 checksum
How to use checksums
5bf59b428cd336dc9e5b9a78d93e0ca168c51b3c63d46adeb49f4284dff067ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / rustmc-0.12.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL rustmc-0.12.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 2.0 MB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
15770a24132235f2293692f09356c8d2931851de88213aa24c4ca8a837b77468
BLAKE2b-256 checksum
How to use checksums
d49768f6985890380de9a703fa86b107e077a481dbd5d305a9ef2101bbf54cff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / rustmc-0.12.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL rustmc-0.12.0-cp39-abi3-macosx_11_0_arm64.whl
Size 1.8 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
204f14c7e0ddcff33fa01c4dd9b14458d8865595104e006ffd4dbd29396a55c2
BLAKE2b-256 checksum
How to use checksums
860198a9094259f6f9ac6e028c8b91332a4a8681c76f1170b6a253fb4af2d221
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / rustmc-0.12.0-cp39-abi3-macosx_10_12_x86_64.whl

Download URL rustmc-0.12.0-cp39-abi3-macosx_10_12_x86_64.whl
Size 1.9 MB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
eddb0d7d226328618ff5038b77da21019a52f3499ac9f2e59a6c8128fa04e518
BLAKE2b-256 checksum
How to use checksums
3d8aa71036337aa28ca790d48970befed462e14f8fa036d6c79dda14a32b8e7e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release history Release notifications | RSS feed

0.13.0

6 release files

This release

0.12.0 This release

6 release files

0.9.0

6 release files

0.8.0

6 release files

0.7.0

6 release files

0.6.0

6 release files

0.5.1

6 release files

0.4.0

5 release files

0.3.1

5 release files

0.3.0

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page