data-apis / array-api

RFC document, tooling and other content related to the array API standard
https://data-apis.github.io/array-api/latest/
MIT License
219 stars 49 forks source link

RFC: add `cbrt` #590

Open steff456 opened 1 year ago

steff456 commented 1 year ago

This RFC requests to include a new API in the array API specification for the purpose of computing the cube root.

Overview

Based on array comparison data, the API is available in the majority of libraries in the PyData ecosystem.

The Array API Specification currently includes pow and sqrt, but does not include the IEEE 754 function cbrt.

While the cube root could be implemented in terms of pow, this is not desirable as the rational 1/3 is not typically equal to 1.0/3.0 due to limited floating-point precision. Cube root implementations are generally more accurate than the equivalent operation via pow.

Prior art

Proposal:

def cbrt(x: array, /) -> array

cc @kgryte

asmeurer commented 1 year ago

It looks like the NumPy cbrt doesn't support complex arguments.

Presumably for a floating-point negative argument cbrt should return a real negative number, but for a complex real negative argument it should return the principle cube root (if we add complex support).

kgryte commented 1 year ago

Complex cube root is tricky (see https://github.com/JuliaLang/julia/issues/36534). My initial sense is that we'd want to leave unspecified if complex dtypes are supported.

asmeurer commented 1 year ago

Even without implementing the complex version there's still the fact that cbrt(-1) returning -1 is a non-principle cube root (differing from power):

>>> np.power(-1, 1/3)
<stdin>:1: RuntimeWarning: invalid value encountered in power
nan
>>> np.cbrt(-1)
-1.0
kgryte commented 1 year ago

Agreed. For negative reals, cbrt should return a negative real number. And thanks for highlighting a key limitation of power.

asmeurer commented 1 year ago

I don't really see it as a limitation. There are very good reasons for power to return principle roots, even if that means returning nan instead of a real value for noncomplex floating-point inputs.

Of course, sometimes you do want a real cube root. And it seems that that's the C standard for what cbrt does, so we should definitely do that.

I agree that omitting an extension to complex numbers is probably best because that would require choosing between either returning different values for negative reals, or using a non-principle branch cut, and both seem problematic. Maybe worth bringing up in a consortium meeting though.

kgryte commented 8 months ago

Linking to a (closed) feature request on PyTorch: https://github.com/pytorch/pytorch/issues/25766