Metadata-Version: 2.4
Name: tributo-algorithms
Version: 0.1.0
Summary: Official algorithm implementations and optional dependency extras for Tributo
Author: Tributo Contributors
License: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: <3.14,>=3.12
Requires-Dist: tributo>=1.2
Provides-Extra: all
Requires-Dist: catboost<2,>=1.2; extra == 'all'
Requires-Dist: causal-learn<0.2,>=0.1.4; extra == 'all'
Requires-Dist: dowhy<0.15,>=0.14; extra == 'all'
Requires-Dist: lightgbm<5,>=4.5; extra == 'all'
Requires-Dist: networkx>=3.0; extra == 'all'
Requires-Dist: numpy<3,>=2; extra == 'all'
Requires-Dist: onnx>=1.16; extra == 'all'
Requires-Dist: onnxmltools>=1.13; extra == 'all'
Requires-Dist: onnxruntime>=1.20; extra == 'all'
Requires-Dist: safetensors>=0.4.3; extra == 'all'
Requires-Dist: scikit-learn<2,>=1.4; extra == 'all'
Requires-Dist: scipy<2,>=1.12; extra == 'all'
Requires-Dist: skl2onnx>=1.17; extra == 'all'
Requires-Dist: torch-geometric>=2.5; extra == 'all'
Requires-Dist: torch<2.14,>=2.5; extra == 'all'
Requires-Dist: tributo[model-export-torch]>=1.2; extra == 'all'
Requires-Dist: tributo[model-export]>=1.2; extra == 'all'
Requires-Dist: xgboost<4,>=2.1; extra == 'all'
Provides-Extra: boosting
Requires-Dist: lightgbm<5,>=4.5; extra == 'boosting'
Requires-Dist: onnxmltools>=1.13; extra == 'boosting'
Requires-Dist: scikit-learn<2,>=1.4; extra == 'boosting'
Requires-Dist: tributo[model-export]>=1.2; extra == 'boosting'
Requires-Dist: xgboost<4,>=2.1; extra == 'boosting'
Provides-Extra: catboost
Requires-Dist: catboost<2,>=1.2; extra == 'catboost'
Requires-Dist: onnxruntime>=1.20; extra == 'catboost'
Provides-Extra: causal-core
Requires-Dist: numpy<3,>=2; extra == 'causal-core'
Requires-Dist: scikit-learn<2,>=1.4; extra == 'causal-core'
Requires-Dist: skl2onnx>=1.17; extra == 'causal-core'
Requires-Dist: tributo[model-export]>=1.2; extra == 'causal-core'
Provides-Extra: causal-discovery
Requires-Dist: causal-learn<0.2,>=0.1.4; extra == 'causal-discovery'
Requires-Dist: numpy<3,>=2; extra == 'causal-discovery'
Requires-Dist: onnx>=1.16; extra == 'causal-discovery'
Requires-Dist: onnxruntime>=1.20; extra == 'causal-discovery'
Provides-Extra: causal-dowhy
Requires-Dist: dowhy<0.15,>=0.14; extra == 'causal-dowhy'
Requires-Dist: networkx>=3.0; extra == 'causal-dowhy'
Requires-Dist: numpy<3,>=2; extra == 'causal-dowhy'
Requires-Dist: onnx>=1.16; extra == 'causal-dowhy'
Requires-Dist: onnxruntime>=1.20; extra == 'causal-dowhy'
Requires-Dist: scikit-learn<2,>=1.4; extra == 'causal-dowhy'
Requires-Dist: skl2onnx>=1.17; extra == 'causal-dowhy'
Requires-Dist: tributo[model-export]>=1.2; extra == 'causal-dowhy'
Provides-Extra: causal-dr
Requires-Dist: lightgbm<5,>=4.5; extra == 'causal-dr'
Requires-Dist: numpy<3,>=2; extra == 'causal-dr'
Requires-Dist: onnxmltools>=1.13; extra == 'causal-dr'
Requires-Dist: scikit-learn<2,>=1.4; extra == 'causal-dr'
Requires-Dist: skl2onnx>=1.17; extra == 'causal-dr'
Requires-Dist: tributo[model-export]>=1.2; extra == 'causal-dr'
Requires-Dist: xgboost<4,>=2.1; extra == 'causal-dr'
Provides-Extra: causal-xlearner
Requires-Dist: lightgbm<5,>=4.5; extra == 'causal-xlearner'
Requires-Dist: numpy<3,>=2; extra == 'causal-xlearner'
Requires-Dist: onnx>=1.16; extra == 'causal-xlearner'
Requires-Dist: onnxmltools>=1.13; extra == 'causal-xlearner'
Requires-Dist: onnxruntime>=1.20; extra == 'causal-xlearner'
Requires-Dist: tributo[model-export]>=1.2; extra == 'causal-xlearner'
Requires-Dist: xgboost<4,>=2.1; extra == 'causal-xlearner'
Provides-Extra: classical
Requires-Dist: numpy<3,>=2; extra == 'classical'
Requires-Dist: onnx>=1.16; extra == 'classical'
Requires-Dist: onnxruntime>=1.20; extra == 'classical'
Requires-Dist: scikit-learn<2,>=1.4; extra == 'classical'
Requires-Dist: scipy<2,>=1.12; extra == 'classical'
Requires-Dist: skl2onnx>=1.17; extra == 'classical'
Provides-Extra: graph-pyg
Requires-Dist: onnx>=1.16; extra == 'graph-pyg'
Requires-Dist: onnxruntime>=1.20; extra == 'graph-pyg'
Requires-Dist: safetensors>=0.4.3; extra == 'graph-pyg'
Requires-Dist: torch-geometric>=2.5; extra == 'graph-pyg'
Requires-Dist: torch<2.14,>=2.5; extra == 'graph-pyg'
Requires-Dist: tributo[model-export-torch]>=1.2; extra == 'graph-pyg'
Provides-Extra: multistage-torch
Requires-Dist: onnx>=1.16; extra == 'multistage-torch'
Requires-Dist: onnxruntime>=1.20; extra == 'multistage-torch'
Requires-Dist: safetensors>=0.4.3; extra == 'multistage-torch'
Requires-Dist: torch>=2.5; extra == 'multistage-torch'
Requires-Dist: tributo[model-export-torch]>=1.2; extra == 'multistage-torch'
Provides-Extra: recsys-torch
Requires-Dist: onnx>=1.16; extra == 'recsys-torch'
Requires-Dist: onnxruntime>=1.20; extra == 'recsys-torch'
Requires-Dist: torch>=2.5; extra == 'recsys-torch'
Requires-Dist: tributo[model-export-torch]>=1.2; extra == 'recsys-torch'
Provides-Extra: representation
Requires-Dist: onnx>=1.16; extra == 'representation'
Requires-Dist: onnxruntime>=1.20; extra == 'representation'
Requires-Dist: torch>=2.5; extra == 'representation'
Provides-Extra: tabular-torch
Requires-Dist: torch>=2.5; extra == 'tabular-torch'
Requires-Dist: tributo[model-export-torch]>=1.2; extra == 'tabular-torch'
Provides-Extra: timeseries
Requires-Dist: onnx>=1.16; extra == 'timeseries'
Requires-Dist: onnxruntime>=1.20; extra == 'timeseries'
Requires-Dist: torch>=2.5; extra == 'timeseries'
Provides-Extra: transformers-nlp
Requires-Dist: onnx>=1.16; extra == 'transformers-nlp'
Requires-Dist: onnxruntime>=1.20; extra == 'transformers-nlp'
Requires-Dist: torch>=2.5; extra == 'transformers-nlp'
Description-Content-Type: text/markdown

# Tributo Official Algorithms

This repository publishes one Python distribution, `tributo-algorithms`. The
Wheel contains all official algorithm descriptors and plugins; optional extras
install the runtime dependencies for each algorithm domain. Third-party
algorithms use the same public contracts and entry-point path.

Tributo Core owns Ray execution, resource allocation, retries, input leases,
checkpoint transport, evidence, Tune, Bundle publication, and inference. This
distribution owns algorithm mathematics, framework-native hooks, executable
contracts, and algorithm-specific delivery plugins.

| Extra | Algorithms and roles |
| --- | --- |
| `classical` | Random Forest, Extra Trees, Logistic/Linear Regression, MultinomialNB, PCA, KMeans, synchronous SGD, Isolation Forest |
| `boosting` | Ray Train XGBoost and LightGBM, ONNX/UBJ export, native flavor |
| `tabular-torch` | DNN, nnPU/uPU, PU prior and metric utilities |
| `timeseries` | Temporal convolution, LSTM, and GRU classification |
| `catboost` | Conditional distributed CatBoost ensemble |
| `representation` | Distributed tabular autoencoder |
| `transformers-nlp` | Pre-tokenized Transformer classification |
| `graph-pyg` | GraphSAGE and relational R-GCN |
| `recsys-torch` | Two-Tower and Jagged EmbeddingBag with All-to-All routing |
| `multistage-torch` | Distillation and pretrain-to-finetune |
| `causal-core` | Difference-in-means, DML, and IV |
| `causal-discovery` | Distributed PC stability discovery |
| `causal-dr` | Doubly robust/AIPW estimation |
| `causal-xlearner` | Five-stage X-Learner and batch CATE flavor |
| `causal-dowhy` | DoWhy estimation/refutation and GCM root-cause analysis |

Install only the domain dependencies you need:

```bash
pip install "tributo-algorithms[classical]"
pip install "tributo-algorithms[causal-xlearner]"
```

Use `tributo-algorithms[all]` to install every domain extra. The base
distribution registers all descriptors, so discovery remains available
without importing the optional algorithm frameworks. Selecting an algorithm
requires installing its corresponding extra.

The `graph-pyg` extra currently supports Torch `>=2.5,<2.14`; `all` follows
the same range. PyG's module import uses TorchScript APIs deprecated in Torch
2.14. Other Torch extras retain their own dependency ranges.

## Core compatibility

The distribution and domain extras require Tributo Core `>=1.2` without an
upper version bound. The XGBoost descriptor also requires `>=1.2` for optional
input routing; other descriptors retain their own minimum versions. Versions
below 1.2 are outside this distribution's declared compatibility range.
An open upper bound does not certify future Core
releases; execution support is established by the Gate for its exact Core
version, algorithm Wheel, and runtime image. Lock those versions in consuming
projects for reproducible deployments.

## macOS arm64 with Python 3.12

DoWhy 0.14 requires SciPy `<=1.15.3` on Python 3.12. The SciPy 1.15.3 macOS 14
Wheel fails dynamic loader validation on affected macOS versions. The official
macOS 12 Wheel of the same version works on these systems. The project's uv
source configuration selects this Wheel for macOS arm64 with Python 3.12 and
records its hash in `uv.lock`.

For pip installations of `causal-dowhy` or `all` on this platform, install that
official SciPy Wheel before the algorithm extra:

```bash
python -m pip install "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl#sha256=185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6"
python -m pip install "tributo-algorithms[causal-dowhy]"
```

## Development

```bash
uv sync --locked --extra all --group dev
uv run ruff format --check .
uv run ruff check .
uv run mypy packages
uv run pytest tests
uv build --no-sources
```

Release the aggregate distribution with a single
`tributo-algorithms-v<semver>` tag. CI builds one Wheel and source distribution,
publishes the same checksummed files to TestPyPI, verifies the installed
metadata, then publishes those files to PyPI.

## XGBoost validation and early stopping

XGBoost accepts a required `train` binding and an optional `validation` binding
through `InputBindingSet`, with `train` as the primary role. Both inputs must
declare the same ordered features and label column and provide compatible
numeric schemas. Validation rows are evaluated separately and never enter the
training gradient matrix. Both roles use lossless partitioning and report
their own `input_rows` counts for Core validation.

For validation-driven model selection, include these fields in the existing
`algorithm_config` (alongside its `data`, `ray`, and `output` configuration):

```json
{
  "model": {"objective": "binary:logistic", "eval_metric": "logloss"},
  "training": {
    "num_rounds": 1000,
    "early_stopping_rounds": 20,
    "maximize": false
  }
}
```

Early stopping requires validation, one explicit `model.eval_metric` string,
positive integer patience, and an explicit boolean `training.maximize`.
Patience may exceed the round limit. The native XGBoost callback selects the
best prefix even when the round limit is reached before patience expires.
Linear Boosters cannot export this selected prefix. A provided validation
shard must be non-empty on every Worker, matching the current train-shard
restriction. Invalid inputs or non-finite selection scores fail training.

Omit early-stopping fields to preserve fixed-round training. Validation can
still be provided for evaluation; train-only requests remain supported.
Execution metrics distinguish `training_rounds` (executed rounds) from
`model_rounds` (rounds in the exported model). Early-stopped fits additionally
return zero-based `best_iteration`, `best_score`, `selection_metric`, and
`maximize`. The `train-*` and `validation-*` metrics describe the last executed
round; `best_score` describes the selected round. Both ONNX and native UBJ
artifacts contain the selected model and a digest-checked
`training_metadata.json` sidecar. Best-model selection does
not depend on a consumer supplying an iteration range at prediction time.

For H&M, use validation logloss for stopping. XGBoost's distributed AUC is an
[approximation](https://xgboost.readthedocs.io/en/stable/parameter.html#learning-task-parameters).
Compute AP, ROC-AUC, and Lift over the complete held-out predictions and labels
in the calling application.

## XGBoost periodic checkpoints and same-run recovery

Enable periodic saving and a finite Worker failure allowance in the existing
configuration:

```json
{
  "training": {"num_rounds": 20, "checkpoint_interval_rounds": 10},
  "ray": {"storage_path": "/shared/checkpoints", "max_failures": 1}
}
```

Both fields default to zero. Values must be non-negative integers; booleans
and infinite retry budgets are rejected. A positive `max_failures` requires
a positive checkpoint interval. Saving without retries is allowed. Ray Train
V2 owns checkpoint transport and Worker group restarts; every trainer invocation
has a unique storage name. All nodes must access the same durable storage path.
Recovery requires `gbtree`, fixed Worker count/environment, and frozen inputs.
The exercised baseline is Ray 2.59.0 with XGBoost 3.4.1 and Core 1.2.0.

`num_rounds` remains the total target: restoring round 10 with a target of 20
adds at most 10 rounds. Checkpoints retain the full training Booster, ordered
features, invocation/plan identity, environment versions, file digests, and
early-stopping score history. Native early stopping replays that history to
retain best score and patience progress. A checkpoint that has reached the
round limit or stopped early adds no further rounds. Corrupt or incompatible
state fails explicitly, without silently restarting from zero. A failure before
the first checkpoint may restart from zero within the configured allowance.

The latest recovery state and selected inference model are separate. Only a
final checkpoint can be exported; both Bundle formats contain the selected
model. Metrics include `resumed_from_round` and `attempt_training_rounds`, whose
sum equals `training_rounds`. Final Worker receipts contain only the successful
group's input counts and newly executed rounds, including zero for terminal
recovery. Failed attempts do not contribute to coverage evidence.

This supports Worker process failures within one `fit()`. Cross-run
`runtime.resume_from`, Driver/Controller or cluster disaster recovery, elastic
Worker counts, and Tune are outside this feature. The public stage-runner API
is unchanged and keeps recovery disabled. Input identity checks do not detect
changed contents behind the same mutable URI. UBJ continuation does not promise
bitwise equivalence for random sampling, GPU training, or changed data shards;
the Gate uses deterministic CPU histogram training without sampling.

## XGBoost Worker Gate

XGBoost consumes replayable Ray Train shards in batches of at most 65,536 rows.
The existing Core Framework Native and multi-stage entry points share this
Worker loop; Core continues to manage execution and Bundle delivery.

The Gate targets a two-node Docker Ray 2.59.0 cluster with the same fixed
Tributo Core 1.2.0 and algorithm Wheels installed on every node, together with the
`boosting` extra. Use a shared directory mounted at the same absolute path on
both nodes. Submit from this repository through Ray Jobs:

```bash
ray job submit --address "$RAY_DASHBOARD_URL" --working-dir . \
  -- python tests/jobs/xgboost_worker_gate.py --root "$GATE_SHARED_ROOT"
```

`GATE_SHARED_ROOT` must name a new directory. The job checks the Core execution
path and `XGBoostStageRunner` with two Workers on different nodes, 131,075 input
train rows, 131,077 validation rows, synchronized model digests, train-only
and validation fits, early stopping, selected-model reload, and ONNX/native
Bundle artifacts. A separate bounded routing fixture verifies row identities
for both input roles, and an empty validation case must fail without publishing
a Bundle. Recovery cases inject real Worker exits after the controller confirms
checkpoint persistence: 10-to-20-round continuation, interruption during
patience, further improvement up to the round cap, final-checkpoint recovery
with no new rounds, finite retry exhaustion, and invocation/checkpoint isolation.
Final receipts are matched to the last successful group. It preserves
`result.json`, failure events, receipts, and model outputs
under that directory. This targeted Gate does not certify other runtime images
or execution profiles.
