我有以下复杂的功能:
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)的复杂根,它位于复平面的第四象限,因为我可以使用scipy.optimize中的newton(),然后将它们存储到一维数组中。我能想出的最好的方法是通过在第四象限的有限部分上以规则间隔的间隔使用newton()来强制它,检查根是否是先前根的副本,检查根是否确实是root,然后将其存储到数组中。一旦该算法完成,我想通过增加实际组件对数组进行排序。我的问题是:
(i)我可以创建一个未定义长度的数组,我可以在找到它们时继续添加值吗?
(ii)我可以用这样的方式绘制函数,以便可视化根部吗?数学表明它们都在复杂平面的一张纸上。
(iii)有没有更好的方法找到根?我觉得我会用我的方法错过很多根域。答案 0 :(得分:1)
一些答案:
(i)使用清单。数组具有固定的大小。附加到列表是一个非常便宜的选择。当您将新根添加到列表中时,请检查前一个根不在列表中,例如,计算np.amin(np.abs(np.array(a)-b))
其中a
是现有根列表,b
是新根。如果此值非常小,则您已到达现有根。 (多小取决于函数。它不能为0.0,因为由于浮点和迭代不准确,你通常不会识别相同的根。)
如果您拥有非常多的根(数千),您可能希望在收到它们后立即对它们进行排序。这使得更快地搜索匹配的根。另一方面,很可能> 90%的时间用于迭代根,而您不必担心其他性能问题。然后你只需编译列表,对它进行排序(列表排序简单快捷)并转换成数组,如果需要的话。
(ii)是的。下面两个例子:(对于countour
的东西,谢谢你属于Warren Weckesser和他非常好的答案!)
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
:
和absval.png
:
请注意,如果要缩放图像,通常需要更改限制并重新计算复杂值z
以避免遗漏细节。图像当然可以相互叠加,图像调色板可以更改,countour
有一百万个选项。如果您只想绘制零,请在[0]
调用中将{5}(轮廓数)替换为countour
(仅绘制列出的轮廓)。
当然,你将用自己的功能替换我的(1-C ^ 2)。唯一需要注意的是,如果函数接收到一个复数数组,它将返回一个以逐点计算的相同形状的结果数组。 Imshow需要接收一系列标量。有关详细信息,请参阅imshow
文档。
(iii)可能有,但没有找到任意函数的所有最小值/最大值/零点的通用方法。 (该函数甚至可能具有无限数量的根。)您首先绘制函数的想法很好。然后你会更容易理解它的行为。
答案 1 :(得分:1)
@ DrV的答案看起来不错,所以这里我只建议另一种方法(ii)
你的问题一种可视化复杂函数根的有用方法
是绘制实部和虚部的0轮廓。也就是说,计算
在合理密集的网格上z = Dm(...)
,然后使用matplotlib
的{{1}}函数
绘制contour
为0且z.real
为零的轮廓。该
函数的根是这些轮廓相交的点。
例如,这里有一些代码可以生成轮廓图。
z.imag
这是情节。红线和蓝线的每个交点都是根。
情节暗示你不应该期望找到大的根 负虚部。您可以查看渐近行为 贝塞尔和汉克尔的函数有大量的论据来证明这一点。