Scipy寻根方法

时间:2016-05-04 15:53:24

标签: python scipy

我正在编写一个具有数学函数作为属性的类,比如 f

f 是:

  • 在真实细分上定义[-w; + w]
  • 正面并以真实的H
  • 为界
  • even(对于[-w; + w]中的所有x,f(x)= f(-x))和f(w)= f(-w)= 0
  • 与[-w; + w]相区别,其衍生物为正 - 连续[-w; 0]

我的班级看起来像:

from scipy.misc import derivative
from scipy.integrate import quad
from math import cosh, sqrt

class Function(object):

    w = 1.
    PRECISION = 1e-6    

    def f(self, x):
        '''This is an example but f could be 
           any math function matching requirments above.
        '''
        return 0.5+1.07432*(1-cosh(x/1.07432)) 

    def deriv_f(self, x):
        return derivative(self.f, x, self.PRECISION)

    def x_to_arc_length(self, x):
        def func(x): 
            return sqrt(1+self.deriv_f(x)**2)
        return quad(func, -self.w, x)[0]

    def arc_length_to_x(self, L):
        bound = [-self.w, self.w]
        while bound[1]-bound[0] > self.PRECISION:
            mid= sum(bound)/2
            bound[(self.x_to_arc_length(mid)-L > 0)] = mid
        return sum(bound)/2

我使用二分法来反转弧长方法,但我正在考虑将其更改为scipy.optimize根寻找方法之一以获得速度。 我是scipy的新手,必须承认我的数学有点生锈...... Scipy让我可以选择brentqbrenhridderbisectnewton

有人能指出我最适合这种情况的方法吗?或者也许有一个更好的库?

2 个答案:

答案 0 :(得分:2)

我不是Python的专家,但我从数值分析中知道,在你列出的方法中(Brent,bisection,Ridder&#39方法和Newton-Raphson),布伦特的方法是通常优先用于单个实变量 x 的通用实数标量函数 f 。正如您可以阅读here,如果 f 是连续的,并且该方法应用于间隔[a,b],其中 f(a)f(b) < 0,然后布伦特的方法保证收敛到零,就像二分法一样。对于许多表现良好的函数,Brent的方法收敛速度比二分法快得多,但在一些不幸的情况下,它可能需要 N ^ 2 迭代,其中 N 是实现给定容差的二分迭代次数。

另一方面,

Newton's method通常在收敛时比布伦特收敛得快,但有时它根本不收敛。对于相同的功能,牛顿方法可能会或可能不会聚,这也取决于起点和根之间的距离。因此,在通用代码中使用它的风险更高。

关于brentqbrenth之间的选择,it looks like它们应该非常相似,第一个更加严格测试。因此,您可以选择brentq,或者,如果您有时间,可以在它们之间进行一些基准测试。

答案 1 :(得分:2)

根据DeltaIV的回答,我根据上面的例子对不同选项进行了基准测试。

 2000    0.005    0.000   10.395    0.005 diff.py:42(arc_length_to_x_newton)
 2000    0.005    0.000   16.842    0.008 diff.py:36(arc_length_to_x_brenth)
 2000    0.005    0.000   17.141    0.009 diff.py:30(arc_length_to_x_brentq)
 2000    0.005    0.000   26.375    0.013 diff.py:48(arc_length_to_x_ridder)
 2000    0.005    0.000   72.249    0.036 diff.py:54(arc_length_to_x_bisect)

在这种情况下,似乎Newton方法是最快的,可能是因为该函数表现良好(即连续和均匀导数下限为1)。

不收敛的风险(固定点,周期或衍生问题)不适用于上述功能,所以我最终选择newton