Skip to content

Commit 809a448

Browse files
committed
Add specification for the __binsparse__ protocol.
1 parent 772fb46 commit 809a448

File tree

6 files changed

+135
-5
lines changed

6 files changed

+135
-5
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,7 @@ tmp/
3535
*.egg
3636
dist/
3737
.DS_STORE
38+
39+
# pixi environments
40+
.pixi
41+
*.egg-info

spec/draft/design_topics/data_interchange.rst

+28-5
Original file line numberDiff line numberDiff line change
@@ -85,17 +85,40 @@ page gives a high-level specification for data exchange in Python using DLPack.
8585
below. They are not required to return an array object from ``from_dlpack``
8686
which conforms to this standard.
8787

88+
binsparse: Extending to sparse arrays
89+
-------------------------------------
90+
91+
Sparse arrays can be represented in-memory by a collection of 1-dimensional and 2-dimensional
92+
dense arrays, alongside some metadata on how to interpret these arrays. This allows us to re-use
93+
the DLPack protocol for the storage of the constituent arrays. The work of specifying the
94+
accompanying metadata has already been performed by the
95+
`binsparse specification <https://graphblas.org/binsparse-specification/>`_.
96+
97+
While initially intended to target file formats, binsparse has relatively few requirements from
98+
back-ends:
99+
100+
1. The ability to represent and parse JSON.
101+
2. To be able to represent/store a key-value store of 1-dimensional (and optionally 2-dimensional)
102+
arrays.
103+
104+
It is the only such specification for sparse representations to have these minimal requirements.
105+
We can satisfy both: The former with the ``json`` built-in Python module or a Python ``dict`` and
106+
the latter with the DLPack protocol.
107+
108+
.. note::
109+
See the `RFC to adopt binsparse <https://github.com/data-apis/array-api/issues/840>`_
110+
for discussion that preceded the adoption of the binsparse protocol.
111+
112+
See :ref:`sparse_interchange` for the Python specification of this protocol.
113+
114+
88115
Non-supported use cases
89116
-----------------------
90117

91118
Use of DLPack requires that the data can be represented by a strided, in-memory
92119
layout on a single device. This covers usage by a large range of, but not all,
93120
known and possible array libraries. Use cases that are not supported by DLPack
94-
include:
95-
96-
- Distributed arrays, i.e., the data residing on multiple nodes or devices,
97-
- Sparse arrays, i.e., sparse representations where a data value (typically
98-
zero) is implicit.
121+
include distributed arrays, i.e., the data residing on multiple nodes or devices.
99122

100123
There may be other reasons why it is not possible or desirable for an
101124
implementation to materialize the array as strided data in memory. In such

spec/draft/extensions/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ the array API standard. See :ref:`api-specification`.
3232

3333
fourier_transform_functions
3434
linear_algebra_functions
35+
sparse_interchange
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
.. _sparse_interchange:
2+
3+
Sparse interchange
4+
==================
5+
6+
Array API specification for sparse interchange functions.
7+
8+
Extension name and usage
9+
------------------------
10+
11+
If implemented, this extension must be retrievable via::
12+
13+
>>> if hasattr(x, '__dlpack__'):
14+
>>> # Use the extension
15+
16+
Objects in API
17+
--------------
18+
19+
A conforming implementation of this extension must provide and support the following
20+
functions/methods.
21+
22+
.. currentmodule:: array_api
23+
24+
..
25+
NOTE: please keep the functions and their inverse together
26+
27+
.. autosummary::
28+
:toctree: generated
29+
:template: method.rst
30+
31+
from_binsparse
32+
33+
34+
.. autosummary::
35+
:toctree: generated
36+
:template: property.rst
37+
38+
array.__binsparse__
39+
array.__binsparse_descriptor__

src/array_api_stubs/_draft/array_object.py

+36
Original file line numberDiff line numberDiff line change
@@ -1246,5 +1246,41 @@ def to_device(
12461246
Clarified behavior when a provided ``device`` object corresponds to the device on which an array instance resides.
12471247
"""
12481248

1249+
def __binsparse_descriptor__(self) -> dict:
1250+
"""
1251+
Returns a `dict` equivalent to a parsed `binsparse JSON descriptor <https://graphblas.org/binsparse-specification/>`_.
1252+
1253+
Parameters
1254+
----------
1255+
self: array
1256+
array instance.
1257+
1258+
Returns
1259+
-------
1260+
out: dict
1261+
A ``dict`` equivalent to a parsed JSON binsparse descriptor of an array. See :ref:`sparse_interchange` for details.
1262+
1263+
1264+
.. versionadded:: 2025.12
1265+
"""
1266+
1267+
def __binsparse__(self) -> dict[str, array]:
1268+
"""
1269+
Returns a key-value store of the constituent arrays of a sparse array, as specified by the `binsparse specification <https://graphblas.org/binsparse-specification/>`_.
1270+
1271+
Parameters
1272+
----------
1273+
self: array
1274+
array instance.
1275+
1276+
Returns
1277+
-------
1278+
out: dict[str, array]
1279+
A ``dict`` equivalent to a parsed JSON binsparse descriptor of an array. See :ref:`sparse_interchange` for details.
1280+
1281+
1282+
.. versionadded:: 2025.12
1283+
"""
1284+
12491285

12501286
array = _array

src/array_api_stubs/_draft/creation_functions.py

+27
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"empty_like",
66
"eye",
77
"from_dlpack",
8+
"from_binsparse",
89
"full",
910
"full_like",
1011
"linspace",
@@ -645,3 +646,29 @@ def zeros_like(
645646
out: array
646647
an array having the same shape as ``x`` and filled with zeros.
647648
"""
649+
650+
651+
def from_binsparse(arrays: dict[str, array], descriptor: dict, /) -> array:
652+
"""
653+
Returns a new array containing the data from another (array) object with a ``__binsparse__`` method.
654+
655+
Parameters
656+
----------
657+
arrays: dict[str, array]
658+
input constituent arrays.
659+
descriptor: dict
660+
The parsed binsparse descriptor of the array.
661+
662+
Returns
663+
-------
664+
out: array
665+
an array containing the data in `arrays` with a format specified by `descriptor`.
666+
667+
.. admonition:: Note
668+
:class: note
669+
670+
The returned array may be either a copy or a view. See :ref:`data-interchange` for details.
671+
672+
673+
.. versionadded:: 2025.12
674+
"""

0 commit comments

Comments
 (0)