API: constraints¶
constraint
¶
constraint(
text: str, feature_names: Sequence[str] | None = None
) -> Linear
Parse "2*a - b <= 3"-style sugar into a canonical Linear object.
Only linear expressions over +/-/* and one of <=/>=/
== are accepted; anything richer (nonlinear terms, multiple
comparisons) must be written as constraint objects directly. Terms on
both sides are folded into coefficients/rhs on the left-hand
side's convention, so "a <= b" and "a - b <= 0" produce the same
Linear. See Constraints.
| PARAMETER | DESCRIPTION |
|---|---|
text
|
The constraint string, e.g.
TYPE:
|
feature_names
|
When given, every identifier in
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
The parsed ``Linear`` constraint.
|
|
| RAISES | DESCRIPTION |
|---|---|
ConstraintParseError
|
If |
Source code in src/treecf/constraints/parser.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | |
objects
¶
Canonical constraint objects. Frozen dataclasses; validation at compile time.
Pass these (or a constraint() string) to Explainer(..., constraints=[...]).
See Constraints for what each one compiles to and
how they compose.
Freeze
dataclass
¶
Freeze(feature: str)
The feature is immutable: the counterfactual keeps the factual value.
| ATTRIBUTE | DESCRIPTION |
|---|---|
feature |
The feature name to freeze.
TYPE:
|
Monotone
dataclass
¶
Monotone(feature: str, direction: str)
The feature may only move in one direction from the factual value.
| ATTRIBUTE | DESCRIPTION |
|---|---|
feature |
The feature name to constrain.
TYPE:
|
direction |
TYPE:
|
Range
dataclass
¶
Range(feature: str, lo: float, hi: float)
Hard domain bounds for the counterfactual value (inclusive).
| ATTRIBUTE | DESCRIPTION |
|---|---|
feature |
The feature name to bound.
TYPE:
|
lo |
Lower bound, inclusive.
TYPE:
|
hi |
Upper bound, inclusive.
TYPE:
|
Linear
dataclass
¶
Linear(
coefficients: dict[str, float],
op: str,
rhs: float,
missing_policy: str = "satisfied",
)
Linear inter-feature constraint: sum(coef * feature) op rhs.
missing_policy resolves the constraint when a referenced feature is NaN
in the counterfactual: "satisfied" (vacuously true, the default),
"violated"/"forbid_missing" (the counterfactual may not use NaN there).
The exact backend supports single-feature and the canonical two-feature
order-pair shape exactly; any other multi-feature shape raises
ConstraintValidationError naming backend="genetic" as the
fallback — see
Certification.
| ATTRIBUTE | DESCRIPTION |
|---|---|
coefficients |
TYPE:
|
op |
TYPE:
|
rhs |
The right-hand-side constant.
TYPE:
|
missing_policy |
TYPE:
|
Equals
dataclass
¶
Equals(feature: str, value: float)
Binary-feature equality (used standalone or inside Implies).
| ATTRIBUTE | DESCRIPTION |
|---|---|
feature |
The feature name to compare.
TYPE:
|
value |
The value
TYPE:
|
Implies
dataclass
¶
OneHot
dataclass
¶
OneHot(features: tuple[str, ...])
The listed binary columns sum to exactly one.
| ATTRIBUTE | DESCRIPTION |
|---|---|
features |
The mutually exclusive binary feature names; at least two.
TYPE:
|
AllowedCategories
dataclass
¶
AllowedCategories(feature: str, allowed: object)
The categorical feature may only take the listed category codes or names.
Entries are integer codes (0..cardinality-1) or display names resolved
through the model's category names. Only valid on a categorical feature;
several declarations on one feature intersect.
| ATTRIBUTE | DESCRIPTION |
|---|---|
feature |
The categorical feature name to restrict.
TYPE:
|
allowed |
The permitted codes (ints) or category names (strs).
TYPE:
|
Source code in src/treecf/constraints/objects.py
163 164 165 166 | |
AllowMissing
dataclass
¶
AllowMissing(
feature: str,
delta_miss: float,
delta_from_miss: float | None = None,
)
NaN is a feasible counterfactual value for this feature.
delta_miss prices the value<->NaN transition; pass delta_from_miss
for an asymmetric NaN->value cost (defaults to delta_miss). See
Missing values.
| ATTRIBUTE | DESCRIPTION |
|---|---|
feature |
The feature name NaN is allowed on.
TYPE:
|
delta_miss |
Distance cost of a value-to-NaN change on this feature.
TYPE:
|
delta_from_miss |
Distance cost of a NaN-to-value change on this
feature; defaults to
TYPE:
|
Mining¶
suggest_constraints
¶
suggest_constraints(
X: FloatArray,
feature_names: Sequence[str] | None = None,
min_support: float = 1.0,
top_k: int = 50,
report_threshold: float = 0.999,
include_ranges: bool = False,
) -> SuggestionSet
Mine candidate invariants from a background sample, for human review.
Scans X for pairwise orders and equalities, binary implications
(a=1 => b=1), one-hot groups, missingness links (miss(a) =>
miss(b)), and integer-valuedness; optionally also observed 1st/99th
percentile ranges. Mined constraints are sample invariants, not domain
truths — min_support=1.0 on a finite sample can be coincidence — so
nothing here is ever auto-applied; inspect result[i].as_code() and
pass the ones you accept to Explainer(..., constraints=[...])
yourself. See
Constraints — mining candidates from
data.
| PARAMETER | DESCRIPTION |
|---|---|
X
|
Background sample, one row per instance, aligned to
TYPE:
|
feature_names
|
Column names for
TYPE:
|
min_support
|
Minimum fraction of co-present rows a pairwise order
must hold on to be suggested (
TYPE:
|
top_k
|
Maximum number of suggestions to return, after ranking by support and rationale strength; findings are not subject to this limit.
TYPE:
|
report_threshold
|
Minimum support for a near-invariant (one below
TYPE:
|
include_ranges
|
When
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
A ``SuggestionSet`` with ``suggestions`` (candidate constraints,
|
|
ranked and trimmed to ``top_k``) and ``findings`` (near-invariants
|
|
that fell short of ``min_support``).
|
|
Source code in src/treecf/mining.py
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | |
SuggestedConstraint
dataclass
¶
SuggestedConstraint(
constraint: Constraint | None,
kind: str,
support: float,
n_rows_checked: int,
n_violations: int,
evidence: list[dict[str, object]] = list(),
rationale: str = "",
)
One candidate invariant mined from a background sample, for human review.
suggest_constraints never applies a suggestion itself; the workflow is
to inspect as_code()/rationale/evidence, decide which
suggestions are real domain rules, and pass their constraint objects
to Explainer(..., constraints=[...]) explicitly. See
Constraints — mining candidates from
data.
| ATTRIBUTE | DESCRIPTION |
|---|---|
constraint |
The compiled constraint object this suggestion proposes,
or
TYPE:
|
kind |
TYPE:
|
support |
Fraction of checked rows the invariant held on, in
TYPE:
|
n_rows_checked |
Number of rows the check was evaluated over; what
counts as checkable depends on
TYPE:
|
n_violations |
Number of those rows that violated the invariant;
TYPE:
|
evidence |
Up to 5 violating rows,
TYPE:
|
rationale |
Human-readable justification: shared name tokens for
TYPE:
|
as_code
¶
as_code() -> str
This suggestion rendered as a copy-pasteable Python snippet.
| RETURNS | DESCRIPTION |
|---|---|
A ``constraint(...)``/``Implies(...)``/``OneHot(...)`` call (or,
|
|
for kinds with no direct constraint form, a ``#``-commented
|
|
description) followed by a ``# support=..., n=...`` trailer.
|
|
Source code in src/treecf/mining.py
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | |
DataQualityFinding
dataclass
¶
DataQualityFinding(
kind: str,
description: str,
support: float,
n_rows_checked: int,
n_violations: int,
evidence: list[dict[str, object]] = list(),
)
A near-invariant that fell short of min_support — likely an ETL defect.
Reported separately from SuggestedConstraint because support in
[report_threshold, min_support) usually means a rule that should be
universal is being violated by a small number of dirty rows, not that the
rule is genuinely conditional — worth fixing upstream rather than
encoding the exception as a constraint.
| ATTRIBUTE | DESCRIPTION |
|---|---|
kind |
Always
TYPE:
|
description |
Human-readable summary, e.g.
TYPE:
|
support |
Fraction of checked rows the near-invariant held on, in
TYPE:
|
n_rows_checked |
Number of rows where both referenced features were present.
TYPE:
|
n_violations |
Number of those rows that violated the near-invariant.
TYPE:
|
evidence |
Up to 5 violating rows,
TYPE:
|
Plausibility¶
Plausibility
dataclass
¶
Plausibility(if_ir: EnsembleIR, max_anomaly_score: float)
A hard isolation-forest bound keeping counterfactuals inside the data manifold.
Construct through Plausibility.isolation_forest rather than the
constructor directly. Pass the result as Explainer(...,
plausibility=...); every returned counterfactual then also satisfies
anomaly_score(x_cf) <= max_anomaly_score, enforced as a hard
constraint by every backend. Cannot be combined with AllowMissing or a
NaN-containing factual (isolation forests define no NaN routing). See
Plausibility.
| ATTRIBUTE | DESCRIPTION |
|---|---|
if_ir |
The isolation forest, parsed through the same tree IR the model uses.
TYPE:
|
max_anomaly_score |
The upper bound on
TYPE:
|
normalizer
property
¶
normalizer: float
The average path length c(n) for the forest's subsample size n.
Standard isolation-forest normalizer, derived from if_ir's
max_samples metadata; used to turn a raw total path length into
the [0, 1] anomaly score.
min_total_path
property
¶
min_total_path: float
The feasibility bound compiled into every backend's plausibility check.
Equivalent to max_anomaly_score re-expressed as a lower bound on
the summed depth-adjusted path length across every tree: a
counterfactual is plausible iff its total path length is at least
this value.
isolation_forest
classmethod
¶
isolation_forest(
model_or_ir: object, max_anomaly_score: float = 0.55
) -> Plausibility
Build a Plausibility bound from a fitted isolation forest.
| PARAMETER | DESCRIPTION |
|---|---|
model_or_ir
|
A native isolation-forest model (currently
sklearn's
TYPE:
|
max_anomaly_score
|
Upper bound on the isolation-forest anomaly
score, in
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
A ``Plausibility`` wrapping the parsed forest.
|
|
| RAISES | DESCRIPTION |
|---|---|
TreecfError
|
If |
Source code in src/treecf/plausibility.py
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | |
anomaly_score
¶
anomaly_score(x: FloatArray) -> float
The isolation-forest anomaly score at x, in [0, 1].
2 ** (-mean_path / normalizer): close to 1 for a point the
forest isolates in very few splits (anomalous), close to 0 for
one that takes many (typical). A point is plausible under this bound
iff its score is <= max_anomaly_score.
| PARAMETER | DESCRIPTION |
|---|---|
x
|
A feature vector, aligned to the forest's feature order.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
The anomaly score at ``x``.
|
|
Source code in src/treecf/plausibility.py
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |