cpomdp
Continuous active inference for Python. The continuous-state sibling of pymdp.
Install
pip install cpomdpPython >=3.10. Documentation at cpomdp.inferogenesis.com.
Example
import jax.numpy as jnp
from cpomdp import Agent, Belief, LinearGaussianModel, StateGoal
# State is [position, velocity]. A push changes velocity, velocity carries
# position along, and we only ever observe position (through a noisy sensor).
dt = 0.1
model = LinearGaussianModel(
dynamics=[[1, dt], [0, 1]], # velocity carries position along
control=[[0], [dt]], # a push nudges velocity
sensor_model=[[1, 0]], # we observe position only
dynamics_noise=jnp.eye(2) * 1e-6,
sensor_noise=[[1e-2]],
prior=Belief(mean=[0, 0], cov=jnp.eye(2)),
)
# Tell it where to go: sit still at position 1.
agent = Agent(model, StateGoal([1.0, 0.0]))
true_state = jnp.array([0.0, 0.0])
for _ in range(100):
obs = model.sensor_model @ true_state # what the agent gets to see
agent.infer_states(obs) # perceive
action = agent.sample_action() # act
true_state = model.dynamics @ true_state + model.control @ action
print(jnp.round(agent.belief.mean, 3)) # ≈ [1, 0]Exact continuous perception
Linear mean dynamics and Gaussian noise make the filter an exact Kalman filter, closed form, nothing sampled. Under fixed noise there is no variational gap. The same code path runs whether the agent is tracking or acting. See the model and belief API.
Action that reaches the posterior covariance
Observation noise can depend on the state, R(x), and so can process noise, Q(x). The
mean stays linear. Because the covariance responds to what the agent does, the epistemic
term of expected free energy differs across policies and information-seeking behaviour
becomes available. See
observation models.
One knob between exploiting and exploring
StateGoal and ObservationGoal carry a precision. The pragmatic term scales with it
and the epistemic term does not, so that one number decides whether an agent heads
straight for the goal or detours to sharpen its belief first. See
action selection and goals.
Multi-step EFE, searched and certified
policy_efe scores an H-step horizon. EnumeratedEfeSearch sweeps the full action
space and returns a CompletenessCertificate, so the best plan is decided over the
declared action set rather than sampled from it. See
expected free energy.
Inference as message passing
Beliefs propagate over a Forney factor graph through the CouplingGraph backend. Where a
model cannot be flattened, cpomdp raises IncompatibleLinearizationError rather than
returning a quietly wrong number. See
factor graph models.
Capabilities
| Feature | Since | JAX | RxInfer |
|---|---|---|---|
| Exact Kalman perception and EFE action for linear-Gaussian models | 0.1.0 | yes | yes |
| State-dependent sensor noise R(x) | 0.3.0 | yes | no |
| Message passing over a Forney factor graph | 0.4.0 | yes | no |
| Multi-step EFE with exhaustive search and a completeness certificate | 0.4.4 | yes | no |
Releases
Cite this
@software{cpomdp2026,
author = {Inferogenesis},
title = {cpomdp},
version = {0.4.4},
year = {2026},
doi = {10.5281/zenodo.21334562},
url = {https://github.com/inferogenesis/cpomdp}
}The same record in Citation File Format: CITATION.cff at v0.4.4.