From ef0d567f7b5967e8d344cd3258c96a58f422f27f Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 13 Jun 2022 01:35:09 -0700 Subject: [PATCH 1/7] Add complex number support to `expm1` --- .gitignore | 1 + .../array_api/elementwise_functions.py | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 73e203a64..86bab2717 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ node_modules/ __pycache__/ *.pyc spec/**/generated +tmp/ \ No newline at end of file diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 7acefaf52..f2dd606b3 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -544,7 +544,7 @@ def exp(x: array, /) -> array: def expm1(x: array, /) -> array: """ - Calculates an implementation-dependent approximation to ``exp(x)-1``, having domain ``[-infinity, +infinity]`` and codomain ``[-1, +infinity]``, for each element ``x_i`` of the input array ``x``. + Calculates an implementation-dependent approximation to ``exp(x)-1`` for each element ``x_i`` of the input array ``x``. .. note:: The purpose of this function is to calculate ``exp(x)-1.0`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``exp(x)-1.0``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. @@ -559,15 +559,34 @@ def expm1(x: array, /) -> array: - If ``x_i`` is ``+infinity``, the result is ``+infinity``. - If ``x_i`` is ``-infinity``, the result is ``-1``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is either ``+0`` or ``-0``, the result is ``0+0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is either ``+0`` or ``-0``, the result is ``infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``-1 + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``infinity + infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is either ``+0`` or ``-0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the evaluated result for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def floor(x: array, /) -> array: From bd0d3a7317bf7da10f948db1e621c05aae795d79 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 13 Jun 2022 01:41:28 -0700 Subject: [PATCH 2/7] Update copy --- spec/API_specification/array_api/elementwise_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index f2dd606b3..9b83a7929 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -551,7 +551,7 @@ def expm1(x: array, /) -> array: **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``+0``. From 3faba09a52ac5ac03e7c052b53974b47b18c7d62 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 13 Jun 2022 01:56:10 -0700 Subject: [PATCH 3/7] Add note concerning complex conjugation --- spec/API_specification/array_api/elementwise_functions.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 9b83a7929..173bdb593 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -578,6 +578,9 @@ def expm1(x: array, /) -> array: .. note:: The exponential function is an entire function in the complex plane and has no branch cuts. + .. note:: + For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. + Parameters ---------- x: array From 2b6ca1bbf6e6d9b8f9bc31280febfa149532a094 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 13 Jun 2022 02:40:13 -0700 Subject: [PATCH 4/7] Specify special cases in terms of `cis` function --- spec/API_specification/array_api/elementwise_functions.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 173bdb593..177c2a22c 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -565,8 +565,8 @@ def expm1(x: array, /) -> array: - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - If ``a`` is ``+infinity`` and ``b`` is either ``+0`` or ``-0``, the result is ``infinity + 0j``. - - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``-1 + 0j``. - - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``infinity + infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(x_i) - 1.0``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(x_i) - 1.0``. - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). @@ -575,6 +575,8 @@ def expm1(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + where ``cis(x_i)`` is ``cos(x_i) + sin(x_i)*1j``. + .. note:: The exponential function is an entire function in the complex plane and has no branch cuts. From 66d0b6267004d1f18633487f157b8cd549bac531 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 20 Jun 2022 00:21:57 -0700 Subject: [PATCH 5/7] Fix special cases and move note --- .../array_api/elementwise_functions.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 177c2a22c..ed9ca5083 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -561,28 +561,28 @@ def expm1(x: array, /) -> array: For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and - - If ``a`` is either ``+0`` or ``-0`` and ``b`` is either ``+0`` or ``-0``, the result is ``0+0j``. + .. note:: + For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``0 + 0j``. - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - - If ``a`` is ``+infinity`` and ``b`` is either ``+0`` or ``-0``, the result is ``infinity + 0j``. - - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(x_i) - 1.0``. - - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(x_i) - 1.0``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b) - 1.0``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b) - 1.0``. - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). - - If ``a`` is ``NaN`` and ``b`` is either ``+0`` or ``-0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - where ``cis(x_i)`` is ``cos(x_i) + sin(x_i)*1j``. + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. .. note:: The exponential function is an entire function in the complex plane and has no branch cuts. - .. note:: - For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. - Parameters ---------- x: array From 2d87088e2897ec7aef281ba35ce3e61be9af1977 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Nov 2022 02:25:01 -0800 Subject: [PATCH 6/7] Move note --- spec/API_specification/array_api/elementwise_functions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index fe2cad280..7f9b7514e 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -659,9 +659,6 @@ def expm1(x: array, /) -> array: For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and - .. note:: - For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. - - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``0 + 0j``. - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. @@ -678,6 +675,9 @@ def expm1(x: array, /) -> array: where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + .. note:: + For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. + .. note:: The exponential function is an entire function in the complex plane and has no branch cuts. From d8e89185d5b60896116a5005da73c36398f83cb6 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Nov 2022 02:28:07 -0800 Subject: [PATCH 7/7] Move note --- spec/API_specification/array_api/elementwise_functions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 7f9b7514e..604d11e55 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -607,9 +607,6 @@ def exp(x: array, /) -> array: For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and - .. note:: - For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. - - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``1 + 0j``. - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. @@ -626,6 +623,9 @@ def exp(x: array, /) -> array: where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + .. note:: + For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. + .. note:: The exponential function is an entire function in the complex plane and has no branch cuts.