treecf 0.0.1__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.
Files changed (45) hide show
  1. treecf-0.0.1/LICENSE +21 -0
  2. treecf-0.0.1/PKG-INFO +116 -0
  3. treecf-0.0.1/README.md +54 -0
  4. treecf-0.0.1/pyproject.toml +132 -0
  5. treecf-0.0.1/rust/Cargo.lock +469 -0
  6. treecf-0.0.1/rust/Cargo.toml +32 -0
  7. treecf-0.0.1/rust/src/cells.rs +186 -0
  8. treecf-0.0.1/rust/src/constraints.rs +364 -0
  9. treecf-0.0.1/rust/src/ga.rs +574 -0
  10. treecf-0.0.1/rust/src/ir.rs +212 -0
  11. treecf-0.0.1/rust/src/lib.rs +9 -0
  12. treecf-0.0.1/rust/src/py.rs +405 -0
  13. treecf-0.0.1/src/treecf/__init__.py +58 -0
  14. treecf-0.0.1/src/treecf/_errors.py +27 -0
  15. treecf-0.0.1/src/treecf/_json.py +37 -0
  16. treecf-0.0.1/src/treecf/aim/__init__.py +5 -0
  17. treecf-0.0.1/src/treecf/aim/cells.py +103 -0
  18. treecf-0.0.1/src/treecf/api.py +592 -0
  19. treecf-0.0.1/src/treecf/backends/__init__.py +1 -0
  20. treecf-0.0.1/src/treecf/backends/genetic.py +196 -0
  21. treecf-0.0.1/src/treecf/backends/genetic_rust.py +214 -0
  22. treecf-0.0.1/src/treecf/batch.py +558 -0
  23. treecf-0.0.1/src/treecf/constraints/__init__.py +30 -0
  24. treecf-0.0.1/src/treecf/constraints/compile.py +293 -0
  25. treecf-0.0.1/src/treecf/constraints/flatten.py +105 -0
  26. treecf-0.0.1/src/treecf/constraints/objects.py +86 -0
  27. treecf-0.0.1/src/treecf/constraints/parser.py +156 -0
  28. treecf-0.0.1/src/treecf/ir/__init__.py +5 -0
  29. treecf-0.0.1/src/treecf/ir/conformance.py +66 -0
  30. treecf-0.0.1/src/treecf/ir/evaluate.py +122 -0
  31. treecf-0.0.1/src/treecf/ir/flatten.py +110 -0
  32. treecf-0.0.1/src/treecf/ir/model.py +59 -0
  33. treecf-0.0.1/src/treecf/ir/parsers/__init__.py +41 -0
  34. treecf-0.0.1/src/treecf/ir/parsers/catboost.py +127 -0
  35. treecf-0.0.1/src/treecf/ir/parsers/json_dump.py +35 -0
  36. treecf-0.0.1/src/treecf/ir/parsers/lightgbm.py +121 -0
  37. treecf-0.0.1/src/treecf/ir/parsers/sklearn.py +223 -0
  38. treecf-0.0.1/src/treecf/ir/parsers/xgboost.py +131 -0
  39. treecf-0.0.1/src/treecf/mining.py +363 -0
  40. treecf-0.0.1/src/treecf/objective.py +55 -0
  41. treecf-0.0.1/src/treecf/plausibility.py +61 -0
  42. treecf-0.0.1/src/treecf/py.typed +0 -0
  43. treecf-0.0.1/src/treecf/targets.py +114 -0
  44. treecf-0.0.1/src/treecf/viz.py +346 -0
  45. treecf-0.0.1/src/treecf/viz_batch.py +257 -0
treecf-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel Wlazlo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
treecf-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.4
2
+ Name: treecf
3
+ Version: 0.0.1
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: Intended Audience :: Science/Research
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Operating System :: OS Independent
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
13
+ Classifier: Typing :: Typed
14
+ Requires-Dist: numpy>=1.24
15
+ Requires-Dist: xgboost>=2.0 ; extra == 'all'
16
+ Requires-Dist: lightgbm>=4.3 ; extra == 'all'
17
+ Requires-Dist: catboost>=1.2 ; extra == 'all'
18
+ Requires-Dist: scikit-learn>=1.4 ; extra == 'all'
19
+ Requires-Dist: matplotlib>=3.8 ; extra == 'all'
20
+ Requires-Dist: catboost>=1.2 ; extra == 'catboost'
21
+ Requires-Dist: maturin>=1.7 ; extra == 'dev'
22
+ Requires-Dist: pytest>=8.0 ; extra == 'dev'
23
+ Requires-Dist: pytest-cov>=5.0 ; extra == 'dev'
24
+ Requires-Dist: hypothesis>=6.100 ; extra == 'dev'
25
+ Requires-Dist: ruff>=0.5 ; extra == 'dev'
26
+ Requires-Dist: mypy>=1.10 ; extra == 'dev'
27
+ Requires-Dist: xgboost>=2.0 ; extra == 'dev'
28
+ Requires-Dist: lightgbm>=4.3 ; extra == 'dev'
29
+ Requires-Dist: catboost>=1.2 ; extra == 'dev'
30
+ Requires-Dist: scikit-learn>=1.4 ; extra == 'dev'
31
+ Requires-Dist: matplotlib>=3.8 ; extra == 'dev'
32
+ Requires-Dist: mkdocs>=1.6 ; extra == 'docs'
33
+ Requires-Dist: mkdocs-material>=9.5 ; extra == 'docs'
34
+ Requires-Dist: mkdocstrings[python]>=0.27 ; extra == 'docs'
35
+ Requires-Dist: pymdown-extensions>=10.9 ; extra == 'docs'
36
+ Requires-Dist: mkdocs-jupyter>=0.24 ; extra == 'docs'
37
+ Requires-Dist: ipykernel>=6.29 ; extra == 'docs'
38
+ Requires-Dist: lightgbm>=4.3 ; extra == 'lightgbm'
39
+ Requires-Dist: scikit-learn>=1.4 ; extra == 'sklearn'
40
+ Requires-Dist: matplotlib>=3.8 ; extra == 'viz'
41
+ Requires-Dist: xgboost>=2.0 ; extra == 'xgboost'
42
+ Provides-Extra: all
43
+ Provides-Extra: catboost
44
+ Provides-Extra: dev
45
+ Provides-Extra: docs
46
+ Provides-Extra: lightgbm
47
+ Provides-Extra: sklearn
48
+ Provides-Extra: viz
49
+ Provides-Extra: xgboost
50
+ License-File: LICENSE
51
+ Summary: Constrained, threshold-aware counterfactual explanations for tree ensembles (XGBoost, LightGBM, CatBoost, sklearn) on a bundled Rust genetic engine.
52
+ Keywords: counterfactual,xai,interpretability,recourse,gbdt,xgboost,lightgbm,catboost,cp-sat,credit-risk
53
+ Author-email: Daniel Wlazlo <wlazlo.daniel@gmail.com>
54
+ License: MIT
55
+ Requires-Python: >=3.11
56
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
57
+ Project-URL: Changelog, https://github.com/wlazlod/treecf/blob/main/CHANGELOG.md
58
+ Project-URL: Documentation, https://wlazlod.github.io/treecf/
59
+ Project-URL: Homepage, https://github.com/wlazlod/treecf
60
+ Project-URL: Issues, https://github.com/wlazlod/treecf/issues
61
+
62
+ # treecf
63
+
64
+ **Constrained, threshold-aware counterfactual explanations for tree ensembles.**
65
+
66
+ `treecf` answers the question: *"what is the minimal, feasible change to this instance such
67
+ that the model's raw output lands in a target interval?"* — for XGBoost, LightGBM, CatBoost
68
+ and scikit-learn tree ensembles.
69
+
70
+ > Status: pre-release (v0.1). See the [documentation](https://wlazlod.github.io/treecf/) for concepts and tutorials.
71
+
72
+ ## Why another counterfactual package?
73
+
74
+ - **Tree-native and fast.** Models are parsed into a shared tree IR; the constrained
75
+ genetic search runs on a bundled **Rust core** 44–58× faster than the equivalent numpy
76
+ implementation (see the "Backends and proofs" docs page; the pure-Python engine remains
77
+ available as `backend="python"`), and every result is float-verified against the IR
78
+ before it is returned.
79
+ - **Decision thresholds are first-class.** Targets are intervals on the raw model output —
80
+ custom probability cutoffs, regression targets, and whole rating-grade ladders in one call.
81
+ - **Real-world constraints.** Declarative layer for immutability, directionality, ranges,
82
+ one-hot consistency, and arbitrary linear inter-feature constraints such as
83
+ `max_dpd_30d <= max_dpd_12m` — compiled once, enforced by every backend.
84
+ - **Missing values are values.** NaN can be a legitimate counterfactual state, with
85
+ per-feature opt-in and explicit transition costs.
86
+ - **Constraint mining.** Candidate invariants are mined from data and presented for human
87
+ review — never auto-applied.
88
+
89
+ ## Installation
90
+
91
+ ```bash
92
+ pip install treecf # bundled Rust engine; numpy is the only Python dep
93
+ pip install "treecf[xgboost]" # model parsers as extras; JSON dumps work without them
94
+ pip install "treecf[viz]" # matplotlib plots
95
+ ```
96
+
97
+ ## Quick look
98
+
99
+ ```python
100
+ from treecf import Explainer, Target, constraint, Freeze
101
+
102
+ exp = Explainer(
103
+ model="model.json", # native object or dump file
104
+ background=X_train_sample,
105
+ constraints=[
106
+ constraint("max_dpd_30d <= max_dpd_12m"),
107
+ Freeze("age_of_bureau_file"),
108
+ ],
109
+ )
110
+ res = exp.explain(x, target=Target.probability(range=(0.0, 0.04)), seed=0)
111
+ ```
112
+
113
+ ## License
114
+
115
+ MIT
116
+
treecf-0.0.1/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # treecf
2
+
3
+ **Constrained, threshold-aware counterfactual explanations for tree ensembles.**
4
+
5
+ `treecf` answers the question: *"what is the minimal, feasible change to this instance such
6
+ that the model's raw output lands in a target interval?"* — for XGBoost, LightGBM, CatBoost
7
+ and scikit-learn tree ensembles.
8
+
9
+ > Status: pre-release (v0.1). See the [documentation](https://wlazlod.github.io/treecf/) for concepts and tutorials.
10
+
11
+ ## Why another counterfactual package?
12
+
13
+ - **Tree-native and fast.** Models are parsed into a shared tree IR; the constrained
14
+ genetic search runs on a bundled **Rust core** 44–58× faster than the equivalent numpy
15
+ implementation (see the "Backends and proofs" docs page; the pure-Python engine remains
16
+ available as `backend="python"`), and every result is float-verified against the IR
17
+ before it is returned.
18
+ - **Decision thresholds are first-class.** Targets are intervals on the raw model output —
19
+ custom probability cutoffs, regression targets, and whole rating-grade ladders in one call.
20
+ - **Real-world constraints.** Declarative layer for immutability, directionality, ranges,
21
+ one-hot consistency, and arbitrary linear inter-feature constraints such as
22
+ `max_dpd_30d <= max_dpd_12m` — compiled once, enforced by every backend.
23
+ - **Missing values are values.** NaN can be a legitimate counterfactual state, with
24
+ per-feature opt-in and explicit transition costs.
25
+ - **Constraint mining.** Candidate invariants are mined from data and presented for human
26
+ review — never auto-applied.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ pip install treecf # bundled Rust engine; numpy is the only Python dep
32
+ pip install "treecf[xgboost]" # model parsers as extras; JSON dumps work without them
33
+ pip install "treecf[viz]" # matplotlib plots
34
+ ```
35
+
36
+ ## Quick look
37
+
38
+ ```python
39
+ from treecf import Explainer, Target, constraint, Freeze
40
+
41
+ exp = Explainer(
42
+ model="model.json", # native object or dump file
43
+ background=X_train_sample,
44
+ constraints=[
45
+ constraint("max_dpd_30d <= max_dpd_12m"),
46
+ Freeze("age_of_bureau_file"),
47
+ ],
48
+ )
49
+ res = exp.explain(x, target=Target.probability(range=(0.0, 0.04)), seed=0)
50
+ ```
51
+
52
+ ## License
53
+
54
+ MIT
@@ -0,0 +1,132 @@
1
+ [project]
2
+ name = "treecf"
3
+ version = "0.0.1"
4
+ description = "Constrained, threshold-aware counterfactual explanations for tree ensembles (XGBoost, LightGBM, CatBoost, sklearn) on a bundled Rust genetic engine."
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ authors = [{ name = "Daniel Wlazlo", email = "wlazlo.daniel@gmail.com" }]
8
+ requires-python = ">=3.11"
9
+ keywords = [
10
+ "counterfactual",
11
+ "xai",
12
+ "interpretability",
13
+ "recourse",
14
+ "gbdt",
15
+ "xgboost",
16
+ "lightgbm",
17
+ "catboost",
18
+ "cp-sat",
19
+ "credit-risk",
20
+ ]
21
+ classifiers = [
22
+ "Development Status :: 3 - Alpha",
23
+ "Intended Audience :: Science/Research",
24
+ "License :: OSI Approved :: MIT License",
25
+ "Operating System :: OS Independent",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.11",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
31
+ "Typing :: Typed",
32
+ ]
33
+ dependencies = ["numpy>=1.24"]
34
+
35
+ [project.optional-dependencies]
36
+ xgboost = ["xgboost>=2.0"]
37
+ lightgbm = ["lightgbm>=4.3"]
38
+ catboost = ["catboost>=1.2"]
39
+ sklearn = ["scikit-learn>=1.4"]
40
+ viz = ["matplotlib>=3.8"]
41
+ all = [
42
+ "xgboost>=2.0",
43
+ "lightgbm>=4.3",
44
+ "catboost>=1.2",
45
+ "scikit-learn>=1.4",
46
+ "matplotlib>=3.8",
47
+ ]
48
+ dev = [
49
+ "maturin>=1.7",
50
+ "pytest>=8.0",
51
+ "pytest-cov>=5.0",
52
+ "hypothesis>=6.100",
53
+ "ruff>=0.5",
54
+ "mypy>=1.10",
55
+ "xgboost>=2.0",
56
+ "lightgbm>=4.3",
57
+ "catboost>=1.2",
58
+ "scikit-learn>=1.4",
59
+ "matplotlib>=3.8",
60
+ ]
61
+ docs = [
62
+ "mkdocs>=1.6",
63
+ "mkdocs-material>=9.5",
64
+ "mkdocstrings[python]>=0.27",
65
+ "pymdown-extensions>=10.9",
66
+ "mkdocs-jupyter>=0.24",
67
+ "ipykernel>=6.29",
68
+ ]
69
+
70
+ [project.urls]
71
+ Homepage = "https://github.com/wlazlod/treecf"
72
+ Documentation = "https://wlazlod.github.io/treecf/"
73
+ Issues = "https://github.com/wlazlod/treecf/issues"
74
+ Changelog = "https://github.com/wlazlod/treecf/blob/main/CHANGELOG.md"
75
+
76
+ [build-system]
77
+ requires = ["maturin>=1.7"]
78
+ build-backend = "maturin"
79
+
80
+ [tool.maturin]
81
+ python-source = "src"
82
+ manifest-path = "rust/Cargo.toml"
83
+ module-name = "treecf._treecf_core"
84
+ features = ["extension-module"]
85
+ include = [{ path = "README.md", format = "sdist" }, { path = "LICENSE", format = "sdist" }]
86
+
87
+ [tool.ruff]
88
+ line-length = 100
89
+ target-version = "py311"
90
+ extend-exclude = ["dist", "build", "docs"]
91
+
92
+ [tool.ruff.lint]
93
+ select = ["E", "F", "W", "I", "B", "UP", "N", "SIM", "RUF"]
94
+ ignore = ["N803", "N806", "RUF001", "RUF002"]
95
+
96
+ [tool.ruff.lint.per-file-ignores]
97
+ "tests/**" = ["N802"]
98
+
99
+ [tool.mypy]
100
+ # no python_version pin: numpy's stubs use PEP 695 `type` statements, which mypy
101
+ # rejects when told to type-check as 3.11 while running under 3.12/3.13
102
+ strict = true
103
+ files = ["src/treecf"]
104
+
105
+ [[tool.mypy.overrides]]
106
+ module = [
107
+ "xgboost.*",
108
+ "lightgbm.*",
109
+ "catboost.*",
110
+ "sklearn.*",
111
+ "matplotlib.*",
112
+ "treecf._treecf_core",
113
+ "pandas",
114
+ ]
115
+ ignore_missing_imports = true
116
+
117
+ [tool.pytest.ini_options]
118
+ testpaths = ["tests"]
119
+ addopts = "-q --strict-markers -m 'not bench'"
120
+ markers = [
121
+ "bench: non-gating performance smoke benchmarks (run with -m bench)",
122
+ "rust: cross-language tests requiring the dev Rust extension (maturin develop)",
123
+ ]
124
+ filterwarnings = [
125
+ "error",
126
+ # sklearn warns when a wrapper fitted on a DataFrame-less array is queried with
127
+ # plain ndarrays; harmless in conformance tests (recorded in CLAUDE.md)
128
+ "ignore:X does not have valid feature names:UserWarning",
129
+ # lightgbm 4.5 still passes force_all_finite to scikit-learn 1.6 (renamed there);
130
+ # only affects the pinned conformance-matrix cell (recorded in CLAUDE.md)
131
+ "ignore:'force_all_finite' was renamed to 'ensure_all_finite':FutureWarning",
132
+ ]