python中的根查找

时间:2014-06-20 17:39:23

标签: python optimization numpy

编辑:这里的一个大问题是scipy.optimize.brentq要求搜索间隔的限制符号相反。如果你将搜索间隔分成任意部分,并像我在下面那样在每个部分上运行brentq,就像Dan在评论中那样,最终会抛出大量无用的ValueErrors。在Python中有没有一种灵巧的方法来处理它?<​​/ p>

原帖: 我一再在python中搜索函数的最大零点。现在我正在使用scipy.optimize.brentq查找根,然后使用粗暴的搜索方法,如果我的初始边界不起作用:

#function to find the largest root of f
def bigRoot(func, pars):
    try:
        root = brentq(func,0.001,4,pars)
    except ValueError:
        s = 0.1
        while True:
            try:
                root = brentq(func,4-s,4,pars)
                break
            except ValueError:
                s += 0.1
                continue
    return root

这有两个大问题。

首先我假设如果某个区间有多个根,则brentq将返回最大的根。我做了一些简单的测试,我从来没有看到它返回除了最大根之外的任何东西,但我不知道在所有情况下是否都是这样。

第二个问题是在脚本中我使用此函数在某些情况下将始终返回零,即使我传递给bigRoot的函数在0处偏离。如果我改变了搜索的步长在这种情况下,它将返回一个恒定的非零值。我意识到这些细节取决于我传递给bigRoot的函数,但我认为问题可能与我正在进行搜索的方式有关。

问题是,在python中寻找函数最大根的更聪明的方法是什么?


谢谢丹;根据要求提供更多信息。

我正在搜索的功能在我感兴趣的地区表现良好。下面绘制了一个示例(帖子末尾的代码)。

I'd like to find the largest root of this function

唯一的奇点是0(从图的顶部开始的峰值是有限的)并且有两个或三个根。最大的根通常不大于1,但它永远不会像跑到无限远那样。根之间的间隔在域的低端变小,但它们永远不会变得非常小(我会说它们总是大于10 ^ -3)。

from numpy import exp as e
#this isn't the function I plotted
def V(r):
    return  27.2*(
                23.2*e(-43.8*r) + 
                8.74E-9*e(-32.9*r)/r**6 - 
                5.98E-6*e(-0.116*r)/r**4 + 
                0.0529*( 23*e(-62.5*r) - 6.44*e(-32*r) )/r -
                29.3*e(-59.5*r)
            )

#this is the definition of the function in the plot
def f(r,b,E):
    return 1 - b**2/r**2 - V(r)/E

#the plot is of f(r,0.1,0.06)

1 个答案:

答案 0 :(得分:5)

很好的问题,但这是一个数学问题而不是Python问题。

如果没有函数根的解析公式,即使在给定的有限区间内,也无法保证找到该函数的最大根。例如,我可以构建一个函数,当它接近1时,它会在更快和更快的速度之间振荡。

f(x) = sin(1/(1-x))

这会使试图在区间[0,1)上找到最大根的任何数值方法都生硬,因为对于任何根,区间内总是有较大的根。

因此,您必须提供有关相关功能特征的背景信息,以便更深入地了解这一一般问题。

更新:看起来这些功能表现良好。 brentq文档表明无法保证找到区间中最大/最小的根。尝试对区间进行分区,并递归搜索越来越小的其他根。

from scipy.optimize import brentq

# This function should recursively find ALL the roots in the interval
# and return them ordered from smallest to largest.

from scipy.optimize import brentq
def find_all_roots(f, a, b, pars=(), min_window=0.01):
    try:
        one_root = brentq(f, a, b, pars)
        print "Root at %g in [%g,%g] interval" % (one_root, a, b)
    except ValueError:
        print "No root in [%g,%g] interval" % (a, b)
        return [] # No root in the interval

    if one_root-min_window>a:
        lesser_roots = find_all_roots(f, a, one_root-min_window, pars)
    else:
        lesser_roots = []

    if one_root+min_window<b:
        greater_roots = find_all_roots(f, one_root+min_window, b, pars)
    else:
        greater_roots = []

    return lesser_roots + [one_root] + greater_roots

我在你的函数上尝试了这个,它找到了最大的根,在~0.14。

brentq有一些棘手的问题:

print find_all_roots(sin, 0, 10, ())

Root at 0 in [0,10] interval
Root at 3.14159 in [0.01,10] interval
No root in [0.01,3.13159] interval
No root in [3.15159,10] interval
[0.0, 3.141592653589793]

sin函数的根应为0,π,2π,3π。但这种方法只能找到前两个。我意识到问题就在那里in the docs f(a)和f(b)必须有相反的符号。 {{strong>全部似乎{{} 1}}根查找函数具有相同的要求,因此任意划分区间将不起作用。