cpomdp

Continuous active inference for Python. The continuous-state sibling of pymdp.

Status
active
Version
0.4.4
Licence
MIT
DOI
10.5281/zenodo.21334562

Install

pip install cpomdp

Python >=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]
From the README Quickstart at v0.4.4.

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

FeatureSinceJAXRxInfer
Exact Kalman perception and EFE action for linear-Gaussian models0.1.0yesyes
State-dependent sensor noise R(x)0.3.0yesno
Message passing over a Forney factor graph0.4.0yesno
Multi-step EFE with exhaustive search and a completeness certificate0.4.4yesno

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.