Migrating to the Rust backend

PyMAB now keeps the public Python policy classes while storing built-in policy state and running compatible experiments in Rust. Existing constructors, updates, recommendations, result shapes, and statistical APIs remain available.

Backend selection

ExperimentConfig.backend accepts three values:

"auto"

Use Rust when the environment, reward model, dynamics, context provider, and every policy are built-ins. Fall back to Python when custom callbacks are present. This is the default.

"rust"

Require native execution. An incompatible custom component raises one aggregated compatibility error before the experiment starts.

"python"

Run the private pure-Python behavioral reference. This is useful for parity investigation, not as the performance path.

Random streams

The Rust runner uses versioned Blake2b-derived ChaCha12 streams. It preserves replay within the Rust backend, common-versus-independent reward coupling, and policy-order isolation. Rust and Python backends intentionally publish different RNG scheme identifiers, so identical seeds do not promise identical stochastic samples across languages. Deterministic single-arm traces and all learned-state transitions are covered by shared parity fixtures.

Custom components

Custom Python policies, reward models, dynamics, and context providers continue to work through backend="auto" or backend="python". Use experiment.backend_compatibility() to inspect every reason a configuration cannot enter the native loop. No Python callback is invoked from the Rust hot loop.

Packaging

Published Python wheels contain the private native extension for CPython 3.11–3.14 on supported Linux, macOS, and Windows platforms. Source builds need Rust 1.83 or newer. Rust applications can depend directly on the matching pymab crate; Python and Rust artifacts share one release version.