Iva*_*van 27 python numpy scipy complex-numbers
我现在正在使用scipy.integrate.quad来成功整合一些真正的整数.现在出现了我需要整合复杂的被积函数的情况.quad似乎无法做到这一点,因为其他scipy.integrate例程,所以我问:有没有办法使用scipy.integrate集成复杂的被积函数,而不必分离实部和虚部的积分?
dr *_*bob 48
将它分成实部和虚部是什么问题? scipy.integrate.quad需要集成函数返回浮点数(也就是实数)用于它使用的算法.
import scipy
from scipy.integrate import quad
def complex_quadrature(func, a, b, **kwargs):
def real_func(x):
return scipy.real(func(x))
def imag_func(x):
return scipy.imag(func(x))
real_integral = quad(real_func, a, b, **kwargs)
imag_integral = quad(imag_func, a, b, **kwargs)
return (real_integral[0] + 1j*imag_integral[0], real_integral[1:], imag_integral[1:])
Run Code Online (Sandbox Code Playgroud)
例如,
>>> complex_quadrature(lambda x: (scipy.exp(1j*x)), 0,scipy.pi/2)
((0.99999999999999989+0.99999999999999989j),
(1.1102230246251564e-14,),
(1.1102230246251564e-14,))
Run Code Online (Sandbox Code Playgroud)
这是你期望舍入误差 - exp(ix)从0的积分,pi/2是(1/i)(e ^ i pi/2 - e ^ 0)= - i(i - 1)= 1 +我〜(0.99999999999999989 + 0.99999999999999989j).
并且为了记录以防万一并非100%清楚,积分是线性函数,意味着∫{f(x)+ kg(x)} dx =∫f(x)dx +k∫g(x )dx(其中k是相对于x的常数).或者对于我们的具体情况,∫z(x)dx =∫Rez(x)dx +i∫Imz(x)dx as z(x)= Re z(x)+ i Im z(x).
如果您尝试在复平面中的路径(除实轴之外)或复杂平面中的区域进行积分,则需要更复杂的算法.
注意:Scipy.integrate不会直接处理复杂的集成.为什么?它在FORTRAN QUADPACK库中进行了繁重的工作,特别是在qagse.f中,它明确要求函数/变量是真实的,然后在每个子区间内进行基于21点Gauss-Kronrod正交的全局自适应正交,并由Peter加速Wynn的epsilon算法." 因此,除非您想尝试修改底层FORTRAN以使其处理复杂数字,将其编译为新库,否则您无法使其工作.
如果你真的想在一个集成中使用复数的Gauss-Kronrod方法,请查看wikipedias页面并直接实现,如下所示(使用15-pt,7-pt规则).注意,我memoize'd函数重复对公共变量的公共调用(假设函数调用很慢,就好像函数非常复杂).也只做了7点和15点的规则,因为我不想自己计算节点/权重,那些是维基百科上列出的那些,但是在测试用例中得到了合理的错误(~1e-14)
import scipy
from scipy import array
def quad_routine(func, a, b, x_list, w_list):
c_1 = (b-a)/2.0
c_2 = (b+a)/2.0
eval_points = map(lambda x: c_1*x+c_2, x_list)
func_evals = map(func, eval_points)
return c_1 * sum(array(func_evals) * array(w_list))
def quad_gauss_7(func, a, b):
x_gauss = [-0.949107912342759, -0.741531185599394, -0.405845151377397, 0, 0.405845151377397, 0.741531185599394, 0.949107912342759]
w_gauss = array([0.129484966168870, 0.279705391489277, 0.381830050505119, 0.417959183673469, 0.381830050505119, 0.279705391489277,0.129484966168870])
return quad_routine(func,a,b,x_gauss, w_gauss)
def quad_kronrod_15(func, a, b):
x_kr = [-0.991455371120813,-0.949107912342759, -0.864864423359769, -0.741531185599394, -0.586087235467691,-0.405845151377397, -0.207784955007898, 0.0, 0.207784955007898,0.405845151377397, 0.586087235467691, 0.741531185599394, 0.864864423359769, 0.949107912342759, 0.991455371120813]
w_kr = [0.022935322010529, 0.063092092629979, 0.104790010322250, 0.140653259715525, 0.169004726639267, 0.190350578064785, 0.204432940075298, 0.209482141084728, 0.204432940075298, 0.190350578064785, 0.169004726639267, 0.140653259715525, 0.104790010322250, 0.063092092629979, 0.022935322010529]
return quad_routine(func,a,b,x_kr, w_kr)
class Memoize(object):
def __init__(self, func):
self.func = func
self.eval_points = {}
def __call__(self, *args):
if args not in self.eval_points:
self.eval_points[args] = self.func(*args)
return self.eval_points[args]
def quad(func,a,b):
''' Output is the 15 point estimate; and the estimated error '''
func = Memoize(func) # Memoize function to skip repeated function calls.
g7 = quad_gauss_7(func,a,b)
k15 = quad_kronrod_15(func,a,b)
# I don't have much faith in this error estimate taken from wikipedia
# without incorporating how it should scale with changing limits
return [k15, (200*scipy.absolute(g7-k15))**1.5]
Run Code Online (Sandbox Code Playgroud)
测试用例:
>>> quad(lambda x: scipy.exp(1j*x), 0,scipy.pi/2.0)
[(0.99999999999999711+0.99999999999999689j), 9.6120083407040365e-19]
Run Code Online (Sandbox Code Playgroud)
我不相信错误估计 - 当从[-1到1]进行积分时,我从维基中获取了一些建议的误差估计,这些值对我来说似乎不合理.例如,上面的误差与真相相比是~5e-15而不是1e-19.我敢肯定,如果有人咨询过num食谱,你可以得到更准确的估计.(可能需要通过(a-b)/2一些功率或类似的功能).
回想一下,python版本不如仅仅两次调用scipy的基于QUADPACK的集成那么准确.(如果需要,你可以改进它).
我知道我参加晚会很晚,但是也许四倍(我的一个项目)可以提供帮助。这个
import quadpy
import scipy
scheme = quadpy.line_segment.gauss_kronrod(3)
val = scheme.integrate(lambda x: scipy.exp(1j*x), [0, 1])
print(val)
Run Code Online (Sandbox Code Playgroud)
正确给出
(0.841470984807897+0.4596976941318605j)
Run Code Online (Sandbox Code Playgroud)
除了gauss_kronrod(3),您可以使用任何其他可用方案。
| 归档时间: |
|
| 查看次数: |
18148 次 |
| 最近记录: |