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

ifmq2ha2  于 2023-06-23  发布在  其他
关注(0)|答案(6)|浏览(115)

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

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]])

等等
我需要对gx上进行数值积分,比如from 0. to 100.(在真实的情况下,积分没有精确解),在我目前的方法中,我必须对g中的每个元素进行lambdify,并对其进行单独积分。我正在使用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循环;我相信第一个是瓶颈,因为g_sympy矩阵最多有10000个项(这对for循环来说不是什么大问题)。
如上所示,lambdify允许计算整个矩阵,所以我想:“有没有办法融合整个矩阵?“
scipy.integrate.quadrature有一个参数vec_func,这给了我希望。我期待的是:

g_int = quadrature( g, x1, x2 )

以得到完全积分的矩阵,但它给出了ValueError:矩阵必须是二维的
编辑:我正在尝试使用quadvhas already been discussed for SciPy来做can apparently be done in Matlab
真实的案例has been made available here
要运行它,您需要:

  • numpy
  • scipy
  • matplotlib
  • 症状

运行:"python curved_beam_mrs.py"
您将看到这个过程已经很慢了,主要是因为集成,如文件curved_beam.py中的TODO所示。
如果删除文件curved_beam_mrs.pyTODO后面的注解,速度会慢得多。
集成的函数矩阵显示在print.txt文件中。
谢谢你!

mbjcgjjk

mbjcgjjk1#

quadquadrature的第一个参数必须是可调用的。quadraturevec_func参数指的是这个可调用的 * 参数 * 是否是一个(可能是多维的)向量。从技术上讲,您可以vectorizequad本身:

>>> 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]))

但这只相当于在a的元素上显式循环。具体来说,它不会给您带来任何性能增益,如果这就是您所追求的。所以,总而言之,问题是为什么以及你到底想在这里实现什么。

gtlvzcf8

gtlvzcf82#

向量化梯形与辛普森积分法则。Trapezoidal只是从另一个使用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和simpson规则累积相对误差:

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

注意,两个梯形规则都使用200个点,而simpson基于上述收敛仅计时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.

在时间上需要指出的是,振亚的回答应该更准确。我相信一切都是正确的,请让我知道如果需要改变。
如果您提供的功能和范围,您将使用我可能会掀起一些更好的为您的系统。另外,您是否有兴趣利用其他内核/节点?

vshtjzan

vshtjzan3#

在真实的情况下,积分没有精确解,你指的是奇点吗?你能更精确地描述它吗,以及你希望整合的矩阵的大小。我不得不承认,当涉及到一些事情时,Sympy非常慢(不确定集成是否是其中的一部分,但我更喜欢远离Sympy,坚持使用Numpy解决方案)。你想得到一个更优雅的解决方案,通过一个矩阵或一个更快的?

  • 注意:显然我不能在你的帖子上添加评论来询问这些东西,所以我不得不发布这个作为答案,也许这是因为我没有足够的声誉?-
    编辑:像这样的东西?
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(asin(bx+c)^ncos(dx+e)^m)这样的东西,对于a,b,c,d,e,m,n的不同系数,我建议分析地做所有这些。(应该有一些公式,因为你可以把sin改写成复指数
当我更好地检查这些函数时,我注意到的另一件事是sin(ax+pi/2)和sin(ax+pi)以及类似的东西可以以删除pi/2或pi的方式重写为cos或sin。我还看到,只要看看你的函数矩阵中的第一个元素:

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的公式,我会检查你需要积分的最一般的公式是什么,但我猜它像a*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)等只是函数的分析集成版本?
(not我真的打算检查你的整个代码,看看剩下的都做了什么,但是它只是把这些函数从a到b集成在txt文件中吗?或者有没有什么东西,比如,求每个函数的平方,或者其他什么东西,可能会破坏分析的可能性?)
这应该简化你的积分,我猜?
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版本的快速方法的时间和一个快速方法的渐近版本的时间时,ditch sympy的点仍然存在)

6vl6ewon

6vl6ewon4#

我可能已经找到了一些有趣的方法来做到这一点,代价是为矩阵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

我认为这种方法在某种程度上更干净,尽管与符号的杂耍。

szqfcxe2

szqfcxe25#

quadpy(我的一个项目)进行矢量化正交。这一

import numpy
import quadpy

def f(x):
    return [
        [k * x for k in range(2, 11)],
        [x ** k for k in range(2, 11)],
    ]

sol, err = quadpy.quad(f, 0.0, 100.0, epsabs=numpy.inf, epsrel=1.0e-10)

print(sol)
print(err)

给予

[[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]]
[[5.11783704e-16 4.17869644e-16 1.02356741e-15 9.15506521e-16
  8.35739289e-16 1.19125717e-15 2.04713482e-15 1.93005721e-15
  1.83101304e-15]
 [6.69117036e-14 9.26814751e-12 1.05290634e-09 1.12081237e-07
  1.09966583e-05 1.09356156e-03 1.00722052e-01 9.31052614e+00
  9.09545305e+02]]

时间:

%timeit quadpy.quad(f, 0.0, 100.0, epsabs=numpy.inf, epsrel=1.0e-10)    
904 µs ± 3.02 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
83qze16e

83qze16e6#

SciPy quad_vec用于自适应求向量函数的正交

对于像我这样多年后才遇到这个问题的人来说,现在有一个特定的SciPy函数scipy.integrate.quad_vec专门解决这个问题。它允许向量函数(或不同函数)的 * 自适应 * 正交。
当要集成的不同函数或组件共享一些计算时,此函数特别有用,这通常是向量函数的情况。
可以使用以下代码行实现向量函数func的非常有效的向量化求积(我重写了原始问题中的精确函数,与其他一些答案中使用的函数略有不同)

import  numpy as np
from scipy import integrate

def func(x):
    return np.vstack([x*np.arange(1, 11), x**np.arange(2, 12)])

res = integrate.quad_vec(func, 0, 100)

print(res[0])  # first element is the integral of every components

打印结果为

[[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]]

相关问题