Skip to main content

causal-automata

PyPI Version Python Versions License

A blazing-fast, JAX-accelerated Cellular Automaton engine for causal discovery.

v0.2.0 — JAX @jit physics, dynamic k, and Maximum Accuracy Mode (--multihop, Directed F1 0.696 on N=100). See CHANGELOG.md.

Installation

pip install "causal-automata==0.2.0"

With CPU JAX:

pip install "causal-automata[jax]"
# or: uv pip install "causal-automata[jax]"

With NVIDIA CUDA JAX (and the Colab-style stack):

pip install "causal-automata[cuda]"

Or using uv in a project:

uv add "causal-automata[jax]"

Benchmark — N=100

Default stack (Upgrade 2): k=3 if N≤50, k=5 if N>50, binary edges, 1-hop gravity. On N=100 (seed=0, static thresholds, ticks=100) that baseline hits Skeleton 0.937 / Directed 0.619 in about 2.8s.

Maximum Accuracy Mode — pass --multihop (Upgrade 4): 2-hop elevation gravity via A @ A lifts Directed F1 to 0.696 with essentially flat wall time.

Algorithm Skeleton F1 Directed F1 Wall Time (s)
PC (gcastle) 0.968 0.813 528.631
GOLEM (gcastle) 0.577 0.403 251.182
Bayesian CA (JAX, k=5, 1-hop) 0.937 0.619 ~2.9
Bayesian CA (JAX, k=5, --multihop) 0.928 0.696 ~2.9

PC / GOLEM wall times are Colab Tesla T4 (num_iter=20000). CA times are CPU JAX for the Upgrade-2 / Upgrade-4 A/B; at historical k=3 the same CA finished in 0.323s on T4 with Directed F1 0.483.

Opt-in flags (defaults stay fast & binary):

  • --multihop — Maximum Accuracy Mode (2-hop gravity, Directed F1 0.696 on this SEM).
  • --fuzzy — continuous A ∈ [0, 1] soft birth/death (experimental; did not beat binary here).

Conditioning-set sweep (CA-only, 1-hop binary, same SEM):

Algorithm Skeleton F1 Directed F1 Wall Time (s)
Bayesian CA (JAX, k=3) 0.812 0.483 2.314
Bayesian CA (JAX, k=4) 0.915 0.546 2.481
Bayesian CA (JAX, k=5) 0.937 0.619 2.871
Bayesian CA (JAX, k=6) 0.937 0.619 2.454
Bayesian CA (JAX, k=7) 0.937 0.619 3.049
Bayesian CA (JAX, k=8) 0.937 0.627 3.647

Documentation

Full docs (theory, physics, API, CLI): https://causal-automata.readthedocs.io/en/latest/

How it works — CA physics + V-well

State is a binary DAG adjacency A, node elevations E ∈ [0,1], and a fixed empirical covariance Cov from continuous observations. Each tick is a local cellular update:

  1. Gravity — keep only downhill edges (E[parent] > E[child]), then drift elevations toward the midpoint of parent/child means. With --multihop, that drift also sees 2-hop neighbors from A @ A (discounted pull) to help break Markov-equivalence ties.
  2. V-structure gravity well — absent undirected pairs that share neighbors and are marginally independent (|ρ| below the death threshold with empty conditioning set) mark shared neighbors as colliders. Those elevations are sunk (E -= 2·lr), so later birth prefers arrows into the collider — the classic V-structure i → k ← j.
  3. Death / birth — kill weak edges and birth strong ones using partial correlations conditioned on the top-k union neighbors ranked by |Cov|. Birth orients by elevation after the |ρ| gate. Optional --fuzzy keeps continuous weights in [0, 1] and binarizes only after the final tick.

The NumPy prototype (bayesian.step) and the pure functional JAX port (jax_core.step, @jax.jit) share this physics.

Run

# Synthetic DAG harness (NumPy default; use --backend jax for JIT)
python -m causal_automata.bayesian_synth --n 10
python -m causal_automata.bayesian_synth --n 50 --backend jax
python -m causal_automata.bayesian_synth --n 100

# Benchmark vs gCastle PC / GOLEM (default N=100, k=5, 1-hop)
python -m causal_automata.benchmark
python -m causal_automata.benchmark --n 100 --seed 0 --ticks 100

# Maximum Accuracy Mode (Upgrade 4) — Directed F1 0.696 on the N=100 SEM
python -m causal_automata.benchmark --n 100 --ca-only --k 5 --multihop
python -m causal_automata.benchmark --n 100 --ca-only --k 5 --compare-multihop

python -m causal_automata.benchmark --n 100 --ca-only --k-sweep 5,6,7,8
python -m causal_automata.benchmark --smoke   # device checks + GOLEM init only

Smoke the JAX compile:

python -c "from causal_automata import warmup; print(warmup())"

Package layout

causal-automata/
├── causal_automata/
│   ├── __init__.py
│   ├── bayesian.py          # NumPy Bayesian CA step
│   ├── bayesian_synth.py    # Synthetic linear-DAG harness
│   ├── jax_core.py          # JAX @jit port of step
│   └── benchmark.py         # vs gCastle PC / GOLEM
├── docs/                    # Sphinx / Read the Docs
├── .readthedocs.yaml
├── pyproject.toml
├── README.md
└── NOTICE

License / notice

See NOTICE. Copyright 2026 Masakazu Yamagiwa.

Metadata

Release files for causal-automata 0.2.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 causal-automata 0.2.0
File Size Uploaded Provenance
causal_automata-0.2.0.tar.gz 27.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for causal-automata 0.2.0
File Interpreter ABI Platform
causal_automata-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 55.1 kB

Release files / causal_automata-0.2.0.tar.gz

Download URL causal_automata-0.2.0.tar.gz
Size 27.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c2940d56b3ab13b18949dc29f6efc74ed3cae0f87e84cb16c4980fb201d45bd9
BLAKE2b-256 checksum
How to use checksums
5c38eaf9a39eba72250124218a5bb22f1390f1407c0b46c75990ee52bb8a6c6e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.3 {"installer":{"name":"uv","version":"0.13.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / causal_automata-0.2.0-py3-none-any.whl

Download URL causal_automata-0.2.0-py3-none-any.whl
Size 28.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
16466cdbe825dc29247dc4de69de719cf296e1d3edb53a6d5de1545fb310719c
BLAKE2b-256 checksum
How to use checksums
9235eb94013c7c069b3135bfc4c7372191e5c6953d28eeab0bc76a0efa8c3c3c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.3 {"installer":{"name":"uv","version":"0.13.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for causal-automata 0.2.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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