causalrl 0.99.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- causalrl-0.99.0/.devcontainer/devcontainer.json +10 -0
- causalrl-0.99.0/.github/ISSUE_TEMPLATE/bug_report.md +24 -0
- causalrl-0.99.0/.github/ISSUE_TEMPLATE/feature_request.md +14 -0
- causalrl-0.99.0/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- causalrl-0.99.0/.github/workflows/ci.yml +56 -0
- causalrl-0.99.0/.github/workflows/docs.yml +38 -0
- causalrl-0.99.0/.github/workflows/publish.yml +28 -0
- causalrl-0.99.0/.gitignore +19 -0
- causalrl-0.99.0/.pre-commit-config.yaml +7 -0
- causalrl-0.99.0/.python-version +1 -0
- causalrl-0.99.0/CHANGELOG.md +370 -0
- causalrl-0.99.0/CITATION.cff +12 -0
- causalrl-0.99.0/CONTRIBUTING.md +30 -0
- causalrl-0.99.0/Dockerfile +13 -0
- causalrl-0.99.0/LICENSE +21 -0
- causalrl-0.99.0/PKG-INFO +392 -0
- causalrl-0.99.0/README.md +346 -0
- causalrl-0.99.0/SECURITY.md +15 -0
- causalrl-0.99.0/benchmarks/scbandit_report.py +41 -0
- causalrl-0.99.0/docs/api.md +155 -0
- causalrl-0.99.0/docs/benchmarks.md +40 -0
- causalrl-0.99.0/docs/classics.md +32 -0
- causalrl-0.99.0/docs/discovery.md +55 -0
- causalrl-0.99.0/docs/guarantees.md +160 -0
- causalrl-0.99.0/docs/index.md +35 -0
- causalrl-0.99.0/docs/superpowers/plans/2026-05-23-causalrl-v0.1.md +1685 -0
- causalrl-0.99.0/docs/superpowers/plans/2026-05-23-causalrl-v0.2.md +2050 -0
- causalrl-0.99.0/docs/superpowers/plans/2026-05-23-causalrl-v0.3.md +988 -0
- causalrl-0.99.0/docs/superpowers/plans/2026-05-26-causalrl-correctness-hardening.md +134 -0
- causalrl-0.99.0/docs/superpowers/plans/2026-05-26-causalrl-task2-pomis.md +1133 -0
- causalrl-0.99.0/docs/superpowers/plans/2026-05-27-causalrl-top-class-foundation.md +229 -0
- causalrl-0.99.0/docs/superpowers/plans/2026-05-27-complete-transportability-sid-mz-meta.md +722 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-23-causalrl-library-design.md +215 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-23-causalrl-v0.2-design.md +223 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-23-causalrl-v0.3-design.md +250 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-26-causalrl-correctness-hardening-design.md +67 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-26-causalrl-nonmanipulable-pomis-design.md +176 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-26-causalrl-task2-pomis-design.md +248 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-26-causalrl-v0.3.0-hardening-design.md +133 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-27-causalrl-task3-counterfactual-ett-design.md +140 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-27-causalrl-task4-transportability-design.md +127 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-27-causalrl-task5-discovery-design.md +110 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-27-causalrl-task6-imitation-design.md +105 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-27-causalrl-task7-curriculum-design.md +84 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-27-causalrl-task8-reward-shaping-design.md +86 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-27-causalrl-task9-causal-games-design.md +85 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-27-causalrl-top-class-foundation-design.md +137 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-27-complete-transportability-sid-mz-meta-design.md +248 -0
- causalrl-0.99.0/docs/superpowers/specs/2026-05-27-fci-latent-discovery-design.md +161 -0
- causalrl-0.99.0/docs/transportability.md +68 -0
- causalrl-0.99.0/examples/mabuc_vertical_slice.ipynb +144 -0
- causalrl-0.99.0/examples/offline_to_online.ipynb +229 -0
- causalrl-0.99.0/examples/where_to_intervene.ipynb +108 -0
- causalrl-0.99.0/mkdocs.yml +34 -0
- causalrl-0.99.0/pyproject.toml +86 -0
- causalrl-0.99.0/src/causalrl/__init__.py +274 -0
- causalrl-0.99.0/src/causalrl/_backend/__init__.py +15 -0
- causalrl-0.99.0/src/causalrl/agents/__init__.py +1 -0
- causalrl-0.99.0/src/causalrl/agents/bandits.py +61 -0
- causalrl-0.99.0/src/causalrl/agents/base.py +22 -0
- causalrl-0.99.0/src/causalrl/agents/baselines.py +59 -0
- causalrl-0.99.0/src/causalrl/agents/counterfactual.py +64 -0
- causalrl-0.99.0/src/causalrl/agents/deep_deconfounded.py +80 -0
- causalrl-0.99.0/src/causalrl/agents/dovi.py +139 -0
- causalrl-0.99.0/src/causalrl/agents/offline_online.py +63 -0
- causalrl-0.99.0/src/causalrl/agents/primitives.py +25 -0
- causalrl-0.99.0/src/causalrl/agents/scbandit.py +100 -0
- causalrl-0.99.0/src/causalrl/curriculum.py +117 -0
- causalrl-0.99.0/src/causalrl/data/__init__.py +1 -0
- causalrl-0.99.0/src/causalrl/data/dataset.py +90 -0
- causalrl-0.99.0/src/causalrl/discovery.py +709 -0
- causalrl-0.99.0/src/causalrl/envs/__init__.py +1 -0
- causalrl-0.99.0/src/causalrl/envs/base.py +49 -0
- causalrl-0.99.0/src/causalrl/envs/suite/__init__.py +1 -0
- causalrl-0.99.0/src/causalrl/envs/suite/counterfactual_bandit.py +93 -0
- causalrl-0.99.0/src/causalrl/envs/suite/curriculum.py +24 -0
- causalrl-0.99.0/src/causalrl/envs/suite/discovery.py +59 -0
- causalrl-0.99.0/src/causalrl/envs/suite/dtr.py +96 -0
- causalrl-0.99.0/src/causalrl/envs/suite/games.py +38 -0
- causalrl-0.99.0/src/causalrl/envs/suite/gridworld.py +91 -0
- causalrl-0.99.0/src/causalrl/envs/suite/imitation.py +82 -0
- causalrl-0.99.0/src/causalrl/envs/suite/mabuc.py +90 -0
- causalrl-0.99.0/src/causalrl/envs/suite/scbandit.py +170 -0
- causalrl-0.99.0/src/causalrl/envs/suite/seq_dtr.py +103 -0
- causalrl-0.99.0/src/causalrl/envs/suite/seq_mabuc.py +96 -0
- causalrl-0.99.0/src/causalrl/envs/suite/shaping.py +34 -0
- causalrl-0.99.0/src/causalrl/envs/suite/transport.py +58 -0
- causalrl-0.99.0/src/causalrl/eval/__init__.py +1 -0
- causalrl-0.99.0/src/causalrl/eval/benchmark.py +168 -0
- causalrl-0.99.0/src/causalrl/eval/harness.py +29 -0
- causalrl-0.99.0/src/causalrl/eval/metrics.py +8 -0
- causalrl-0.99.0/src/causalrl/eval/ope.py +20 -0
- causalrl-0.99.0/src/causalrl/exceptions.py +25 -0
- causalrl-0.99.0/src/causalrl/experimental/__init__.py +1 -0
- causalrl-0.99.0/src/causalrl/experimental/ope.py +19 -0
- causalrl-0.99.0/src/causalrl/games.py +331 -0
- causalrl-0.99.0/src/causalrl/identification/__init__.py +1 -0
- causalrl-0.99.0/src/causalrl/identification/_separation.py +50 -0
- causalrl-0.99.0/src/causalrl/identification/bounds.py +114 -0
- causalrl-0.99.0/src/causalrl/identification/counterfactual.py +131 -0
- causalrl-0.99.0/src/causalrl/identification/criteria.py +33 -0
- causalrl-0.99.0/src/causalrl/identification/id_algorithm.py +816 -0
- causalrl-0.99.0/src/causalrl/identification/intervention_sets.py +152 -0
- causalrl-0.99.0/src/causalrl/identification/transport.py +204 -0
- causalrl-0.99.0/src/causalrl/imitation.py +124 -0
- causalrl-0.99.0/src/causalrl/py.typed +0 -0
- causalrl-0.99.0/src/causalrl/scm/__init__.py +1 -0
- causalrl-0.99.0/src/causalrl/scm/graph.py +169 -0
- causalrl-0.99.0/src/causalrl/scm/mechanisms.py +57 -0
- causalrl-0.99.0/src/causalrl/scm/scm.py +131 -0
- causalrl-0.99.0/src/causalrl/shaping.py +116 -0
- causalrl-0.99.0/tests/test_bandits.py +42 -0
- causalrl-0.99.0/tests/test_baselines.py +21 -0
- causalrl-0.99.0/tests/test_benchmark.py +33 -0
- causalrl-0.99.0/tests/test_bounds.py +44 -0
- causalrl-0.99.0/tests/test_bounds_properties.py +34 -0
- causalrl-0.99.0/tests/test_counterfactual.py +107 -0
- causalrl-0.99.0/tests/test_counterfactual_agents.py +53 -0
- causalrl-0.99.0/tests/test_counterfactual_bandit.py +63 -0
- causalrl-0.99.0/tests/test_counterfactual_decision.py +45 -0
- causalrl-0.99.0/tests/test_curriculum.py +57 -0
- causalrl-0.99.0/tests/test_curriculum_rl.py +67 -0
- causalrl-0.99.0/tests/test_dataset.py +45 -0
- causalrl-0.99.0/tests/test_deep_deconfounded.py +31 -0
- causalrl-0.99.0/tests/test_discovery.py +109 -0
- causalrl-0.99.0/tests/test_discovery_interventional.py +100 -0
- causalrl-0.99.0/tests/test_dovi.py +136 -0
- causalrl-0.99.0/tests/test_dtr_env.py +46 -0
- causalrl-0.99.0/tests/test_fci.py +357 -0
- causalrl-0.99.0/tests/test_games.py +55 -0
- causalrl-0.99.0/tests/test_games_mixed.py +104 -0
- causalrl-0.99.0/tests/test_gid.py +157 -0
- causalrl-0.99.0/tests/test_graph.py +50 -0
- causalrl-0.99.0/tests/test_graph_pomis_ops.py +48 -0
- causalrl-0.99.0/tests/test_graph_projection.py +45 -0
- causalrl-0.99.0/tests/test_gridworld_env.py +29 -0
- causalrl-0.99.0/tests/test_gymnasium_contract.py +77 -0
- causalrl-0.99.0/tests/test_harness.py +43 -0
- causalrl-0.99.0/tests/test_id_algorithm.py +144 -0
- causalrl-0.99.0/tests/test_identification.py +37 -0
- causalrl-0.99.0/tests/test_imitation.py +58 -0
- causalrl-0.99.0/tests/test_imitation_env.py +37 -0
- causalrl-0.99.0/tests/test_integration_curriculum.py +27 -0
- causalrl-0.99.0/tests/test_integration_deep.py +26 -0
- causalrl-0.99.0/tests/test_integration_discovery.py +16 -0
- causalrl-0.99.0/tests/test_integration_dovi.py +92 -0
- causalrl-0.99.0/tests/test_integration_games.py +12 -0
- causalrl-0.99.0/tests/test_integration_imitation.py +44 -0
- causalrl-0.99.0/tests/test_integration_mabuc.py +35 -0
- causalrl-0.99.0/tests/test_integration_nonmanip.py +46 -0
- causalrl-0.99.0/tests/test_integration_scbandit.py +52 -0
- causalrl-0.99.0/tests/test_integration_shaping.py +21 -0
- causalrl-0.99.0/tests/test_integration_transport.py +35 -0
- causalrl-0.99.0/tests/test_integration_ucdtr.py +32 -0
- causalrl-0.99.0/tests/test_intervention_sets.py +71 -0
- causalrl-0.99.0/tests/test_intervention_sets_nonmanip.py +93 -0
- causalrl-0.99.0/tests/test_intervention_sets_properties.py +44 -0
- causalrl-0.99.0/tests/test_literature_classics.py +238 -0
- causalrl-0.99.0/tests/test_mabuc_env.py +56 -0
- causalrl-0.99.0/tests/test_mechanisms.py +40 -0
- causalrl-0.99.0/tests/test_ope.py +27 -0
- causalrl-0.99.0/tests/test_ope_bounds.py +77 -0
- causalrl-0.99.0/tests/test_packaging.py +32 -0
- causalrl-0.99.0/tests/test_primitives.py +32 -0
- causalrl-0.99.0/tests/test_public_api.py +76 -0
- causalrl-0.99.0/tests/test_scbandit_agents.py +71 -0
- causalrl-0.99.0/tests/test_scbandit_agents_nonmanip.py +41 -0
- causalrl-0.99.0/tests/test_scbandit_env.py +47 -0
- causalrl-0.99.0/tests/test_scbandit_frontdoor.py +21 -0
- causalrl-0.99.0/tests/test_scm_counterfactual.py +49 -0
- causalrl-0.99.0/tests/test_scm_do.py +42 -0
- causalrl-0.99.0/tests/test_scm_properties.py +71 -0
- causalrl-0.99.0/tests/test_scm_see.py +94 -0
- causalrl-0.99.0/tests/test_separation.py +20 -0
- causalrl-0.99.0/tests/test_seq_dtr_env.py +51 -0
- causalrl-0.99.0/tests/test_seq_mabuc_env.py +66 -0
- causalrl-0.99.0/tests/test_shaping.py +42 -0
- causalrl-0.99.0/tests/test_sid.py +102 -0
- causalrl-0.99.0/tests/test_sid_complete.py +218 -0
- causalrl-0.99.0/tests/test_transport.py +82 -0
- causalrl-0.99.0/tests/test_transport_domains.py +26 -0
- causalrl-0.99.0/tests/test_ucdtr.py +46 -0
- causalrl-0.99.0/tests/test_when_to_intervene.py +24 -0
- causalrl-0.99.0/uv.lock +2728 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Report incorrect behavior or a crash
|
|
4
|
+
labels: bug
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Describe the bug**
|
|
8
|
+
A clear description of what is wrong.
|
|
9
|
+
|
|
10
|
+
**To reproduce**
|
|
11
|
+
A minimal snippet:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
# ...
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Expected behavior**
|
|
18
|
+
What you expected — and, for causal methods, the assumption or criterion you relied on.
|
|
19
|
+
|
|
20
|
+
**Environment**
|
|
21
|
+
- causalrl version:
|
|
22
|
+
- Python version:
|
|
23
|
+
- OS:
|
|
24
|
+
- torch installed? (yes/no)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest a method, environment, or improvement
|
|
4
|
+
labels: enhancement
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**What and why**
|
|
8
|
+
The capability you want and the problem it solves.
|
|
9
|
+
|
|
10
|
+
**Causal grounding**
|
|
11
|
+
If proposing a causal method, cite the primary source and note its assumptions and scope.
|
|
12
|
+
|
|
13
|
+
**Alternatives considered**
|
|
14
|
+
Anything else you tried or considered.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
What this changes and why.
|
|
4
|
+
|
|
5
|
+
## Causal / software contract
|
|
6
|
+
|
|
7
|
+
For causal methods: the criterion or guarantee, its assumptions, and the primary source cited.
|
|
8
|
+
|
|
9
|
+
## Validation
|
|
10
|
+
|
|
11
|
+
- [ ] Tests added/updated (oracle fixtures or reproducible benchmark evidence where applicable)
|
|
12
|
+
- [ ] `uv run pytest` passes
|
|
13
|
+
- [ ] `uv run ruff check .` and `uv run ruff format --check .` clean
|
|
14
|
+
- [ ] `uv run pyright src` clean
|
|
15
|
+
- [ ] Docs/CHANGELOG updated for public API changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ${{ matrix.os }}
|
|
10
|
+
strategy:
|
|
11
|
+
fail-fast: false
|
|
12
|
+
matrix:
|
|
13
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
14
|
+
python-version: ["3.11", "3.14"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@v3
|
|
19
|
+
with:
|
|
20
|
+
python-version: "${{ matrix.python-version }}"
|
|
21
|
+
- name: Sync dependencies
|
|
22
|
+
run: uv sync --extra dev
|
|
23
|
+
- name: Lint
|
|
24
|
+
run: uv run ruff check .
|
|
25
|
+
- name: Format check
|
|
26
|
+
run: uv run ruff format --check .
|
|
27
|
+
- name: Type check
|
|
28
|
+
run: uv run pyright src
|
|
29
|
+
- name: Test
|
|
30
|
+
run: uv run pytest -v --cov-fail-under=90
|
|
31
|
+
|
|
32
|
+
docs:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- name: Install uv
|
|
37
|
+
uses: astral-sh/setup-uv@v3
|
|
38
|
+
with:
|
|
39
|
+
python-version: "3.11"
|
|
40
|
+
- name: Sync documentation dependencies
|
|
41
|
+
run: uv sync --extra docs
|
|
42
|
+
- name: Build documentation
|
|
43
|
+
run: uv run --extra docs mkdocs build --strict
|
|
44
|
+
|
|
45
|
+
notebooks:
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v4
|
|
49
|
+
- name: Install uv
|
|
50
|
+
uses: astral-sh/setup-uv@v3
|
|
51
|
+
with:
|
|
52
|
+
python-version: "3.11"
|
|
53
|
+
- name: Sync dependencies
|
|
54
|
+
run: uv sync --extra dev
|
|
55
|
+
- name: Execute example notebooks
|
|
56
|
+
run: uv run pytest --nbmake --no-cov examples/
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Documentation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pages: write
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: pages
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
deploy:
|
|
19
|
+
environment:
|
|
20
|
+
name: github-pages
|
|
21
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
- name: Install uv
|
|
26
|
+
uses: astral-sh/setup-uv@v3
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.11"
|
|
29
|
+
- name: Build documentation
|
|
30
|
+
run: uv run --extra docs mkdocs build --strict
|
|
31
|
+
- uses: actions/configure-pages@v5
|
|
32
|
+
with:
|
|
33
|
+
enablement: true
|
|
34
|
+
- uses: actions/upload-pages-artifact@v3
|
|
35
|
+
with:
|
|
36
|
+
path: site
|
|
37
|
+
- id: deployment
|
|
38
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
pypi:
|
|
12
|
+
name: Publish to PyPI
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment: pypi
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v3
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.11"
|
|
23
|
+
- name: Build distributions
|
|
24
|
+
run: uv build
|
|
25
|
+
- name: Check distributions
|
|
26
|
+
run: uvx twine check dist/*
|
|
27
|
+
- name: Publish through trusted publishing
|
|
28
|
+
run: uv publish
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
.venv/
|
|
4
|
+
.uv/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.coverage
|
|
11
|
+
htmlcov/
|
|
12
|
+
site/
|
|
13
|
+
.ipynb_checkpoints/
|
|
14
|
+
|
|
15
|
+
# Claude Code local worktrees / settings (not part of the project)
|
|
16
|
+
.claude/
|
|
17
|
+
|
|
18
|
+
# Reference papers — kept locally for citation/reproducibility, not redistributed (copyright)
|
|
19
|
+
papers/*.pdf
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.99.0] - 2026-05-27
|
|
11
|
+
|
|
12
|
+
### Stable
|
|
13
|
+
- **API stabilized, humbly labelled v0.99** — a deliberate step short of a 1.0 tag while it settles
|
|
14
|
+
in real use. The public API (the names exported from `causalrl`) follows semantic
|
|
15
|
+
versioning. The full Bareinboim 9-task causal-RL taxonomy is implemented, with the depth
|
|
16
|
+
extensions of v0.13–v0.20: the complete Shpitser–Pearl ID algorithm, gID, sID / mz / meta
|
|
17
|
+
transportability, FCI (latent-confounder discovery), mixed Nash for any number of players,
|
|
18
|
+
validated Manski and marginal-sensitivity-model OPE bounds, and a "reproducing the literature"
|
|
19
|
+
gallery.
|
|
20
|
+
|
|
21
|
+
### Removed
|
|
22
|
+
- Deprecated shims: `POMISThompsonSampling` now requires `manipulable=` explicitly (arm-inference
|
|
23
|
+
removed); the deprecated `causalrl.eval.ope.confounding_sensitivity_bounds` bridge is gone (use
|
|
24
|
+
`causalrl.identification.bounds.ipw_sensitivity_bounds`).
|
|
25
|
+
- The partial hand-maintained `causalrl/__init__.pyi` stub — `py.typed` plus complete inline
|
|
26
|
+
annotations (checked by pyright in strict mode) are now the authoritative types.
|
|
27
|
+
|
|
28
|
+
## [0.20.0] - 2026-05-27
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **"Reproducing the literature" gallery** (`tests/test_literature_classics.py` + a
|
|
32
|
+
[docs gallery](docs/classics.md)): classic causal cases reproduced end-to-end with the library —
|
|
33
|
+
Simpson's paradox (kidney stones), the front-door criterion (smoking → tar → cancer), Pearl's
|
|
34
|
+
napkin, the instrumental variable (non-identified but Manski-bounded), the bow arc, and
|
|
35
|
+
cross-domain transport (LA → NYC).
|
|
36
|
+
- **Difficult RL problems where causal beats associational RL**: MABUC (a confounding-aware bandit
|
|
37
|
+
beats the naive one), the counterfactual "Greedy Casino" (acting on the counterfactual ≈ 0.80
|
|
38
|
+
doubles the best fixed interventional arm ≈ 0.37), and curriculum-driven hard exploration (a causal
|
|
39
|
+
prerequisite curriculum reaches a sparse goal flat Q-learning misses on the same budget).
|
|
40
|
+
|
|
41
|
+
## [0.19.0] - 2026-05-27
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
- **Validated partial-identification / OPE bounds** (closing the sensitivity-bounds gap):
|
|
45
|
+
- `manski_bounds` — sharp no-assumptions (Manski 1990) bounds on `E[outcome | do(treatment)]` from
|
|
46
|
+
observational data (the observational counterpart of `causal_q_bounds`).
|
|
47
|
+
- `ipw_sensitivity_bounds` — the marginal sensitivity model (Tan 2006; Zhao–Small–Bhattacharya
|
|
48
|
+
2019): an odds-ratio-Γ interval on the treated counterfactual mean that collapses to the IPW
|
|
49
|
+
point at Γ=1, widens monotonically with Γ, and contains the truth once Γ exceeds the true
|
|
50
|
+
confounding odds ratio. Validated against a confounded SCM with a known effect.
|
|
51
|
+
|
|
52
|
+
## [0.18.0] - 2026-05-27
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
- **Mixed-strategy Nash equilibria for three or more players** (taxonomy Task 9): `mixed_nash_equilibria`
|
|
56
|
+
now handles any number of agents. Two-player games stay exact (rational support enumeration); games
|
|
57
|
+
with ≥3 agents use support enumeration with a numerical Newton solve of the multilinear indifference
|
|
58
|
+
system, and **every returned profile is verified to be an ε-Nash equilibrium**. Validated on a
|
|
59
|
+
three-player cyclic matching game (recovers the uniform `(1/2, 1/2)` equilibrium).
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
- `mixed_nash_equilibria` no longer raises `NotImplementedError` for more than two agents; it raises
|
|
63
|
+
`CausalGraphError` only for fewer than two agents.
|
|
64
|
+
|
|
65
|
+
## [0.17.0] - 2026-05-27
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
- **FCI: causal discovery with latent confounders** (taxonomy Task 5): `discover_latent` learns a
|
|
69
|
+
`PAG` (partial ancestral graph) without assuming causal sufficiency — PC skeleton + Possible-D-SEP
|
|
70
|
+
refinement + the complete orientation rules R1-R10 (Zhang 2008, sound and complete for latent
|
|
71
|
+
confounders and selection bias). `a <-> b` marks a latent confounder; a circle endpoint is
|
|
72
|
+
undetermined by the equivalence class. Validated against the true MAG of the data-generating
|
|
73
|
+
DAG-with-latents (latent-confounder detection and the M-bias collider), with per-rule unit
|
|
74
|
+
fixtures for R1-R10.
|
|
75
|
+
- `PAG` (endpoint marks `o` / `>` / `-`, with `is_directed` / `is_bidirected` / `render`) and a
|
|
76
|
+
Causal Discovery guide (`docs/discovery.md`).
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
- Internal: the PC skeleton phase is factored into `_pc_skeleton`, shared by `discover` and
|
|
80
|
+
`discover_latent` (no behaviour change to `discover`).
|
|
81
|
+
|
|
82
|
+
## [0.16.0] - 2026-05-27
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
- **Multi-domain and experimental transportability (mz / meta)** (taxonomy Task 4): a general
|
|
86
|
+
engine resolves each c-factor of the target effect by searching the domains that can supply it.
|
|
87
|
+
- `Domain` describes a source domain — its selection-marked variables and the surrogate
|
|
88
|
+
experiments it offers.
|
|
89
|
+
- `identify_transport_general` / `is_transportable_general` / `estimate_transport_general` decide
|
|
90
|
+
and compute `P*(y | do(x))` across one or more `Domain`s plus the target. With a single
|
|
91
|
+
observational source they coincide with `identify_transport`; with no selection and no
|
|
92
|
+
experiments they reduce to the ID algorithm.
|
|
93
|
+
- **mz**: a surrogate experiment in a source domain supplies a c-factor that no observational
|
|
94
|
+
distribution can (validated: a source `do(X)` breaks a bow-arc hedge, matching simulation).
|
|
95
|
+
- **meta**: invariant c-factors are contributed by different source domains (validated: an effect
|
|
96
|
+
assembled from two sources marked on different covariates matches the target's true `do()`).
|
|
97
|
+
- A [Transportability guide](docs/transportability.md) with runnable covariate-shift, mz, and meta
|
|
98
|
+
examples.
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
- The single-source `identify_transport` now delegates to the general engine — behaviour-preserving;
|
|
102
|
+
its signature and results are unchanged.
|
|
103
|
+
- Internal: S-node separation helpers moved to `causalrl.identification._separation` (shared by the
|
|
104
|
+
transport code and the ID engine; no public API change).
|
|
105
|
+
|
|
106
|
+
### Notes
|
|
107
|
+
- At c-factor granularity, invariance is exactly "touches no selection-marked variable", so
|
|
108
|
+
single-source observational transport was already complete; this release adds surrogate
|
|
109
|
+
experiments and multiple source domains. The one remaining edge — a single c-factor identifiable
|
|
110
|
+
only by *combining several experiments* — is reported non-transportable rather than guessed.
|
|
111
|
+
|
|
112
|
+
## [0.15.0] - 2026-05-27
|
|
113
|
+
|
|
114
|
+
### Added
|
|
115
|
+
- **Cross-domain transportability (sID)** (taxonomy Task 4): `identify_transport` /
|
|
116
|
+
`is_transportable_effect` / `estimate_transported_effect` (and the `transport_estimand`
|
|
117
|
+
`SelectionDiagram` adapter) decide and compute the target effect `P*(y | do(x))` across a
|
|
118
|
+
selection diagram by routing each c-factor — invariant factors transfer from the source,
|
|
119
|
+
selection-marked factors are identified from the target. With no selection it reduces to ID.
|
|
120
|
+
Validated by simulation: under a covariate shift the transported estimate matches the target's
|
|
121
|
+
true `do()` distribution (and differs from naively reusing the source). It subsumes the
|
|
122
|
+
direct / S-admissible-adjustment cases; it is sound but not the *complete* sID.
|
|
123
|
+
|
|
124
|
+
### Fixed
|
|
125
|
+
- gID: Tian's `Identify` assumes its domain is a single c-component. Both gID and sID now route
|
|
126
|
+
through `_c_factor_from`, which decomposes the domain into c-components before extracting — fixing
|
|
127
|
+
a latent error on multi-component experiment/source domains (previous gID tests only hit the
|
|
128
|
+
single-component case).
|
|
129
|
+
|
|
130
|
+
### Notes
|
|
131
|
+
- The complete sID (transport c-factors identifiable only by combining source and target) is still
|
|
132
|
+
out of scope and reported as non-transportable rather than guessed.
|
|
133
|
+
|
|
134
|
+
## [0.14.0] - 2026-05-27
|
|
135
|
+
|
|
136
|
+
### Added
|
|
137
|
+
- **General identification from surrogate experiments (gID)** (taxonomy Task 4):
|
|
138
|
+
`identify_effect_with_experiments` extends the ID recursion so that a c-factor observation cannot
|
|
139
|
+
identify (a hedge) is instead obtained from an available experiment (Tian's `Identify`
|
|
140
|
+
subroutine). `is_gid_identifiable` gives the decision and `estimate_effect_with_experiments`
|
|
141
|
+
evaluates the estimand on observational plus randomized-experimental data. With no experiments it
|
|
142
|
+
coincides exactly with the ID algorithm. Validated by simulation: the bow-arc and a
|
|
143
|
+
confounded-mediator graph (neither observationally identifiable) are recovered from a surrogate
|
|
144
|
+
experiment, matching the true `do()` distribution.
|
|
145
|
+
|
|
146
|
+
### Notes
|
|
147
|
+
- Full cross-domain transportability (the complete sID algorithm) remains out of scope: it reduces
|
|
148
|
+
to a conditional-gID over an augmented selection diagram and is documented as the next frontier.
|
|
149
|
+
Transportability stays at the direct / S-admissible-adjustment slice for now.
|
|
150
|
+
|
|
151
|
+
## [0.13.0] - 2026-05-27
|
|
152
|
+
|
|
153
|
+
Depth pass closing the taxonomy gaps surfaced by re-checking the library against the Bareinboim
|
|
154
|
+
causal-RL program page.
|
|
155
|
+
|
|
156
|
+
### Added
|
|
157
|
+
- **General causal-effect identification** (taxonomy Task 4): `identify_effect` runs the sound and
|
|
158
|
+
complete Shpitser-Pearl ID algorithm, returning a do-free `Estimand` for `P(y | do(x))` in any
|
|
159
|
+
ADMG or raising `NotIdentifiableError` with the witnessing hedge. `estimate_effect` evaluates the
|
|
160
|
+
estimand on data; `is_identifiable_effect` gives the decision. Validated by simulation:
|
|
161
|
+
back-door/front-door estimands match the true `do()` distribution, and the bow-arc and
|
|
162
|
+
instrumental-variable graphs are correctly non-identifiable.
|
|
163
|
+
- **Interventional causal discovery** (Task 5): `discover_interventional` combines observational
|
|
164
|
+
(L1) and experimental (L2) data, orienting edges incident to each intervention target by the
|
|
165
|
+
invariance principle to recover the interventional essential graph.
|
|
166
|
+
- **Mixed-strategy Nash equilibria** (Task 9): `mixed_nash_equilibria` finds all equilibria of a
|
|
167
|
+
two-player game exactly by support enumeration over rational arithmetic.
|
|
168
|
+
- **Curriculum-driven RL** (Task 7): `curriculum_q_learning` trains Q-learning through a sequence of
|
|
169
|
+
subtasks with warm-start transfer, reaching a sparse target that flat learning misses.
|
|
170
|
+
- **"When to intervene"** (Task 2): `requires_experiment` reports when an experiment is necessary —
|
|
171
|
+
exactly when the effect is not observationally identifiable.
|
|
172
|
+
|
|
173
|
+
### Changed
|
|
174
|
+
- `is_identifiable` now delegates to the complete ID algorithm, returning a definite boolean for any
|
|
175
|
+
ADMG (no longer `None` for front-door-style cases).
|
|
176
|
+
- Documentation: the API reference and `guarantees.md` now cover the full taxonomy (tasks 3-9).
|
|
177
|
+
- Packaging: added `authors`, `keywords`, per-version classifiers, `Typing :: Typed`, and a
|
|
178
|
+
Changelog URL to the project metadata.
|
|
179
|
+
- CI: the test matrix now spans Linux/macOS/Windows; added a 90% coverage gate, example-notebook
|
|
180
|
+
execution (`nbmake`), and a `twine check` before publishing.
|
|
181
|
+
- Repository hygiene: added `SECURITY.md` and issue/PR templates; stopped tracking a reference PDF
|
|
182
|
+
(`papers/*.pdf` is gitignored).
|
|
183
|
+
|
|
184
|
+
### Fixed
|
|
185
|
+
- `examples/offline_to_online.ipynb`: multi-stage `DOVI` now passes
|
|
186
|
+
`transition_assumption="unconfounded"` (made mandatory by the correctness-hardening pass); the
|
|
187
|
+
notebook previously raised `UnverifiedAssumptionError`.
|
|
188
|
+
|
|
189
|
+
## [0.12.0] - 2026-05-27
|
|
190
|
+
|
|
191
|
+
### Added
|
|
192
|
+
- **Causal game theory** (taxonomy Task 9, completing the 9-task taxonomy). `CausalGame` represents a
|
|
193
|
+
finite game as a multi-agent causal influence diagram (a decision and a utility node per agent);
|
|
194
|
+
`best_response`, `is_nash_equilibrium`, and `pure_nash_equilibria` reason about equilibria by
|
|
195
|
+
enumeration. The canonical games recover their textbook pure equilibria: Prisoner's Dilemma (mutual
|
|
196
|
+
defection), a coordination game (two equilibria), matching pennies (none). Faithful to Koller &
|
|
197
|
+
Milch (MAIDs, 2003) and Hammond et al., *Reasoning about Causality in Games* (2023).
|
|
198
|
+
- `prisoners_dilemma`, `coordination_game`, `matching_pennies` demo games.
|
|
199
|
+
|
|
200
|
+
## [0.11.0] - 2026-05-27
|
|
201
|
+
|
|
202
|
+
### Added
|
|
203
|
+
- **Causal reward shaping** (taxonomy Task 8). `apply_potential_shaping` adds `gamma*Phi(s') - Phi(s)`
|
|
204
|
+
to an MDP's rewards — policy-invariant for any potential (Ng, Harada & Russell, ICML 1999) — and
|
|
205
|
+
`causal_potential` supplies the ideal potential `V*` from the causal model. With `TabularMDP`,
|
|
206
|
+
`value_iteration`, and tabular `q_learning`, causal-potential shaping makes a sparse reward dense:
|
|
207
|
+
the shaped learner reaches the optimal policy within a few episodes while unshaped Q-learning lags,
|
|
208
|
+
and the optimal policy is provably unchanged.
|
|
209
|
+
- `make_sparse_chain_mdp` — the sparse-reward chain demo.
|
|
210
|
+
|
|
211
|
+
## [0.10.0] - 2026-05-27
|
|
212
|
+
|
|
213
|
+
### Added
|
|
214
|
+
- **Causal curriculum learning** (taxonomy Task 7). `causal_curriculum` orders skills by a
|
|
215
|
+
topological sort of the causal/prerequisite graph (learn causes before effects),
|
|
216
|
+
`is_valid_curriculum` checks an order respects prerequisites, and `PrerequisiteLearner` models
|
|
217
|
+
causally-gated mastery (a skill is learned only once its parents are). On a skill chain/diamond the
|
|
218
|
+
causal curriculum masters the goal while a prerequisite-violating order does not. Faithful to
|
|
219
|
+
Bengio, Louradour, Collobert & Weston, *Curriculum Learning* (ICML 2009).
|
|
220
|
+
- `make_skill_chain` / `make_skill_diamond` prerequisite-graph demos.
|
|
221
|
+
|
|
222
|
+
## [0.9.0] - 2026-05-27
|
|
223
|
+
|
|
224
|
+
### Added
|
|
225
|
+
- **Causal imitation learning** (taxonomy Task 6). `is_imitable` / `imitation_backdoor_set` decide
|
|
226
|
+
whether an expert can be imitated from observed demonstrations and return the observed back-door
|
|
227
|
+
set to clone on; `CausalImitator` clones `P(A | Z)` and reproduces the expert's reward, while the
|
|
228
|
+
`BehavioralCloning` baseline (cloning the marginal `P(A)`) is biased by the confounding.
|
|
229
|
+
Conservative: returns `None` / `False` when no observed admissible set exists rather than a biased
|
|
230
|
+
policy. Faithful to Zhang, Kumor & Bareinboim, *Causal Imitation Learning with Unobserved
|
|
231
|
+
Confounders* (NeurIPS 2020).
|
|
232
|
+
- `ImitationEnv` (`make_imitation_diagram`, `generate_demonstrations`, `expert_policy`): a confounded
|
|
233
|
+
one-step demo where the causal imitator matches the expert (~0.9) and naive BC is stuck near ~0.5.
|
|
234
|
+
- `is_backdoor_admissible` (the back-door criterion check) is now public, shared by transportability
|
|
235
|
+
and imitation.
|
|
236
|
+
|
|
237
|
+
## [0.8.0] - 2026-05-27
|
|
238
|
+
|
|
239
|
+
### Added
|
|
240
|
+
- **Causal discovery** (taxonomy Task 5, learning causal models). `discover` runs the PC algorithm
|
|
241
|
+
over discrete data — conditional-independence tests by thresholded conditional mutual information
|
|
242
|
+
(`conditional_mutual_information`), then collider orientation and Meek rules R1–R3 — returning a
|
|
243
|
+
`CPDAG`. `CPDAG.to_causal_graph()` bridges a fully oriented result into the rest of the library, so
|
|
244
|
+
a discovered structure feeds straight into POMIS planning. Faithful to Spirtes, Glymour & Scheines
|
|
245
|
+
(PC) and Meek (UAI 1995). Conservative: assumes causal sufficiency, and the bridge raises rather
|
|
246
|
+
than guessing an orientation.
|
|
247
|
+
- `build_discovery_scm` / `sample_discovery_data` — a collider demo (`X→Z←Y`, `Z→W`) whose CPDAG is
|
|
248
|
+
recovered from data and then handed to `pomis`.
|
|
249
|
+
|
|
250
|
+
## [0.7.0] - 2026-05-27
|
|
251
|
+
|
|
252
|
+
### Added
|
|
253
|
+
- **Transportability** (taxonomy Task 4, generalizability & robustness). `SelectionDiagram`
|
|
254
|
+
represents a source/target pair differing in some mechanisms; `transport_formula` /
|
|
255
|
+
`is_transportable` decide whether `P*(y | do(x))` transfers and return the transport formula
|
|
256
|
+
(direct or S-admissible adjustment); `transported_effect` computes the transported estimate by
|
|
257
|
+
reweighting source conditionals with the target covariate marginal. Conservative — returns `None`
|
|
258
|
+
outside the supported class (no hedge-based sID completeness check). Faithful to Bareinboim &
|
|
259
|
+
Pearl (AAAI 2012; J. Causal Inference 2013) and Pearl & Bareinboim (Statistical Science 2014).
|
|
260
|
+
- `make_transport_domains` — the canonical covariate-shift demo (`Z→X, Z→Y, X→Y`, selection on
|
|
261
|
+
`Z`): the transport formula recovers the true target effect (~0.82) while naively reusing the
|
|
262
|
+
source effect is biased (~0.58).
|
|
263
|
+
- `CausalGraph.directed_edges` and `CausalGraph.bidirected_edges` accessors.
|
|
264
|
+
|
|
265
|
+
## [0.6.0] - 2026-05-27
|
|
266
|
+
|
|
267
|
+
### Added
|
|
268
|
+
- **Counterfactual decision-making** (taxonomy Task 3, Layer 3). `counterfactual_expectation`
|
|
269
|
+
returns `E[Y_{do(x)} | evidence]` and `effect_of_treatment_on_treated` returns the ETT
|
|
270
|
+
`E[Y_{treated} − Y_{control} | X = treated]`, both computed on an executable
|
|
271
|
+
`StructuralCausalModel` via abduction-action-prediction (`causalrl.identification.counterfactual`).
|
|
272
|
+
Faithful to Bareinboim, Forney & Pearl, *Bandits with Unobserved Confounders: A Causal Approach*
|
|
273
|
+
(NeurIPS 2015) and Pearl, *Causality* (2nd ed.) §8.2.1.
|
|
274
|
+
- `CounterfactualOptimalPolicy` — a model-based Regret Decision Criterion policy that decides by
|
|
275
|
+
`argmax_a E[Y_{do(a)} | intent]` — and `CounterfactualBanditEnv` /
|
|
276
|
+
`make_counterfactual_bandit_env`, a 3-arm confounded bandit. The counterfactual-optimal policy and
|
|
277
|
+
a trained `CausalThompsonSampling` reach the per-intent optimum (~0.8); a confounding-naive agent
|
|
278
|
+
is stuck at the best fixed intervention (the `do`-optimum, ~0.367).
|
|
279
|
+
|
|
280
|
+
### Changed
|
|
281
|
+
- Public environments now satisfy Gymnasium's checker, rollout helpers handle truncation, SCM
|
|
282
|
+
sampling isolates Torch RNG state, executable SCM definitions validate their graph contract,
|
|
283
|
+
and structural-bandit Thompson sampling supports bounded fractional rewards correctly.
|
|
284
|
+
- Multi-stage `DOVI` exposes whether transition-value propagation is causally certified, and
|
|
285
|
+
`POMISThompsonSampling` accepts an explicit validated `manipulable` contract.
|
|
286
|
+
- Deterministic multi-seed benchmark reporting, API documentation, citation/contribution
|
|
287
|
+
metadata, documentation CI, and release-only trusted PyPI publishing scaffolding were added.
|
|
288
|
+
|
|
289
|
+
## [0.5.0] - 2026-05-26
|
|
290
|
+
|
|
291
|
+
### Added
|
|
292
|
+
- **Non-manipulable variables** (extends taxonomy Task 2): `pomis` and
|
|
293
|
+
`minimal_intervention_sets` accept an optional `manipulable` subset. With non-manipulable set
|
|
294
|
+
`N`, POMIS equals the unconstrained POMIS of the latent projection onto `V\N` (Lee &
|
|
295
|
+
Bareinboim, *Structural Causal Bandits with Non-Manipulable Variables*, AAAI 2019, R-40,
|
|
296
|
+
Theorem 4); MIS simply filters to sets disjoint from `N`.
|
|
297
|
+
- `CausalGraph.latent_projection(keep)` — the Tian-Pearl / Verma latent projection.
|
|
298
|
+
- `make_frontdoor_env` (the R-40 front-door / cholesterol demo, with `Z` non-manipulable) and
|
|
299
|
+
`NaivePOMISThompsonSampling`; the manipulability-aware `POMISThompsonSampling` reaches the
|
|
300
|
+
`do(X)` optimum (~0.56) that the naive filter baseline (stuck at ~0.50 observation) cannot see.
|
|
301
|
+
|
|
302
|
+
### Changed
|
|
303
|
+
- `POMISThompsonSampling` infers its manipulable set from the environment's arms, so it
|
|
304
|
+
respects non-manipulable variables automatically (identical behavior when all variables are
|
|
305
|
+
manipulable).
|
|
306
|
+
- Stable causal-method contracts are now conservative: `StructuralCausalModel` executes
|
|
307
|
+
explicit-latent DAGs only, `backdoor_adjustment_set` refuses latent-confounded treatments,
|
|
308
|
+
and `is_identifiable` returns unknown for unsupported ADMG cases rather than an optimistic
|
|
309
|
+
positive result.
|
|
310
|
+
- The qualitative `confounding_sensitivity_bounds` helper moved to
|
|
311
|
+
`causalrl.experimental.ope`; its previous module path remains as a deprecated bridge and it
|
|
312
|
+
is no longer part of the stable top-level exports.
|
|
313
|
+
- Stable public exports are loaded lazily. Core graph, POMIS, tabular-agent, and tabular-env
|
|
314
|
+
use no longer requires PyTorch; install the `torch` extra for SCM/neural/Torch-backed
|
|
315
|
+
components. Supported Python now begins at 3.11 and CI covers 3.11 and 3.14.
|
|
316
|
+
|
|
317
|
+
## [0.4.0] - 2026-05-26
|
|
318
|
+
|
|
319
|
+
### Added
|
|
320
|
+
- **POMIS engine** (taxonomy Task 2, "where to intervene"): `pomis` and
|
|
321
|
+
`minimal_intervention_sets` compute the possibly-optimal / minimal intervention sets of a
|
|
322
|
+
single-reward ADMG via MUCT (minimal unobserved-confounder territory) and the
|
|
323
|
+
interventional border. Adapted from the MIT-licensed reference implementation of
|
|
324
|
+
Lee & Bareinboim, *Structural Causal Bandits: Where to Intervene?* (NeurIPS 2018),
|
|
325
|
+
github.com/sanghack81/SCMMAB-NIPS2018 (Copyright (c) 2018 Sanghack Lee).
|
|
326
|
+
- `StructuralCausalBanditEnv` — an SCM-backed bandit whose arms are interventions, plus the
|
|
327
|
+
`make_confounded_chain_env` demo where observing beats every fixed intervention.
|
|
328
|
+
- `POMISThompsonSampling`, `BruteForceInterventionTS`, and `FixedSetThompsonSampling` agents;
|
|
329
|
+
the POMIS agent converges to the optimal arm far faster than brute force and beats a naive
|
|
330
|
+
fixed-set agent.
|
|
331
|
+
- `CausalGraph` gains `ancestors`, `descendants`, `induced_subgraph`, and `do_mutilate`.
|
|
332
|
+
|
|
333
|
+
## [0.3.0] - 2026-05-26
|
|
334
|
+
|
|
335
|
+
### Added
|
|
336
|
+
- Horizon-indexed **DOVI** (Deconfounded Optimistic Value Iteration): finite-horizon backward
|
|
337
|
+
induction with Manski-bound-capped rewards; reduces exactly to the v0.2 backup at `H=1`.
|
|
338
|
+
- `SequentialDTREnv` — a genuinely confounded, multi-stage dynamic-treatment-regime environment
|
|
339
|
+
with a foresight gap (the immediate-greedy and lookahead-optimal first actions diverge).
|
|
340
|
+
- Curated top-level public API with an explicit `__all__`:
|
|
341
|
+
`from causalrl import DOVI, StructuralCausalModel, DTREnv, generate_logs, ...`.
|
|
342
|
+
- `py.typed` marker (PEP 561) so downstream consumers receive our type information.
|
|
343
|
+
- `LICENSE` file (MIT) and this changelog.
|
|
344
|
+
|
|
345
|
+
### Changed
|
|
346
|
+
- `SequentialMABUCEnv` rewritten to be genuinely confounded: a hidden confounder drives both
|
|
347
|
+
logging and reward, so the naive per-context mean is biased above the true interventional value.
|
|
348
|
+
- Sharpened the Manski-bounds property tests (higher sample size, tighter propensity, smaller slack).
|
|
349
|
+
- Version is single-sourced from `pyproject.toml` and read at runtime via `importlib.metadata`.
|
|
350
|
+
|
|
351
|
+
### Fixed
|
|
352
|
+
- The offline-to-online example re-imported names already imported in an earlier cell, tripping
|
|
353
|
+
ruff's `F811` and failing the CI lint step; the redundant imports are removed (the notebook
|
|
354
|
+
runs identically). `ruff check .` is now clean across the whole repository, including notebooks.
|
|
355
|
+
|
|
356
|
+
## [0.2.0] - 2026-05-23
|
|
357
|
+
|
|
358
|
+
### Added
|
|
359
|
+
- Causal **offline-to-online** learning (taxonomy Task 1): `UCDTR`, `DOVI`, and
|
|
360
|
+
`DeepDeconfoundedQ` agents that read confounded logs through causal bounds.
|
|
361
|
+
- Confounded environments: `DTREnv`, `ConfoundedGridworld`, `SequentialMABUCEnv`.
|
|
362
|
+
- Manski natural bounds (`causal_q_bounds`) and the offline-to-online evaluation harness.
|
|
363
|
+
|
|
364
|
+
## [0.1.0] - 2026-05-23
|
|
365
|
+
|
|
366
|
+
### Added
|
|
367
|
+
- Structural causal model core: `CausalGraph`, mechanisms, and `StructuralCausalModel` with
|
|
368
|
+
`see` (L1), `do` (L2), and `counterfactual` (L3) queries.
|
|
369
|
+
- Scoped identification: back-door parent set and bow-arc detection.
|
|
370
|
+
- MABUC bandit slice with causal Thompson sampling that beats a confounding-naive baseline.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use causalrl in research, please cite this software."
|
|
3
|
+
title: "causalrl: Causal intervention-selection and causal-RL research tools"
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: "Coelho"
|
|
7
|
+
given-names: "Raphael"
|
|
8
|
+
repository-code: "https://github.com/raphaelrrcoelho/causalrl"
|
|
9
|
+
url: "https://github.com/raphaelrrcoelho/causalrl"
|
|
10
|
+
license: MIT
|
|
11
|
+
version: "0.5.0"
|
|
12
|
+
date-released: "2026-05-26"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
`causalrl` accepts focused fixes, reference-validated causal algorithms, benchmark
|
|
4
|
+
improvements, and documentation corrections.
|
|
5
|
+
|
|
6
|
+
## Development Setup
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
git clone https://github.com/raphaelrrcoelho/causalrl.git
|
|
10
|
+
cd causalrl
|
|
11
|
+
uv sync --extra dev --extra docs
|
|
12
|
+
uv run --extra dev pytest
|
|
13
|
+
uv run --extra dev ruff check .
|
|
14
|
+
uv run --extra dev pyright src
|
|
15
|
+
uv run --extra docs mkdocs build --strict
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Expectations
|
|
19
|
+
|
|
20
|
+
- Add tests before changing behavior.
|
|
21
|
+
- Cite a primary source for implemented causal algorithms and include oracle fixtures or
|
|
22
|
+
reproducible benchmark evidence where applicable.
|
|
23
|
+
- State method assumptions in public APIs and documentation; do not present experimental
|
|
24
|
+
helpers as validated estimators.
|
|
25
|
+
- Keep new public API changes typed and documented.
|
|
26
|
+
|
|
27
|
+
## Pull Requests
|
|
28
|
+
|
|
29
|
+
Describe the causal or software contract changed, the evidence used for validation, and the
|
|
30
|
+
commands run. Small, reviewable changes are preferred.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Multi-stage build using the official uv image.
|
|
2
|
+
FROM ghcr.io/astral-sh/uv:python3.14-bookworm-slim AS base
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
|
|
5
|
+
# Install dependencies first (cached layer)
|
|
6
|
+
COPY pyproject.toml ./
|
|
7
|
+
COPY README.md ./
|
|
8
|
+
COPY src ./src
|
|
9
|
+
RUN uv sync --extra dev --no-install-project
|
|
10
|
+
RUN uv sync --extra dev
|
|
11
|
+
|
|
12
|
+
# Default: run the test suite
|
|
13
|
+
CMD ["uv", "run", "pytest", "-v"]
|