|
1 |
| -array-api-strict |
2 |
| -================ |
| 1 | +# array-api-strict |
3 | 2 |
|
4 |
| -A strict, minimal implementation of the [Python array |
| 3 | +`array_api_strict` is a strict, minimal implementation of the [Python array |
5 | 4 | API](https://data-apis.org/array-api/latest/)
|
6 | 5 |
|
| 6 | +The purpose of array-api-strict is to provide an implementation of the array |
| 7 | +API for consuming libraries to test against so they can be completely sure |
| 8 | +their usage of the array API is portable. |
| 9 | + |
| 10 | +It is *not* intended to be used by end-users. End-users of the array API |
| 11 | +should just use their favorite array library (NumPy, CuPy, PyTorch, etc.) as |
| 12 | +usual. It is also not intended to be used as a dependency by consuming |
| 13 | +libraries. Consuming library code should use the |
| 14 | +[array-api-compat](https://github.com/data-apis/array-api-compat) package to |
| 15 | +support the array API. Rather, it is intended to be used in the test suites of |
| 16 | +consuming libraries to test their array API usage. |
| 17 | + |
| 18 | +## Install |
| 19 | + |
| 20 | +`array-api-strict` is available on both |
| 21 | +[PyPI](https://pypi.org/project/array-api-strict/) |
| 22 | + |
| 23 | +``` |
| 24 | +python -m pip install array-api-strict |
| 25 | +``` |
| 26 | + |
| 27 | +and [Conda-forge](https://anaconda.org/conda-forge/array-api-strict) |
| 28 | + |
| 29 | +``` |
| 30 | +conda install --channel conda-forge array-api-strict |
| 31 | +``` |
| 32 | + |
| 33 | +array-api-strict supports NumPy 1.26 and (the upcoming) NumPy 2.0. |
| 34 | + |
| 35 | +## Rationale |
| 36 | + |
| 37 | +The array API has many functions and behaviors that are required to be |
| 38 | +implemented by conforming libraries, but it does not, in most cases, disallow |
| 39 | +implementing additional functions, keyword arguments, and behaviors that |
| 40 | +aren't explicitly required by the standard. |
| 41 | + |
| 42 | +However, this poses a problem for consumers of the array API, as they may |
| 43 | +accidentally use a function or rely on a behavior which just happens to be |
| 44 | +implemented in every array library they test against (e.g., NumPy and |
| 45 | +PyTorch), but isn't required by the standard and may not be included in other |
| 46 | +libraries. |
| 47 | + |
| 48 | +array-api-strict solves this problem by providing a strict, minimal |
| 49 | +implementation of the array API standard. Only those functions and behaviors |
| 50 | +that are explicitly *required* by the standard are implemented. For example, |
| 51 | +most NumPy functions accept Python scalars as inputs: |
| 52 | + |
| 53 | +```py |
| 54 | +>>> import numpy as np |
| 55 | +>>> np.sin(0.0) |
| 56 | +0.0 |
| 57 | +``` |
| 58 | + |
| 59 | +However, the standard only specifies function inputs on `Array` objects. And |
| 60 | +indeed, some libraries, such as PyTorch, do not allow this: |
| 61 | + |
| 62 | +```py |
| 63 | +>>> import torch |
| 64 | +>>> torch.sin(0.0) |
| 65 | +Traceback (most recent call last): |
| 66 | + File "<stdin>", line 1, in <module> |
| 67 | +TypeError: sin(): argument 'input' (position 1) must be Tensor, not float |
| 68 | +``` |
| 69 | + |
| 70 | +In array-api-strict, this is also an error: |
| 71 | + |
| 72 | +```py |
| 73 | +>>> import array_api_strict as xp |
| 74 | +>>> xp.sin(0.0) |
| 75 | +Traceback (most recent call last): |
| 76 | +... |
| 77 | +AttributeError: 'float' object has no attribute 'dtype' |
| 78 | +``` |
| 79 | + |
| 80 | +Here is an (incomplete) list of the sorts of ways that array-api-strict is |
| 81 | +strict/minimal: |
| 82 | + |
| 83 | +- Only those functions and methods that are [defined in the |
| 84 | + standard](https://data-apis.org/array-api/draft/API_specification/index.html) |
| 85 | + are included. |
| 86 | + |
| 87 | +- In those functions, only the keyword-arguments that are defined by the |
| 88 | + standard are included. All signatures in array-api-strict use |
| 89 | + [positional-only |
| 90 | + arguments](https://data-apis.org/array-api/draft/API_specification/function_and_method_signatures.html#function-and-method-signatures). |
| 91 | + As noted above, only array_api_strict array objects are accepted by |
| 92 | + functions, except in the places where the standard allows Python scalars |
| 93 | + (i.e., functions to not automatically call `asarray` on their inputs). |
| 94 | + |
| 95 | +- Only those [dtypes that are defined in the |
| 96 | + standard](https://data-apis.org/array-api/draft/API_specification/data_types.html) |
| 97 | + are included. |
| 98 | + |
| 99 | +- All functions and methods reject inputs if the standard does not *require* |
| 100 | + the input dtype(s) to be supported. This is one of the most restrictive |
| 101 | + aspects of the library. For example, in NumPy, most transcendental functions |
| 102 | + like `sin` will accept integer array inputs, but the [standard only requires |
| 103 | + them to accept floating-point |
| 104 | + inputs](https://data-apis.org/array-api/draft/API_specification/generated/array_api.sin.html#array_api.sin), |
| 105 | + so in array-api-strict, `sin(integer_array)` will raise an exception. |
| 106 | + |
| 107 | +- The |
| 108 | + [indexing](https://data-apis.org/array-api/draft/API_specification/indexing.html) |
| 109 | + semantics required by the standard are not |
| 110 | + |
| 111 | +- There are no distinct "scalar" objects as in NumPy. There are only 0-D |
| 112 | + arrays. |
| 113 | + |
| 114 | +- Dtype objects are just empty objects that only implement [equality |
| 115 | + comparison](https://data-apis.org/array-api/draft/API_specification/generated/array_api.data_types.__eq__.html). |
| 116 | + The way to access dtype objects in the standard is by name, like |
| 117 | + `xp.float32`. |
| 118 | + |
| 119 | +- The array object type itself is private and should not be accessed. |
| 120 | + Subclassing or otherwise trying to directly initialize this object is not |
| 121 | + supported. Arrays should created with one of the [array creation |
| 122 | + functions](https://data-apis.org/array-api/draft/API_specification/creation_functions.html) |
| 123 | + such as `asarray`. |
| 124 | + |
| 125 | +## Caveats |
| 126 | + |
| 127 | +array-api-strict is a thin pure Python wrapper around NumPy. NumPy 2.0 fully |
| 128 | +supports the array API but NumPy 1.26 does not, so many behaviors are wrapped |
| 129 | +in NumPy 1.26 to provide array API compatible behavior. Although it is based |
| 130 | +on NumPy, mixing NumPy arrays with array-api-strict arrays is not supported. |
| 131 | +This should generally raise an error, as it indicates a potential portability |
| 132 | +issue, but this hasn't necessarily been tested thoroughly. |
| 133 | + |
| 134 | +1. array-api-strict is validated against the [array API test |
| 135 | + suite](https://github.com/data-apis/array-api-tests). However, there may be |
| 136 | + a few minor instances where NumPy deviates from the standard in a way that |
| 137 | + is inconvenient to workaround in array-api-strict, since it aims to remain |
| 138 | + pure Python. You can see the full list of tests that are known to fail in |
| 139 | + the [xfails |
| 140 | + file](https://github.com/data-apis/array-api-strict/blob/main/array-api-tests-xfails.txt). |
| 141 | + |
| 142 | + The most notable of these is that in NumPy 1.26, the `copy=False` flag is |
| 143 | + not implemented for `asarray` and therefore `array_api_strict` raises |
| 144 | + `NotImplementedError` in that case. |
| 145 | + |
| 146 | +2. Since NumPy is a CPU-only library, the [device |
| 147 | + support](https://data-apis.org/array-api/draft/design_topics/device_support.html) |
| 148 | + in array-api-strict is superficial only. `x.device` is always a (private) |
| 149 | + `_CPU_DEVICE` object, and `device` keywords to creation functions only |
| 150 | + accept either this object or `None`. A future version of array-api-strict |
| 151 | + [may add support for a CuPy |
| 152 | + backend](https://github.com/data-apis/array-api-strict/issues/5) so that |
| 153 | + more significant device support can be tested. |
| 154 | + |
| 155 | +3. Although only array types are expected in array-api-strict functions, |
| 156 | + currently most functions do not do extensive type checking on their inputs, |
| 157 | + so a sufficiently duck-typed object may pass through silently (or at best, |
| 158 | + you may get `AttributeError` instead of `TypeError`). However, all type |
| 159 | + signatures have type annotations (based on those from the standard), so |
| 160 | + this deviation may be tested with type checking. This [behavior may improve |
| 161 | + in the future](https://github.com/data-apis/array-api-strict/issues/6). |
| 162 | + |
| 163 | +4. There are some behaviors in the standard that are not required to be |
| 164 | + implemented by libraries that cannot support [data dependent |
| 165 | + shapes](https://data-apis.org/array-api/draft/design_topics/data_dependent_output_shapes.html). |
| 166 | + This includes [the `unique_*` |
| 167 | + functions](https://data-apis.org/array-api/draft/API_specification/set_functions.html), |
| 168 | + [boolean array |
| 169 | + indexing](https://data-apis.org/array-api/draft/API_specification/indexing.html#boolean-array-indexing), |
| 170 | + and the |
| 171 | + [`nonzero`](https://data-apis.org/array-api/draft/API_specification/generated/array_api.nonzero.html) |
| 172 | + function. array-api-strict currently implements all of these. In the |
| 173 | + future, [there may be a way to disable them](https://github.com/data-apis/array-api-strict/issues/7). |
| 174 | + |
| 175 | +5. array-api-strict currently only supports the latest version of the array |
| 176 | + API standard. [This may change in the future depending on |
| 177 | + need](https://github.com/data-apis/array-api-strict/issues/8). |
| 178 | + |
| 179 | +## Usage |
| 180 | + |
| 181 | +TODO: Add a sample CI script here. |
| 182 | + |
| 183 | +## Relationship to `numpy.array_api` |
| 184 | + |
7 | 185 | Previously this implementation was available as `numpy.array_api`, but it was
|
8 | 186 | moved to a separate package for NumPy 2.0.
|
9 | 187 |
|
10 |
| -Note: the history of this repo prior to commit |
| 188 | +Note that the history of this repo prior to commit |
11 | 189 | fbefd42e4d11e9be20e0a4785f2619fc1aef1e7c was generated automatically
|
12 | 190 | from the numpy git history, using the following
|
13 | 191 | [git-filter-repo](https://github.com/newren/git-filter-repo) command:
|
|
0 commit comments