Skip to main content

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 SystemModel class) 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:

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)

Source distribution for actualcauses 2.0.0
File Size Uploaded
actualcauses-2.0.0.tar.gz 27.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for actualcauses 2.0.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.3

2 release files

0.2

2 release files

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page