Description
The array API standard is now clear (in Type Promotion Rules):
This means that following does not have defined behavior:
x = xp.asarray([1., 2., 3.])
x + 1j
However, the behavior is defined consistently in NumPy, CuPy, PyTorch, jax.numpy1, Dask array, and Tensorflow2 in the intuitive way: the real and imaginary component dtypes of the complex output array match the dtype of the input array.
This issue was discussed explicitly in gh-478 beginning with #478 (comment). I see several comments that seem supportive of allowing this operation, e.g.
I would hope it at least works for Python scalars.
x + 0j
seems like the simplest and most obvious way to convert a real array to a complex one.
The comment I see against it (#478 (comment)) is
I know it's very common to do this (also *
1.0
to convert integer to real). However, it doesn't seem like great practice irrespective of the decision here - there's an explicitastype
function for converting to other dtypes.
It looked like the summary comments suggested that this would be allowed, but it was not specifically addressed in the PR that closed the issue. (See postscript for more information.)
I thought it might help to add some perspective on how this impacts a developer translating code to the standard: when tests including an operation like
x + 1j
begin to fail with array_api_strict
only, the developer is faced with the choice of skipping the array_api_strict
tests or figuring out what is wrong and changing the code to something like:
xp.astype(x, xp.result_type(x.dtype, xp.complex64)) + 1j
If they also want it to be able to preserve the lower precision types supported by some libraries (e.g. for NumPy), there would be additional hurdles. I tested for a few libraries, and array API standard compatible version of the code also increases the execution time notably for small arrays. Individually, the inconvenience, complexity, and overhead are small, but they add up. I am excited about adding array API support to SciPy, but not everyone is supportive, and performance regressions and complicated-looking diffs can make it difficult to garner support.
I would suggest that the operation be defined, even if it means adding an exception to the simply stated rules for array/Python arithmetic.
The more specific language about this not being defined was added in gh-513, which provided the justification:
Given that current guidance requires converting a scalar to the array data type, to accommodate complex scalars and real-valued arrays, we'd need to specify casting rules for complex to real,
I think that is referring to the language:
That guidance was added in gh-74, but I can't trace the origin further. Perhaps there can be exceptions to that rule?
Footnotes
-
With NumPy experimental behavior (https://github.com/data-apis/array-api/issues/478#issuecomment-1272631595). Vanilla Tensorflow doesn't seem to support the other array-scalar operations that are defined, but already this was not deemed to be sufficient reason to prevent their inclusion in the standard (https://github.com/data-apis/array-api/issues/478#issuecomment-1270409660). ↩