numpy 中余弦的真反函数? (不是 arccos)

True inverse function for cosine in numpy? (NOT arccos)

这是一个奇怪的:

我发现自己需要一个 numpy 函数,我称之为 np.cos 的真反函数(或另一个三角函数,这里使用余弦来确定)。我所说的“'true inverse'”是一个函数invcos,这样

np.cos(invcos(x)) = x

对于任何实数浮点数 x。两个观察结果:invcos(x) 存在(它是一个复杂的浮点数)并且 np.arccos(x) 确实 而不是 完成这项工作,因为它只适用于 -1 < x < 1.

我的问题是这个操作是否有一个有效的 numpy 函数,或者它是否可以从现有的函数轻松构建?

我的尝试是结合使用 np.arccosnp.arccosh 来手动构建函数。这是基于 np.arccos 可以处理 [-1,1] 内的 x 并且 np.arccosh 可以处理 [-1,1] 外的 x 如果一个乘以复数单位的观察。看看这是否有效:

cos_x = np.array([0.5, 1., 1.5])

x = np.arccos(cos_x)
cos_x_reconstucted = np.cos(x)
# [0.5 1.  nan]

x2 = 1j*np.arccosh(cos_x)
cos_x_reconstructed2 = np.cos(x2)
# [nan+nanj 1.-0.j 1.5-0.j]

所以我们可以将其合并为

def invcos(array):
    x1 = np.arccos(array)
    x2 = 1j*np.arccosh(array)
    print(x1)
    print(x2)
    x = np.empty_like(x1, dtype=np.complex128)
    x[~np.isnan(x1)] = x1[~np.isnan(x1)]
    x[~np.isnan(x2)] = x2[~np.isnan(x2)]
    return x

cos_x = np.array([0.5, 1., 1.5])
x = invcos(cos_x)
cos_x_reconstructed = np.cos(x)
# [0.5-0.j 1.-0.j 1.5-0.j]

这给出了正确的结果,但自然会引发 RuntimeWarnings:

RuntimeWarning: invalid value encountered in arccos.

我想既然 numpy 甚至告诉我我的算法效率不高,那么它可能效率不高。有更好的方法吗?


对于对为什么这个奇怪的功能可能有用感兴趣的读者:动机来自物理学背景。在某些理论中,向量分量可以是 'off-shell',这意味着分量甚至可能比向量更长。上面的函数对于根据角度对事物进行参数化仍然很有用。

My question is if there is an efficient numpy function for this operation or if it can built from existing ones easily?

是;它是... np.arccos.

来自文档:

For real-valued input data types, arccos always returns real output. For each value that cannot be expressed as a real number or infinity, it yields nan and sets the invalid floating point error flag.

For complex-valued input, arccos is a complex analytic function that has branch cuts [-inf, -1] and [1, inf] and is continuous from above on the former and from below on the latter.

所以我们需要做的就是确保输入是一个复数(即使它的虚部为零):

>>> import numpy as np
>>> np.arccos(2.0)
__main__:1: RuntimeWarning: invalid value encountered in arccos
nan
>>> np.arccos(2 + 0j)
-1.3169578969248166j

对于数组,我们需要合适的dtype:

>>> np.arccos(np.ones((3,3)) * 2)
array([[nan, nan, nan],
       [nan, nan, nan],
       [nan, nan, nan]])
>>> np.arccos(np.ones((3,3), dtype=np.complex) * 2)
array([[0.-1.3169579j, 0.-1.3169579j, 0.-1.3169579j],
       [0.-1.3169579j, 0.-1.3169579j, 0.-1.3169579j],
       [0.-1.3169579j, 0.-1.3169579j, 0.-1.3169579j]])