rustylab 0.3.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.
- rustylab-0.3.0/.claude/settings.json +8 -0
- rustylab-0.3.0/.forgejo/workflows/num_acc_testing.yml +46 -0
- rustylab-0.3.0/.github/workflows/build-wheels.yml +122 -0
- rustylab-0.3.0/.gitignore +76 -0
- rustylab-0.3.0/.vscode/ltex.dictionary.en-GB.txt +6 -0
- rustylab-0.3.0/.vscode/ltex.hiddenFalsePositives.en-GB.txt +7 -0
- rustylab-0.3.0/CLAUDE.md +22 -0
- rustylab-0.3.0/CONTRIBUTING.md +122 -0
- rustylab-0.3.0/Cargo.lock +2399 -0
- rustylab-0.3.0/Cargo.toml +25 -0
- rustylab-0.3.0/LICENSE +9 -0
- rustylab-0.3.0/PKG-INFO +128 -0
- rustylab-0.3.0/README.md +103 -0
- rustylab-0.3.0/RELEASING.md +280 -0
- rustylab-0.3.0/benchmarks/bench_misc.ipynb +245 -0
- rustylab-0.3.0/benchmarks/bench_misc.md +182 -0
- rustylab-0.3.0/benchmarks/bench_optimize.ipynb +208 -0
- rustylab-0.3.0/benchmarks/bench_optimize.md +155 -0
- rustylab-0.3.0/benchmarks/bench_special.ipynb +810 -0
- rustylab-0.3.0/benchmarks/bench_special.md +607 -0
- rustylab-0.3.0/benchmarks/bench_stats_prob_dists.ipynb +3286 -0
- rustylab-0.3.0/benchmarks/bench_stats_prob_dists.md +3125 -0
- rustylab-0.3.0/benchmarks/export_notebooks.sh +19 -0
- rustylab-0.3.0/benchmarks/requirements-benchmarking.txt +35 -0
- rustylab-0.3.0/docs/.gitignore +2 -0
- rustylab-0.3.0/docs/.vscode/ltex.dictionary.en-GB.txt +29 -0
- rustylab-0.3.0/docs/.vscode/ltex.dictionary.en-US.txt +1 -0
- rustylab-0.3.0/docs/.vscode/ltex.hiddenFalsePositives.en-GB.txt +40 -0
- rustylab-0.3.0/docs/.vscode/ltex.hiddenFalsePositives.en-US.txt +1 -0
- rustylab-0.3.0/docs/Home.qmd +346 -0
- rustylab-0.3.0/docs/_quarto.yml +6 -0
- rustylab-0.3.0/docs/misc.qmd +111 -0
- rustylab-0.3.0/docs/optimize.qmd +64 -0
- rustylab-0.3.0/docs/special.qmd +799 -0
- rustylab-0.3.0/docs/stats/bernoulli.qmd +576 -0
- rustylab-0.3.0/docs/stats/beta.qmd +595 -0
- rustylab-0.3.0/docs/stats/binom.qmd +597 -0
- rustylab-0.3.0/docs/stats/cauchy.qmd +565 -0
- rustylab-0.3.0/docs/stats/chi2.qmd +586 -0
- rustylab-0.3.0/docs/stats/expon.qmd +565 -0
- rustylab-0.3.0/docs/stats/f.qmd +591 -0
- rustylab-0.3.0/docs/stats/gamma.qmd +584 -0
- rustylab-0.3.0/docs/stats/norm.qmd +575 -0
- rustylab-0.3.0/docs/stats/poisson.qmd +574 -0
- rustylab-0.3.0/docs/stats/randint.qmd +575 -0
- rustylab-0.3.0/docs/stats/t.qmd +580 -0
- rustylab-0.3.0/docs/stats/uniform.qmd +564 -0
- rustylab-0.3.0/docs/stats.qmd +31 -0
- rustylab-0.3.0/images/avatar.png +0 -0
- rustylab-0.3.0/images/banner.jpg +0 -0
- rustylab-0.3.0/pyproject.toml +39 -0
- rustylab-0.3.0/python/rustylab/__init__.py +3 -0
- rustylab-0.3.0/python/rustylab/expr/__init__.py +3 -0
- rustylab-0.3.0/python/rustylab/expr/misc.py +15 -0
- rustylab-0.3.0/python/rustylab/expr/special.py +138 -0
- rustylab-0.3.0/python/rustylab/expr/stats/__init__.py +17 -0
- rustylab-0.3.0/python/rustylab/expr/stats/_common.py +25 -0
- rustylab-0.3.0/python/rustylab/expr/stats/bernoulli.py +125 -0
- rustylab-0.3.0/python/rustylab/expr/stats/beta.py +126 -0
- rustylab-0.3.0/python/rustylab/expr/stats/binom.py +127 -0
- rustylab-0.3.0/python/rustylab/expr/stats/cauchy.py +128 -0
- rustylab-0.3.0/python/rustylab/expr/stats/chi2.py +113 -0
- rustylab-0.3.0/python/rustylab/expr/stats/expon.py +125 -0
- rustylab-0.3.0/python/rustylab/expr/stats/f.py +126 -0
- rustylab-0.3.0/python/rustylab/expr/stats/gamma.py +127 -0
- rustylab-0.3.0/python/rustylab/expr/stats/norm.py +125 -0
- rustylab-0.3.0/python/rustylab/expr/stats/poisson.py +125 -0
- rustylab-0.3.0/python/rustylab/expr/stats/randint.py +127 -0
- rustylab-0.3.0/python/rustylab/expr/stats/t.py +113 -0
- rustylab-0.3.0/python/rustylab/expr/stats/uniform.py +125 -0
- rustylab-0.3.0/requirements.txt +3 -0
- rustylab-0.3.0/src/constants.rs +366 -0
- rustylab-0.3.0/src/lib.rs +62 -0
- rustylab-0.3.0/src/misc/fsum.rs +680 -0
- rustylab-0.3.0/src/misc/mod.rs +18 -0
- rustylab-0.3.0/src/optimize/mod.rs +19 -0
- rustylab-0.3.0/src/optimize/newton.rs +323 -0
- rustylab-0.3.0/src/optimize/results.rs +138 -0
- rustylab-0.3.0/src/pyerr.rs +108 -0
- rustylab-0.3.0/src/special/beta.rs +94 -0
- rustylab-0.3.0/src/special/betainc.rs +2643 -0
- rustylab-0.3.0/src/special/betaincc.rs +136 -0
- rustylab-0.3.0/src/special/betainccinv.rs +122 -0
- rustylab-0.3.0/src/special/betaincinv.rs +373 -0
- rustylab-0.3.0/src/special/erf.rs +277 -0
- rustylab-0.3.0/src/special/erfc.rs +277 -0
- rustylab-0.3.0/src/special/factorial.rs +148 -0
- rustylab-0.3.0/src/special/gamma.rs +191 -0
- rustylab-0.3.0/src/special/gammainc.rs +136 -0
- rustylab-0.3.0/src/special/gammaincc.rs +137 -0
- rustylab-0.3.0/src/special/gammainccinv.rs +305 -0
- rustylab-0.3.0/src/special/gammaincinv.rs +297 -0
- rustylab-0.3.0/src/special/lbeta.rs +155 -0
- rustylab-0.3.0/src/special/lfactorial.rs +153 -0
- rustylab-0.3.0/src/special/lgamma.rs +205 -0
- rustylab-0.3.0/src/special/mod.rs +47 -0
- rustylab-0.3.0/src/stats/bernoulli.rs +1021 -0
- rustylab-0.3.0/src/stats/beta.rs +1362 -0
- rustylab-0.3.0/src/stats/binom.rs +1461 -0
- rustylab-0.3.0/src/stats/cauchy.rs +1132 -0
- rustylab-0.3.0/src/stats/chi2.rs +1155 -0
- rustylab-0.3.0/src/stats/expon.rs +1059 -0
- rustylab-0.3.0/src/stats/f.rs +1449 -0
- rustylab-0.3.0/src/stats/gamma.rs +1138 -0
- rustylab-0.3.0/src/stats/mod.rs +123 -0
- rustylab-0.3.0/src/stats/norm.rs +1086 -0
- rustylab-0.3.0/src/stats/poisson.rs +1294 -0
- rustylab-0.3.0/src/stats/randint.rs +1068 -0
- rustylab-0.3.0/src/stats/t.rs +1418 -0
- rustylab-0.3.0/src/stats/uniform.rs +1067 -0
- rustylab-0.3.0/src/utils.rs +3021 -0
- rustylab-0.3.0/tests/datasets/datasets.py +23 -0
- rustylab-0.3.0/tests/datasets/housing.parquet +0 -0
- rustylab-0.3.0/tests/datasets/iris.parquet +0 -0
- rustylab-0.3.0/tests/datasets/titanic.parquet +0 -0
- rustylab-0.3.0/tests/requirements-testing.txt +11 -0
- rustylab-0.3.0/tests/test_misc.py +268 -0
- rustylab-0.3.0/tests/test_optimize.py +234 -0
- rustylab-0.3.0/tests/test_plugin_symbols.py +25 -0
- rustylab-0.3.0/tests/test_special.py +1431 -0
- rustylab-0.3.0/tests/test_stats_bernoulli.py +1626 -0
- rustylab-0.3.0/tests/test_stats_beta.py +1869 -0
- rustylab-0.3.0/tests/test_stats_binom.py +1368 -0
- rustylab-0.3.0/tests/test_stats_cauchy.py +1791 -0
- rustylab-0.3.0/tests/test_stats_chi2.py +1962 -0
- rustylab-0.3.0/tests/test_stats_expon.py +1874 -0
- rustylab-0.3.0/tests/test_stats_f.py +1927 -0
- rustylab-0.3.0/tests/test_stats_gamma.py +1979 -0
- rustylab-0.3.0/tests/test_stats_norm.py +1844 -0
- rustylab-0.3.0/tests/test_stats_poisson.py +1460 -0
- rustylab-0.3.0/tests/test_stats_randint.py +1793 -0
- rustylab-0.3.0/tests/test_stats_t.py +2094 -0
- rustylab-0.3.0/tests/test_stats_uniform.py +938 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Numerical Accuracy Testing
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
types: [closed]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: codeberg-medium-lazy
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout repository
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Install Rust manually
|
|
20
|
+
run: |
|
|
21
|
+
curl https://sh.rustup.rs -sSf | sh -s -- -y
|
|
22
|
+
source $HOME/.cargo/env
|
|
23
|
+
rustup default stable
|
|
24
|
+
|
|
25
|
+
- name: Add Rust to PATH
|
|
26
|
+
run: echo "PATH=$HOME/.cargo/bin:$PATH" >> $GITHUB_ENV
|
|
27
|
+
|
|
28
|
+
- name: Create Python virtual environment
|
|
29
|
+
run: python3 -m venv venv
|
|
30
|
+
|
|
31
|
+
- name: Activate virtual environment and install Python dependencies
|
|
32
|
+
run: |
|
|
33
|
+
source venv/bin/activate
|
|
34
|
+
python -m pip install --upgrade pip
|
|
35
|
+
python -m pip install maturin
|
|
36
|
+
python -m pip install -r ./tests/requirements-testing.txt
|
|
37
|
+
|
|
38
|
+
- name: Build and install Rust extension
|
|
39
|
+
run: |
|
|
40
|
+
source venv/bin/activate
|
|
41
|
+
maturin develop --release --strip
|
|
42
|
+
|
|
43
|
+
- name: Run tests
|
|
44
|
+
run: |
|
|
45
|
+
source venv/bin/activate
|
|
46
|
+
pytest
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
name: Build wheels
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
pull_request:
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build-wheels:
|
|
12
|
+
name: Build wheels on ${{ matrix.os }}
|
|
13
|
+
runs-on: ${{ matrix.os }}
|
|
14
|
+
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Set up Python (for maturin & metadata)
|
|
25
|
+
uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
|
|
29
|
+
- name: Install Rust
|
|
30
|
+
uses: dtolnay/rust-toolchain@stable
|
|
31
|
+
|
|
32
|
+
- name: Build wheels with maturin
|
|
33
|
+
uses: PyO3/maturin-action@v1
|
|
34
|
+
with:
|
|
35
|
+
command: build
|
|
36
|
+
args: >
|
|
37
|
+
--release
|
|
38
|
+
--strip
|
|
39
|
+
manylinux: "2014" # only used on Linux
|
|
40
|
+
|
|
41
|
+
- name: Verify the wheel ships the Python layer
|
|
42
|
+
shell: bash
|
|
43
|
+
run: |
|
|
44
|
+
python - <<'PY'
|
|
45
|
+
import pathlib, sys, zipfile
|
|
46
|
+
|
|
47
|
+
want = {p.relative_to("python").as_posix()
|
|
48
|
+
for p in pathlib.Path("python/rustylab").rglob("*.py")}
|
|
49
|
+
bad = False
|
|
50
|
+
for whl in sorted(pathlib.Path("target/wheels").glob("*.whl")):
|
|
51
|
+
have = {n for n in zipfile.ZipFile(whl).namelist() if n.endswith(".py")}
|
|
52
|
+
missing = sorted(want - have)
|
|
53
|
+
print(whl.name, "OK" if not missing else f"MISSING {missing}")
|
|
54
|
+
bad |= bool(missing)
|
|
55
|
+
sys.exit(1 if bad else 0)
|
|
56
|
+
PY
|
|
57
|
+
|
|
58
|
+
- name: Smoke-test the wheel
|
|
59
|
+
shell: bash
|
|
60
|
+
run: |
|
|
61
|
+
python -m venv smoke
|
|
62
|
+
PY=smoke/bin/python
|
|
63
|
+
[ -x smoke/Scripts/python.exe ] && PY=smoke/Scripts/python.exe
|
|
64
|
+
"$PY" -m pip install --upgrade pip
|
|
65
|
+
"$PY" -m pip install target/wheels/*.whl
|
|
66
|
+
"$PY" - <<'PY'
|
|
67
|
+
import polars as pl
|
|
68
|
+
from rustylab import expr, stats
|
|
69
|
+
|
|
70
|
+
print("eager:", stats.norm.pdf(0.0))
|
|
71
|
+
lf = pl.LazyFrame({"x": [0.0, 1.0, 2.0]}).select(p=expr.stats.norm.pdf("x"))
|
|
72
|
+
a = lf.collect(engine="in-memory")["p"].to_list()
|
|
73
|
+
b = lf.collect(engine="streaming")["p"].to_list()
|
|
74
|
+
assert a == b, (a, b)
|
|
75
|
+
print("plugin:", a)
|
|
76
|
+
PY
|
|
77
|
+
|
|
78
|
+
- name: Upload wheels
|
|
79
|
+
uses: actions/upload-artifact@v4
|
|
80
|
+
with:
|
|
81
|
+
name: wheels-${{ matrix.os }}
|
|
82
|
+
path: target/wheels/*.whl
|
|
83
|
+
|
|
84
|
+
build-sdist:
|
|
85
|
+
name: Build sdist
|
|
86
|
+
runs-on: ubuntu-latest
|
|
87
|
+
|
|
88
|
+
steps:
|
|
89
|
+
- name: Checkout
|
|
90
|
+
uses: actions/checkout@v4
|
|
91
|
+
|
|
92
|
+
- name: Set up Python (for maturin & metadata)
|
|
93
|
+
uses: actions/setup-python@v5
|
|
94
|
+
with:
|
|
95
|
+
python-version: "3.12"
|
|
96
|
+
|
|
97
|
+
- name: Build sdist with maturin
|
|
98
|
+
uses: PyO3/maturin-action@v1
|
|
99
|
+
with:
|
|
100
|
+
command: sdist
|
|
101
|
+
args: --out target/wheels
|
|
102
|
+
|
|
103
|
+
- name: Verify the sdist carries both halves of the package
|
|
104
|
+
shell: bash
|
|
105
|
+
run: |
|
|
106
|
+
python - <<'PY'
|
|
107
|
+
import pathlib, tarfile
|
|
108
|
+
|
|
109
|
+
sdist = next(pathlib.Path("target/wheels").glob("*.tar.gz"))
|
|
110
|
+
names = tarfile.open(sdist).getnames()
|
|
111
|
+
for required in ("Cargo.toml", "pyproject.toml", "src/lib.rs",
|
|
112
|
+
"python/rustylab/__init__.py",
|
|
113
|
+
"python/rustylab/expr/stats/norm.py"):
|
|
114
|
+
assert any(n.endswith("/" + required) for n in names), required
|
|
115
|
+
print(sdist.name, "OK -", len(names), "entries")
|
|
116
|
+
PY
|
|
117
|
+
|
|
118
|
+
- name: Upload sdist
|
|
119
|
+
uses: actions/upload-artifact@v4
|
|
120
|
+
with:
|
|
121
|
+
name: sdist
|
|
122
|
+
path: target/wheels/*.tar.gz
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/target
|
|
2
|
+
|
|
3
|
+
# Quarto
|
|
4
|
+
**/.quarto/
|
|
5
|
+
**/*.quarto_ipynb
|
|
6
|
+
|
|
7
|
+
# Byte-compiled / optimized / DLL files
|
|
8
|
+
__pycache__/
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
*.py[cod]
|
|
11
|
+
|
|
12
|
+
# C extensions
|
|
13
|
+
*.so
|
|
14
|
+
|
|
15
|
+
# Distribution / packaging
|
|
16
|
+
.Python
|
|
17
|
+
.venv/
|
|
18
|
+
env/
|
|
19
|
+
bin/
|
|
20
|
+
build/
|
|
21
|
+
develop-eggs/
|
|
22
|
+
dist/
|
|
23
|
+
eggs/
|
|
24
|
+
lib/
|
|
25
|
+
lib64/
|
|
26
|
+
parts/
|
|
27
|
+
sdist/
|
|
28
|
+
var/
|
|
29
|
+
include/
|
|
30
|
+
man/
|
|
31
|
+
venv/
|
|
32
|
+
*.egg-info/
|
|
33
|
+
.installed.cfg
|
|
34
|
+
*.egg
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
pip-selfcheck.json
|
|
40
|
+
|
|
41
|
+
# Unit test / coverage reports
|
|
42
|
+
htmlcov/
|
|
43
|
+
.tox/
|
|
44
|
+
.coverage
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
|
|
49
|
+
# Translations
|
|
50
|
+
*.mo
|
|
51
|
+
|
|
52
|
+
# Mr Developer
|
|
53
|
+
.mr.developer.cfg
|
|
54
|
+
.project
|
|
55
|
+
.pydevproject
|
|
56
|
+
|
|
57
|
+
# Rope
|
|
58
|
+
.ropeproject
|
|
59
|
+
|
|
60
|
+
# Django stuff:
|
|
61
|
+
*.log
|
|
62
|
+
*.pot
|
|
63
|
+
|
|
64
|
+
.DS_Store
|
|
65
|
+
|
|
66
|
+
# Sphinx documentation
|
|
67
|
+
docs/_build/
|
|
68
|
+
|
|
69
|
+
# PyCharm
|
|
70
|
+
.idea/
|
|
71
|
+
|
|
72
|
+
# VSCode
|
|
73
|
+
#.vscode/
|
|
74
|
+
|
|
75
|
+
# Pyenv
|
|
76
|
+
.python-version
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{"rule":"UPPERCASE_SENTENCE_START","sentence":"^\\Qlinear_models\\E$"}
|
|
2
|
+
{"rule":"LICENCE_LICENSE_NOUN_SINGULAR","sentence":"^\\QMIT License\\E$"}
|
|
3
|
+
{"rule":"MORFOLOGIK_RULE_EN_GB","sentence":"^\\QCopyright © 2026 esuriddick\\E$"}
|
|
4
|
+
{"rule":"MORFOLOGIK_RULE_EN_GB","sentence":"^\\QTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\\E$"}
|
|
5
|
+
{"rule":"UPPERCASE_SENTENCE_START","sentence":"^\\Qspecial\\E$"}
|
|
6
|
+
{"rule":"LICENCE_LICENSE_NOUN_SINGULAR","sentence":"^\\QLicence\n{{< include ../LICENSE >}}\\E$"}
|
|
7
|
+
{"rule":"UPPERCASE_SENTENCE_START","sentence":"^\\Qmisc\nspecial\nstats\\E$"}
|
rustylab-0.3.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# rustylab
|
|
2
|
+
|
|
3
|
+
A Python library with a Rust backend, built to merge and unify functionality
|
|
4
|
+
from SciPy, NumPy, statsmodels, scikit-learn, and river into a single API.
|
|
5
|
+
|
|
6
|
+
## Architecture
|
|
7
|
+
|
|
8
|
+
- Rust project where all functions are explicitly built for Python
|
|
9
|
+
interoperability (via `pyo3` or similar crates).
|
|
10
|
+
- The project includes custom Rust modules that are part of this codebase,
|
|
11
|
+
not external crates.
|
|
12
|
+
- Internal Rust functions are called through: `use crate::constants`,
|
|
13
|
+
`use crate::optimize`, `use crate::special`, `use crate::stats`,
|
|
14
|
+
`use crate::utils`, etc.
|
|
15
|
+
|
|
16
|
+
## How to work with me
|
|
17
|
+
|
|
18
|
+
- Do not edit files. Propose changes as suggestions or copy-pasteable
|
|
19
|
+
code replacements, and show enough surrounding context that I can
|
|
20
|
+
place the change myself.
|
|
21
|
+
- When suggesting a function, respect the existing `crate::` module
|
|
22
|
+
boundaries above rather than introducing new top-level modules.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Contributing to RustyLab
|
|
2
|
+
Thank you for your interest in contributing to RustyLab! Contributions of all kinds are welcome — whether you want to report an issue, propose a feature, improve documentation, or submit code.
|
|
3
|
+
|
|
4
|
+
## Getting Help
|
|
5
|
+
Something is not working as expected? Is there a feature you would like to see implemented but are unsure how to approach it? Please head to the [Issues Page](https://codeberg.org/esuriddick/rustylab/issues) and open an issue.
|
|
6
|
+
|
|
7
|
+
When creating an issue, please include one of the following tags in the title:
|
|
8
|
+
|
|
9
|
+
- **FEATURE** — propose a new feature or an improvement to an existing one.
|
|
10
|
+
- **BUG** — report unexpected or incorrect behaviour.
|
|
11
|
+
- **HELP** — ask a question that does not fit the categories above.
|
|
12
|
+
|
|
13
|
+
Examples:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
[FEATURE] Generalized Linear Models
|
|
17
|
+
[BUG] Function special.factorial is not returning the correct value
|
|
18
|
+
[HELP] How to install RustyLab in Python?
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Propose your own code
|
|
22
|
+
|
|
23
|
+
### Prerequisites
|
|
24
|
+
|
|
25
|
+
* **Python:** 3.12 or higher for development; released wheels support 3.10+.
|
|
26
|
+
* **Rust:** 1.92.0 or higher
|
|
27
|
+
|
|
28
|
+
### Optional Tools
|
|
29
|
+
|
|
30
|
+
* **Python package manager:** [uv](https://docs.astral.sh/uv/)
|
|
31
|
+
* **IDE:** [Positron](https://positron.posit.co/)
|
|
32
|
+
|
|
33
|
+
### Project layout
|
|
34
|
+
|
|
35
|
+
RustyLab is a hybrid package - a Rust core plus a Python layer, both shipped in the wheel:
|
|
36
|
+
|
|
37
|
+
* `src/**` - the Rust core. Eager functions are exposed with `pyo3`; expression functions
|
|
38
|
+
are exposed with `#[polars_expr]`, which turns each one into an exported symbol.
|
|
39
|
+
* `python/rustylab/**` - the Python layer. The `expr/**` modules are thin wrappers that call
|
|
40
|
+
`register_plugin_function(..., function_name="…")`, where the name **must** match the
|
|
41
|
+
symbol exported by the Rust side.
|
|
42
|
+
* `tests/**` and `benchmarks/**` - the numerical accuracy suite and the benchmark notebooks.
|
|
43
|
+
* `docs/**` - the Quarto sources rendered into the Wiki.
|
|
44
|
+
|
|
45
|
+
### Quick setup
|
|
46
|
+
1. **Clone the repository**:
|
|
47
|
+
```bash
|
|
48
|
+
git clone https://codeberg.org/esuriddick/rustylab.git
|
|
49
|
+
cd rustylab
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
2. **Set up the required virtual environments**
|
|
53
|
+
|
|
54
|
+
There are three virtual environments, namely:
|
|
55
|
+
|
|
56
|
+
* **Development** (`./requirements.txt`) — includes `maturin` for building and packaging Rust-based Python extension.
|
|
57
|
+
* **Benchmarking** (`./benchmarks/requirements-benchmarking.txt`) — includes packages required for benchmarking.
|
|
58
|
+
* **Testing** (`./tests/requirements-testing.txt`) — includes packages used for numerical accuracy tests.
|
|
59
|
+
|
|
60
|
+
If you use `uv`, you can create the Development environment with:
|
|
61
|
+
```bash
|
|
62
|
+
uv venv
|
|
63
|
+
uv pip install -r requirements.txt
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
To set up the Benchmarking environment:
|
|
67
|
+
```bash
|
|
68
|
+
cd benchmarks
|
|
69
|
+
uv venv
|
|
70
|
+
uv pip install -r requirements-benchmarking.txt
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
To set up the Testing environment:
|
|
74
|
+
```bash
|
|
75
|
+
cd ../ # To return to the repository's root folder
|
|
76
|
+
cd tests
|
|
77
|
+
uv venv
|
|
78
|
+
uv pip install -r requirements-testing.txt
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Development Workflow
|
|
82
|
+
Please follow the existing project structure and create new modules only when necessary. RustyLab aims to maintain conceptual alignment with established Python libraries such as SciPy, scikit-learn, and statsmodels.
|
|
83
|
+
|
|
84
|
+
When adding new functions or classes:
|
|
85
|
+
|
|
86
|
+
- Provide clear documentation, so others can understand and review your work.
|
|
87
|
+
- Ensure your implementation is testable.
|
|
88
|
+
- Include benchmarks and tests where appropriate.
|
|
89
|
+
|
|
90
|
+
An expression function is not finished until all five exist:
|
|
91
|
+
|
|
92
|
+
1. The Rust implementation, exposed with `#[polars_expr]` in the right `crate::` module;
|
|
93
|
+
2. The Python wrapper in `python/rustylab/expr/**`, whose `function_name` matches the exported symbol - `tests/test_plugin_symbols.py` enforces this;
|
|
94
|
+
3. A test that collects the expression under **both** the `in-memory` and `streaming` engines and compares the results;
|
|
95
|
+
4. A docstring on both sides - the eager one in `src/**`, the expression one in the Python wrapper;
|
|
96
|
+
5. The matching section in `docs/**`.
|
|
97
|
+
|
|
98
|
+
To debug your work before submission, build the RustyLab Python package using the Development environment:
|
|
99
|
+
```bash
|
|
100
|
+
source .venv/bin/activate # Linux / macOS
|
|
101
|
+
.\.venv\Scripts\activate # Windows
|
|
102
|
+
maturin develop --release --strip
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`maturin develop` installs **both** halves of the package, and it *copies* the modules under `python/rustylab/**` into `site-packages`. A Python-only edit is therefore not live: rebuild after touching `python/rustylab/**`, exactly as you would after touching `src/**`.
|
|
106
|
+
|
|
107
|
+
This allows you to import and test RustyLab directly from your local environment.
|
|
108
|
+
|
|
109
|
+
### Commit Guidelines
|
|
110
|
+
Commits should follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification. Examples:
|
|
111
|
+
```
|
|
112
|
+
docs: documentation only changes
|
|
113
|
+
feat: a new feature is introduced
|
|
114
|
+
fix: a bug is fixed
|
|
115
|
+
perf: code change that improves performance
|
|
116
|
+
refactor: code change that neither fixes a bug nor adds a feature
|
|
117
|
+
style: changes that do not affect the meaning of the code (whitespace, formatting, missing semi-colons, etc.)
|
|
118
|
+
test: add missing tests or correcting existing tests
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Licence of contributions
|
|
122
|
+
By contributing, you agree that your contributions will be licensed under the [MIT licence](https://opensource.org/license/MIT).
|