我正在编写一个具有数学函数作为属性的类,比如 f 。
f 是:
我的班级看起来像:
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让我可以选择brentq
,brenh
,ridder
,bisect
和newton
。
有人能指出我最适合这种情况的方法吗?或者也许有一个更好的库?
答案 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通常在收敛时比布伦特收敛得快,但有时它根本不收敛。对于相同的功能,牛顿方法可能会或可能不会聚,这也取决于起点和根之间的距离。因此,在通用代码中使用它的风险更高。
关于brentq
和brenth
之间的选择,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
。