Skip to content

Commit af8fd33

Browse files
authored
Merge branch 'main' into notebooks
2 parents 55a2da7 + 5cf299c commit af8fd33

File tree

11 files changed

+84
-42
lines changed

11 files changed

+84
-42
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@ jobs:
1111
strategy:
1212
matrix:
1313
os: ['ubuntu-latest']
14-
python: ['3.10', '3.11', '3.12']
14+
python: ['3.11', '3.12', '3.13']
1515
pip_opts: ['']
1616
numba_boundscheck: [0]
1717
include:
1818
- os: macos-latest
19-
python: '3.10'
19+
python: '3.11'
2020
- os: windows-latest
21-
python: '3.10'
21+
python: '3.11'
2222
- os: ubuntu-latest
23-
python: '3.10'
23+
python: '3.11'
2424
numba_boundscheck: 1
2525
- os: ubuntu-latest
26-
python: '3.10'
26+
python: '3.11'
2727
pip_opts: 'numpy<2'
2828
fail-fast: false
2929
runs-on: ${{ matrix.os }}

.pre-commit-config.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v5.0.0
3+
rev: v6.0.0
44
hooks:
55
- id: check-yaml
66
- id: end-of-file-fixer
77
- id: trailing-whitespace
88
- id: fix-byte-order-marker
99
- id: destroyed-symlinks
10-
- id: fix-encoding-pragma
11-
args: ["--remove"]
1210
- id: mixed-line-ending
1311
- id: name-tests-test
1412
args: ["--pytest-test-first"]
@@ -18,7 +16,7 @@ repos:
1816
exclude: ".ipynb"
1917

2018
- repo: https://github.com/astral-sh/ruff-pre-commit
21-
rev: v0.12.4
19+
rev: v0.14.1
2220
hooks:
2321
- id: ruff-check
2422
args: ["--fix"]

benchmarks/test_benchmark_coo.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,26 @@ def format_id(format):
1212
return f"{format=}"
1313

1414

15-
@pytest.mark.parametrize("format", ["coo", "gcxs"])
16-
def test_matmul(benchmark, sides, format, rng, max_size, ids=format_id):
15+
@pytest.fixture(params=["coo", "gcxs"], ids=format_id)
16+
def format_param(request):
17+
return request.param
18+
19+
20+
@pytest.fixture
21+
def matmul_args(sides, format_param, rng, max_size):
1722
m, n, p = sides
1823

1924
if m * n >= max_size or n * p >= max_size:
2025
pytest.skip()
2126

22-
x = sparse.random((m, n), density=DENSITY, format=format, random_state=rng)
23-
y = sparse.random((n, p), density=DENSITY, format=format, random_state=rng)
27+
x = sparse.random((m, n), density=DENSITY, format=format_param, random_state=rng)
28+
y = sparse.random((n, p), density=DENSITY, format=format_param, random_state=rng)
29+
30+
return x, y
31+
32+
33+
def test_matmul(benchmark, matmul_args):
34+
x, y = matmul_args
2435

2536
x @ y # Numba compilation
2637

benchmarks/test_elemwise.py

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import importlib
2-
import itertools
32
import operator
43
import os
54

@@ -28,41 +27,48 @@ def elemwise_args(request, rng, max_size):
2827
return s1_sps, s2_sps
2928

3029

31-
def get_elemwise_id(param):
32-
f, backend = param
33-
return f"{f=}-{backend=}"
30+
@pytest.fixture(params=[operator.add, operator.mul, operator.gt])
31+
def elemwise_function(request):
32+
return request.param
3433

3534

36-
@pytest.fixture(
37-
params=itertools.product([operator.add, operator.mul, operator.gt], ["SciPy", "Numba", "Finch"]),
38-
scope="function",
39-
ids=get_elemwise_id,
40-
)
41-
def backend(request):
42-
f, backend = request.param
43-
os.environ[sparse._ENV_VAR_NAME] = backend
35+
@pytest.fixture(params=["SciPy", "Numba", "Finch"])
36+
def backend_name(request):
37+
return request.param
38+
39+
40+
@pytest.fixture
41+
def backend_setup(backend_name):
42+
os.environ[sparse._ENV_VAR_NAME] = backend_name
4443
importlib.reload(sparse)
45-
yield f, sparse, backend
44+
yield sparse, backend_name
4645
del os.environ[sparse._ENV_VAR_NAME]
4746
importlib.reload(sparse)
4847

4948

50-
def test_elemwise(benchmark, backend, elemwise_args):
49+
@pytest.fixture
50+
def sparse_arrays(elemwise_args, backend_setup):
5151
s1_sps, s2_sps = elemwise_args
52-
f, sparse, backend = backend
52+
sparse, backend_name = backend_setup
5353

54-
if backend == "SciPy":
54+
if backend_name == "SciPy":
5555
s1 = s1_sps
5656
s2 = s2_sps
57-
elif backend == "Numba":
57+
elif backend_name == "Numba":
5858
s1 = sparse.asarray(s1_sps)
5959
s2 = sparse.asarray(s2_sps)
60-
elif backend == "Finch":
60+
elif backend_name == "Finch":
6161
s1 = sparse.asarray(s1_sps.asformat("csc"), format="csc")
6262
s2 = sparse.asarray(s2_sps.asformat("csc"), format="csc")
6363

64-
f(s1, s2)
64+
return s1, s2
65+
66+
67+
def test_elemwise(benchmark, elemwise_function, sparse_arrays):
68+
s1, s2 = sparse_arrays
69+
70+
elemwise_function(s1, s2)
6571

6672
@benchmark
6773
def bench():
68-
f(s1, s2)
74+
elemwise_function(s1, s2)

ci/environment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ dependencies:
66
- python
77
- pip
88
- pip:
9-
- finch-tensor>=0.2.12
9+
- finch-tensor>=0.2.13
1010
- finch-mlir>=0.0.2
1111
- pytest-codspeed
1212
- numpy

docs/migration-jl.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Migration to the Finch Julia backend
2+
To switch to the Finch Julia backend, set the environment variable `SPARSE_BACKEND="Finch"`, then continue using.
3+
4+
While this is largely compatible with the Array API, support for some functions may not be present, and API compatibility isn't strictly preserved with the default (Numba) backend.
5+
6+
However, the new backend has a large performance benefit over the default backend. Below, you will find a table of common invocations, with their equivalents in the Finch Julia backend. The most common change is a standard API for construction of arrays.
7+
8+
| Numba Backend<br>(`SPARSE_BACKEND="Numba"`) | Finch Julia Backend<br>(`SPARSE_BACKEND="Finch"`) | Notes |
9+
|---------------------------------------------|----------------------------------------------------|-------|
10+
| `sparse.COO.from_numpy(arr, fill_value=fv)`<br>`sparse.COO.from_scipy(arr)`<br>`sparse.COO(x)` | `sparse.asarray(x, format="coo", [fill_value=fv])` | Doesn't support pulling out individual arrays |
11+
| `sparse.GCXS.from_numpy(arr, fill_value=fv)`<br>`sparse.GCXS.from_scipy(arr)`<br>`sparse.GCXS(x)` | `sparse.asarray(x, format="csf", [fill_value=fv])` | Format might not be a 1:1 match |
12+
| `sparse.DOK.from_numpy(arr, fill_value=fv)`<br>`sparse.DOK.from_scipy(arr)`<br>`sparse.DOK(x)` | `sparse.asarray(x, format="dok", [fill_value=fv])` | Format might not be a 1:1 match |
13+
14+
Most things work as expected, with the following exceptions, which aren't defined yet for Finch:
15+
16+
* `sparse.broadcast_to`
17+
* `sparse.solve`
18+
* Statistical functions: `mean`, `std`, `var`
19+
* `sparse.isdtype`
20+
* `sparse.reshape`
21+
* Some elementwise functions
22+
* Manipulation functions: `concat`, `expand_dims`, `squeeze`, `flip`, `roll`, `stack`
23+
* `arg*` functions: `argmin`, `argmax`
24+
* Sorting functions: `sort`, `argsort`
25+
26+
IEEE-754 compliance is hard to maintain with sparse arrays in general. This is now even more true of the Julia backend, which trades off performance for IEEE-754 compatibility.

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ nav:
9494
- quickstart.md
9595
- construct.md
9696
- operations.md
97+
- migration-jl.md
9798
- API:
9899
- api.md
99100
- api/*

pixi.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ numba = ">=0.49"
1010
numpy = ">=1.17"
1111

1212
[dependencies]
13-
python = ">=3.10,<3.13"
13+
python = ">=3.11,<3.14"
1414

1515
[feature.extra.pypi-dependencies]
1616
dask = { version = ">=2024", extras = ["array"] }
@@ -55,7 +55,7 @@ juliaup = ">=1.17.10"
5555

5656
[feature.finch.pypi-dependencies]
5757
scipy = ">=1.13"
58-
finch-tensor = ">=0.2.12"
58+
finch-tensor = ">=0.2.13"
5959

6060
[feature.finch.activation.env]
6161
SPARSE_BACKEND = "Finch"

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description = "Sparse n-dimensional arrays for the PyData ecosystem"
99
readme = "README.md"
1010
dependencies = ["numpy>=1.17", "numba>=0.49"]
1111
maintainers = [{ name = "Hameer Abbasi", email = "hameerabbasi@yahoo.com" }]
12-
requires-python = ">=3.10"
12+
requires-python = ">=3.11"
1313
license = { file = "LICENSE" }
1414
keywords = ["sparse", "numpy", "scipy", "dask"]
1515
classifiers = [
@@ -54,7 +54,7 @@ tests = [
5454
tox = ["sparse[tests]", "tox"]
5555
notebooks = ["sparse[tests]", "nbmake", "matplotlib"]
5656
all = ["sparse[docs,tox,notebooks,mlir]", "matrepr"]
57-
finch = ["finch-tensor>=0.2.12"]
57+
finch = ["finch-tensor>=0.2.13"]
5858
mlir = ["finch-mlir>=0.0.2"]
5959

6060
[project.urls]

sparse/numba_backend/_coo/core.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -596,12 +596,12 @@ def nnz(self):
596596
--------
597597
>>> x = np.array([0, 0, 1, 0, 1, 2, 0, 1, 2, 3, 0, 0])
598598
>>> np.count_nonzero(x)
599-
6
599+
np.int64(6)
600600
>>> s = COO.from_numpy(x)
601601
>>> s.nnz
602602
6
603603
>>> np.count_nonzero(x) == s.nnz
604-
True
604+
np.True_
605605
"""
606606
return self.coords.shape[1]
607607

0 commit comments

Comments
 (0)