Backends¶
The inference engine is swappable behind the InferenceBackend protocol. KalmanBackend is the default fast path; RxInferBackend — imported from cpomdp.backends.rxinfer and gated behind the optional rxinfer extra — re-derives the same answers through Julia and exists as an independent correctness oracle [^bagaev2023rxinfer].
InferenceBackend ¶
Bases: Protocol
A swappable inference engine for a LinearGaussianModel.
A backend is built from a model: any expensive, data-independent work
(front-loading — see DECISIONS.md ADR-002) happens at construction, so the
per-step infer_states stays cheap. Each call advances the belief one
recursive filter step: the current belief goes in as the prior and the
updated belief comes back as the posterior.
The Protocol is structural: any class with a matching infer_states is a
backend, with no shared base class. This is the abstraction wall — the
native Kalman fast path and the RxInfer oracle are interchangeable behind it,
and neither's implementation (JAX, juliacall, …) leaks into this signature.
infer_states ¶
Advance the belief by one filter step: prior in, posterior out.
Given the current belief (prior) and a new observation (plus the
action just taken, if the model has a control matrix), return the
updated belief.
Source code in src/cpomdp/backends/base.py
KalmanBackend ¶
KalmanBackend(
model: LinearGaussianModel,
*,
steady_state: bool = False,
tol: float = 1e-12,
max_iter: int = 1000,
)
Exact Kalman-filter inference for a LinearGaussianModel.
Implements the InferenceBackend protocol: constructed from a model,
then advances a belief one step at a time (prior in, posterior out) via
the standard predict/update recursion.
Two modes:
- Per-step (default): recomputes the Kalman gain and covariance every step from the incoming belief. Correct for any linear-Gaussian model, including transient (pre-convergence) behaviour. This is the analytic oracle the rest of the toolbox is validated against.
- Steady-state (
steady_state=True): solves the covariance recursion once at construction to a fixed point, then reuses the frozen gain and covariance every step. Cheap (no per-step covariance maths), but only valid for time-invariant models with regular complete observations. RaisesRuntimeErrorif the recursion does not converge withinmax_iter(i.e. the model is not stabilisable/detectable).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
LinearGaussianModel
|
The linear-Gaussian generative model to filter under. |
required |
steady_state
|
bool
|
If True, precompute and freeze the steady-state gain. |
False
|
tol
|
float
|
Convergence tolerance for the steady-state fixed point (absolute, on successive covariances). |
1e-12
|
max_iter
|
int
|
Cap on steady-state iterations before giving up. |
1000
|
Source code in src/cpomdp/backends/kalman.py
infer_states ¶
Advance the belief by one filter step.
Runs one predict/update cycle: step the prior through the dynamics
(applying action if the model has a control matrix), then correct the
prediction toward observation using the Kalman gain. In steady-state
mode the gain and covariance are the frozen fixed-point values; otherwise
they are recomputed from prior.cov on this step.
The numeric work is delegated to the jit-compiled module kernels
(_gain_and_posterior_cov, _posterior_mean); this method stays the
eager orchestrator that validates inputs and wraps the result in a
Belief.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
observation
|
ArrayLike
|
The latest sensor reading, shape |
required |
prior
|
Belief
|
The current belief, treated as this step's previous posterior. Never mutated. |
required |
action
|
ArrayLike | None
|
The action just taken, shape |
None
|
Returns:
| Type | Description |
|---|---|
Belief
|
The posterior belief — a new |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/cpomdp/backends/kalman.py
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | |
RxInferBackend ¶
Linear-Gaussian filtering via RxInfer.jl — the oracle backend.
Satisfies the InferenceBackend protocol: built from a model, advances a belief one step at a time. No steady-state mode — that belongs to the native fast path; this backend exists for correctness, not speed. The first instance built in a process loads the Julia runtime; later ones reuse it.
Source code in src/cpomdp/backends/rxinfer.py
infer_states ¶
Advance the belief one filter step: prior in, posterior out.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
observation
|
ArrayLike
|
Latest sensor reading, shape |
required |
prior
|
Belief
|
Current belief; never mutated. |
required |
action
|
ArrayLike | None
|
Action just taken, shape |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
On a shape/None mismatch (see |
Source code in src/cpomdp/backends/rxinfer.py
[^bagaev2023rxinfer]: Dmitry Bagaev, Albert Podusenko, and Bert de Vries. Rxinfer: a julia package for reactive real-time bayesian inference. Journal of Open Source Software, 8(84):5161, 2023. URL: https://doi.org/10.21105/joss.05161, doi:10.21105/joss.05161.