fastscipy 0.1.0a1__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.
- fastscipy-0.1.0a1/.github/ISSUE_TEMPLATE/bug_report.md +24 -0
- fastscipy-0.1.0a1/.github/workflows/ci.yml +81 -0
- fastscipy-0.1.0a1/.github/workflows/linux.yml +42 -0
- fastscipy-0.1.0a1/.github/workflows/release.yml +112 -0
- fastscipy-0.1.0a1/.gitignore +8 -0
- fastscipy-0.1.0a1/CONTRIBUTING.md +98 -0
- fastscipy-0.1.0a1/Cargo.lock +280 -0
- fastscipy-0.1.0a1/Cargo.toml +33 -0
- fastscipy-0.1.0a1/LICENSE +31 -0
- fastscipy-0.1.0a1/LICENSES/scipy-LICENSE.txt +30 -0
- fastscipy-0.1.0a1/PKG-INFO +103 -0
- fastscipy-0.1.0a1/README.md +65 -0
- fastscipy-0.1.0a1/pyproject.toml +57 -0
- fastscipy-0.1.0a1/python/fastscipy/__init__.py +108 -0
- fastscipy-0.1.0a1/python/fastscipy/_cluster.py +112 -0
- fastscipy-0.1.0a1/python/fastscipy/_csgraph.py +241 -0
- fastscipy-0.1.0a1/python/fastscipy/_integrate.py +364 -0
- fastscipy-0.1.0a1/python/fastscipy/_interpolate.py +343 -0
- fastscipy-0.1.0a1/python/fastscipy/_linalg.py +477 -0
- fastscipy-0.1.0a1/python/fastscipy/_ndimage.py +53 -0
- fastscipy-0.1.0a1/python/fastscipy/_ndimage_correlate.py +293 -0
- fastscipy-0.1.0a1/python/fastscipy/_ndimage_generic.py +72 -0
- fastscipy-0.1.0a1/python/fastscipy/_ndimage_interp.py +172 -0
- fastscipy-0.1.0a1/python/fastscipy/_ndimage_label.py +180 -0
- fastscipy-0.1.0a1/python/fastscipy/_ndimage_morph.py +222 -0
- fastscipy-0.1.0a1/python/fastscipy/_ndimage_rank.py +171 -0
- fastscipy-0.1.0a1/python/fastscipy/_ndimage_seam.py +59 -0
- fastscipy-0.1.0a1/python/fastscipy/_optimize.py +193 -0
- fastscipy-0.1.0a1/python/fastscipy/_patch.py +126 -0
- fastscipy-0.1.0a1/python/fastscipy/_signal.py +109 -0
- fastscipy-0.1.0a1/python/fastscipy/_signal_algo.py +169 -0
- fastscipy-0.1.0a1/python/fastscipy/_signal_small.py +596 -0
- fastscipy-0.1.0a1/python/fastscipy/_signal_threads.py +169 -0
- fastscipy-0.1.0a1/python/fastscipy/_sparse.py +387 -0
- fastscipy-0.1.0a1/python/fastscipy/_sparse_linalg.py +82 -0
- fastscipy-0.1.0a1/python/fastscipy/_spatial.py +224 -0
- fastscipy-0.1.0a1/python/fastscipy/_special.py +145 -0
- fastscipy-0.1.0a1/python/fastscipy/_stats.py +37 -0
- fastscipy-0.1.0a1/python/fastscipy/_stats_algos.py +153 -0
- fastscipy-0.1.0a1/python/fastscipy/_stats_dist.py +502 -0
- fastscipy-0.1.0a1/python/fastscipy/_stats_loop.py +529 -0
- fastscipy-0.1.0a1/python/fastscipy/_stats_rank.py +52 -0
- fastscipy-0.1.0a1/python/fastscipy/_threads.py +75 -0
- fastscipy-0.1.0a1/python/fastscipy/pytest_plugin.py +38 -0
- fastscipy-0.1.0a1/python/fastscipy/testing.py +69 -0
- fastscipy-0.1.0a1/src/csgraph/components.rs +130 -0
- fastscipy-0.1.0a1/src/csgraph/mod.rs +93 -0
- fastscipy-0.1.0a1/src/csgraph/paths.rs +366 -0
- fastscipy-0.1.0a1/src/interp/bspline.rs +91 -0
- fastscipy-0.1.0a1/src/interp/mod.rs +43 -0
- fastscipy-0.1.0a1/src/interp/pchip.rs +151 -0
- fastscipy-0.1.0a1/src/interp/simplex.rs +202 -0
- fastscipy-0.1.0a1/src/lib.rs +46 -0
- fastscipy-0.1.0a1/src/linalg/mod.rs +454 -0
- fastscipy-0.1.0a1/src/ndimage/binmorph.rs +410 -0
- fastscipy-0.1.0a1/src/ndimage/common.rs +134 -0
- fastscipy-0.1.0a1/src/ndimage/correlate/cast.rs +494 -0
- fastscipy-0.1.0a1/src/ndimage/correlate/ext.rs +234 -0
- fastscipy-0.1.0a1/src/ndimage/correlate/kern.rs +758 -0
- fastscipy-0.1.0a1/src/ndimage/correlate/line.rs +722 -0
- fastscipy-0.1.0a1/src/ndimage/correlate/nd.rs +335 -0
- fastscipy-0.1.0a1/src/ndimage/correlate/simd.rs +245 -0
- fastscipy-0.1.0a1/src/ndimage/correlate.rs +33 -0
- fastscipy-0.1.0a1/src/ndimage/edt.rs +310 -0
- fastscipy-0.1.0a1/src/ndimage/fill.rs +367 -0
- fastscipy-0.1.0a1/src/ndimage/genfilt.rs +204 -0
- fastscipy-0.1.0a1/src/ndimage/interp/band.rs +357 -0
- fastscipy-0.1.0a1/src/ndimage/interp/geom.rs +836 -0
- fastscipy-0.1.0a1/src/ndimage/interp/spline.rs +432 -0
- fastscipy-0.1.0a1/src/ndimage/interp/support.rs +519 -0
- fastscipy-0.1.0a1/src/ndimage/interp/zoom.rs +495 -0
- fastscipy-0.1.0a1/src/ndimage/interp.rs +346 -0
- fastscipy-0.1.0a1/src/ndimage/label.rs +607 -0
- fastscipy-0.1.0a1/src/ndimage/measure.rs +392 -0
- fastscipy-0.1.0a1/src/ndimage/mod.rs +34 -0
- fastscipy-0.1.0a1/src/ndimage/objects.rs +179 -0
- fastscipy-0.1.0a1/src/ndimage/rank/boundary.rs +46 -0
- fastscipy-0.1.0a1/src/ndimage/rank/elem.rs +212 -0
- fastscipy-0.1.0a1/src/ndimage/rank/engine.rs +755 -0
- fastscipy-0.1.0a1/src/ndimage/rank/gen_networks.py +376 -0
- fastscipy-0.1.0a1/src/ndimage/rank/minmax1d.rs +625 -0
- fastscipy-0.1.0a1/src/ndimage/rank/nets.rs +33024 -0
- fastscipy-0.1.0a1/src/ndimage/rank/network.rs +265 -0
- fastscipy-0.1.0a1/src/ndimage/rank/par.rs +140 -0
- fastscipy-0.1.0a1/src/ndimage/rank/simd.rs +201 -0
- fastscipy-0.1.0a1/src/ndimage/rank.rs +699 -0
- fastscipy-0.1.0a1/src/ndimage/watershed.rs +198 -0
- fastscipy-0.1.0a1/src/pool.rs +89 -0
- fastscipy-0.1.0a1/src/signal/correlate.rs +226 -0
- fastscipy-0.1.0a1/src/signal/dlsim.rs +131 -0
- fastscipy-0.1.0a1/src/signal/mod.rs +16 -0
- fastscipy-0.1.0a1/src/signal/peaks.rs +275 -0
- fastscipy-0.1.0a1/src/sparse/mod.rs +488 -0
- fastscipy-0.1.0a1/src/stats/mod.rs +9 -0
- fastscipy-0.1.0a1/src/stats/rank.rs +191 -0
- fastscipy-0.1.0a1/tests/conftest.py +13 -0
- fastscipy-0.1.0a1/tests/test_cluster.py +192 -0
- fastscipy-0.1.0a1/tests/test_core.py +270 -0
- fastscipy-0.1.0a1/tests/test_csgraph.py +308 -0
- fastscipy-0.1.0a1/tests/test_integrate.py +594 -0
- fastscipy-0.1.0a1/tests/test_interpolate.py +483 -0
- fastscipy-0.1.0a1/tests/test_linalg.py +433 -0
- fastscipy-0.1.0a1/tests/test_ndimage.py +567 -0
- fastscipy-0.1.0a1/tests/test_optimize.py +281 -0
- fastscipy-0.1.0a1/tests/test_signal.py +927 -0
- fastscipy-0.1.0a1/tests/test_sparse.py +447 -0
- fastscipy-0.1.0a1/tests/test_sparse_linalg.py +257 -0
- fastscipy-0.1.0a1/tests/test_spatial.py +270 -0
- fastscipy-0.1.0a1/tests/test_special.py +276 -0
- fastscipy-0.1.0a1/tests/test_stats.py +466 -0
- fastscipy-0.1.0a1/tests/test_testing.py +43 -0
- fastscipy-0.1.0a1/tools/check_release.py +113 -0
- fastscipy-0.1.0a1/tools/coverage_inventory.py +101 -0
- fastscipy-0.1.0a1/tools/scipy_suite.py +61 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: A result that differs from SciPy, a crash, or a slowdown
|
|
4
|
+
labels: bug
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**What happened**
|
|
8
|
+
|
|
9
|
+
<!-- A minimal script. If a result differs, show it with and without fastscipy:
|
|
10
|
+
|
|
11
|
+
import numpy as np, scipy.ndimage, fastscipy
|
|
12
|
+
fastscipy.patch()
|
|
13
|
+
x = ...
|
|
14
|
+
with fastscipy.disabled():
|
|
15
|
+
expected = scipy.ndimage.gaussian_filter(x, 2)
|
|
16
|
+
got = scipy.ndimage.gaussian_filter(x, 2)
|
|
17
|
+
print(np.array_equal(expected, got))
|
|
18
|
+
-->
|
|
19
|
+
|
|
20
|
+
**Environment**
|
|
21
|
+
|
|
22
|
+
<!-- Output of:
|
|
23
|
+
python -c "import fastscipy, scipy, numpy, platform, sys; print(fastscipy.__version__, scipy.__version__, numpy.__version__, platform.platform(), sys.version); print(fastscipy.patch())"
|
|
24
|
+
-->
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
env:
|
|
16
|
+
CARGO_TERM_COLOR: always
|
|
17
|
+
SCIPY_VERSION: "1.18.1"
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
lint:
|
|
21
|
+
name: Lint
|
|
22
|
+
runs-on: ubuntu-24.04
|
|
23
|
+
timeout-minutes: 15
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v5
|
|
26
|
+
- uses: actions/setup-python@v6
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.13"
|
|
29
|
+
- uses: dtolnay/rust-toolchain@1.97.1
|
|
30
|
+
with:
|
|
31
|
+
components: clippy, rustfmt
|
|
32
|
+
- uses: Swatinem/rust-cache@v2
|
|
33
|
+
- run: pip install ruff
|
|
34
|
+
- run: ruff check python tests bench tools examples
|
|
35
|
+
- run: ruff format --check python tests bench tools examples
|
|
36
|
+
- run: cargo fmt --check
|
|
37
|
+
- run: cargo clippy --profile dev-release --all-targets -- -D warnings
|
|
38
|
+
|
|
39
|
+
test:
|
|
40
|
+
name: Tests (macOS arm64, Python ${{ matrix.python }})
|
|
41
|
+
runs-on: macos-15
|
|
42
|
+
timeout-minutes: 30
|
|
43
|
+
strategy:
|
|
44
|
+
fail-fast: false
|
|
45
|
+
matrix:
|
|
46
|
+
python: ["3.12", "3.13", "3.14"]
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v5
|
|
49
|
+
- uses: actions/setup-python@v6
|
|
50
|
+
with:
|
|
51
|
+
python-version: ${{ matrix.python }}
|
|
52
|
+
- uses: dtolnay/rust-toolchain@1.97.1
|
|
53
|
+
- uses: Swatinem/rust-cache@v2
|
|
54
|
+
- name: Build
|
|
55
|
+
run: |
|
|
56
|
+
python -m venv .venv
|
|
57
|
+
source .venv/bin/activate
|
|
58
|
+
pip install maturin "scipy==$SCIPY_VERSION" pytest pytest-xdist hypothesis
|
|
59
|
+
maturin develop --profile dev-release
|
|
60
|
+
- name: Identity tests
|
|
61
|
+
run: .venv/bin/python -m pytest tests -n auto -q
|
|
62
|
+
|
|
63
|
+
scipy-suite:
|
|
64
|
+
name: SciPy's test suite, with and without fastscipy
|
|
65
|
+
runs-on: macos-15
|
|
66
|
+
timeout-minutes: 60
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v5
|
|
69
|
+
- uses: actions/setup-python@v6
|
|
70
|
+
with:
|
|
71
|
+
python-version: "3.13"
|
|
72
|
+
- uses: dtolnay/rust-toolchain@1.97.1
|
|
73
|
+
- uses: Swatinem/rust-cache@v2
|
|
74
|
+
- name: Build
|
|
75
|
+
run: |
|
|
76
|
+
python -m venv .venv
|
|
77
|
+
source .venv/bin/activate
|
|
78
|
+
pip install maturin "scipy==$SCIPY_VERSION" pytest pytest-xdist hypothesis pooch
|
|
79
|
+
maturin develop --profile dev-release
|
|
80
|
+
- name: Compare every test's outcome
|
|
81
|
+
run: .venv/bin/python tools/scipy_suite.py --pyargs scipy -n auto
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Linux is not supported yet: SciPy's Linux wheels are built with a different
|
|
2
|
+
# compiler and BLAS, so some fast paths may not reproduce their last bit.
|
|
3
|
+
# This workflow runs the identity tests there anyway to find out which.
|
|
4
|
+
name: Linux (experimental)
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
env:
|
|
15
|
+
CARGO_TERM_COLOR: always
|
|
16
|
+
FASTSCIPY_ANY_PLATFORM: "1"
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
test:
|
|
20
|
+
name: Identity tests (${{ matrix.os }})
|
|
21
|
+
runs-on: ${{ matrix.os }}
|
|
22
|
+
continue-on-error: true
|
|
23
|
+
timeout-minutes: 60 # the x86-64 build alone takes over 30 minutes on hosted runners
|
|
24
|
+
strategy:
|
|
25
|
+
fail-fast: false
|
|
26
|
+
matrix:
|
|
27
|
+
os: [ubuntu-24.04, ubuntu-24.04-arm]
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v5
|
|
30
|
+
- uses: actions/setup-python@v6
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.13"
|
|
33
|
+
- uses: dtolnay/rust-toolchain@1.97.1
|
|
34
|
+
- uses: Swatinem/rust-cache@v2
|
|
35
|
+
- name: Build
|
|
36
|
+
run: |
|
|
37
|
+
python -m venv .venv
|
|
38
|
+
source .venv/bin/activate
|
|
39
|
+
pip install maturin "scipy==1.18.1" pytest pytest-xdist hypothesis
|
|
40
|
+
maturin develop --profile dev-release
|
|
41
|
+
- name: Identity tests
|
|
42
|
+
run: .venv/bin/python -m pytest tests -n auto -q -rf --tb=no
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
publish:
|
|
9
|
+
description: "Destination (none only builds and verifies artifacts)"
|
|
10
|
+
type: choice
|
|
11
|
+
options: [none, testpypi, pypi]
|
|
12
|
+
default: none
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: release-${{ github.ref }}
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
21
|
+
env:
|
|
22
|
+
CARGO_BUILD_JOBS: "2"
|
|
23
|
+
MACOSX_DEPLOYMENT_TARGET: "14.0"
|
|
24
|
+
FASTSCIPY_NUM_THREADS: "2"
|
|
25
|
+
OPENBLAS_NUM_THREADS: "1"
|
|
26
|
+
OMP_NUM_THREADS: "1"
|
|
27
|
+
VECLIB_MAXIMUM_THREADS: "1"
|
|
28
|
+
RUSTFLAGS: ""
|
|
29
|
+
RELEASE_TARGET: ${{ inputs.publish || 'pypi' }}
|
|
30
|
+
|
|
31
|
+
jobs:
|
|
32
|
+
wheels:
|
|
33
|
+
name: Wheel / Python ${{ matrix.python }}
|
|
34
|
+
runs-on: macos-15
|
|
35
|
+
timeout-minutes: 35
|
|
36
|
+
strategy:
|
|
37
|
+
fail-fast: false
|
|
38
|
+
max-parallel: 2
|
|
39
|
+
matrix:
|
|
40
|
+
python: ["3.12", "3.13", "3.14"]
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v5
|
|
43
|
+
- uses: actions/setup-python@v6
|
|
44
|
+
with:
|
|
45
|
+
python-version: ${{ matrix.python }}
|
|
46
|
+
- uses: dtolnay/rust-toolchain@1.97.1
|
|
47
|
+
- uses: Swatinem/rust-cache@v2
|
|
48
|
+
- name: Install build tools
|
|
49
|
+
run: python -m pip install "maturin>=1.9,<2" twine pytest hypothesis
|
|
50
|
+
- name: Check versions and architecture
|
|
51
|
+
run: |
|
|
52
|
+
python tools/check_release.py
|
|
53
|
+
python -c "import platform; assert platform.machine() == 'arm64'"
|
|
54
|
+
- name: Build release wheel from source distribution
|
|
55
|
+
run: maturin build --release --locked --sdist --out dist --interpreter python
|
|
56
|
+
- name: Check package contents and PyPI metadata
|
|
57
|
+
run: |
|
|
58
|
+
python tools/check_release.py --dist dist
|
|
59
|
+
python -m twine check --strict dist/*
|
|
60
|
+
- name: Install the wheel
|
|
61
|
+
run: |
|
|
62
|
+
python -m pip install --only-binary=:all: dist/*.whl
|
|
63
|
+
- name: Verify installed wheel
|
|
64
|
+
run: python -I tools/check_release.py --installed
|
|
65
|
+
- name: Identity suite against installed wheel
|
|
66
|
+
run: python -m pytest tests -q --tb=short
|
|
67
|
+
- name: Upstream comparison
|
|
68
|
+
if: matrix.python == '3.13'
|
|
69
|
+
run: |
|
|
70
|
+
python -m pip install pytest-xdist pooch
|
|
71
|
+
python tools/scipy_suite.py --pyargs scipy -n 2
|
|
72
|
+
- name: Keep one source distribution
|
|
73
|
+
if: matrix.python != '3.13'
|
|
74
|
+
run: rm dist/*.tar.gz
|
|
75
|
+
- uses: actions/upload-artifact@v4
|
|
76
|
+
with:
|
|
77
|
+
name: release-${{ matrix.python }}
|
|
78
|
+
path: dist/*
|
|
79
|
+
if-no-files-found: error
|
|
80
|
+
retention-days: 14
|
|
81
|
+
|
|
82
|
+
testpypi:
|
|
83
|
+
needs: wheels
|
|
84
|
+
if: github.event_name == 'workflow_dispatch' && inputs.publish == 'testpypi'
|
|
85
|
+
runs-on: ubuntu-24.04
|
|
86
|
+
environment: testpypi
|
|
87
|
+
permissions:
|
|
88
|
+
id-token: write
|
|
89
|
+
steps:
|
|
90
|
+
- uses: actions/download-artifact@v4
|
|
91
|
+
with:
|
|
92
|
+
pattern: release-*
|
|
93
|
+
merge-multiple: true
|
|
94
|
+
path: dist
|
|
95
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
96
|
+
with:
|
|
97
|
+
repository-url: https://test.pypi.org/legacy/
|
|
98
|
+
|
|
99
|
+
pypi:
|
|
100
|
+
needs: wheels
|
|
101
|
+
if: startsWith(github.ref, 'refs/tags/v') && (github.event_name == 'push' || inputs.publish == 'pypi')
|
|
102
|
+
runs-on: ubuntu-24.04
|
|
103
|
+
environment: pypi
|
|
104
|
+
permissions:
|
|
105
|
+
id-token: write
|
|
106
|
+
steps:
|
|
107
|
+
- uses: actions/download-artifact@v4
|
|
108
|
+
with:
|
|
109
|
+
pattern: release-*
|
|
110
|
+
merge-multiple: true
|
|
111
|
+
path: dist
|
|
112
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Contributions are welcome: new fast paths, ports to other platforms, bug
|
|
4
|
+
reports with a reproducer, and benchmark results from other machines.
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
You need Rust (stable) and Python 3.12 to 3.14.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
python -m venv .venv && source .venv/bin/activate
|
|
12
|
+
pip install maturin "scipy==1.18.1" pytest pytest-xdist hypothesis ruff
|
|
13
|
+
maturin develop --profile dev-release # rebuild after every Rust change
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Checks
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
pytest tests -n auto # identity tests
|
|
20
|
+
python tools/scipy_suite.py --pyargs scipy.ndimage -n auto # SciPy's suite, with vs without
|
|
21
|
+
python bench/run.py ndimage --check # benchmarks
|
|
22
|
+
ruff check python tests bench tools examples && ruff format --check python tests bench tools examples
|
|
23
|
+
cargo fmt --check && cargo clippy --profile dev-release --all-targets -- -D warnings
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
CI runs all of these on macOS arm64. A separate workflow runs the identity
|
|
27
|
+
tests on Linux to track that port.
|
|
28
|
+
|
|
29
|
+
## Adding a fast path
|
|
30
|
+
|
|
31
|
+
Each SciPy area is one component, `python/fastscipy/_<area>.py`, with
|
|
32
|
+
Rust kernels in `src/<area>/` exposed as `fastscipy._native.<area>`.
|
|
33
|
+
A component defines:
|
|
34
|
+
|
|
35
|
+
- `patch()`, which starts with `_patch.require_validated("1.18.")` and
|
|
36
|
+
installs fast paths with `_patch.wrap`, `_patch.replace` and
|
|
37
|
+
`_patch.rebind` (never by assigning to SciPy directly, or `unpatch()`
|
|
38
|
+
cannot restore it);
|
|
39
|
+
- `smoke()`, a few small calls that reach every fast path, used by the fork
|
|
40
|
+
test.
|
|
41
|
+
|
|
42
|
+
A fast path takes the same arguments as the function it replaces, and either
|
|
43
|
+
returns SciPy's exact result or `NotImplemented` to hand the call to SciPy.
|
|
44
|
+
The rules that keep results identical:
|
|
45
|
+
|
|
46
|
+
1. **Decline anything you have not matched.** Check dtype, layout, options
|
|
47
|
+
and sizes up front, and leave every warning and error to SciPy. Never
|
|
48
|
+
write into a caller's `out=` array and then decline.
|
|
49
|
+
2. **Reproduce SciPy's arithmetic, not just its algorithm.** Keep the
|
|
50
|
+
summation order, and use `mul_add` where SciPy's compiled code fuses a
|
|
51
|
+
multiply and add (see [docs/design.md](docs/design.md)).
|
|
52
|
+
3. **Parallel work goes through the shared pools**:
|
|
53
|
+
`crate::pool::pool().install(...)` in Rust, inside `py.detach(...)`, and
|
|
54
|
+
`fastscipy._threads.parallel_map` in Python. Never create another pool.
|
|
55
|
+
Only go parallel above a measured size.
|
|
56
|
+
4. **Test against SciPy, not against expected values.** Add randomized
|
|
57
|
+
cases to `tests/test_<area>.py` with `fastscipy.testing.check`, which
|
|
58
|
+
compares bytes and asserts the fast path ran, on 1 and several threads.
|
|
59
|
+
Include declined cases and edge cases (empty, NaN, inf, ties, strided).
|
|
60
|
+
5. **Show it is faster.** Add cases to `bench/bench_<area>.py`, and make
|
|
61
|
+
sure `bench/run.py <area> --check` passes.
|
|
62
|
+
|
|
63
|
+
Before opening a pull request, run SciPy's suite for the area with
|
|
64
|
+
`tools/scipy_suite.py`; no test may change outcome.
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
By contributing you agree that your contributions are licensed under the
|
|
69
|
+
BSD-3-Clause license of this project.
|
|
70
|
+
|
|
71
|
+
## Releases
|
|
72
|
+
|
|
73
|
+
The `Release` workflow builds macOS 14+ arm64 wheels for Python 3.12–3.14,
|
|
74
|
+
installs the wheels, and runs the project checks plus a paired upstream SciPy
|
|
75
|
+
comparison. Builds use two Cargo jobs and bounded numerical thread budgets.
|
|
76
|
+
|
|
77
|
+
To rehearse, run the workflow manually with `publish: none`. Download the three
|
|
78
|
+
wheel artifacts and source archive from that run. `publish: testpypi` exercises
|
|
79
|
+
an upload to TestPyPI. Publishing to PyPI requires a matching `v<version>` tag;
|
|
80
|
+
version declarations in Python, Cargo and the lockfile must agree.
|
|
81
|
+
|
|
82
|
+
Before the first upload, sign into PyPI and configure a pending Trusted Publisher:
|
|
83
|
+
|
|
84
|
+
| Field | Value |
|
|
85
|
+
|---|---|
|
|
86
|
+
| Project | `fastscipy` |
|
|
87
|
+
| Owner | `michael-L-i` |
|
|
88
|
+
| Repository | `fastscipy` |
|
|
89
|
+
| Workflow | `release.yml` |
|
|
90
|
+
| Environment | `pypi` |
|
|
91
|
+
|
|
92
|
+
Use a separate `testpypi` environment and publisher on TestPyPI for rehearsals.
|
|
93
|
+
No API token is needed. The workflow publishes only after the wheel checks pass.
|
|
94
|
+
A pending publisher does not reserve the package name until the first upload.
|
|
95
|
+
|
|
96
|
+
Update the README's installation instructions in the release commit before
|
|
97
|
+
creating and pushing the version tag: PyPI renders the README from that archive.
|
|
98
|
+
Push the tag only when ready to publish.
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "autocfg"
|
|
7
|
+
version = "1.5.1"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
|
10
|
+
|
|
11
|
+
[[package]]
|
|
12
|
+
name = "crossbeam-deque"
|
|
13
|
+
version = "0.8.8"
|
|
14
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
+
checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a"
|
|
16
|
+
dependencies = [
|
|
17
|
+
"crossbeam-epoch",
|
|
18
|
+
"crossbeam-utils",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[[package]]
|
|
22
|
+
name = "crossbeam-epoch"
|
|
23
|
+
version = "0.9.21"
|
|
24
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
25
|
+
checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d"
|
|
26
|
+
dependencies = [
|
|
27
|
+
"crossbeam-utils",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[[package]]
|
|
31
|
+
name = "crossbeam-utils"
|
|
32
|
+
version = "0.8.23"
|
|
33
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
34
|
+
checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
|
|
35
|
+
|
|
36
|
+
[[package]]
|
|
37
|
+
name = "either"
|
|
38
|
+
version = "1.19.0"
|
|
39
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
40
|
+
checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
|
|
41
|
+
|
|
42
|
+
[[package]]
|
|
43
|
+
name = "fastscipy"
|
|
44
|
+
version = "0.1.0-alpha.1"
|
|
45
|
+
dependencies = [
|
|
46
|
+
"numpy",
|
|
47
|
+
"pyo3",
|
|
48
|
+
"rayon",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[[package]]
|
|
52
|
+
name = "heck"
|
|
53
|
+
version = "0.5.0"
|
|
54
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
55
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
56
|
+
|
|
57
|
+
[[package]]
|
|
58
|
+
name = "libc"
|
|
59
|
+
version = "0.2.190"
|
|
60
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
61
|
+
checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
|
|
62
|
+
|
|
63
|
+
[[package]]
|
|
64
|
+
name = "matrixmultiply"
|
|
65
|
+
version = "0.3.11"
|
|
66
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
67
|
+
checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7"
|
|
68
|
+
dependencies = [
|
|
69
|
+
"autocfg",
|
|
70
|
+
"rawpointer",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[[package]]
|
|
74
|
+
name = "ndarray"
|
|
75
|
+
version = "0.17.2"
|
|
76
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
77
|
+
checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d"
|
|
78
|
+
dependencies = [
|
|
79
|
+
"matrixmultiply",
|
|
80
|
+
"num-complex",
|
|
81
|
+
"num-integer",
|
|
82
|
+
"num-traits",
|
|
83
|
+
"portable-atomic",
|
|
84
|
+
"portable-atomic-util",
|
|
85
|
+
"rawpointer",
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
[[package]]
|
|
89
|
+
name = "num-complex"
|
|
90
|
+
version = "0.4.6"
|
|
91
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
92
|
+
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
|
93
|
+
dependencies = [
|
|
94
|
+
"num-traits",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
[[package]]
|
|
98
|
+
name = "num-integer"
|
|
99
|
+
version = "0.1.47"
|
|
100
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
101
|
+
checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b"
|
|
102
|
+
dependencies = [
|
|
103
|
+
"num-traits",
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
[[package]]
|
|
107
|
+
name = "num-traits"
|
|
108
|
+
version = "0.2.19"
|
|
109
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
110
|
+
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
|
111
|
+
dependencies = [
|
|
112
|
+
"autocfg",
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
[[package]]
|
|
116
|
+
name = "numpy"
|
|
117
|
+
version = "0.30.0"
|
|
118
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
119
|
+
checksum = "aa0b9111761885449e894981fa8051dcf69e0bd114aecbd4bcdd830b6be4ed92"
|
|
120
|
+
dependencies = [
|
|
121
|
+
"libc",
|
|
122
|
+
"ndarray",
|
|
123
|
+
"num-complex",
|
|
124
|
+
"num-integer",
|
|
125
|
+
"num-traits",
|
|
126
|
+
"pyo3",
|
|
127
|
+
"pyo3-build-config",
|
|
128
|
+
"rustc-hash",
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
[[package]]
|
|
132
|
+
name = "once_cell"
|
|
133
|
+
version = "1.21.4"
|
|
134
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
135
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
136
|
+
|
|
137
|
+
[[package]]
|
|
138
|
+
name = "portable-atomic"
|
|
139
|
+
version = "1.15.0"
|
|
140
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
141
|
+
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
|
142
|
+
|
|
143
|
+
[[package]]
|
|
144
|
+
name = "portable-atomic-util"
|
|
145
|
+
version = "0.2.8"
|
|
146
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
147
|
+
checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715"
|
|
148
|
+
dependencies = [
|
|
149
|
+
"portable-atomic",
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
[[package]]
|
|
153
|
+
name = "proc-macro2"
|
|
154
|
+
version = "1.0.107"
|
|
155
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
156
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
157
|
+
dependencies = [
|
|
158
|
+
"unicode-ident",
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
[[package]]
|
|
162
|
+
name = "pyo3"
|
|
163
|
+
version = "0.30.1"
|
|
164
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
165
|
+
checksum = "229ca13b8a15bb0d1487b81ab975bfcd97513416499a8312011b6036e42e0de4"
|
|
166
|
+
dependencies = [
|
|
167
|
+
"libc",
|
|
168
|
+
"once_cell",
|
|
169
|
+
"portable-atomic",
|
|
170
|
+
"pyo3-build-config",
|
|
171
|
+
"pyo3-ffi",
|
|
172
|
+
"pyo3-macros",
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
[[package]]
|
|
176
|
+
name = "pyo3-build-config"
|
|
177
|
+
version = "0.30.1"
|
|
178
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
179
|
+
checksum = "70130e2b6dd1ee589a8788026a429561ca5c40fa7a2fa7914c2282eddae24700"
|
|
180
|
+
dependencies = [
|
|
181
|
+
"target-lexicon",
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
[[package]]
|
|
185
|
+
name = "pyo3-ffi"
|
|
186
|
+
version = "0.30.1"
|
|
187
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
188
|
+
checksum = "5e7ff73c555c286d212d4ce7e5fbda845a973c4f61bd5f160f5f2c3c2a04d1c4"
|
|
189
|
+
dependencies = [
|
|
190
|
+
"libc",
|
|
191
|
+
"pyo3-build-config",
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
[[package]]
|
|
195
|
+
name = "pyo3-macros"
|
|
196
|
+
version = "0.30.1"
|
|
197
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
198
|
+
checksum = "c46d2e5862c7bb8207e3b639f713dda3c499933444784154c11d013c5a691b60"
|
|
199
|
+
dependencies = [
|
|
200
|
+
"proc-macro2",
|
|
201
|
+
"pyo3-macros-backend",
|
|
202
|
+
"quote",
|
|
203
|
+
"syn",
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
[[package]]
|
|
207
|
+
name = "pyo3-macros-backend"
|
|
208
|
+
version = "0.30.1"
|
|
209
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
210
|
+
checksum = "38b89f066f2ae72a2aef52d1537ca2fcd104440ebfadee06e97aa90738a25b9b"
|
|
211
|
+
dependencies = [
|
|
212
|
+
"heck",
|
|
213
|
+
"proc-macro2",
|
|
214
|
+
"quote",
|
|
215
|
+
"syn",
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
[[package]]
|
|
219
|
+
name = "quote"
|
|
220
|
+
version = "1.0.47"
|
|
221
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
222
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
223
|
+
dependencies = [
|
|
224
|
+
"proc-macro2",
|
|
225
|
+
]
|
|
226
|
+
|
|
227
|
+
[[package]]
|
|
228
|
+
name = "rawpointer"
|
|
229
|
+
version = "0.2.1"
|
|
230
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
231
|
+
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
|
232
|
+
|
|
233
|
+
[[package]]
|
|
234
|
+
name = "rayon"
|
|
235
|
+
version = "1.12.0"
|
|
236
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
237
|
+
checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
|
|
238
|
+
dependencies = [
|
|
239
|
+
"either",
|
|
240
|
+
"rayon-core",
|
|
241
|
+
]
|
|
242
|
+
|
|
243
|
+
[[package]]
|
|
244
|
+
name = "rayon-core"
|
|
245
|
+
version = "1.13.0"
|
|
246
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
247
|
+
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
|
248
|
+
dependencies = [
|
|
249
|
+
"crossbeam-deque",
|
|
250
|
+
"crossbeam-utils",
|
|
251
|
+
]
|
|
252
|
+
|
|
253
|
+
[[package]]
|
|
254
|
+
name = "rustc-hash"
|
|
255
|
+
version = "2.1.3"
|
|
256
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
257
|
+
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
|
258
|
+
|
|
259
|
+
[[package]]
|
|
260
|
+
name = "syn"
|
|
261
|
+
version = "3.0.9"
|
|
262
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
263
|
+
checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
|
|
264
|
+
dependencies = [
|
|
265
|
+
"proc-macro2",
|
|
266
|
+
"quote",
|
|
267
|
+
"unicode-ident",
|
|
268
|
+
]
|
|
269
|
+
|
|
270
|
+
[[package]]
|
|
271
|
+
name = "target-lexicon"
|
|
272
|
+
version = "0.13.5"
|
|
273
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
274
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
275
|
+
|
|
276
|
+
[[package]]
|
|
277
|
+
name = "unicode-ident"
|
|
278
|
+
version = "1.0.27"
|
|
279
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
280
|
+
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "fastscipy"
|
|
3
|
+
version = "0.1.0-alpha.1"
|
|
4
|
+
edition = "2024"
|
|
5
|
+
license = "BSD-3-Clause"
|
|
6
|
+
description = "Rust kernels for fastscipy, a drop-in accelerator for SciPy"
|
|
7
|
+
repository = "https://github.com/michael-L-i/fastscipy"
|
|
8
|
+
publish = false
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
|
|
11
|
+
[lib]
|
|
12
|
+
name = "_native"
|
|
13
|
+
crate-type = ["cdylib"]
|
|
14
|
+
|
|
15
|
+
[dependencies]
|
|
16
|
+
numpy = "0.30.0"
|
|
17
|
+
pyo3 = { version = "0.30.1", features = ["extension-module"] }
|
|
18
|
+
rayon = "1.12.0"
|
|
19
|
+
|
|
20
|
+
[profile.release]
|
|
21
|
+
opt-level = 3
|
|
22
|
+
lto = "thin" # fat LTO with one codegen unit needs more than 6 GB to link
|
|
23
|
+
codegen-units = 8
|
|
24
|
+
panic = "abort"
|
|
25
|
+
strip = "symbols"
|
|
26
|
+
|
|
27
|
+
# Fast rebuilds while developing: `maturin develop --profile dev-release`.
|
|
28
|
+
[profile.dev-release]
|
|
29
|
+
inherits = "release"
|
|
30
|
+
lto = false
|
|
31
|
+
codegen-units = 16
|
|
32
|
+
incremental = true
|
|
33
|
+
strip = false
|