A Python package for solving Markov Decision Processes with Active Inference
Project description
A Python package for simulating Active Inference agents in Markov Decision Process environments. Please see our companion paper, published in the Journal of Open Source Software: "pymdp: A Python library for active inference in discrete state spaces" for an overview of the package and its motivation. For a more in-depth, tutorial-style introduction to the package and a mathematical overview of active inference in Markov Decision Processes, see the longer arxiv version of the paper.
Citing pymdp
If you use pymdp in your work or research, please cite:
@article{Heins2022,
doi = {10.21105/joss.04098},
url = {https://doi.org/10.21105/joss.04098},
year = {2022},
publisher = {The Open Journal},
volume = {7},
number = {73},
pages = {4098},
author = {Conor Heins and Beren Millidge and Daphne Demekas and Brennan Klein and Karl Friston and Iain D. Couzin and Alexander Tschantz},
title = {pymdp: A Python library for active inference in discrete state spaces},
journal = {Journal of Open Source Software}
}
This package is hosted on the infer-actively GitHub organization, which was built with the intention of hosting open-source active inference and free-energy-principle related software.
Most of the low-level mathematical operations are NumPy ports of their equivalent functions from the SPM implementation in MATLAB. We have benchmarked and validated most of these functions against their SPM counterparts.
Status
pymdp in action
Here's a visualization of pymdp agents in action. One of the defining features of active inference agents is the drive to maximize "epistemic value" (i.e. curiosity). Equipped with such a drive in environments with uncertain yet disclosable hidden structure, active inference can ultimately allow agents to simultaneously learn about the environment as well as maximize reward.
The simulation below (see associated JAX notebook here) demonstrates what might be called "epistemic chaining," where an agent (here, analogized to a mouse seeking food) forages for a chain of cues, each of which discloses the location of the subsequent cue in the chain. The final cue (here, "Cue 2") reveals the location a hidden reward. This is similar in spirit to "behavior chaining" used in operant conditioning, except that here, each successive action in the behavioral sequence doesn't need to be learned through instrumental conditioning. Rather, active inference agents will naturally forage the sequence of cues based on an intrinsic desire to disclose information. This ultimately leads the agent to the hidden reward source in the fewest number of moves as possible.
You can run the code behind simulating tasks like this one and others in the Examples section of the official documentation. The GIF generation script used for these animations is available here.
|
|
|
Quick-start: Installation and Usage
We recommend installing pymdp using uv, with an explicit virtual environment:
uv venv .venv
source .venv/bin/activate
uv pip install inferactively-pymdp
If you prefer pip, use:
pip install inferactively-pymdp
If uv sync --group test or uv sync --extra nb fails while building pygraphviz, install Graphviz first and then retry. On macOS, install graphviz with Homebrew. On Ubuntu/Debian, install graphviz libgraphviz-dev pkg-config build-essential python3-dev (or the version-matched python3.x-dev package if needed). The full troubleshooting notes live in docs-mkdocs/getting-started/installation.md.
Once in Python, you can then directly import pymdp, its sub-packages, and functions.
from jax import numpy as jnp, random as jr
from pymdp import utils
from pymdp.agent import Agent
key = jr.PRNGKey(0)
keys = jr.split(key, 3)
num_obs = [3, 5]
num_states = [3, 2]
num_controls = [3, 1]
A = utils.random_A_array(keys[0], num_obs, num_states)
B = utils.random_B_array(keys[1], num_states, num_controls)
C = utils.list_array_uniform([[no] for no in num_obs])
agent = Agent(A=A, B=B, C=C, batch_size=1)
observation = [jnp.array([1]), jnp.array([4])]
qs, info = agent.infer_states(observation, empirical_prior=agent.D, return_info=True)
# Optional diagnostic: current variational free energy for each batch element.
vfe = info["vfe"]
q_pi, neg_efe = agent.infer_policies(qs)
action_keys = jr.split(keys[2], agent.batch_size + 1)
action = agent.sample_action(q_pi, rng_key=action_keys[1:])
Getting started / introductory material
We recommend starting with the JAX-first official documentation for the repository, which provides practical guides, curated notebooks, and generated API references.
For new users to pymdp, we specifically recommend stepping through following three Jupyter notebooks (can also be used on Google Colab):
We also have (and are continuing to build) a series of notebooks that walk through active inference agents performing different types of tasks in the Notebook Gallery.
Contributing
This package is under active development. If you would like to contribute, please refer to CONTRIBUTING.md.
Recommended local setup:
cd <path_to_repo_fork>
uv venv .venv
source .venv/bin/activate
uv sync --group test
Recommended contributor hooks:
uv sync --group dev
uv run --group dev pre-commit install
Useful variants:
# tests + contributor hooks
uv sync --group test --group dev
# docs work
uv sync --group test --extra docs
# notebook/media extras
uv sync --group test --extra nb
# model fitting extras
uv sync --group test --extra modelfit
Run tests:
pytest test
Build docs locally:
./scripts/docs_build.sh
Contributors
- Conor Heins @conorheins
- Tim Verbelen @tverbele
- Dimitrije Markovic @dimarkov
- Riddhi Jain Pitliya @riddhipits
- Arun Niranjan @Arun-Niranjan
- Toon Van de Maele @toonvdm
- Ozan Catal @OzanCatalVerses
- Tommaso Salvatori @salvatomm
- Aswin Paul @aswinpaul
- Lancelot Da Costa @lancelotdacosta
- Ran Wei @ran-weii
- Alexander Tschantz @alec-tschantz
- Miguel de Prado @praesc
- Nikola Pižurica @NIkolaPizurica
- Nikola Milović @nikolamilovic-ft
- Matteo Risso @matteorisso
- Christopher Buckley @clb27
- Beren Millidge @BerenMillidge
- Daphne Demekas @daphnedemekas
- Cooper Williams @coopwilliams
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file inferactively_pymdp-1.0.1.tar.gz.
File metadata
- Download URL: inferactively_pymdp-1.0.1.tar.gz
- Upload date:
- Size: 701.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff1570f4b312f034adc239f9f73755c3219d76a414632592d813fd580778a5b6
|
|
| MD5 |
0fd2d220d97d4cf9561bb11b9e0c00c9
|
|
| BLAKE2b-256 |
b08bb76e545698e08e2d3bac8ec38c7075656359dad1139f5f03c0c3074c5799
|
Provenance
The following attestation bundles were made for inferactively_pymdp-1.0.1.tar.gz:
Publisher:
release-please.yml on infer-actively/pymdp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
inferactively_pymdp-1.0.1.tar.gz -
Subject digest:
ff1570f4b312f034adc239f9f73755c3219d76a414632592d813fd580778a5b6 - Sigstore transparency entry: 1397795887
- Sigstore integration time:
-
Permalink:
infer-actively/pymdp@bb0aa7e4234820cc2213aca0c012219a1683f568 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/infer-actively
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-please.yml@bb0aa7e4234820cc2213aca0c012219a1683f568 -
Trigger Event:
push
-
Statement type:
File details
Details for the file inferactively_pymdp-1.0.1-py3-none-any.whl.
File metadata
- Download URL: inferactively_pymdp-1.0.1-py3-none-any.whl
- Upload date:
- Size: 636.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86d55f96982be8cdeca9ad010eeb174f17c610ca77ef548c42a2b898a9b572a8
|
|
| MD5 |
0a9323dcfd876a75c25908c640fcbcf5
|
|
| BLAKE2b-256 |
43144bb966ea73c696e66cbec9746cb99ad575da4d0bf93d41530bbad6e4bf95
|
Provenance
The following attestation bundles were made for inferactively_pymdp-1.0.1-py3-none-any.whl:
Publisher:
release-please.yml on infer-actively/pymdp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
inferactively_pymdp-1.0.1-py3-none-any.whl -
Subject digest:
86d55f96982be8cdeca9ad010eeb174f17c610ca77ef548c42a2b898a9b572a8 - Sigstore transparency entry: 1397795898
- Sigstore integration time:
-
Permalink:
infer-actively/pymdp@bb0aa7e4234820cc2213aca0c012219a1683f568 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/infer-actively
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-please.yml@bb0aa7e4234820cc2213aca0c012219a1683f568 -
Trigger Event:
push
-
Statement type: