# CausationEntropy
[](https://opensource.org/licenses/MIT)
[](https://www.python.org/downloads/)
[](https://causationentropy.readthedocs.io/en/latest/?badge=latest)
[](https://codecov.io/gh/kslote1/causationentropy)
[](https://github.com/kslote1/causationentropy/actions)
A Python library for discovering causal networks from time series data using **Optimal Causation Entropy (oCSE)**.
## Overview
CausationEntropy implements state-of-the-art information-theoretic methods for causal discovery from multivariate time series. The library provides robust algorithms that can identify causal relationships while controlling for confounding variables and false discoveries.
### What it does
Given time series data, CausationEntropy finds which variables cause changes in other variables by:
1. **Predictive Testing**: Testing if knowing variable X at time t helps predict variable Y at time t+1
2. **Information Theory**: Using conditional mutual information to measure predictive relationships
3. **Statistical Control**: Rigorous statistical testing to avoid false discoveries
4. **Multiple Methods**: Supporting various information estimators and discovery algorithms
## Installation
### From PyPI (recommended)
```bash
pip install causationentropy
```
### Development Installation
```bash
git clone https://github.com/kslote1/causationentropy.git
cd causationentropy
pip install -e .[dev,docs,plotting]
```
## Quick Start
### Basic Usage
```python
import numpy as np
import pandas as pd
from causationentropy import discover_network
# Load your time series data (variables as columns, time as rows)
data = pd.read_csv('your_data.csv')
# Discover causal network
network = discover_network(data, method='standard', max_lag=5)
# Examine results
print(f"Found {network.number_of_edges()} causal relationships")
for source, sink in network.edges(data=True):
print(f"{source} → {sink}: {network[source][sink]}")
```
### Advanced Configuration
```python
# Configure discovery parameters
network = discover_network(
data,
method='standard', # 'standard', 'alternative', 'information_lasso', or 'lasso'
information='gaussian', # 'gaussian', 'knn', 'kde', 'geometric_knn', or 'poisson'
max_lag=5, # Maximum time lag to consider
alpha_forward=0.05, # Forward selection significance
alpha_backward=0.05, # Backward elimination significance
n_shuffles=200 # Permutation test iterations
)
```
### Synthetic Data Example
```python
from causationentropy.datasets import synthetic
# Generate synthetic causal time series
data, true_network = synthetic.linear_stochastic_gaussian_process(
n_variables=5,
n_samples=1000,
sparsity=0.3
)
# Discover network
discovered = discover_network(data)
# Compare with ground truth
print(f"True edges: {true_network.number_of_edges()}")
print(f"Discovered edges: {discovered.number_of_edges()}")
```
## Key Features
- **Multiple Algorithms**: Standard, alternative, information lasso, and lasso variants of oCSE
- **Flexible Information Estimators**: Gaussian, k-NN, KDE, geometric k-NN, and Poisson methods
- **Statistical Rigor**: Permutation-based significance testing with comprehensive test coverage
- **Synthetic Data**: Built-in generators for testing and validation
- **Visualization**: Network plotting and analysis tools
- **Performance**: Optimized implementations with parallel processing support
## Mathematical Foundation
The algorithm uses **conditional mutual information** to quantify causal relationships:
$$I(X; Y | Z) = H(X | Z) + H(Y | Z) - H(X, Y | Z)$$
This measures how much variable X tells us about variable Y, beyond what we already know from conditioning set Z.
**Causal Discovery Rule**: Variable X causes Y if knowing X(t) significantly improves prediction of Y(t+1), even when controlling for all other relevant variables.
The algorithm implements a two-phase approach:
1. **Forward Selection**: Iteratively adds predictors that maximize conditional mutual information
2. **Backward Elimination**: Removes predictors that lose significance when conditioned on others
## Documentation
📚 **[Read the full documentation on ReadTheDocs](https://causationentropy.readthedocs.io/)**
- **[API Reference](https://causationentropy.readthedocs.io/en/latest/api/)**: Complete function and class documentation
- **[User Guide](https://causationentropy.readthedocs.io/en/latest/user_guide/)**: Detailed tutorials and examples
- **[Theory](https://causationentropy.readthedocs.io/en/latest/theory/)**: Mathematical background and algorithms
- **Examples**: Check the `examples/` and `notebooks/` directories
- **Research Papers**: See the `papers/` directory for theoretical foundations
### Local Documentation
Build documentation locally:
```bash
cd docs/
make html
# Open docs/_build/html/index.html
```
## Contributing
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
## Citation
If you use this library in your research, please cite:
```bibtex
@misc{slote2025causationentropy,
author = {Slote, Kevin and Fish Jeremie and Bollt, Erirk},
title = {CausationEntropy: A Python Library for Causal Discovery},
url = {https://github.com/kslote1/causationentropy},
doi = {}
}
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE.txt) file for details.
## Support
- **Issues**: [GitHub Issues](https://github.com/kslote1/causationentropy/issues)
- **Discussions**: [GitHub Discussions](https://github.com/kslote1/causationentropy/discussions)
- **Email**: kslote1@gmail.com
## Acknowledgments
This work builds upon fundamental research in information theory, causal inference, and time series analysis.
Special thanks to the open-source scientific Python community.
[Original Code](https://github.com/jefish003/NetworkInference)
## LLM Disclosure
Generative AI was used to help with doc strings, documentation, and unit tests.
Raw data
{
"_id": null,
"home_page": null,
"name": "causationentropy",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "causality, entropy, time-series, network, causal-discovery, information-theory",
"author": null,
"author_email": "Kevin Slote <kslote1@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/95/8f/b8763267d8351a66a170c87dd2a3ce0032028f076244a96dceb83f7e955e/causationentropy-0.1.0.tar.gz",
"platform": null,
"description": "# CausationEntropy\n\n[](https://opensource.org/licenses/MIT)\n[](https://www.python.org/downloads/)\n[](https://causationentropy.readthedocs.io/en/latest/?badge=latest)\n[](https://codecov.io/gh/kslote1/causationentropy)\n[](https://github.com/kslote1/causationentropy/actions)\n\nA Python library for discovering causal networks from time series data using **Optimal Causation Entropy (oCSE)**.\n\n## Overview\n\nCausationEntropy implements state-of-the-art information-theoretic methods for causal discovery from multivariate time series. The library provides robust algorithms that can identify causal relationships while controlling for confounding variables and false discoveries.\n\n### What it does\n\nGiven time series data, CausationEntropy finds which variables cause changes in other variables by:\n\n1. **Predictive Testing**: Testing if knowing variable X at time t helps predict variable Y at time t+1\n2. **Information Theory**: Using conditional mutual information to measure predictive relationships\n3. **Statistical Control**: Rigorous statistical testing to avoid false discoveries\n4. **Multiple Methods**: Supporting various information estimators and discovery algorithms\n\n## Installation\n\n### From PyPI (recommended)\n```bash\npip install causationentropy\n```\n\n### Development Installation\n```bash\ngit clone https://github.com/kslote1/causationentropy.git\ncd causationentropy\npip install -e .[dev,docs,plotting]\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport numpy as np\nimport pandas as pd\nfrom causationentropy import discover_network\n\n# Load your time series data (variables as columns, time as rows)\ndata = pd.read_csv('your_data.csv')\n\n# Discover causal network\nnetwork = discover_network(data, method='standard', max_lag=5)\n\n# Examine results\nprint(f\"Found {network.number_of_edges()} causal relationships\")\nfor source, sink in network.edges(data=True):\n print(f\"{source} \u2192 {sink}: {network[source][sink]}\")\n```\n\n### Advanced Configuration\n\n```python\n# Configure discovery parameters\nnetwork = discover_network(\n data,\n method='standard', # 'standard', 'alternative', 'information_lasso', or 'lasso'\n information='gaussian', # 'gaussian', 'knn', 'kde', 'geometric_knn', or 'poisson'\n max_lag=5, # Maximum time lag to consider\n alpha_forward=0.05, # Forward selection significance\n alpha_backward=0.05, # Backward elimination significance\n n_shuffles=200 # Permutation test iterations\n)\n```\n\n### Synthetic Data Example\n\n```python\nfrom causationentropy.datasets import synthetic\n\n# Generate synthetic causal time series\ndata, true_network = synthetic.linear_stochastic_gaussian_process(\n n_variables=5, \n n_samples=1000, \n sparsity=0.3\n)\n\n# Discover network\ndiscovered = discover_network(data)\n\n# Compare with ground truth\nprint(f\"True edges: {true_network.number_of_edges()}\")\nprint(f\"Discovered edges: {discovered.number_of_edges()}\")\n```\n\n## Key Features\n\n- **Multiple Algorithms**: Standard, alternative, information lasso, and lasso variants of oCSE\n- **Flexible Information Estimators**: Gaussian, k-NN, KDE, geometric k-NN, and Poisson methods \n- **Statistical Rigor**: Permutation-based significance testing with comprehensive test coverage\n- **Synthetic Data**: Built-in generators for testing and validation\n- **Visualization**: Network plotting and analysis tools\n- **Performance**: Optimized implementations with parallel processing support\n\n## Mathematical Foundation\n\nThe algorithm uses **conditional mutual information** to quantify causal relationships:\n\n$$I(X; Y | Z) = H(X | Z) + H(Y | Z) - H(X, Y | Z)$$\n\nThis measures how much variable X tells us about variable Y, beyond what we already know from conditioning set Z.\n\n**Causal Discovery Rule**: Variable X causes Y if knowing X(t) significantly improves prediction of Y(t+1), even when controlling for all other relevant variables.\n\nThe algorithm implements a two-phase approach:\n1. **Forward Selection**: Iteratively adds predictors that maximize conditional mutual information\n2. **Backward Elimination**: Removes predictors that lose significance when conditioned on others\n\n## Documentation\n\n\ud83d\udcda **[Read the full documentation on ReadTheDocs](https://causationentropy.readthedocs.io/)**\n\n- **[API Reference](https://causationentropy.readthedocs.io/en/latest/api/)**: Complete function and class documentation\n- **[User Guide](https://causationentropy.readthedocs.io/en/latest/user_guide/)**: Detailed tutorials and examples\n- **[Theory](https://causationentropy.readthedocs.io/en/latest/theory/)**: Mathematical background and algorithms\n- **Examples**: Check the `examples/` and `notebooks/` directories\n- **Research Papers**: See the `papers/` directory for theoretical foundations\n\n### Local Documentation\n\nBuild documentation locally:\n```bash\ncd docs/\nmake html\n# Open docs/_build/html/index.html\n```\n\n## Contributing\n\nWe welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## Citation\n\nIf you use this library in your research, please cite:\n\n```bibtex\n @misc{slote2025causationentropy,\n author = {Slote, Kevin and Fish Jeremie and Bollt, Erirk},\n title = {CausationEntropy: A Python Library for Causal Discovery},\n url = {https://github.com/kslote1/causationentropy},\n doi = {}\n }\n```\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE.txt) file for details.\n\n## Support\n\n- **Issues**: [GitHub Issues](https://github.com/kslote1/causationentropy/issues)\n- **Discussions**: [GitHub Discussions](https://github.com/kslote1/causationentropy/discussions)\n- **Email**: kslote1@gmail.com\n\n## Acknowledgments\n\nThis work builds upon fundamental research in information theory, causal inference, and time series analysis.\nSpecial thanks to the open-source scientific Python community.\n\n[Original Code](https://github.com/jefish003/NetworkInference)\n\n## LLM Disclosure\n\nGenerative AI was used to help with doc strings, documentation, and unit tests.\n",
"bugtrack_url": null,
"license": null,
"summary": "Causal network discovery using optimal causation entropy",
"version": "0.1.0",
"project_urls": {
"Bug Tracker": "https://github.com/Center-For-Complex-Systems-Science/causationentropy/issues",
"Documentation": "https://causationentropy.readthedocs.io/en/latest/",
"Homepage": "https://github.com/Center-For-Complex-Systems-Science/causationentropy",
"Repository": "https://github.com/Center-For-Complex-Systems-Science/causationentropy"
},
"split_keywords": [
"causality",
" entropy",
" time-series",
" network",
" causal-discovery",
" information-theory"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "829c58838ca04c26698c8b601f5a1a708ecb0808b9e12daec3ac1c7b656992c6",
"md5": "eda16d94717b2e4f64e6422777e4f6b0",
"sha256": "722a1e4d1cd99fef85de2f3ea144b68f66f2b85ef1d9ee2598641306712d5e31"
},
"downloads": -1,
"filename": "causationentropy-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "eda16d94717b2e4f64e6422777e4f6b0",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 55892,
"upload_time": "2025-09-03T13:47:14",
"upload_time_iso_8601": "2025-09-03T13:47:14.570970Z",
"url": "https://files.pythonhosted.org/packages/82/9c/58838ca04c26698c8b601f5a1a708ecb0808b9e12daec3ac1c7b656992c6/causationentropy-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "958fb8763267d8351a66a170c87dd2a3ce0032028f076244a96dceb83f7e955e",
"md5": "6adcc187534c5155840ac5f1ca8b57fb",
"sha256": "d092e71a443b6a17825bc599b70fbc185dc4a435e5956caccfad4a4bffd8d6cd"
},
"downloads": -1,
"filename": "causationentropy-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "6adcc187534c5155840ac5f1ca8b57fb",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 48484,
"upload_time": "2025-09-03T13:47:16",
"upload_time_iso_8601": "2025-09-03T13:47:16.400304Z",
"url": "https://files.pythonhosted.org/packages/95/8f/b8763267d8351a66a170c87dd2a3ce0032028f076244a96dceb83f7e955e/causationentropy-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-03 13:47:16",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Center-For-Complex-Systems-Science",
"github_project": "causationentropy",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "setuptools",
"specs": [
[
"~=",
"78.1.0"
]
]
},
{
"name": "numpy",
"specs": [
[
"~=",
"2.2.6"
]
]
},
{
"name": "scikit-learn",
"specs": [
[
"~=",
"1.7.0"
]
]
},
{
"name": "networkx",
"specs": [
[
"~=",
"3.4.2"
]
]
},
{
"name": "scipy",
"specs": [
[
"~=",
"1.15.3"
]
]
},
{
"name": "pandas",
"specs": [
[
"~=",
"2.3.0"
]
]
},
{
"name": "alabaster",
"specs": [
[
"==",
"1.0.0"
]
]
},
{
"name": "anyio",
"specs": [
[
"==",
"4.9.0"
]
]
},
{
"name": "appnope",
"specs": [
[
"==",
"0.1.4"
]
]
},
{
"name": "argon2-cffi",
"specs": [
[
"==",
"25.1.0"
]
]
},
{
"name": "argon2-cffi-bindings",
"specs": [
[
"==",
"21.2.0"
]
]
},
{
"name": "arrow",
"specs": [
[
"==",
"1.3.0"
]
]
},
{
"name": "asttokens",
"specs": [
[
"==",
"3.0.0"
]
]
},
{
"name": "async-lru",
"specs": [
[
"==",
"2.0.5"
]
]
},
{
"name": "attrs",
"specs": [
[
"==",
"25.3.0"
]
]
},
{
"name": "babel",
"specs": [
[
"==",
"2.17.0"
]
]
},
{
"name": "beautifulsoup4",
"specs": [
[
"==",
"4.13.4"
]
]
},
{
"name": "bleach",
"specs": [
[
"==",
"6.2.0"
]
]
},
{
"name": "certifi",
"specs": [
[
"==",
"2025.4.26"
]
]
},
{
"name": "cffi",
"specs": [
[
"==",
"1.17.1"
]
]
},
{
"name": "charset-normalizer",
"specs": [
[
"==",
"3.4.2"
]
]
},
{
"name": "comm",
"specs": [
[
"==",
"0.2.2"
]
]
},
{
"name": "contourpy",
"specs": [
[
"==",
"1.3.2"
]
]
},
{
"name": "cycler",
"specs": [
[
"==",
"0.12.1"
]
]
},
{
"name": "debugpy",
"specs": [
[
"==",
"1.8.14"
]
]
},
{
"name": "decorator",
"specs": [
[
"==",
"5.2.1"
]
]
},
{
"name": "defusedxml",
"specs": [
[
"==",
"0.7.1"
]
]
},
{
"name": "docutils",
"specs": [
[
"==",
"0.21.2"
]
]
},
{
"name": "executing",
"specs": [
[
"==",
"2.2.0"
]
]
},
{
"name": "fastjsonschema",
"specs": [
[
"==",
"2.21.1"
]
]
},
{
"name": "fonttools",
"specs": [
[
"==",
"4.58.3"
]
]
},
{
"name": "fqdn",
"specs": [
[
"==",
"1.5.1"
]
]
},
{
"name": "furo",
"specs": [
[
"==",
"2024.8.6"
]
]
},
{
"name": "h11",
"specs": [
[
"==",
"0.16.0"
]
]
},
{
"name": "httpcore",
"specs": [
[
"==",
"1.0.9"
]
]
},
{
"name": "httpx",
"specs": [
[
"==",
"0.28.1"
]
]
},
{
"name": "idna",
"specs": [
[
"==",
"3.10"
]
]
},
{
"name": "imagesize",
"specs": [
[
"==",
"1.4.1"
]
]
},
{
"name": "ipykernel",
"specs": [
[
"==",
"6.29.5"
]
]
},
{
"name": "ipython",
"specs": [
[
"==",
"9.3.0"
]
]
},
{
"name": "ipython_pygments_lexers",
"specs": [
[
"==",
"1.1.1"
]
]
},
{
"name": "ipywidgets",
"specs": [
[
"==",
"8.1.7"
]
]
},
{
"name": "isoduration",
"specs": [
[
"==",
"20.11.0"
]
]
},
{
"name": "jedi",
"specs": [
[
"==",
"0.19.2"
]
]
},
{
"name": "Jinja2",
"specs": [
[
"==",
"3.1.6"
]
]
},
{
"name": "joblib",
"specs": [
[
"==",
"1.5.1"
]
]
},
{
"name": "json5",
"specs": [
[
"==",
"0.12.0"
]
]
},
{
"name": "jsonpointer",
"specs": [
[
"==",
"3.0.0"
]
]
},
{
"name": "jsonschema",
"specs": [
[
"==",
"4.24.0"
]
]
},
{
"name": "jsonschema-specifications",
"specs": [
[
"==",
"2025.4.1"
]
]
},
{
"name": "jupyter",
"specs": [
[
"==",
"1.1.1"
]
]
},
{
"name": "jupyter-console",
"specs": [
[
"==",
"6.6.3"
]
]
},
{
"name": "jupyter-events",
"specs": [
[
"==",
"0.12.0"
]
]
},
{
"name": "jupyter-lsp",
"specs": [
[
"==",
"2.2.5"
]
]
},
{
"name": "jupyter_client",
"specs": [
[
"==",
"8.6.3"
]
]
},
{
"name": "jupyter_core",
"specs": [
[
"==",
"5.8.1"
]
]
},
{
"name": "jupyter_server",
"specs": [
[
"==",
"2.16.0"
]
]
},
{
"name": "jupyter_server_terminals",
"specs": [
[
"==",
"0.5.3"
]
]
},
{
"name": "jupyterlab",
"specs": [
[
"==",
"4.4.3"
]
]
},
{
"name": "jupyterlab_pygments",
"specs": [
[
"==",
"0.3.0"
]
]
},
{
"name": "jupyterlab_server",
"specs": [
[
"==",
"2.27.3"
]
]
},
{
"name": "jupyterlab_widgets",
"specs": [
[
"==",
"3.0.15"
]
]
},
{
"name": "kiwisolver",
"specs": [
[
"==",
"1.4.8"
]
]
},
{
"name": "markdown-it-py",
"specs": [
[
"==",
"3.0.0"
]
]
},
{
"name": "MarkupSafe",
"specs": [
[
"==",
"3.0.2"
]
]
},
{
"name": "matplotlib",
"specs": [
[
"==",
"3.10.3"
]
]
},
{
"name": "matplotlib-inline",
"specs": [
[
"==",
"0.1.7"
]
]
},
{
"name": "mdit-py-plugins",
"specs": [
[
"==",
"0.4.2"
]
]
},
{
"name": "mdurl",
"specs": [
[
"==",
"0.1.2"
]
]
},
{
"name": "mistune",
"specs": [
[
"==",
"3.1.3"
]
]
},
{
"name": "myst-parser",
"specs": [
[
"==",
"4.0.1"
]
]
},
{
"name": "nbclient",
"specs": [
[
"==",
"0.10.2"
]
]
},
{
"name": "nbconvert",
"specs": [
[
"==",
"7.16.6"
]
]
},
{
"name": "nbformat",
"specs": [
[
"==",
"5.10.4"
]
]
},
{
"name": "nbsphinx",
"specs": [
[
"==",
"0.9.7"
]
]
},
{
"name": "nest-asyncio",
"specs": [
[
"==",
"1.6.0"
]
]
},
{
"name": "networkx",
"specs": [
[
"==",
"3.5"
]
]
},
{
"name": "notebook",
"specs": [
[
"==",
"7.4.3"
]
]
},
{
"name": "notebook_shim",
"specs": [
[
"==",
"0.2.4"
]
]
},
{
"name": "numpy",
"specs": [
[
"==",
"2.3.0"
]
]
},
{
"name": "overrides",
"specs": [
[
"==",
"7.7.0"
]
]
},
{
"name": "packaging",
"specs": [
[
"==",
"25.0"
]
]
},
{
"name": "pandas",
"specs": [
[
"==",
"2.3.0"
]
]
},
{
"name": "pandocfilters",
"specs": [
[
"==",
"1.5.1"
]
]
},
{
"name": "parso",
"specs": [
[
"==",
"0.8.4"
]
]
},
{
"name": "pexpect",
"specs": [
[
"==",
"4.9.0"
]
]
},
{
"name": "pillow",
"specs": [
[
"==",
"11.2.1"
]
]
},
{
"name": "platformdirs",
"specs": [
[
"==",
"4.3.8"
]
]
},
{
"name": "prometheus_client",
"specs": [
[
"==",
"0.22.1"
]
]
},
{
"name": "prompt_toolkit",
"specs": [
[
"==",
"3.0.51"
]
]
},
{
"name": "psutil",
"specs": [
[
"==",
"7.0.0"
]
]
},
{
"name": "ptyprocess",
"specs": [
[
"==",
"0.7.0"
]
]
},
{
"name": "pure_eval",
"specs": [
[
"==",
"0.2.3"
]
]
},
{
"name": "pycparser",
"specs": [
[
"==",
"2.22"
]
]
},
{
"name": "Pygments",
"specs": [
[
"==",
"2.19.1"
]
]
},
{
"name": "pyparsing",
"specs": [
[
"==",
"3.2.3"
]
]
},
{
"name": "python-dateutil",
"specs": [
[
"==",
"2.9.0.post0"
]
]
},
{
"name": "python-json-logger",
"specs": [
[
"==",
"3.3.0"
]
]
},
{
"name": "pytz",
"specs": [
[
"==",
"2025.2"
]
]
},
{
"name": "PyYAML",
"specs": [
[
"==",
"6.0.2"
]
]
},
{
"name": "pyzmq",
"specs": [
[
"==",
"27.0.0"
]
]
},
{
"name": "referencing",
"specs": [
[
"==",
"0.36.2"
]
]
},
{
"name": "requests",
"specs": [
[
"==",
"2.32.4"
]
]
},
{
"name": "rfc3339-validator",
"specs": [
[
"==",
"0.1.4"
]
]
},
{
"name": "rfc3986-validator",
"specs": [
[
"==",
"0.1.1"
]
]
},
{
"name": "roman-numerals-py",
"specs": [
[
"==",
"3.1.0"
]
]
},
{
"name": "rpds-py",
"specs": [
[
"==",
"0.25.1"
]
]
},
{
"name": "scikit-learn",
"specs": [
[
"==",
"1.7.0"
]
]
},
{
"name": "scipy",
"specs": [
[
"==",
"1.15.3"
]
]
},
{
"name": "Send2Trash",
"specs": [
[
"==",
"1.8.3"
]
]
},
{
"name": "setuptools",
"specs": [
[
"==",
"80.9.0"
]
]
},
{
"name": "six",
"specs": [
[
"==",
"1.17.0"
]
]
},
{
"name": "sniffio",
"specs": [
[
"==",
"1.3.1"
]
]
},
{
"name": "snowballstemmer",
"specs": [
[
"==",
"3.0.1"
]
]
},
{
"name": "soupsieve",
"specs": [
[
"==",
"2.7"
]
]
},
{
"name": "Sphinx",
"specs": [
[
"==",
"8.2.3"
]
]
},
{
"name": "sphinx-autodoc-typehints",
"specs": [
[
"==",
"3.2.0"
]
]
},
{
"name": "sphinx-basic-ng",
"specs": [
[
"==",
"1.0.0b2"
]
]
},
{
"name": "sphinx-copybutton",
"specs": [
[
"==",
"0.5.2"
]
]
},
{
"name": "sphinx-gallery",
"specs": [
[
"==",
"0.19.0"
]
]
},
{
"name": "sphinx-rtd-theme",
"specs": [
[
"==",
"3.0.2"
]
]
},
{
"name": "sphinxcontrib-applehelp",
"specs": [
[
"==",
"2.0.0"
]
]
},
{
"name": "sphinxcontrib-devhelp",
"specs": [
[
"==",
"2.0.0"
]
]
},
{
"name": "sphinxcontrib-htmlhelp",
"specs": [
[
"==",
"2.1.0"
]
]
},
{
"name": "sphinxcontrib-jquery",
"specs": [
[
"==",
"4.1"
]
]
},
{
"name": "sphinxcontrib-jsmath",
"specs": [
[
"==",
"1.0.1"
]
]
},
{
"name": "sphinxcontrib-qthelp",
"specs": [
[
"==",
"2.0.0"
]
]
},
{
"name": "sphinxcontrib-serializinghtml",
"specs": [
[
"==",
"2.0.0"
]
]
},
{
"name": "stack-data",
"specs": [
[
"==",
"0.6.3"
]
]
},
{
"name": "terminado",
"specs": [
[
"==",
"0.18.1"
]
]
},
{
"name": "threadpoolctl",
"specs": [
[
"==",
"3.6.0"
]
]
},
{
"name": "tinycss2",
"specs": [
[
"==",
"1.4.0"
]
]
},
{
"name": "tornado",
"specs": [
[
"==",
"6.5.1"
]
]
},
{
"name": "traitlets",
"specs": [
[
"==",
"5.14.3"
]
]
},
{
"name": "types-python-dateutil",
"specs": [
[
"==",
"2.9.0.20250516"
]
]
},
{
"name": "typing_extensions",
"specs": [
[
"==",
"4.14.0"
]
]
},
{
"name": "tzdata",
"specs": [
[
"==",
"2025.2"
]
]
},
{
"name": "uri-template",
"specs": [
[
"==",
"1.3.0"
]
]
},
{
"name": "urllib3",
"specs": [
[
"==",
"2.4.0"
]
]
},
{
"name": "wcwidth",
"specs": [
[
"==",
"0.2.13"
]
]
},
{
"name": "webcolors",
"specs": [
[
"==",
"24.11.1"
]
]
},
{
"name": "webencodings",
"specs": [
[
"==",
"0.5.1"
]
]
},
{
"name": "websocket-client",
"specs": [
[
"==",
"1.8.0"
]
]
},
{
"name": "widgetsnbextension",
"specs": [
[
"==",
"4.0.14"
]
]
}
],
"lcname": "causationentropy"
}