Правда обратная функция для косинуса в numpy? (НЕ арккос) - PullRequest
3 голосов
/ 04 апреля 2020

Вот странный пример:

Мне понадобилась функция numpy, которую я бы назвал истинной инверсией np.cos (или другой функцией тригонометрии c, используется косинус здесь для определенности). Под истинным обратным я подразумеваю функцию invcos, такую, что

np.cos(invcos(x)) = x

для любого реального числа с плавающей запятой x. Два наблюдения: invcos(x) существует (это сложное число с плавающей точкой) и np.arccos(x) выполняет , а не выполняет свою работу, потому что это работает только для -1 < x < 1.

Мой вопрос есть ли эффективная функция numpy для этой операции или если она может быть легко построена из существующих?

Я пытался использовать комбинацию np.arccos и np.arccosh для построения функция от руки. Это основано на наблюдении, что np.arccos может иметь дело с x в [-1,1], а np.arccosh может иметь дело с x вне [-1,1], если умножить на комплексную единицу. Чтобы убедиться, что это работает:

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 даже говорит мне, что мой алгоритм неэффективен, он, вероятно, неэффективен. Есть ли лучший способ сделать это?


Для читателей, которые интересуются, почему эта странная функция может быть полезна: мотивация исходит из физики. В некоторых теориях можно иметь векторные компоненты, находящиеся вне оболочки, что означает, что компоненты могут быть даже длиннее, чем вектор. Приведенная выше функция может быть полезна для параметризации вещей в терминах углов.

1 Ответ

2 голосов
/ 05 апреля 2020

У меня вопрос: есть ли эффективная функция numpy для этой операции или она может быть легко построена из существующих?

Да; это ... np.arccos.

Из документации:

Для вещественных типов входных данных arccos всегда возвращает реальный вывод. Для каждого значения, которое не может быть выражено как действительное число или бесконечность, он возвращает nan и устанавливает недопустимый флаг ошибки с плавающей запятой.

Для входных данных со сложным значением arccos - это комплексная функция analyti c, имеющая ответвление обрезает [-inf, -1] и [1, inf] и непрерывно сверху на первом и снизу на втором.

Так что все, что нам нужно сделать, это убедиться, что ввод комплексное число (даже если его мнимая часть равна нулю):

>>> 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]])
...