A four-package Python suite for constraint-based causal discovery — simulation, conditional independence testing, structure learning, and metric / visualisation. Each package is independent and stands on its own; cross-package interoperability is via structural Protocols, not imports.
Full documentation is hosted on GitHub Pages.
| package | purpose | status | docs |
|---|---|---|---|
dagsampler |
Configurable DAG / SCM simulator producing synthetic mixed-type data and an optional CI oracle. | v0.2.0, on PyPI | docs |
cbcd |
Constraint-based causal discovery algorithms: PC, FCI, RFCI, anytime-FCI, PCMCI. | v0.1.0, not yet on PyPI | docs |
citests |
Conditional independence test toolkit: FisherZ and Spearman native; KCI / CMIknn / RegressionCI / GCM and others via optional extras. | v0.1.0, not yet on PyPI | docs |
bnmetrics |
DAG / CPDAG / PAG comparison metrics and visualisation: SHD, HD, F1, SID, per-Markov-blanket comparisons. | v0.2.2, on PyPI | docs |
The four packages communicate only through structural Protocols (PEP 544 — small interfaces that any conforming object satisfies, no inheritance required). citests's CI tests and the graphs that cbcd and dagsampler produce cross package boundaries via these Protocols, so no package imports another at runtime. Each piece can therefore be installed and updated independently.
flowchart LR
dagsampler -- "true_dag, data" --> cbcd
citests -- "cbcd.CITest" --> cbcd
cbcd -- "bnmetrics.GraphLike" --> bnmetrics
| data flow | Protocol |
|---|---|
citests → cbcd |
cbcd.CITest |
cbcd → bnmetrics, dagsampler → bnmetrics |
bnmetrics.GraphLike |
dagsampler additionally exposes an optional CI oracle (via
CausalDataGenerator.as_ci_oracle()) that conforms to cbcd.CITest
— useful when you want d-separation testing alongside simulated
data, but not part of the standard simulate → recover → compare
pipeline.
Each package installs independently. dagsampler and bnmetrics are
on PyPI; cbcd and citests install from this monorepo via git+https
(no PyPI release yet):
uv pip install \
dagsampler \
bnmetrics \
"cbcd @ git+https://github.com/averinpa/constraint-based-causal-discovery-suite#subdirectory=cbcd" \
"citests @ git+https://github.com/averinpa/constraint-based-causal-discovery-suite#subdirectory=citests"(Replace uv pip with pip if you don't use uv. Per-package
READMEs document optional extras — kernel- and ML-based CI tests in
citests, visualisation in bnmetrics.)
from dagsampler import CausalDataGenerator
from citests.tests.partial_correlation_tests import FisherZ
from cbcd import pc
import bnmetrics
# 1. Simulate a DAG and data, and grab a d-separation CI oracle.
gen = CausalDataGenerator({
"simulation_params": {"n_samples": 3000, "seed_structure": 1,
"seed_data": 2, "binary_proportion": 0.0},
"graph_params": {"type": "custom",
"nodes": ["A", "B", "C"],
"edges": [["A", "C"], ["B", "C"]]}, # collider A → C ← B
})
result = gen.simulate()
# 2. Recover the CPDAG twice: once with dagsampler's oracle (gold standard),
# once with citests's FisherZ on the simulated data (empirical method).
true_cpdag = pc(result["data"], ci_test=gen.as_ci_oracle(), alpha=0.05)
recovered = pc(result["data"], ci_test=FisherZ(result["data"].to_numpy()), alpha=0.05)
# 3. Score the empirical recovery against the gold standard.
print("SHD:", bnmetrics.shd(true_cpdag, recovered)) # 0
print("F1: ", bnmetrics.f1 (true_cpdag, recovered)) # 1.0The full walkthrough — per-line breakdown, visualisation, and a
noisier 4-node example — is at docs/tutorial.md.
Each package has its own uv environment; there's no shared venv:
cd dagsampler && uv sync --all-extras && uv run pytest
cd cbcd && uv sync --all-extras && uv run pytest
cd citests && uv sync --all-extras && uv run pytest
cd bnmetrics && uv sync --all-extras && uv run pytestThe suite-level integration harness chains all four packages on a
5-fixture set (collider_3, fork_3, chain_3, diamond_4,
asia_like_5) and asserts per-fixture SHD/F1 bounds:
cd parity/suite && uv sync && uv run python run.pyA failure there means either a numerical regression or a broken Protocol contract between the packages.
All suite-level and per-package content is MIT-licensed.
Prior-art relationships, attribution for upstream sources
(causal-learn, tigramite, DAGMetrics, mCMIkNN), and the
GPL-3 boundary for tigramite-based optional extras are documented in
NOTICE.md.
The bnmetrics evaluation metrics in this suite implement and extend the methods introduced in:
Averin, P.; Mellidou, I.; Ganopoulou, M.; Xanthopoulou, A.; Moysiadis, T. Evaluating Directed Acyclic Graphs with DAGMetrics: Insights from Tuber and Soil Microbiome Data. Agronomy 2025, 15(4), 987. https://doi.org/10.3390/agronomy15040987