使用SciPy集成返回矩阵或数组的函数

时间:2013-06-12 16:10:05

标签: python matrix numpy scipy numerical-integration

我有一个符号数组,可以表示为:

from sympy import lambdify, Matrix

g_sympy = Matrix([[   x,  2*x,  3*x,  4*x,  5*x,  6*x,  7*x,  8*x,   9*x,  10*x],
                  [x**2, x**3, x**4, x**5, x**6, x**7, x**8, x**9, x**10, x**11]])

g = lambdify( (x), g_sympy )

因此,对于每个x,我得到一个不同的矩阵:

g(1.) # matrix([[  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.],
      #         [  1.,   1.,   1.,   1.,   1.,   1.,   1.,   1.,   1.,   1.]])
g(2.) # matrix([[  2.00e+00,   4.00e+00,   6.00e+00,   8.00e+00,   1.00e+01, 1.20e+01,   1.40e+01,   1.60e+01,   1.80e+01,   2.00e+01],
      #         [  4.00e+00,   8.00e+00,   1.60e+01,   3.20e+01,   6.40e+01, 1.28e+02,   2.56e+02,   5.12e+02,   1.02e+03,   2.05e+03]])

等等......

我需要在g上数x进行数字整合,比如from 0. to 100.(在实际情况下,积分没有确切的解决方案),在我目前的方法中,我必须lambdify g中的每个元素并单独集成。我使用quad进行元素整合,如:

ans = np.zeros( g_sympy.shape )
for (i,j), func_sympy in ndenumerate(g_sympy):
    func = lambdify( (x), func_sympy)
    ans[i,j] = quad( func, 0., 100. )

这里有两个问题: 1)lambdify多次使用 2)for loop ;我相信第一个是瓶颈,因为g_sympy矩阵最多有10000个术语(这对for循环来说不是什么大问题。)

如上所示lambdify允许评估整个矩阵,所以我想:“有没有办法整合整个矩阵?”

scipy.integrate.quadrature有一个参数vec_func给了我希望。我期待的是:

g_int = quadrature( g, x1, x2 )

获得完全集成的矩阵,但它给出ValueError:矩阵必须是2维


编辑:我正在尝试quadv使用"python curved_beam_mrs.py"can apparently be done in Matlab

真实案例has already been discussed for SciPy

要运行它,您需要:

  • numpy的
  • SciPy的
  • matplotlib
  • sympy

运行:TODO

您将看到该过程已经很慢,主要是因为文件curved_beam.py中的TODO指示的集成。

如果您删除文件curved_beam_mrs.pyprint.txt后面显示的评论,则会慢得多。

集成的函数矩阵显示在{{1}}文件中。

谢谢!

5 个答案:

答案 0 :(得分:6)

quadquadrature的第一个参数必须是可调用的。 vec_func的{​​{1}}参数指的是此可调用的参数是否是(可能是多维的)向量。从技术上讲,您可以quadrature vectorize本身:

quad

但这恰好等同于>>> from math import sin, cos, pi >>> from scipy.integrate import quad >>> from numpy import vectorize >>> a = [sin, cos] >>> vectorize(quad)(a, 0, pi) (array([ 2.00000000e+00, 4.92255263e-17]), array([ 2.22044605e-14, 2.21022394e-14])) 元素的显式循环。具体来说,它不会给你任何性能提升,如果这是你所追求的。所以,总而言之,问题是为什么以及你究竟想要在这里实现什么。

答案 1 :(得分:3)

在实际情况下,积分没有精确的解,你的意思是奇点吗?你能更准确地说明它,以及你希望整合的矩阵的大小。我不得不承认,当谈到某些事情时,情绪非常缓慢(不确定整合是否属于它的一部分,但我更愿意远离同情并坚持使用numpy解决方案)。你想通过矩阵或更快的矩阵来获得更优雅的解决方案吗?

-note:显然我不能在你的帖子上添加评论来询问这些内容,所以我不得不将这个帖子作为答案发布,也许这是因为我没有足够的声誉? -

编辑:这样的事情?

    import numpy
    from scipy.integrate import trapz
    g=lambda x: numpy.array([[x,2*x,3*x],[x**2,x**3,x**4]])
    xv=numpy.linspace(0,100,200)
    print trapz(g(xv))

已经看到你要整合诸如sum(a * sin(bx + c)^ n * cos(dx + e)^ m)之类的东西,用于a,b,c,d,e的不同系数,嗯,我建议分析地做所有这些。 (应该有一些公式,因为你可以将sin重写为复指数

我在检查那些功能时更加注意的另一件事是sin(a * x + pi / 2)和sin(a * x + pi)以及类似的东西可以用某种方式重写为cos或sin删除pi / 2或pi。 我所看到的只是通过查看函数矩阵中的第一个元素:

a*sin(bx+c)^2+d*cos(bx+c)^2 = a*(sin^2+cos^2)+(d-a)*cos(bx+c)^2 = a+(d-a)*cos(bx+c)^2 

这也简化了计算。如果你的公式没有涉及大量的txtfile左右,那么id检查你需要整合的最通用公式是什么,但我想它的东西就像一个* sin ^ n(bx + c)* cos ^ m(dx + e),m和n为0 1或2,这些东西可以简化为可以分析整合的东西。因此,如果您发现了最常用的分析功能,您可以轻松制作类似

的内容
f=lambda x: [[s1(x),s2(x)],[s3(x),s4(x)]]
res=f(x2)-f(x1)

其中s1(x)等只是函数的分析集成版本?

(并没有真正计划通过你的整个代码来看看其他所有的代码,但是它只是将这些函数集成到txt文件中,从a到b或类似的东西?或者是否有类似于你所采取的某些东西每个函数的平方或任何可能会破坏分析的可能性的东西?)

这应该简化你的积分我猜?

first integral和:第二个

嗯,第二个链接不起作用,但你从第一个想法得到了想法

编辑,因为您不需要分析解决方案: 改善仍然是摆脱同情:

from sympy import sin as SIN
from numpy import sin as SIN2
from scipy.integrate import trapz
import time
import numpy as np

def integrand(rlin):
    first=np.arange(1,11)[:,None]
    second=np.arange(2,12)[:,None]
    return np.vstack((rlin*first,np.power(rlin,second)))

def simpson2(func,a,b,num):
    a=float(a)
    b=float(b)
    h=(b-a)/num
    p1=a+h*np.arange(1,num,2)
    p2=a+h*np.arange(2,num-1,2)
    points=np.hstack((p1,p2,a,b))
    mult=np.hstack((np.repeat(4,p1.shape[0]),np.repeat(2,p2.shape[0]),1,1))
    return np.dot(integrand(points),mult)*h/3


A=np.linspace(0,100.,200)

B=lambda x: SIN(x)
C=lambda x: SIN2(x)

t0=time.time()
D=simpson2(B,0,100.,200)
print time.time()-t0
t1=time.time()
E=trapz(C(A))
print time.time()-t1

    t2=time.time()
    F=simpson2(C,0,100.,200)
    print time.time()-t2

结果:

0.000764131546021 sec for the faster method, but when using sympy

7.58171081543e-05 sec for my slower method, but which uses numpy

0.000519037246704 sec for the faster method, when using numpy, 

结论:使用numpy,ditch sympy,(在这种情况下,我的慢numpy方法实际上更快,因为在这个例子中我只在一个sin函数上尝试它,而不是在它们的ndarray上,但是放弃点当比较快速方法的numpy版本的时间与更快方法的sympy版本的时间时,仍然存在同情心。

答案 2 :(得分:3)

矢量化梯形和辛普森的积分规则。梯形只是从另一个使用logspace而不是linspace的项目中复制和粘贴,以便它可以使用非均匀网格。

def trap(func,a,b,num):
    xlinear=np.linspace(a,b,num)
    slicevol=np.diff(xlinear)
    output=integrand(xlinear)
    output=output[:,:-1]+output[:,1:]
    return np.dot(output,slicevol)/2

def simpson(func,a,b,num):
    a=float(a)
    b=float(b)
    h=(b-a)/num

    output=4*np.sum(integrand(a+h*np.arange(1,num,2)),axis=1)
    output+=2*np.sum(integrand(a+h*np.arange(2,num-1,2)),axis=1)
    output+=np.sum(integrand(b),axis=1)
    output+=np.sum(integrand(a),axis=1)
    return output*h/3

def integrand(rlin):
    first=np.arange(1,11)[:,None]
    second=np.arange(2,12)[:,None]
    return np.vstack((rlin*first,np.power(rlin,second)))

检查trapazoidal和simpsons规则累积相对误差:

b=float(100)
first=np.arange(1,11)*(b**2)/2
second=np.power(b,np.arange(3,13))/np.arange(3,13)
exact=np.vstack((first,second))

for x in range(3):
    num=x*100+100
    tr=trap(integrand,0,b,num).reshape(2,-1)
    si=simpson(integrand,0,b,num).reshape(2,-1)
    rel_trap=np.sum(abs((tr-exact)/exact))*100
    rel_simp=np.sum(abs((si-exact)/exact))*100
    print 'Number of points:',num,'Trap Rel',round(rel_trap,6),'Simp Rel',round(rel_simp,6)

Number of points: 100 Trap Rel 0.4846   Simp Rel 0.000171
Number of points: 200 Trap Rel 0.119944 Simp Rel 1.1e-05
Number of points: 300 Trap Rel 0.053131 Simp Rel 2e-06

Timeit。请注意,基于上述收敛,两个梯形规则使用200个点,而辛普森一个时间仅为100。对不起,我没有同情:

s="""
import numpy as np
from scipy.integrate import trapz

def integrand(rlin):
    first=np.arange(1,11)[:,None]
    second=np.arange(2,12)[:,None]
    return np.vstack((rlin*first,np.power(rlin,second)))

def trap(func,a,b,num):
    xlinear=np.linspace(a,b,num)
    slicevol=np.diff(xlinear)
    output=integrand(xlinear)
    output=output[:,:-1]+output[:,1:]
    return np.dot(output,slicevol)/2

def simpson(func,a,b,num):
    a=float(a)
    b=float(b)
    h=(b-a)/num

    output=4*np.sum(integrand(a+h*np.arange(1,num,2)),axis=1)
    output+=2*np.sum(integrand(a+h*np.arange(2,num-1,2)),axis=1)
    output+=np.sum(integrand(b),axis=1)
    output+=np.sum(integrand(a),axis=1)
    return output*h/3

def simpson2(func,a,b,num):
    a=float(a)
    b=float(b)
    h=(b-a)/num
    p1=a+h*np.arange(1,num,2)
    p2=a+h*np.arange(2,num-1,2)
    points=np.hstack((p1,p2,a,b))
    mult=np.hstack((np.repeat(4,p1.shape[0]),np.repeat(2,p2.shape[0]),1,1))
    return np.dot(integrand(points),mult)*h/3

def x2(x):
    return x**2
def x3(x):
    return x**3
def x4(x):
    return x**4
def x5(x):
    return x**5
def x5(x):
    return x**5
def x6(x):
    return x**6
def x7(x):
    return x**7
def x8(x):
    return x**8
def x9(x):
    return x**9
def x10(x):
    return x**10
def x11(x):
    return x**11
def xt5(x):
    return 5*x
"""

zhenya="""
a=[xt5,xt5,xt5,xt5,xt5,xt5,xt5,xt5,xt5,xt5,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11]
vectorize(quad)(a, 0, 100)
"""

usethedeathstar="""
g=lambda x: np.array([[x,2*x,3*x,4*x,5*x,6*x,7*x,8*x,9*x,10*x],[x**2,x**3,x**4,x**5,x**6,x**7,x**8,x**9,x**10,x**11]])
xv=np.linspace(0,100,200)
trapz(g(xv))
"""

vectrap="""
trap(integrand,0,100,200)
"""

vecsimp="""
simpson(integrand,0,100,100)
"""

vecsimp2="""
simpson2(integrand,0,100,100)
"""

print 'zhenya took',timeit.timeit(zhenya,setup=s,number=100),'seconds.'
print 'usethedeathstar took',timeit.timeit(usethedeathstar,setup=s,number=100),'seconds.'
print 'vectrap took',timeit.timeit(vectrap,setup=s,number=100),'seconds.'
print 'vecsimp took',timeit.timeit(vecsimp,setup=s,number=100),'seconds.'
print 'vecsimp2 took',timeit.timeit(vecsimp2,setup=s,number=100),'seconds.'

结果:

zhenya took 0.0500509738922 seconds.
usethedeathstar took 0.109386920929 seconds.
vectrap took 0.041011095047 seconds.
vecsimp took 0.0376999378204 seconds.
vecsimp2 took 0.0311458110809 seconds.

在时间上要指出的是,zhenya的回答应该更准确。我相信一切都是正确的,如果需要更改,请告诉我。

如果您提供将要使用的功能和范围,我可以为您的系统提供更好的功能。您是否也有兴趣使用其他核心/节点?

答案 3 :(得分:1)

我可能已经找到了一些有趣的方法,但却以为矩阵g_symp定义不同的符号为代价:

import numpy as np
from scipy.integrate import quad
import sympy as sy

@np.vectorize
def vec_lambdify(var, expr, *args, **kw):
    return sy.lambdify(var, expr, *args, **kw)

@np.vectorize
def vec_quad(f, a, b, *args, **kw):
    return quad(f, a, b, *args, **kw)[0]

Y = sy.symbols("y1:11")
x = sy.symbols("x")
mul_x = [y.subs(y,x*(i+1)) for (i,y) in enumerate(Y)]
pow_x = [y.subs(y,x**(i+1)) for (i,y) in enumerate(Y)]

g_sympy = np.array(mul_x + pow_x).reshape((2,10))
X = x*np.ones_like(g_sympy)
G = vec_lambdify(X, g_sympy)
I = vec_quad(G, 0, 100)
print(I)

结果:

[[  5.00000000e+03   1.00000000e+04   1.50000000e+04   2.00000000e+04
    2.50000000e+04   3.00000000e+04   3.50000000e+04   4.00000000e+04
    4.50000000e+04   5.00000000e+04]
[  5.00000000e+03   3.33333333e+05   2.50000000e+07   2.00000000e+09
   1.66666667e+11   1.42857143e+13   1.25000000e+15   1.11111111e+17
   1.00000000e+19   9.09090909e+20]]

并使用ipython magic %timeit vec_quad(G,0,100)我得到了

1000 loops, best of 3: 527 µs per loop

我觉得这种方法虽然有符号的麻烦,但还是比较干净。

答案 4 :(得分:1)

quadpy(我的一个项目)矢量化正交。此

import numpy
import quadpy


def f(x):
    return [
        [x,  2*x,  3*x,  4*x,  5*x,  6*x,  7*x,  8*x,   9*x,  10*x],
        [x**2, x**3, x**4, x**5, x**6, x**7, x**8, x**9, x**10, x**11]
        ]


sol = quadpy.line_segment.integrate(
        f,
        numpy.array([[0.0], [100.0]]),
        quadpy.line_segment.GaussLegendre(6)
        )

print(sol)

给出

[[[  5.00000000e+03]
[  1.00000000e+04]
[  1.50000000e+04]
[  2.00000000e+04]
[  2.50000000e+04]
[  3.00000000e+04]
[  3.50000000e+04]
[  4.00000000e+04]
[  4.50000000e+04]
[  5.00000000e+04]]

[[  3.33333333e+05]
[  2.50000000e+07]
[  2.00000000e+09]
[  1.66666667e+11]
[  1.42857143e+13]
[  1.25000000e+15]
[  1.11111111e+17]
[  1.00000000e+19]
[  9.09090909e+20]
[  8.33333333e+22]]]

时序:

%timeit quadpy.line_segment.integrate(f, [0.0, 100.0], gl)
10000 loops, best of 3: 65.1 µs per loop