Skip to content

Commit e996d22

Browse files
committed
Add more information to the README
1 parent 6c54b6b commit e996d22

File tree

2 files changed

+142
-30
lines changed

2 files changed

+142
-30
lines changed

README.md

Lines changed: 140 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
# Array API compatibility library
22

3-
This is a small wrapper around NumPy that is compatible with the [Array API
4-
standard](https://data-apis.org/array-api/latest/). See also [NEP 47](https://numpy.org/neps/nep-0047-array-api-standard.html).
3+
This is a small wrapper around NumPy and CuPy that is compatible with the
4+
[Array API standard](https://data-apis.org/array-api/latest/). See also [NEP
5+
47](https://numpy.org/neps/nep-0047-array-api-standard.html).
56

67
Unlike `numpy.array_api`, this is not a strict minimal implementation of the
78
Array API, but rather just an extension of the main NumPy namespace with
8-
changes needed to be compliant with the Array API. See
9-
https://numpy.org/doc/stable/reference/array_api.html for a full list of
9+
changes needed to be compliant with the Array API.
10+
11+
Library authors using the Array API may wish to test against numpy.array_api
12+
to ensure they are not using functionality outside of the standard, but prefer
13+
this implementation for the default when working with NumPy arrays.
14+
15+
See https://numpy.org/doc/stable/reference/array_api.html for a full list of
1016
changes. In particular, unlike `numpy.array_api`, this package does not use a
1117
separate Array object, but rather just uses `numpy.ndarray` directly.
1218

1319
Note that some of the functionality in this library is backwards incompatible
1420
with NumPy.
1521

16-
This library also supports CuPy in addition to NumPy.
22+
This library also supports CuPy in addition to NumPy. If you want support for
23+
other array libraries, please [open an
24+
issue](https://github.com/data-apis/array-api-compat/issues).
1725

1826
Library authors using the Array API may wish to test against `numpy.array_api`
1927
to ensure they are not using functionality outside of the standard, but prefer
@@ -44,3 +52,130 @@ with
4452
```py
4553
import array_api_compat.cupy as cp
4654
```
55+
56+
Each will include all the functions from the normal NumPy/CuPy namespace,
57+
except that functions that are part of the array API are wrapped so that they
58+
have the correct array API behavior. In each case, the array object
59+
60+
61+
## Helper Functions
62+
63+
In addition to the default NumPy/CuPy namespace and functions in the array API
64+
specification, there are several helper functions
65+
included that aren't part of the specification but which are useful for using
66+
the array API:
67+
68+
- `is_array_api_obj(x)`: Return `True` if `x` is an array API compatible array
69+
object.
70+
71+
- `get_namespace(*xs)`: Get the corresponding array API namespace for the
72+
arrays `xs`. If the arrays are NumPy or CuPy arrays, the returned namespace
73+
will be `array_api_compat.numpy` or `array_api_compat.cupy` so that it is
74+
array API compatible.
75+
76+
- `device(x)`: Equivalent to
77+
[`x.device`](https://data-apis.org/array-api/latest/API_specification/generated/signatures.array_object.array.device.html)
78+
in the array API specification. Included because `numpy.ndarray` does not
79+
include the `device` attribute and this library does not wrap or extend the
80+
array object. Note that for NumPy, `device` is always `"cpu"`.
81+
82+
- `to_device(x, device, /, *, stream=None)`: Equivalent to
83+
[`x.to_device`](https://data-apis.org/array-api/latest/API_specification/generated/signatures.array_object.array.to_device.html).
84+
Included because neither NumPy's nor CuPy's ndarray objects include this
85+
method. For NumPy, this function effectively does nothing since the only
86+
supported device is the CPU, but for CuPy, this method supports CuPy CUDA
87+
[Device](https://docs.cupy.dev/en/stable/reference/generated/cupy.cuda.Device.html)
88+
and
89+
[Stream](https://docs.cupy.dev/en/stable/reference/generated/cupy.cuda.Stream.html)
90+
objects.
91+
92+
## Known Differences from the Array API Specification
93+
94+
There are some known differences between this library and the array API
95+
specification:
96+
97+
- The array methods `__array_namespace__`, `device` (for NumPy), `to_device`,
98+
and `mT` are not defined. This reuses `np.ndarray` and `cp.ndarray` and we
99+
don't want to monkeypatch or wrap it. The helper functions `device()` and
100+
`to_device()` are provided to work around these missing methods (see above).
101+
`x.mT` can be replaced with `xp.linalg.matrix_transpose(x)`.
102+
`get_namespace(x)` should be used instead of `x.__array_namespace__`.
103+
104+
- NumPy value-based casting for scalars will be in effect unless explicitly
105+
disabled with the environment variable NPY_PROMOTION_STATE=weak or
106+
np._set_promotion_state('weak') (requires NumPy 1.24 or newer, see NEP 50
107+
and https://github.com/numpy/numpy/issues/22341)
108+
109+
- Functions which are not wrapped may not have the same type annotations
110+
as the spec.
111+
112+
- Functions which are not wrapped may not use positional-only arguments.
113+
114+
## Vendoring
115+
116+
This library supports vendoring as an installation method. To vendor the
117+
library, simply copy `array_api_compat` into the appropriate place in the
118+
library, like
119+
120+
```
121+
cp -R array_api_compat/ mylib/vendored/array_api_compat
122+
```
123+
124+
You may also rename it to something else if you like (nowhere in the code
125+
references the name "array_api_compat").
126+
127+
Alternatively, the library may be installed as dependency on PyPI.
128+
129+
## Implementation
130+
131+
As noted before, the goal of this library is to reuse the NumPy and CuPy array
132+
objects, rather than wrapping or extending them. This means that the functions
133+
need to accept and return `np.ndarray` for NumPy and `cp.ndarray` for CuPy.
134+
135+
Each namespace (`array_api_compat.numpy` and `array_api_compat.cupy`) is
136+
populated with the normal library namespace (like `from numpy import *`). Then
137+
specific functions are replaced with wrapped variants. Wrapped functions that
138+
have the same logic between NumPy and CuPy (which is most functions) are in
139+
`array_api_compat/common/`. These functions are defined like
140+
141+
```py
142+
# In array_api_compat/common/_aliases.py
143+
144+
def acos(x, /, xp):
145+
return xp.arccos(x)
146+
```
147+
148+
The `xp` argument refers to the original array namespace (either `numpy` or
149+
`cupy`). Then in the specific `array_api_compat/numpy` and
150+
`array_api_compat/cupy` namespace, the `get_xp` decorator is applied to these
151+
functions, which automatically removes the `xp` argument from the function
152+
signature and replaces it with the corresponding array library, like
153+
154+
```py
155+
# In array_api_compat/numpy/_aliases.py
156+
157+
from ..common import _aliases
158+
159+
import numpy as np
160+
161+
acos = get_xp(np)(_aliases.acos)
162+
```
163+
164+
This `acos` now has the signature `acos(x, /)` and calls `numpy.arccos`.
165+
166+
Similarly, for CuPy:
167+
168+
```py
169+
# In array_api_compat/cupy/_aliases.py
170+
171+
from ..common import _aliases
172+
173+
import cupy as cp
174+
175+
acos = get_xp(cp)(_aliases.acos)
176+
```
177+
178+
Since NumPy and CuPy are nearly identical in their behaviors, this allows
179+
writing the wrapping logic for both libraries only once. If support is added
180+
for other libraries which differ significantly from NumPy, their wrapper code
181+
should go in their specific sub-namespace instead of `common/`.

array_api_compat/__init__.py

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""
22
NumPy Array API compatibility library
33
4-
This is a small wrapper around NumPy that is compatible with the Array API
5-
standard https://data-apis.org/array-api/latest/. See also NEP 47
4+
This is a small wrapper around NumPy and CuPy that is compatible with the
5+
Array API standard https://data-apis.org/array-api/latest/. See also NEP 47
66
https://numpy.org/neps/nep-0047-array-api-standard.html.
77
88
Unlike numpy.array_api, this is not a strict minimal implementation of the
@@ -16,28 +16,5 @@
1616
to ensure they are not using functionality outside of the standard, but prefer
1717
this implementation for the default when working with NumPy arrays.
1818
19-
In addition, several helper functions are provided in this library which are
20-
not part of the array API specification but which are useful for libraries
21-
writing against the array API specification who wish to support NumPy and
22-
other array API compatible libraries.
23-
24-
Known differences from the Array API spec:
25-
26-
- The array methods __array_namespace__, device, to_device, and mT are not
27-
defined. This reuses np.ndarray and we don't want to monkeypatch or wrap it.
28-
The helper functions device() and to_device() are provided to work around
29-
these missing methods. x.mT can be replaced with
30-
xp.linalg.matrix_transpose(x).
31-
32-
- NumPy value-based casting for scalars will be in effect unless explicitly
33-
disabled with the environment variable NPY_PROMOTION_STATE=weak or
34-
np._set_promotion_state('weak') (requires NumPy 1.24 or newer, see NEP 50
35-
and https://github.com/numpy/numpy/issues/22341)
36-
37-
- NumPy functions which are not wrapped may not have the same type annotations
38-
as the spec.
39-
40-
- NumPy functions which are not wrapped may not use positional-only arguments.
41-
4219
"""
4320
from .common import *

0 commit comments

Comments
 (0)