Skip to content

Commit f5d1642

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

File tree

5 files changed

+122
-5
lines changed

5 files changed

+122
-5
lines changed

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

src/array_api_stubs/_2021_12/creation_functions.py

+23
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,29 @@ def from_dlpack(x: object, /) -> array:
197197
"""
198198

199199

200+
def from_binsparse(arrays: dict[str, array], descriptor: dict, /) -> array:
201+
"""
202+
Returns a new array containing the data from another (array) object with a ``__binsparse__`` method.
203+
204+
Parameters
205+
----------
206+
arrays: dict[str, array]
207+
input constituent arrays.
208+
descriptor: dict
209+
The parsed binsparse descriptor of the array.
210+
211+
Returns
212+
-------
213+
out: array
214+
an array containing the data in `arrays` with a format specified by `descriptor`.
215+
216+
.. admonition:: Note
217+
:class: note
218+
219+
The returned array may be either a copy or a view. See :ref:`data-interchange` for details.
220+
"""
221+
222+
200223
def full(
201224
shape: Union[int, Tuple[int, ...]],
202225
fill_value: Union[int, float],

src/array_api_stubs/_draft/array_object.py

+34
Original file line numberDiff line numberDiff line change
@@ -1246,5 +1246,39 @@ 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:`extensions/sparse_interchange` for details.
1262+
1263+
.. versionadded:: 2025.12
1264+
"""
1265+
1266+
def __binsparse__(self) -> dict[str, array]:
1267+
"""
1268+
Returns a key-value store of the constituent arrays of a sparse array, as specified by the `binsparse specification <https://graphblas.org/binsparse-specification/>`_.
1269+
1270+
Parameters
1271+
----------
1272+
self: array
1273+
array instance.
1274+
1275+
Returns
1276+
-------
1277+
out: dict[str, array]
1278+
A ``dict`` equivalent to a parsed JSON binsparse descriptor of an array. See :ref:`extensions/sparse_interchange` for details.
1279+
1280+
.. versionadded:: 2025.12
1281+
"""
1282+
12491283

12501284
array = _array

0 commit comments

Comments
 (0)