如何找到没有解析解的方程的复根?

huangapple go评论71阅读模式
英文:

How to find complex roots of an equation without analytical solution?

问题

我有一个复杂的函数```f```,它用函数表示如下

```python
from sympy import *

def alpha(n, rho, l):
    return n**2 + (2*rho + 2)*n + 2*rho + 1

def beta(n, rho, l):
    return -(2*n**2 + (8*rho + 2)*n + 8*rho**2 + 4*rho + l*(l+1) -3)

def gamma(n, rho, l):
    return n**2 + 4*rho*n + 4*rho**2 - 4

利用这些函数,我离散化了一个特定的连分数:

def ContinuedFrac(n, rho, l):
    cf = 0
    for i in reversed(range(1,n+1)):
        cf = cf + beta(i, rho, l)/alpha(i, rho, l)
        cf = (-gamma(i, rho, l)/alpha(i, rho, l)) / cf
    return cf

最后,我组装了要解的方程:

omega = symbols("ω")
n = 5
rho_guess = -I*omega
l=2

f = ContinuedFrac(n, rho_guess, l) + beta(0, rho_guess, l)/alpha(0, I*omega, l)

我的目标是解出变量omega的函数f,以找到复数根,例如(0.7473, -0.1779)。问题是这个函数似乎没有解析解,但有无穷多个数值根。

我尝试使用lambdify函数解决它,但是使用它们时,我需要提供一个初始值,我想知道是否可以直接找到函数f的多个omega根的列表。

以下是我尝试做的事情。它可以工作,但我只能根据特定的初始值找到一个函数。

import mpmath as mp

omega = symbols("ω")

def findomega(n, rho_guess, l):
    return lambdify(omega, ContinuedFrac(n, rho_guess, l) + beta(0, rho_guess, l)/alpha(0, rho_guess , l))

f = findomega(15, -I*omega, 3)
mp.findroot(f, 1.16-0.56j)

输出: mpc(real='1.1652715765041771', imag='-0.56260091739349236')
英文:

I have a complex function f which is given in terms of functions:

from sympy import *

def alpha(n, rho, l):
    return n**2 + (2*rho + 2)*n + 2*rho + 1

def beta(n, rho, l):
    return -(2*n**2 + (8*rho + 2)*n + 8*rho**2 + 4*rho + l*(l+1) -3)

def gamma(n, rho, l):
    return n**2 + 4*rho*n + 4*rho**2 - 4

With these functions I discretize a certain continued fraction:

def ContinuedFrac(n, rho, l):
    cf = 0
    for i in reversed(range(1,n+1)):
        cf = cf + beta(i, rho, l)/alpha(i, rho, l)
        cf = (-gamma(i, rho, l)/alpha(i, rho, l)) / cf
    return cf

And finally, I assemble the equation to be solved:

omega = symbols("ω")
n = 5
rho_guess = -I*omega
l=2

f = ContinuedFrac(n, rho_guess, l) + beta(0, rho_guess, l)/alpha(0, I*omega, l)

My goal is to solve the function f for the variable omega in order to find the complex roots, for example (0.7473, -0.1779). The problem is that this function does not apparently have an analytic solution, but has infinite numerical roots.

I tried to solve it using the lambdfy function, but with them, I need to give an initial value and I would like to know if it is possible to directly find a list with several omega roots of the function f.

Below is what I tried to do. It works, but I only find a function according to a certain initial value.

import mpmath as mp

omega = symbols("ω")

def findomega(n, rho_guess, l):
    return lambdify(omega, ContinuedFrac(n, rho_guess, l) + beta(0, rho_guess, l)/alpha(0, rho_guess , l))

f = findomega(15, -I*omega, 3)
mp.findroot(f, 1.16-0.56j)

output: mpc(real='1.1652715765041771', imag='-0.56260091739349236')

答案1

得分: 2

... and I would like to know if it is possible to directly find a list with several omega roots of the function f.

不能直接找到函数 f 的多个 omega 根,但是通过一些努力,你可以接近实现它。下面是我的方法...

我将使用 Sympy 绘图后端 模块,特别是 plot_complex 函数创建一种领域着色图。对于这种特殊情况,我选择了一个黑白色彩方案,突出显示零点(黑色)和极点(白色)。

from spb import plot_complex

n = 5
l = 2
f = ContinuedFrac(n, rho_guess, l) + beta(0, rho_guess, l)/alpha(0, I*omega, l)
plot_complex(
    f, (omega, -2-2j, 2+2j),
    grid=False, coloring="k", n=500
)

如何找到没有解析解的方程的复根?

所以,黑点是零点,白点是极点(通常来说,白点是幅度较高的区域。在这种特殊情况下,它们是极点)。通过这张图片,你可以轻松提取用于零点的初始猜测,并使用 sympy 的 nsolve 找到数值根。例如:

nsolve(f, omega, 0.54-0.1j)
# 输出: 0.533191990477995−0.100182203167779𝑖

使用这种特定的颜色方案,我相信你可以轻松编写一个函数来定位图像上最暗的点,以自动提取初始猜测并将其提供给 nsolve。例如:

p = plot_complex(...)
xx, yy, _, _, img, _ = p[0].get_data()

# 从图像中提取零点的过程。例如:
# 1. `img` 是一个黑白 RGB 数组(n x m x 3)。将其转换为
#    灰度数组(n x m),因此每个元素都表示灰度值。
#    0=黑色,1=白色,...
# 2. 增加图像的对比度(你可以使用 PIL):这会使浅灰色区域变成白色,而深灰色区域变成黑色。
# 3. 对黑色级别运行聚类算法:这将找到
#    图像坐标中黑点的中心。
# 4. 将中心点转换为数据坐标(你可以使用图像的 x
#    和 y 范围)。
# 5. 将数据坐标中的中心点用作 nsolve 的初始猜测。

这就由你来尝试了 如何找到没有解析解的方程的复根?

由于你似乎有兴趣通过改变 nl 来研究这个函数,我还会使用绘图模块的交互功能创建一个滑动窗口,以便可以轻松移动/缩放到绘图中感兴趣的区域。

如果你能以 SymPy 的 Sum 重新编写你的函数,那么在绘图函数中声明它们为参数,可以快速使用小部件更改它们的值(例如,对于整数值,可以使用 ipywidgets.BoundedIntText,它会呈现为一个微调器)。

%matplotlib widget
from spb import plot_complex, prange

n = 5
l = 2
f = ContinuedFrac(n, rho_guess, l) + beta(0, rho_guess, l)/alpha(0, I*omega, l)

# 绘图的滑动窗口:中心 x,中心 y,宽度,高度
cx, cy, w, h = symbols("cx, cy, w, h")

plot_complex(
    f, prange(omega, (cx - w / 2) + (cy - h / 2)*I, (cx + w / 2) + (cy + h / 2)*I),
    grid=False, coloring="k", n=500,
    params={
        cx: (0, -5, 5),
        cy: (0, -5, 5),
        w: (4, 0, 10),
        h: (4, 0, 10),
    }
)
英文:

> ... and I would like to know if it is possible to directly find a list with several omega roots of the function f.

Not directly, but with a bit of effort you could get close to it. Here is how I would do it...

I'm going to use the Sympy Plotting Backend module, in particular the plot_complex function to create some kind of domain coloring plot. For this particular case, I'm choosing a black and white color scheme highlighting the zeros (black) and poles (white).

from spb import plot_complex

n = 5
l = 2
f = ContinuedFrac(n, rho_guess, l) + beta(0, rho_guess, l)/alpha(0, I*omega, l)
plot_complex(
    f, (omega, -2-2j, 2+2j),
    grid=False, coloring="k", n=500
)

如何找到没有解析解的方程的复根?

So, black spots are zeros, white spots are poles (in general, white spots are zones of higher magnitude. In this particular case, it happens that they are poles).
From this picture you can easily extract initial guesses for the zeros, and use sympy's nsolve to find the numerical root. For example:

nsolve(f, omega, 0.54-0.1j)
# out: 0.533191990477995−0.100182203167779𝑖

Using this particular color scheme, I believe one could easily write a function to locate the darkest spots on the image, in order to automatically extract initial guesses and provide them to nsolve. For example:

p = plot_complex(...
xx, yy, _, _, img, _ = p[0].get_data()

# your procedure to extract zeros from img. For example:
# 1. `img` is a black and white RGB array (n x m x 3). Convert it to
#    a grey scale array (n x m), so each element gives the grey value.
#    0=black, 1=white, ...
# 2. Increase the contrast of the image (you can use PIL): this
#    makes the light-grey areas become white, and dark grey areas
#    become black.
# 3. Run a clustering algorithm on black levels: this will find
#    the centers of the black spots in image coordinates.
# 4. Convert the centers in data coordinates (you can use the x
#    and y extent of the image).
# 5. Use the centers in data coordinates as initial guesses
#    for nsolve.

That's for your to try 如何找到没有解析解的方程的复根?

Since it appears that you are interested in studying the function by varying n and l, I would also use the interactive capabilities of the plotting module to create a sliding window so that I can easily move/zoom around the interested region of the plot.

If you are somehow able to rewrite your function using SymPy's Sum, it would also be possible to use symbolic n and l, declare them as parameters in the plotting function, in order to quickly change their values with a widget (for example, ipywidgets.BoundedIntText which would render as a spinner for integer values).

%matplotlib widget
from spb import plot_complex, prange

n = 5
l = 2
f = ContinuedFrac(n, rho_guess, l) + beta(0, rho_guess, l)/alpha(0, I*omega, l)

# sliding window of the plot: center x, center y, width, height
cx, cy, w, h = symbols("cx, cy, w, h")

plot_complex(
    f, prange(omega, (cx - w / 2) + (cy - h / 2)*I, (cx + w / 2) + (cy + h / 2)*I),
    grid=False, coloring="k", n=500,
    params={
        cx: (0, -5, 5),
        cy: (0, -5, 5),
        w: (4, 0, 10),
        h: (4, 0, 10),
    }
)

huangapple
  • 本文由 发表于 2023年6月12日 10:16:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76453302.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定