A hierarchical Active Inference model of interoceptive precision collapse in compulsive behaviour
This package implements a two-level hierarchical Active Inference model that formalises the theory of interoceptive precision collapse in compulsive sexual behaviour disorder (CSBD).
The core proposal: compulsive behaviour emerges not from noisy bottom-up interoceptive sensing, but from a top-down failure to weight interoceptive prediction errors appropriately — a precision collapse that renders bodily signals uninformative for regulating motivated behaviour.
The model:
- Recovers a quantitative precision parameter ω from peripheral physiological data (HRV, EDA, pupillometry)
- Formally compares flat vs. single-level vs. two-level hierarchical architectures via Bayesian Model Selection
- Simulates three mechanistically distinct intervention types across timing windows
- Is fully installable, tested, and documented
git clone https://github.com/YOUR_USERNAME/interoceptive-precision-csbd.git
cd interoceptive-precision-csbd
pip install -e ".[dev]"Python 3.9+ required. No GPU needed.
import numpy as np
from interoceptive_precision import HierarchicalPrecisionAgent
# Create a high-compulsivity agent
agent = HierarchicalPrecisionAgent(
omega_0=0.8, # baseline interoceptive precision
compulsivity_score=0.85, # normalised severity [0, 1]
l2_timescale=5, # L2 updates 5x slower than L1
seed=42,
)
# Generate a dummy observation sequence (27-bin one-hot, 100 trials)
rng = np.random.default_rng(42)
obs = np.eye(27)[rng.integers(0, 27, size=100)]
# Run the agent
results = agent.run(obs)
print(f"Mean precision: {results.omega_trajectory.mean():.3f}")
print(f"Entered compulsive drive: {results.entered_compulsive_drive}")
print(f"Precision collapse onset: {results.precision_collapse_onset}")from interoceptive_precision.simulation.generator import SyntheticDataGenerator
from interoceptive_precision.inference.inverter import ModelInverter
from interoceptive_precision.analysis.model_comparison import BayesianModelSelector
from interoceptive_precision.simulation.interventions import InterventionSimulator
# 1. Generate synthetic data
gen = SyntheticDataGenerator(seed=42)
df = gen.generate(n_agents=200, omega_levels=[0.1, 0.3, 0.5, 0.7, 0.9], n_trials=100)
# 2. Fit model — recover omega per agent
true_omega, obs = gen.generate_parameter_recovery_dataset(n_agents=200)
inverter = ModelInverter(n_restarts=5)
results = inverter.fit_dataset(obs, compulsivity_scores=1.0 - true_omega)
print(f"Convergence rate: {results.convergence_rate:.1%}")
# 3. Bayesian Model Selection
bms = BayesianModelSelector()
# ... (fit three models, collect log evidences, call bms.run())
# 4. Intervention sweep
sim = InterventionSimulator(n_agents=200, omega_0=0.6)
sweep = sim.run_sweep(timing_points=[1, 5, 10, 20, 40], compulsivity_score=0.8)
print(sweep.optimal)Run the complete example end-to-end:
python examples/full_pipeline.pyinteroceptive_precision/
├── core.py # Numerically stable Active Inference maths
├── agents/
│ ├── matrices.py # A, B, C matrix builders
│ ├── single_level.py # Flat baseline agent
│ └── hierarchical.py # Two-level hierarchical agent (main model)
├── inference/
│ └── inverter.py # Variational Laplace parameter recovery
├── simulation/
│ ├── generator.py # Synthetic physiological data generator
│ └── interventions.py # In-silico intervention simulator
├── analysis/
│ └── model_comparison.py # Bayesian Model Selection
└── visualization/
└── __init__.py # Publication-quality figure functions
tests/
├── unit/
│ ├── test_core.py
│ └── test_agents.py
└── integration/
examples/
└── full_pipeline.py # End-to-end runnable example
Hidden states encode arousal level × cue context (6 states). The agent receives observations from three physiological modalities (HRV, EDA, pupil size) and updates beliefs via:
where ω is the interoceptive precision parameter.
Maintains a binary belief over interoceptive reliability (calibrated / miscalibrated). Updates every l2_timescale steps using evidence from Level 1 free energy. Modulates Level 1 precision via:
When Level 2 shifts toward the miscalibrated state, ω_t → 0. Level 1 observations carry no information, and the agent's policy is driven entirely by prior preferences (compulsive drive). This is the computational signature of an irresistible urge.
pytest # all tests with coverage
pytest tests/unit/test_core.py # core math only
pytest -k "not integration" # skip slow integration testsThe package is designed to be extended at three levels:
New observation modalities — modify build_likelihood_matrix() in agents/matrices.py and update N_HRV_BINS, N_EDA_BINS, N_PUPIL_BINS.
New hidden states — change N_AROUSAL_STATES and N_CUE_CONTEXTS, update transition matrix accordingly.
New inference algorithms — subclass ModelInverter and override _objective() and _run_single_restart().
If you use this package in your research, please cite:
@software{interoceptive_precision_2026,
author = {Your Name},
title = {interoceptive-precision-csbd: A hierarchical Active Inference model of interoceptive precision collapse},
year = {2026},
url = {https://github.com/YOUR_USERNAME/interoceptive-precision-csbd},
license = {MIT}
}- Friston, K. (2010). The free-energy principle: a unified brain theory? Nature Reviews Neuroscience, 11(2), 127–138.
- Seth, A. K., & Friston, K. J. (2016). Active interoceptive inference and the emotional brain. Phil. Trans. R. Soc. B, 371, 20160007.
- Kiebel, S. J., Daunizeau, J., & Friston, K. J. (2008). A hierarchy of time-scales and the brain. PLoS Computational Biology, 4(11), e1000209.
- Parr, T., & Friston, K. J. (2019). Generalised free energy and active inference. Biological Cybernetics, 113(5), 495–513.
- Stephan, K. E., et al. (2009). Bayesian model selection for group studies. NeuroImage, 46(4), 1004–1017.
MIT — see LICENSE.