Хранение корней сложной функции в массиве в SciPy

#python #numpy #scipy #complex-numbers #equation-solving

#python #numpy #scipy #комплексные числа #решение уравнений

Вопрос:

У меня есть сложная функция ниже:

  import numpy as np
 import scipy as sp
 from scipy.special import jv, hankel1, jvp, h1vp, h2vp, gamma

 nr = 2
 m = 20

 def Dm(x):
     return nr * jvp(m,nr*x,1) * hankel1(m,x) - jv(m,nr*x) * h1vp(m,x,1)
  

Я ищу, чтобы найти столько комплексных корней Dm (x), которые лежат в 4-м квадранте комплексной плоскости, сколько смогу, используя newton() из scipy.optimize, а затем сохранить их в одномерный массив. Лучший метод, который я могу придумать, — это перебирать его с помощью newton() с регулярными интервалами через конечную часть 4-го квадранта, проверить, является ли корень дубликатом предыдущего корня, проверить, действительно ли корень является корнем, а затем сохранить его в массив. Как только этот алгоритм завершится, я хочу отсортировать массив путем увеличения реальных компонентов. Мои вопросы:

(i) Могу ли я создать массив неопределенной длины, к которому я могу продолжать добавлять значения по мере их нахождения?

(ii) Могу ли я построить функцию таким образом, чтобы я мог визуализировать корни? Математика говорит, что все они находятся на одном листе комплексной плоскости.

(iii) Есть ли лучший метод поиска корней? Я чувствую, что с моим методом я пропущу много корней в домене.

Ответ №1:

Некоторые ответы:

(i) использовать список. Массивы имеют фиксированный размер. Добавление в список — очень дешевый вариант. Когда вы добавляете новый корень в список, убедитесь, что предыдущий корень отсутствует в списке, например, вычисляя np.amin(np.abs(np.array(a)-b)) , где a находится список существующих корней и b является новым корнем. Если это значение очень мало, вы попали в существующий корень. (Насколько мал, зависит от функции. Оно не может быть 0.0, так как тогда вы обычно не распознаете один и тот же корень из-за неточностей с плавающей запятой и итерации.)

Если у вас очень большое количество корней (тысячи), вы можете захотеть отсортировать их, как только вы их получите. Это ускоряет поиск соответствующих корней. С другой стороны, скорее всего, > 90% времени тратится на итерацию корней, и вам не нужно беспокоиться о других проблемах с производительностью. Затем вы просто компилируете список, сортируете его (сортировка списка проста и быстра) и преобразуете в массив, если вам нужно.

(ii) Да. Два примера ниже: (За countour материал спасибо Уоррену Векессеру и его очень хороший ответ!)

 import numpy as np
from scipy.special import jv, hankel1, jvp, h1vp
import matplotlib.pyplot as plt


nr = 2
m = 20

# create a 2000 x 2000 sample complex plane between -2-2i ..  2 2i
x = np.linspace(-2, 2, 2000)
y = np.linspace(-2, 2, 2000)
X, Y = np.meshgrid(x, y)
C = X   1j * Y 
z = 1-C**2

# draw a contour image of the imaginary part (red) and real part (blue)
csr = plt.contour(x, y, z.real, 5, colors='b')
plt.clabel(csr)
csi = plt.contour(x, y, z.imag, 5, colors='r')
plt.clabel(csi)
plt.axis('equal')
plt.savefig('contours.png')

# draw an image of the absolute value of the function, black representing zeros
plt.figure()
plt.imshow(abs(z), extent=[-2,2,-2,2], cmap=plt.cm.gray)
plt.axis('equal')
plt.savefig('absval.png')
  

Это дает countours.png :

Количество 1-C ^ 2

и absval.png :

Абсолютное значение 1-C ^ 2

Обратите внимание, что если вы хотите увеличить изображения, обычно необходимо изменить пределы и пересчитать комплексные значения z , чтобы избежать пропущенных деталей. Изображения, конечно, могут быть нанесены друг на друга, цветовая палитра изображения может быть изменена, countour имеет миллион вариантов. Если вы хотите рисовать только нули, замените число 5 (количество контуров) на [0] (отображать только указанный контур) в countour вызовах.

Конечно, вы замените my (1-C ^ 2) своей собственной функцией. Единственное, о чем нужно позаботиться, это то, что если функция получает массив комплексных чисел, она возвращает массив результатов в той же форме, вычисленной точечно. Imshow должен получить массив скаляров. Для получения дополнительной информации, пожалуйста, обратитесь к imshow документации.

(iii) Могут быть, но нет общих методов для нахождения всех минимумов / максимумов / нулей произвольных функций. (Функция может даже иметь бесконечное количество корней.) Ваша идея первого построения функции — хорошая. Тогда вам будет легче понять ее поведение.

Комментарии:

1. Быстрый вопрос: в этом процессе метод Ньютона обречен на неудачу бесчисленное количество раз. Есть ли способ проигнорировать ошибку и продолжить выполнение скрипта? Моя программа останавливается, как только появляется ошибка «не удалось сойтись».

2. Конечно, если вы получаете исключение, используйте предложение python try /except . (Поиск в Google или поиск на этом сайте даст вам много примеров.)

Ответ №2:

ответ @DrV выглядит хорошо, поэтому здесь я предложу только другой подход к части (ii) вашего вопроса. Полезным способом визуализации корней сложной функции является построение 0 контуров действительной и мнимой частей. То есть вычислите z = Dm(...) на достаточно плотной сетке, а затем используйте matplotlib contour функцию ‘s для построения контуров, где z.real 0, а где z.imag ноль. Корни функции — это точки, в которых эти контуры пересекаются.

Например, вот некоторый код, который генерирует график контуров.

 import numpy as np
from scipy.special import jv, hankel1, jvp, h1vp
import matplotlib.pyplot as plt


nr = 2
m = 20

def Dm(x):
    return nr * jvp(m,nr*x,1) * hankel1(m,x) - jv(m,nr*x) * h1vp(m,x,1)


x = np.linspace(0, 40, 2500)
y = np.linspace(-15, 5, 2000)
X, Y = np.meshgrid(x, y)
z = Dm(X   1j*Y)

plt.contour(x, y, z.real, [0], colors='b', lw=0.25)
plt.contour(x, y, z.imag, [0], colors='r', lw=0.25)
plt.savefig('contours.png')
  

Вот сюжет. Каждое пересечение красной и синей линий является корнем.

контуры

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

Комментарии:

1. Очень хорошее решение, которое я упустил из виду. Я отредактировал это в свой ответ для полноты (и постараюсь отдать вам должное!).