mixle.inference.backends module¶
Inference-backend registry — register, don’t branch for mixle.inference.
Mirrors mixle.stats.compute.kernel.register_kernel_factory(): each engine’s NUTS
implementation self-registers an InferenceBackend at import time, so the dispatcher
(mixle.inference.nuts()) never grows a central if engine == ... switch. A backend declares
name— the selector string ("numpy","numba","torch","jax").available— a zero-arg predicate: is the engine importable on this host? Kept lazy soimport mixle.inferenceworks with any subset of optional engines installed.target_kind— what contract the caller’s target must satisfy: a numpy fusedvalue_and_grad("numpy_vg"), an@njitfusedvalue_and_grad("njit_vg"), a torch scalarlogp("torch_logp"), or a jax scalarlogp("jax_logp"). The kinds cannot be auto-converted across autodiff systems, so the target is what ultimately picks a backend in"auto"mode (seeselect_backend()).nuts— the callable that runs the sampler and returns amixle.inference.NutsResult.
available_backends() lists the installed engines; select_backend() resolves the
backend= argument (including "auto").
- class InferenceBackend(name, available, target_kind, nuts)[source]
Bases:
objectA registered inference engine: a name, an availability probe, a target contract, a sampler.
- register_inference_backend(backend, *, replace=False)[source]
Register an inference backend under
backend.name.The registry is global process state that
select_backend()dispatches everynutscall through, so one malformed registration is not a local mistake – it corrupts dispatch for every caller. A backend with an empty name and an unrecognizedtarget_kindused to register successfully and become selectable, even thoughselect_backend()rejects that same kind string when a caller supplies it.Replacing an already-registered name requires
replace=True. Silent replacement let a second import or a typo’d name swap out a live sampler with no trace; an intentional override (a test double, a vendored engine) says so explicitly.- Raises:
TypeError – if
backendis not anInferenceBackend, oravailable/nutsare not callable.ValueError – for an empty/blank name, an unrecognized
target_kind, or an unrequested replacement of a registered name.
- Parameters:
backend (InferenceBackend)
replace (bool)
- Return type:
None
- get_inference_backend(name)[source]
Return the registered backend named
name(raises if unknown).- Parameters:
name (str)
- Return type:
InferenceBackend
- available_backends()[source]
Return the names of registered backends whose engine is importable, in registration order.
Each probe is isolated: one backend whose
available()raises used to propagate out of this call and hide every healthy backend, so a single broken third-party registration made the always-present numpy path look unavailable too. A raising probe answers “unknown”, which is reported as a warning and treated as unavailable – it cannot be silently equivalent to a probe that returnedFalse, because the caller may need to know its engine is misconfigured rather than absent.
- backend_availability()[source]
Per-backend
(name, available, probe_error)in registration order.probe_errorisNoneunless that backend’savailable()raised, in which case it is the formatted exception andavailableisFalse.
- select_backend(backend='auto', target=None)[source]
Resolve a
backend=argument to a concrete, available backend name.Policy:
An explicit
backend(anything but"auto") is honored — it must be registered and its engine importable, else a clear error."auto"with atargetkind hint picks the first preferred-and-available backend for that kind (e.g."torch_logp"-> torch;"numpy_vg"-> numpy, then numba). This keeps the always-available numpy path the default for plain numpy targets. A declared kind is a contract, not a preference: if no backend advertising that contract is available, this raises rather than silently handing e.g. a torch/jax scalarlogpto a backend that will call it expecting a numpyvalue_and_grad -> (value, gradient)pair. The kinds are not convertible across autodiff systems, so there is no correct fallback between them."auto"with no hint (target=None) falls back to the first available backend, preferring"numpy"(the always-present, dependency-free path) when it is available. This is the genuinely undetermined case – a numpy and an@njitvalue_and_gradare indistinguishable plain callables – and stays unchanged.
- Raises:
ValueError – if
targetis not one of the known target kinds.RuntimeError – if nothing is available, the explicit choice is unavailable, or no available backend implements the declared
targetkind.
- Parameters:
- Return type: