Actual Causes Identification — actualcauses
Description
actualcauses is a Python package to identify actual causes (Halpern–Pearl style) in deterministic or stochastic systems.
It implements approximate algorithms with adjustable precision introduced in the paper:
Searching for actual causes: approximate algorithms with adjustable precision (Reyd, Diaconescu, Dessalles).
Accepted at Transactions on Machine Learning Research (TMLR), 2026 — OpenReview.
The package is designed for explainability and causal analysis of autonomous / AI-based systems: given a system model, a context, and a target consequence, it searches for exact or approximate actual causes.
Installation
pip install actualcauses
For local development:
git clone https://github.com/SamuelReyd/ActualCausesIdentification
cd ActualCausesIdentification
python -m pip install -e ".[dev]"
Core concepts
SCM
An SCM object represents a Structural Causal Model:
- V: endogenous variables (names)
- U: exogenous variables (names)
- D: variable domains
- u: a context (values for exogenous variables)
- dag: optional causal graph (for algorithms that exploit structure)
- model: a system model (see
SystemModelclass) used to evaluate interventions
Once created, you call:
scm.find_causes(...)
scm.show_identification_result()
The result is stored on the SCM (scm.causes, scm.witnesses, scm.interventions, scm.n_calls, ...) and can be saved with scm.save(path) / SCM.load(path, model).
System models (SystemModel, BaseNumpyModel, …)
A system model defines how the system responds to interventions.
For simple Python models, subclass SystemModel and implement call(u, e).
For accelerated / vectorized evaluation, subclass BaseNumpyModel (and optionally its stochastic variants).
Quickstart (Suzzy rock-throwing example)
The package provides a ready-to-run example SCM:
from actualcauses import suzzy_example_scm
# Identify causes with two algorithms (Beam Search / ISI)
suzzy_example_scm.find_causes(ISI=False, max_steps=5, beam_size=20, epsilon=0.05, early_stop=False, verbose=2)
suzzy_example_scm.show_identification_result()
suzzy_example_scm.find_causes(ISI=True, max_steps=5, beam_size=20, epsilon=0.05, early_stop=False, verbose=2)
suzzy_example_scm.show_identification_result()
A complete runnable version is in examples/quickstart.py.
See the examples/ folder for additional scenarios and advanced usage.
Minimal custom SCM example (deterministic)
This mirrors examples/custom_scm.py (forest fire scenario). The important part is implementing a SystemModel and passing it to SCM.
from actualcauses import SCM, SystemModel
class ForestFireModel(SystemModel):
def __init__(self, disjunctive=True):
super().__init__(
phi=lambda s: s[-1], # consequence predicate (example: last variable)
psi=lambda s: sum(s), # heuristic used by search
)
self.disjunctive = disjunctive
def __call__(self, u, e):
md, l = u
e = dict(e)
MD = e.get("MD", md)
L = e.get("L", l)
if self.disjunctive:
FF = e.get("FF", int(L or MD))
else:
FF = e.get("FF", int(L and MD))
self.n_calls += 1
return [MD, L, FF]
scm = SCM(
V=("MD", "L", "FF"),
U=("md", "l"),
D=(0, 1),
u=(1, 1),
model=ForestFireModel(disjunctive=True),
dag={"MD": [], "L": [], "FF": ["MD", "L"]},
)
scm.find_causes()
scm.show_identification_result()
Algorithms
All parameters are passed through SCM.find_causes(ISI=..., **kwargs). Every algorithm has 3 levels of verbosity (verbose=1, 2 or 3).
MBS — Minimal Beam Search (ISI=False, the default)
A beam search over interventions of increasing size, which only needs the oracle phi and the heuristic psi.
| Parameter | Default | Meaning |
|---|---|---|
beam_size |
10 |
Interventions kept from one step to the next (-1: all). |
max_steps |
5 |
Largest intervention size explored (-1: unlimited). |
epsilon |
0.05 |
The target is canceled when phi is below this value. |
early_stop |
False |
Stop at the first cause (approximate smallest cause). |
max_time |
None |
Time limit in seconds. |
prune_supersets, expand_causes, include_actual_initial |
True, False, False |
Ablations of the minimality mechanisms (paper, Section 5.5). |
With beam_size=-1 and max_steps=-1, MBS is exhaustive.
ISI — Iterative Sub-Instance identification (ISI=True)
Uses the causal graph (dag) to split the search into subproblems, starting from the parents of the target and “causally backtracking” from every canceling intervention (paper, Section 4.2).
| Parameter | Default | Meaning |
|---|---|---|
exhaustive |
auto | Solve each subproblem by enumeration (exact ISI). Automatically on unless a beam_size other than -1 or a max_steps limit is given, so ISI is exact by default. |
beam_size, max_steps, ... |
When not exhaustive, subproblems are solved with MBS using these parameters. | |
minimal_only |
False |
Inner MBS keeps only minimal causes, and only those are expanded (faster, not complete). |
assign |
"greedy" |
How the inner MBS completes a partial intervention: "greedy" (keeps the cancellation) or "naive" (actual values, no extra call, may return non-canceling pairs). |
do_decomposition |
True |
Assemble expansions from independent singletons when the graph allows it (exact optimisation). |
backtrack |
"subsets" |
"subsets" or "singleton" expansion of each cause. |
max_backtrack |
-1 |
Maximum number of expansion levels (-1: unlimited). |
sample_backtrack |
-1 |
Keep only this many random subproblems per level (-1: all). |
mbs_verbose, mbs_early_stop |
Override verbose / early_stop for the inner MBS only. |
Exact ISI returns exactly the HP-causes (paper, Appendix G). Its cost follows the structure of the graph rather than the size of the model; for models whose causes are all singletons, MBS can be cheaper.
LUCB — adaptive sampling for stochastic models
LUCBNumpyModel(V, t, lucb_params) estimates phi and psi with confidence bounds and only resamples the interventions whose status is still ambiguous (paper, Section 4.3). lucb_params contains beam_size, a (canceling threshold), cause_eps, non_cause_eps, beam_eps (slacks), delta (confidence level), max_iter (average budget per intervention), init_batch_size, batch_size, and optionally seed and verbose. AverageNumpyModel is the fixed-budget baseline.
Examples
The examples/ folder contains scripts intended to be read and modified:
- quickstart.py — Minimal end-to-end run using suzzy_example_scm.
- custom_scm.py — Implement a custom basic SCM and identify actual causes.
- custom_heuristic.py — Use different heuristics (psi) with a fixed system model and SCM.
- vectorized_system_model.py — Use BaseNumpyModel to accelerate identification by vectorizing intervention evaluation.
- stochastic_system_model.py — Stochastic evaluation with a naive average estimator and the LUCB estimator.
Run any example from the repository root, e.g.:
python examples/quickstart.py
The code of the paper's experiments is available at SearchingForCauses.
License
MIT License. See LICENSE.
Citation
If you use this software in academic work, please cite:
Reyd, S., Diaconescu, A., & Dessalles, J.-L. (2026). Searching for actual causes: Approximate algorithms with adjustable precision. Transactions on Machine Learning Research (accepted).
@article{reyd2026searchingactualcauses,
title = {Searching for actual causes: Approximate algorithms with adjustable precision},
author = {Samuel Reyd and Ada Diaconescu and Jean-Louis Dessalles},
journal = {Transactions on Machine Learning Research},
year = {2026},
url = {https://openreview.net/forum?id=3NlYZPCH9v&}
}
```
Metadata
Release files for actualcauses 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| actualcauses-2.0.0.tar.gz | 27.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| actualcauses-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 52.4 kB
Release files / actualcauses-2.0.0.tar.gz
| Download URL | actualcauses-2.0.0.tar.gz |
|---|---|
| Size | 27.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ac61134c89c46b29f098e40c980a2edd56b54bd8eeed5a25c18949a5d5ca8397
|
|
BLAKE2b-256 checksum How to use checksums |
95ec8fcfd828f4f1327071f571886e862d0c6ec7af8d77145c5cf88b796de85a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / actualcauses-2.0.0-py3-none-any.whl
| Download URL | actualcauses-2.0.0-py3-none-any.whl |
|---|---|
| Size | 24.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3b8eadc068f272224333aea34842532dbccf59da485c227011e9961349b36da6
|
|
BLAKE2b-256 checksum How to use checksums |
f7f41db0e9308f8c8e77fefbe56443573b24dd57a5f7629d57b4d6c8d6983362
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency log