From ca5eeb4e37e10ace25af837e6dc94e670050fba7 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 22 Jun 2022 17:51:30 -0700 Subject: [PATCH 01/12] Add complex number support to `sqrt` --- .gitignore | 1 + .../array_api/elementwise_functions.py | 35 ++++++++++++++++--- 2 files changed, 31 insertions(+), 5 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 e75b087c9..a57dab161 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1276,12 +1276,15 @@ def square(x: array, /) -> array: """ def sqrt(x: array, /) -> array: - """ - Calculates the square root, having domain ``[0, +infinity]`` and codomain ``[0, +infinity]``, for each element ``x_i`` of the input array ``x``. After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). + r""" + Calculates the square root for each element ``x_i`` of the input array ``x``. + + .. note:: + After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). **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 less than ``0``, the result is ``NaN``. @@ -1289,15 +1292,37 @@ def sqrt(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is any value (including ``NaN``) and ``b`` is ``+infinity``, the result is ``+infinity + infinity j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN + infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. note:: + A branch cut is a curve in the complex plane across which a given complex function fails to be continuous. By convention, the branch cut of square root is the real interval :math:`[\infty, 0)`. + + The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty]` along the real axis and :math:`[-\infty, +\infty]` along the imaginary axis. + 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 square root of 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 square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def subtract(x1: array, x2: array, /) -> array: From 47b13efc2b9b4ea2140ae17bb5320965f2bd635d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 22 Jun 2022 18:03:15 -0700 Subject: [PATCH 02/12] Fix missing parenthesis --- 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 a57dab161..1ceec2f96 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1312,7 +1312,7 @@ def sqrt(x: array, /) -> array: The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component. - Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty]` along the real axis and :math:`[-\infty, +\infty]` along the imaginary axis. + Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty]` along the real axis and :math:`[-\infty, +\infty]` along the imaginary axis). Parameters ---------- From d0574a6cbdc177004b0c33dbf8f0d2e075d04aef Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Nov 2022 01:25:52 -0800 Subject: [PATCH 03/12] Move definition of branch cut to definition list --- spec/API_specification/array_api/elementwise_functions.py | 2 +- spec/purpose_and_scope.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 720fd3ed4..16abbbe98 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1490,7 +1490,7 @@ def sqrt(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. .. note:: - A branch cut is a curve in the complex plane across which a given complex function fails to be continuous. By convention, the branch cut of square root is the real interval :math:`[\infty, 0)`. + By convention, the branch cut of square root is the real interval :math:`[\infty, 0)`. The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component. diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index fc8433c7f..62e9bb8ba 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -434,6 +434,9 @@ a (usually fixed-size) multidimensional container of items of the same type and **axis**: an array dimension. +**branch cut**: +a curve in the complex plane across which a given complex function fails to be continuous. + **broadcast**: automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. From 5b7e18218ec3ffa014b0612ba918d09ef65e173e Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Nov 2022 01:50:30 -0800 Subject: [PATCH 04/12] Update description and reorder notes --- spec/API_specification/array_api/elementwise_functions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 16abbbe98..6cda9fadf 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1459,7 +1459,7 @@ def square(x: array, /) -> array: def sqrt(x: array, /) -> array: r""" - Calculates the square root for each element ``x_i`` of the input array ``x``. + Calculates the principal square root for each element ``x_i`` of the input array ``x``. .. note:: After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). @@ -1476,9 +1476,6 @@ def sqrt(x: array, /) -> array: For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and - .. note:: - For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. - - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. - If ``a`` is any value (including ``NaN``) and ``b`` is ``+infinity``, the result is ``+infinity + infinity j``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. @@ -1489,6 +1486,9 @@ def sqrt(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + .. note:: + For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. + .. note:: By convention, the branch cut of square root is the real interval :math:`[\infty, 0)`. From 51fee427fc51717c6b3fc24fea1b09488e65d3f8 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Nov 2022 01:57:22 -0800 Subject: [PATCH 05/12] Update intervals --- spec/API_specification/array_api/elementwise_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 6cda9fadf..451d3cdb7 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1490,11 +1490,11 @@ def sqrt(x: array, /) -> array: For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. .. note:: - By convention, the branch cut of square root is the real interval :math:`[\infty, 0)`. + By convention, the branch cut of square root is the negative real axis :math:`(-\infty, 0)`. The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component. - Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty]` along the real axis and :math:`[-\infty, +\infty]` along the imaginary axis). + Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). Parameters ---------- From 3b0fe4f293bde934e589977cde581b545115904c Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Nov 2022 02:11:05 -0800 Subject: [PATCH 06/12] Add warning concerning provisional status --- spec/API_specification/array_api/elementwise_functions.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 451d3cdb7..1bed5fe95 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1495,6 +1495,11 @@ def sqrt(x: array, /) -> array: The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component. Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). + + .. warning:: + The choice of the branch cut is considered _provisional_. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should _not_ assume that branch cuts are consistent between implementations. + + Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. Parameters ---------- From 2d88bc6d4986d76fcb958be953f7bab0ee7f1b5d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Nov 2022 02:14:23 -0800 Subject: [PATCH 07/12] Fix formatting --- 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 1bed5fe95..b59431688 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1497,7 +1497,7 @@ def sqrt(x: array, /) -> array: Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). .. warning:: - The choice of the branch cut is considered _provisional_. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should _not_ assume that branch cuts are consistent between implementations. + The choice of the branch cut is considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. From 4f53beb314e43f5d1568a45eac66ae66d7ca67f7 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 21 Nov 2022 00:56:43 -0800 Subject: [PATCH 08/12] Create separate document describing branch cuts and specification conventions --- .../array_api/elementwise_functions.py | 5 +---- spec/design_topics/branch_cuts.rst | 17 +++++++++++++++++ spec/design_topics/index.rst | 1 + 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 spec/design_topics/branch_cuts.rst diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index b59431688..ce415ebd7 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1496,10 +1496,7 @@ def sqrt(x: array, /) -> array: Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). - .. warning:: - The choice of the branch cut is considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. - - Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. + Note: branch cuts have provisional status (see :ref:`branch-cuts`). Parameters ---------- diff --git a/spec/design_topics/branch_cuts.rst b/spec/design_topics/branch_cuts.rst new file mode 100644 index 000000000..6989afbc7 --- /dev/null +++ b/spec/design_topics/branch_cuts.rst @@ -0,0 +1,17 @@ +.. _branch-cuts: + +Branch Cuts +=========== + +In the mathematical field of complex analysis, a **branch cut** is a curve in the complex plane across which an analytic multi-valued function is discontinuous. Branch cuts are often taken as lines or line segments, and the choice of any particular branch cut is a matter of convention. + +For example, consider the function :math:`z^2` which maps a complex number :math:`z` to a well-defined number :math:`z^2`. The function's inverse function :math:`\sqrt{z}` does not, however, map to a single value. For example, for :math:`z = 1`, :math:`\sqrt{1} = \pm 1`. While one can choose a unique principal value for this and similar functions (e.g., in this case, the principal square root is :math:`+1`), choices cannot be made continuous over the whole complex plane, as lines of discontinuity must occur. To handle discontinuities, one commonly adopts branch cuts, which are not, in general, unique. Instead, one chooses a branch cut as a matter of convention in order to give simple analytic properties. + +Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer power, or exponential functions; however, branch cuts do arise for their multi-valued inverses. + +In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. + +.. warning:: + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + + Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. \ No newline at end of file diff --git a/spec/design_topics/index.rst b/spec/design_topics/index.rst index 2729cdbe4..c8c55b3be 100644 --- a/spec/design_topics/index.rst +++ b/spec/design_topics/index.rst @@ -11,5 +11,6 @@ Design topics & constraints device_support static_typing accuracy + branch_cuts C_API parallelism From bfa655431f4c1a8fc42fdc8f8b2b2836e30e7f71 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 21 Nov 2022 00:58:20 -0800 Subject: [PATCH 09/12] Convert text to italtic --- 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 ce415ebd7..8a62074c7 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1496,7 +1496,7 @@ def sqrt(x: array, /) -> array: Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). - Note: branch cuts have provisional status (see :ref:`branch-cuts`). + _Note: branch cuts have provisional status (see :ref:`branch-cuts`)._ Parameters ---------- From 37308655f143f2ea0694c02135a642d298b91d3a Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 21 Nov 2022 01:01:33 -0800 Subject: [PATCH 10/12] Fix markup --- 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 8a62074c7..b1ec63df2 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1496,7 +1496,7 @@ def sqrt(x: array, /) -> array: Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). - _Note: branch cuts have provisional status (see :ref:`branch-cuts`)._ + *Note: branch cuts have provisional status (see :ref:`branch-cuts`).* Parameters ---------- From 8f8395d621096b669c2f42f317bd20f25064a5e6 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 21 Nov 2022 01:05:21 -0800 Subject: [PATCH 11/12] Fix nested directive --- 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 b1ec63df2..bba86f43c 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1496,7 +1496,7 @@ def sqrt(x: array, /) -> array: Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). - *Note: branch cuts have provisional status (see :ref:`branch-cuts`).* + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). Parameters ---------- From c65ffe302c8607a626a8b4ff1e3809b82fe5fbee Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 21 Nov 2022 01:08:34 -0800 Subject: [PATCH 12/12] 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 bba86f43c..90390d9b0 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1490,7 +1490,7 @@ def sqrt(x: array, /) -> array: For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. .. note:: - By convention, the branch cut of square root is the negative real axis :math:`(-\infty, 0)`. + By convention, the branch cut of the square root is the negative real axis :math:`(-\infty, 0)`. The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component.