RFC: Adding complex number support to the specification
See original GitHub issueComplex Number Support
Plan for complex number support in the array API specification.
What follows is a plan for adding complex number support to the 2022 array API specification. This RFC is comprised of the following sections:
- Prior discussions
- High-level summary concerns and questions
- Individual API changes
Prior Discussions
- Issue: https://github.com/data-apis/array-api/issues/102
- Issue: https://github.com/data-apis/array-api/issues/153
General Concerns
New APIs
real
conj (complex conjugate)
imag
arg/angle/phase (phase angle)
linalg.eig
linalg.eigvals
Decisions
-
initial data types:
complex64
andcomplex128
?- Update: only
complex64
andcomplex128
to be added, thus mirroringfloat32
andfloat64
.
- Update: only
-
rounding complex numbers (component-wise)
- NumPy supports round, but not ceil, floor, and trunc.
- Update: ceiling, flooring, and truncating complex numbers is not well-defined. The only rounding operation which is commonly supported is
round
.
-
ordering (lexicographic?)
- necessary for sorting, maximum, minimum (e.g.,
argsort
,argmax
,argmin
,min
,max
,sort
) - issue: https://github.com/data-apis/array-api/issues/102#issuecomment-748328170
- choices are to define a complex number ordering or leave out of the specification
- Update: ordering complex numbers is left out of the specification.
- necessary for sorting, maximum, minimum (e.g.,
-
branch cut policy?
- branch cut reference: https://en.wikipedia.org/wiki/Branch_point#Branch_cuts
- should we strictly follow NumPy/C99, or should we allow for implementation flexibility?
- if we strictly follow something other than NumPy/C99, obvious backward compat concern
- Update: branch cuts will be included in the 2022 revision under a provisional status. Provided no issues arise during adoption and implementation, the provisional status may be lifted in a future revision of the standard.
-
casting from complex to real
- discard imaginary component (as in C, NumPy)
- other choice would to require user to explicitly invoke
real
before casting - Update: decision was to require that array API consumers be explicit in specifying which component they want to cast when casting from complex to real.
-
complex numbers with components which are infinity and/or NaN
-
in Python, a complex number can be both infinite and NaN (according to
cmath.isinf
,cmath.isnan
)In [1]: z = complex(float('inf'), float('nan')) In [2]: z Out[2]: (inf+nanj) In [3]: cmath.isinf(z) Out[3]: True In [4]: cmath.isnan(z) Out[4]: True
-
in NumPy (v1.23.5), behavior is consistent with Python
In [1]: z = np.complex128(complex(float('inf'), float('nan'))) In [2]: z Out[2]: (inf+nanj) In [3]: np.isnan([z]) Out[3]: array([True]) In [4]: np.isinf([z]) Out[4]: array([True])
-
in C99 (see “complex floating types” section), one infinity model (e.g.,
inf + nan*j
==inf
) -
update: decision was made to allow implementation-dependent behavior for modeling complex NaNs and infinities. In particular, for complex multiplication and division, handling of complex infinities and NaNs may not be consistent across implementations.
-
Creation Functions
arange
-
No changes. No complex number support.
-
NumPy issue: https://github.com/numpy/numpy/issues/10332
- can be difficult to resolve step/length
-
asarray
-
dtype
- if one or more values are complex Python scalars, the output data type must be the default complex floating-point data type.
-
status: implemented
empty
- No changes. Output array data type has no restrictions.
empty_like
- No changes. Output array data type has no restrictions.
eye
-
No changes. Output array data type has not restrictions.
- May want to include note that, for complex numbers, ones along the diagonal means
1 + 0j
.
- May want to include note that, for complex numbers, ones along the diagonal means
-
status: implemented
from_dlpack
- No changes.
full
-
fill_value
- update to accept
complex
fill value.
- update to accept
-
dtype
- if fill value is
complex
, output array data type must be the default complex floating-point data type.
- if fill value is
-
status: implemented
full_like
-
fill_value
- update to accept
complex
fill value.
- update to accept
-
dtype
- update note for when
dtype
isNone
to includecomplex
.
- update note for when
-
status: implemented
linspace
-
start
- add support for
complex
- add support for
-
stop
- add support for
complex
- add support for
-
when either
start
orstop
is complex, the result must be complex. -
status: implemented
meshgrid
-
update to accept all numeric dtypes.
-
status: implemented
ones
-
No changes necessary.
- May be useful to add a note that, for complex numbers, ones means
1 + 0j
.
- May be useful to add a note that, for complex numbers, ones means
-
status: implemented
ones_like
-
No changes necessary.
- May be useful to add a note that, for complex numbers, ones means
1 + 0j
.
- May be useful to add a note that, for complex numbers, ones means
-
status: implemented
tril
- No changes necessary. No restrictions on input array data types.
triu
- No changes necessary. No restrictions on input array data types.
zeros
- No changes necessary. No restrictions on output array data types.
zeros_like
- No changes necessary. No restrictions on output array data types.
Data Type Functions
astype
-
Add note stating that, when casting from a complex data type to a real data type stating, the imaginary component is discarded and casting to integral data types is unspecified and thus implementation-dependent.- Discarding the imaginary component follows C and is done in NumPy.
- Could also disallow/omit/not explicitly support casting from complex to real and require users to explicitly call
real
if they want to discard the imaginary component. - Update: casting from a complex data type to a real-valued data type was disallowed in the specification in favor of API consumers being explicit wrt which component should be cast.
-
status: implemented
broadcast_arrays
- No changes necessary.
broadcast_to
- No changes necessary.
can_cast
- No changes necessary. Follows promotion rules for complex numbers.
finfo
- No changes necessary.
iinfo
- No changes necessary.
result_type
- No changes necessary. Follows promotion rules for complex numbers.
Data Types
-
Add
complex64
andcomplex128
following precedent where the numeric suffix specifies the number of bits.- The real and imaginary components should be IEEE 754 floating-point numbers.
-
status: implemented
Default Data Types
-
The default complex number data type is dependent on the default floating-point data type. If the latter is
float32
, the default complex data type must becomplex64
.- PyTorch already does this.
-
status: implemented
Data Type Categories
-
Add complex data types to list of numeric data types.
-
Add “Real Data Types” category which should be equal to the current list of numeric data types.
-
Add “Complex Data Types” category which only includes the complex number data types.
-
status: implemented
Element-wise Functions
abs
-
Add support by returning the complex magnitude.
-
Add complex number special cases: same as
hypot(creal(z), cimag(z))
. -
status: implemented
acos
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/cacos
[-inf,-1]
,[1,inf]
- Python branch cuts: https://docs.python.org/3/library/cmath.html#cmath.acos
- same as C
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.arccos.html
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/cacos
-
status: implemented
acosh
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/cacosh
[-inf,1]
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.arccosh.html
- same as C
- Python branch cuts: https://docs.python.org/3/library/cmath.html#cmath.acosh
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/cacosh
-
status: implemented
add
-
Add complex number support. Complex number addition is well-defined.
- Some care should be given to infinities and NaNs.
-
status: implemented
asin
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/casin
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.arcsin.html
- Python branch cuts: https://docs.python.org/3/library/cmath.html#cmath.asin
-
status: implemented
asinh
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/casinh
[-inf*i, -i]
,[i, inf*i]
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.arcsinh.html
- same as C
- Python branch cuts: https://docs.python.org/3/library/cmath.html#cmath.asinh
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/casinh
-
status: implemented
atan
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/catan
[-inf*i, -i]
,[i, inf*i]
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.arctan.html
- same as C
- Python branch cuts: https://docs.python.org/3/library/cmath.html#cmath.atan
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/catan
-
status: implemented
atan2
- No complex number support.
- No changes necessary as already limited to real number data types.
atanh
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/catanh
[-inf, -1]
,[1,inf]
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.arctanh.html
- same as C
- Python branch cuts: https://docs.python.org/3/library/cmath.html#cmath.atanh
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/catanh
-
status: implemented
bitwise_and
- No changes. Complex dtypes are not allowed.
bitwise_left_shift
- No changes. Complex dtypes are not allowed.
bitwise_invert
- No changes. Complex dtypes are not allowed.
bitwise_or
- No changes. Complex dtypes are not allowed.
bitwise_right_shift
- No changes. Complex dtypes are not allowed.
bitwise_xor
- No changes. Complex dtypes are not allowed.
ceil
-
Add complex number support. Independently round components (e.g., as in MATLAB).- NumPy does not support in np.ceil.
- No complex number support due to implementation ambiguity.
cos
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/ccos
- no branch cuts
- NumPy: https://numpy.org/doc/stable/reference/generated/numpy.cos.html
- same as C
- Python: https://docs.python.org/3/library/cmath.html#cmath.cos
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/ccos
-
status: implemented
cosh
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/ccosh
- no branch cuts
- NumPy: https://numpy.org/doc/stable/reference/generated/numpy.cosh.html
- same as C
- Python: https://docs.python.org/3/library/cmath.html#cmath.cosh
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/ccosh
-
status: implemented
divide
-
Add complex number support.
-
Define special cases.
-
status: implemented
equal
-
Add complex number support.
- Care should be taken with infinities and NaNs.
-
status: implemented
exp
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/cexp
- no branch cuts
- NumPy: https://numpy.org/doc/stable/reference/generated/numpy.exp.html
- same as C
- Python: https://docs.python.org/3/library/cmath.html#cmath.exp
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/cexp
-
status: implemented
expm1
-
Add complex number support.
-
Define special cases.
- should follow
exp
- should follow
-
status: implemented
floor
-
Add complex number support. Independently round components (e.g., as in MATLAB).- NumPy does not support in np.floor.
- No complex number support due to implementation ambiguity.
floor_divide
- No complex number support.
- No changes necessary as already limited to real number data types.
greater
-
No complex number support due to complex numbers lacking a natural ordering.
-
status: implemented
greater_equal
-
No complex number support due to complex numbers lacking a natural ordering.
-
status: implemented
isfinite
-
Add support for complex numbers.
- Care should be taken for infinities and NaNs.
-
status: implemented
isinf
-
Add support for complex numbers.
- Care should be taken for infinities and NaNs.
- how to classify a complex number as infinite?
- Care should be taken for infinities and NaNs.
-
status: implemented
isnan
-
Add support for complex numbers.
- Care should be taken for infinities and NaNs.
- how to classify a complex number as NaN?
- Update: if any component is
NaN
, the complex number is considered “NaN”
- Care should be taken for infinities and NaNs.
-
status: implemented
less
-
No complex number support due to complex numbers lacking a natural ordering.
-
status: implemented
less_equal
-
No complex number support due to complex numbers lacking a natural ordering.
-
status: implemented
log
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/clog
- same as NumPy
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.log.html
[-inf, 0]
- Python branch cuts: https://docs.python.org/3/library/cmath.html#cmath.log
- same as NumPy
- C: https://en.cppreference.com/w/c/numeric/complex/clog
-
status: implemented
log1p
-
Add complex number support.
-
Define special cases.
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.log1p.html
- should follow similarly to
log
-
status: implemented
log2
-
Add complex number support.
-
Define special cases.
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.log2.html
- same as
log
- same as
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.log2.html
-
status: implemented
log10
-
Add complex number support.
-
Define special cases.
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.log10.html
- same as
log
- same as
- Python branch cuts: https://docs.python.org/3/library/cmath.html#cmath.log10
- same as NumPy
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.log10.html
-
status: implemented
logaddexp
- No complex number support. This function is mainly useful for stats.
- No changes necessary as already limited to real-valued data types.
logical_and
- No changes necessary. Input arrays expected to have boolean data type.
logical_not
- No changes necessary. Input arrays expected to have boolean data type.
logical_or
- No changes necessary. Input arrays expected to have boolean data type.
logical_xor
- No changes necessary. Input arrays expected to have boolean data type.
multiply
-
Add complex number support. Complex number multiplication is well-defined.
- Care should be taken with regard to infinities and NaNs.
-
Define special cases.
-
status: implemented
negative
-
Add complex number support. No real changes necessary, as relies on
multiply
. -
status: implemented
not_equal
-
Add complex number support.
- Care should be taken with infinities and NaNs.
-
status: implemented
positive
-
Add complex number support. No changes necessary, as this is effectively the identity function.
-
status: implemented
pow
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/cpow
- branch cut for the first parameter along the negative real axis
- NumPy: https://numpy.org/doc/stable/reference/generated/numpy.power.html
- Python supports, but not exposed via cmath.
- pinning down exact behavior could be tricky (see Python issue 15996)
- C: https://en.cppreference.com/w/c/numeric/complex/cpow
-
status: implemented
remainder
- No complex number support.
- No changes necessary as already limited to real-valued data types.
round
-
Add complex number support.
- Independently round components (e.g., as in MATLAB and NumPy).
-
status: implemented
sign
-
Add complex number support.
-
Define special cases.
-
NumPy: https://numpy.org/doc/stable/reference/generated/numpy.sign.html
- NumPy uses
x / sqrt(x*x)
; could also usex/|x|
- see comment: https://github.com/data-apis/array-api/issues/153#issuecomment-869059671
- NumPy uses
-
Update: consensus is to use
x/|x|
.
-
-
status: implemented
sin
-
Add complex number support.
-
Define special cases. No branch cuts.
- C: https://en.cppreference.com/w/c/numeric/complex/csin
- no branch cuts
- NumPy: https://numpy.org/doc/stable/reference/generated/numpy.sin.html
- same as C
- Python: https://docs.python.org/3/library/cmath.html#cmath.sin
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/csin
-
status: implemented
sinh
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/csinh
- no branch cuts
- NumPy: https://numpy.org/doc/stable/reference/generated/numpy.sinh.html
- same as C
- Python: https://docs.python.org/3/library/cmath.html#cmath.sinh
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/csinh
-
status: implemented
square
-
Add complex number support. Complex number multiplication is well-defined.
- question whether to add
abs2
: https://github.com/data-apis/array-api/issues/153#issuecomment-896339259
- question whether to add
-
status: implemented
sqrt
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/csqrt
- branch cut along the negative real axis
[-inf,0)
- branch cut along the negative real axis
- NumPy branch cuts: https://numpy.org/doc/stable/reference/generated/numpy.sqrt.html
- same as C
- Python branch cuts: https://docs.python.org/3/library/cmath.html#cmath.sqrt
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/csqrt
-
status: implemented
subtract
-
Add complex number support. Complex number addition is well-defined.
-
status: implemented
tan
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/ctan
- no branch cuts
- NumPy: https://numpy.org/doc/stable/reference/generated/numpy.tan.html
- same as C
- Python: https://docs.python.org/3/library/cmath.html#cmath.tan
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/ctan
-
status: implemented
tanh
-
Add complex number support.
-
Define special cases.
- C: https://en.cppreference.com/w/c/numeric/complex/ctanh
- no branch cuts
- NumPy: https://numpy.org/doc/stable/reference/generated/numpy.tanh.html
- same as C
- Python branch cuts: https://docs.python.org/3/library/cmath.html#cmath.tanh
- same as C
- C: https://en.cppreference.com/w/c/numeric/complex/ctanh
-
status: implemented
trunc
-
Add complex number support. Independently truncate components (e.g., as in MATLAB).- NumPy does not support in np.trunc.
- No complex number support due to implementation ambiguity.
Linear Algebra Functions
matmul
-
Add complex number support.
- complex number addition is well-defined.
- complex number multiplication is less well-defined and depends on how an implementation chooses to model complex infinity.
-
status: implemented
matrix_transpose
- No changes necessary.
tensordot
-
Add complex number support.
- complex number addition is well-defined.
- complex number multiplication is less well-defined and depends on how an implementation chooses to model complex infinity.
-
status: implemented
vecdot
-
Implementations should conjugate when computing the complex dot product:
x^H y
-
status: implemented
Manipulation Functions
concat
- No changes necessary.
expand_dims
- No changes necessary.
flip
- No changes necessary.
permute_dims
- No changes necessary.
reshape
- No changes necessary.
roll
- No changes necessary.
squeeze
- No changes necessary.
stack
- No changes necessary.
Searching Functions
argmax
-
Require that complex numbers be ordered in lexicographic order?
- While not compatible with multiplication, lexicographic order is a common total order. E.g., NumPy uses lexicographic order.
- Another alternative is by magnitude and then phase angle. E.g., MATLAB supports this order.
- The specification could default to lexicographic, and revisit the ordering relation in the future with possible support for optionally specifying an alternative comparison method.
- Some care needs to be given to sorting when one or more components is NaN.
- Update: no support for complex numbers due to a lack of a natural order.
-
status: implemented
argmin
-
No complex number support due to complex numbers lacking a natural ordering.
-
status: implemented
nonzero
-
No changes necessary. A nonzero complex number is a complex number whose real or imaginary component is nonzero.
-
status: implemented
where
- No changes necessary.
Set Functions
unique_all
-
Specify complex number value equality.
- In C, “In order to support the one-infinity model of complex number arithmetic, C regards any complex value with at least one infinite part as an infinity even if its other part is a NaN…”
- Need to resolve isinf and isnan duality
- Update: base equality comparison on
equal
.
-
status: implemented
unique_counts
-
Same as
unique_all
. -
status: implemented
unique_inverse
-
Same as
unique_all
. -
status: implemented
unique_values
-
Same as
unique_all
. -
status: implemented
Sorting Functions
argsort
-
No complex number support due to complex numbers lacking a natural ordering.
-
status: implemented
sort
-
No complex number support due to complex numbers lacking a natural ordering.
-
status: implemented
Statistical Functions
max
-
No complex number support due to complex numbers lacking a natural ordering.
-
status: implemented
mean
- No complex number support.
- Change to only real number data types.
min
-
No complex number support due to complex numbers lacking a natural ordering.
-
status: implemented
prod
-
Add support for complex numbers. Complex number multiplication is well-defined.
- The
dtype
option needs to be updated to accommodate complex numbers.
- The
-
status: implemented
std
- No complex number support.
- Change to only real number data types.
sum
-
Add support for complex numbers. Complex number addition is well-defined.
- The
dtype
option needs to be updated to accommodate complex numbers.
- The
-
status: implemented
var
- No complex number support.
- Change to only real number data types.
Type Promotion
Rules
-
Add complex number type promotion table.
-
Related complex number type promotion to floating-point number type promotion (e.g.,
f8
andc16
) -
status: implemented
Mixing arrays with Python Scalars
-
Add
complex
Python scalars. -
Update note concerning mixed “kind” operations.
-
status: implemented
Utility Functions
all
-
No changes necessary. The value
0+0j
should evaluate toFalse
. If a complex number has a non-zero component, the value should evaluate toTrue
. -
status: implemented
any
-
Same as
all
. -
status: implemented
Linear Algebra Extension
cholesky
-
Add complex number support.
-
Require that each square matrix must be Hermitian.
-
status: implemented
cross
-
Add complex number support.
-
status: implemented
det (determinant)
-
Add complex number support.
-
status: implemented
diagonal
- No changes necessary.
eigh
-
Add complex number support.
- Require that each matrix must be Hermitian and the returned Q unitary.
- May want to make the dtype of the eigevalues unconditionally real.
-
status: implemented
eigvalsh
-
Add complex number support.
- Require that each matrix must be Hermitian.
-
status: implemented
inv
-
Add complex number support.
-
status: implemented
matmul
- Support added in main namespace.
matrix_norm
-
Add complex number support.
-
Depends on svd.
-
status: implemented
matrix_power
-
Add complex number support.
-
status: implemented
matrix_rank
-
Add complex number support.
-
Depends on svd.
-
status: implemented
matrix_transpose
- No changes necessary.
outer
-
Add complex number support.
-
status: implemented
pinv
-
Add complex number support.
-
Depends on svd.
-
status: implemented
qr
-
Add complex number support.
-
status: implemented
slogdet
-
Add complex number support.
-
status: implemented
solve
-
Add complex number support.
-
status: implemented
svd
-
Add complex number support.
- Require that each U, Vh must be unitary.
- May want to require that the returned dtype of
S
is unconditionally real.
-
status: implemented
svdvals
-
Add complex number support.
-
status: implemented
trace
-
Add complex number support.
-
status: implemented
vecdot
- Changes made in main namespace.
vector_norm
-
Add complex number support.
-
status: implemented
Issue Analytics
- State:
- Created 2 years ago
- Reactions:3
- Comments:5 (5 by maintainers)
Top GitHub Comments
All PRs have been merged - adding complex number support to the API is complete. Thanks a lot to everyone who contributed - and in particular @kgryte for all the spec writing.
I don’t know why I missed it… CuPy uses Thrust (and it’s likely being used by many other projects that depends on CUDA; IIUC the implementation was ported to libcudacxx) so it’s worth mentioning.
Thrust’s complex math funcs were based on FreeBSD’s. In each FreeBSD man page the branch cut is clearly documented so it’s a good starting point. However, as Thrust didn’t document it clearly (I asked internally and was told to inspect the source directly, which is challenging given my lack of bandwidth) and it’s unclear to me if the Thrust impl was a one-to-one translation of FreeBSD’s since I don’t have access to the FreeBSD source code, I’d proceed with caution.