Description
Complex 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: Question: complex number support in Array API? #102
- Issue: Specify the expected behaviors for handling complex numbers #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: Question: complex number support in Array API? #102 (comment)
- 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: BUG: arange behaves poorly on complex numbers numpy/numpy#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: Specify the expected behaviors for handling complex numbers #153 (comment)
- 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
: Specify the expected behaviors for handling complex numbers #153 (comment)
- 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