Metadata-Version: 2.4
Name: rustmc
Version: 0.13.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Mathematics
Requires-Dist: numpy
Requires-Dist: arviz ; extra == 'benchmark'
Requires-Dist: pymc ; extra == 'benchmark'
Requires-Dist: nutpie ; extra == 'benchmark'
Requires-Dist: numpyro ; extra == 'benchmark'
Requires-Dist: pytest>=7 ; extra == 'test'
Requires-Dist: maturin>=1.9.3,<2.0 ; extra == 'test'
Requires-Dist: numpy ; extra == 'test'
Requires-Dist: arviz ; extra == 'viz'
Requires-Dist: matplotlib ; extra == 'viz'
Provides-Extra: benchmark
Provides-Extra: test
Provides-Extra: viz
License-File: LICENSE
Summary: Structure-aware Bayesian inference powered by Rust
Keywords: bayesian,inference,mcmc,statistics,rust,python
License-Expression: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Changelog, https://github.com/tbosier/rustmc/blob/main/CHANGELOG.md
Project-URL: Documentation, https://tbosier.github.io/rustmc/
Project-URL: Issues, https://github.com/tbosier/rustmc/issues
Project-URL: Repository, https://github.com/tbosier/rustmc

# rustmc

Bayesian models in Python. Inference in Rust.

rustmc focuses on small, structured models you need to fit repeatedly: regressions,
group comparisons, calibration, and forecasts. Build a model once, fit new datasets,
and keep the posterior draws for prediction and diagnostics.

The project is **alpha**. The Python package is supported; the Rust API is still
changing. Check convergence and model fit on your own data.

```bash
pip install rustmc
```

NumPy is the only required Python dependency. Install `rustmc[viz]` for ArviZ and
Matplotlib. Python 3.9–3.14 are covered by install tests.

## Fit a regression

This example estimates an instrument's offset, gain, and measurement noise.

```python
import numpy as np
import rustmc as rmc

rng = np.random.default_rng(42)
x = np.linspace(-2, 2, 100)
y = 0.3 + 1.2 * x + rng.normal(0, 0.2, x.size)

model = rmc.ModelBuilder()
offset = model.normal_prior("offset", 0.0, 1.0)
gain = model.normal_prior("gain", 1.0, 0.5)
noise = model.half_normal_prior("noise", 0.5)
model.normal_likelihood("reading", offset + gain * "x", noise, "y")
compiled = model.compile()

fit = compiled.sample(
    {"x": x, "y": y}, chains=4, warmup=1000, draws=1000, seed=42,
    show_progress=False,
)
print(fit.summary())

future = fit.predict({"x": np.array([-1.0, 0.0, 1.0])}, seed=43)
print(np.quantile(future["reading"], [0.025, 0.975], axis=(0, 1)))
```

`predict` keeps the `(chain, draw, observation)` axes. Use `expected=True` for the
conditional mean without new observation noise. Priors above are chosen for this
example's units.

## Reuse the model

`compiled.sample()` accepts another dataset with the same columns and a different
number of rows. `compiled.sample_batch()` fits independent datasets with stable IDs:

```python
batch = compiled.sample_batch(
    [{"x": x, "y": y}, {"x": x[:50], "y": y[:50]}],
    ids=["instrument-a", "instrument-b"],
    chains=4, warmup=1000, draws=1000, threads=2, errors="collect",
    show_progress=False,
)
for instrument in batch.ids:
    if instrument not in batch.errors:
        print(instrument, batch.get(instrument).summary())
print(batch.errors)
```

Independent fits do not share information. For related groups, build one
[partial-pooling model](https://tbosier.github.io/rustmc/examples/site-effects/).

## What's included

- NUTS and HMC with autodiff, constrained parameters, and parallel chains.
- Scalar and vector regressions, group indexing, nonlinear expressions, and custom
  log-density terms. See [custom models](https://tbosier.github.io/rustmc/custom-models/).
- Prior and posterior prediction, pointwise log likelihood, R-hat, effective sample
  size, Monte Carlo error, and ArviZ export.
- Exact Gaussian AR regression, Gaussian hierarchical models, and Kalman/FFBS
  algorithms for state-space models.
- [Forecasting workflows](https://tbosier.github.io/rustmc/forecasting-workflows/) for structural, count,
  hurdle, and runoff models, with joint predictive paths and backtests.
- Versioned model and fit artifacts. Compiled model artifacts omit training data;
  fitted artifacts include it. Neither resumes sampler adaptation or RNG state.

## Two engines, one result surface

Models you write with `ModelBuilder` compile to a differentiable graph and are fitted
by NUTS or HMC. The forecasting models are different: structural, seasonal, AR,
dynamic GLM, hurdle, runoff, and the Gaussian hierarchy are hand-written samplers that
do not use that graph, its autodiff, or its samplers. Each exploits structure the
general sampler cannot, and they are not all the same kind: Gibbs with FFBS for the
Gaussian state-space models, exact independent conjugate draws for AR, block
elliptical slice sampling for dynamic GLMs, and — for runoff — either exact conjugate
draws or latent-count Gibbs, depending on whether every ultimate total is known.
`sampler_stats` on a fit reports which one ran, and whether warmup applied.

What they share is narrower than "one engine" suggests. `diagnostics` is genuinely
common: R-hat, ESS and MCSE are computed by the same code for every fit. The batch
executor is shared inside Rust, not just at the Python edge. `state_space` and
`forecast_diagnostics` are shared among the forecasting models but are not used by the
graph sampler at all. What every model does share is the Python surface: `summary()`
and `diagnostics()` mean the same thing wherever you find them. A change to the NUTS
sampler does not change a forecast, and vice versa.

The modeling language is deliberately small. PyMC and Stan offer broader model
support. rustmc aims to earn its place through repeated fitting and a few well-tested
specialized algorithms. Performance depends on the workload; see the
[benchmark protocol](https://github.com/tbosier/rustmc/blob/main/benchmarks/README.md).

## Start here

- [Instrument calibration](https://github.com/tbosier/rustmc/blob/main/examples/instrument_calibration.py): regression and new-data prediction.
- [Repeated calibration](https://github.com/tbosier/rustmc/blob/main/examples/repeated_calibration.py): one model, several datasets.
- [Site effects](https://github.com/tbosier/rustmc/blob/main/examples/site_effects.py): partial pooling with unequal group sizes.
- [Forecasting](https://github.com/tbosier/rustmc/blob/main/examples/custom_forecast_workflow.py): fit, predict, and evaluate.
- [Examples guide](https://github.com/tbosier/rustmc/blob/main/examples/README.md) and [API reference](https://tbosier.github.io/rustmc/reference/).

The [roadmap](https://github.com/tbosier/rustmc/blob/main/ROADMAP.md) tracks five priorities: statistical release gates,
representative benchmarks, native model artifacts, bounded batches, and consistent
results and diagnostics. Most of that work sits in the shared layer, so it reaches the
forecasting models and the graph models alike.

For source builds and checks, see [Contributing](https://github.com/tbosier/rustmc/blob/main/CONTRIBUTING.md).
MIT licensed.

