scipy求根方法

Jac*_*din 4 python scipy

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

f是:

  • 定义在实数段上 [-w;+w]
  • 正数且以上界为实数 H
  • 偶数(对于 [-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
Run Code Online (Sandbox Code Playgroud)

我使用二分法来反转弧长方法,但我正在考虑更改此方法以使用一种scipy.optimize求根方法来提高速度。我是 scipy 的新手,必须承认我的数学有点生锈了...Scipy 让我在brentqbrenhridderbisect之间进行选择newton

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

Del*_*aIV 5

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

另一方面,牛顿法收敛时通常比布伦特法收敛得更快,但也有根本不收敛的情况。对于相同的函数,牛顿法可能会也可能不会收敛,这也取决于起点和根之间的距离。因此,在通用代码中使用它的风险更大。

brentq关于和 之间的选择brenth看起来它们应该非常相似,第一个经过了更严格的测试。因此,您可以选择brentq,或者,如果您有时间,可以在它们之间进行一些基准测试。

  • 我可以确认这是我迄今为止的经历。我还没有对牛顿与布伦特进行足够的测试,但布伦特似乎足够快并且收敛。 (2认同)