Python 使用SciPy集成返回矩阵或数组的函数
我有一个符号数组,可以表示为:Python 使用SciPy集成返回矩阵或数组的函数,python,matrix,numpy,scipy,numerical-integration,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 ) 因此
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
进行数值积分,比如说从0开始积分。到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 loop;我认为第一个是瓶颈,因为g_sympy
矩阵最多有10000个术语(这对于for循环来说不是什么大问题)
如上所示,lambdify
允许对整个矩阵进行求值,因此我想:“有没有办法整合整个矩阵?”
scipy.integrate.quarture
有一个参数vec_func
给了我希望。我期待着这样的事情:
g_int = quadrature( g, x1, x2 )
为了得到完全积分的矩阵,但它给出了值error:
矩阵必须是二维的
编辑:我正在使用
quadv
和
真实情况
要运行它,您需要:
- 努比
- 松软的
- matplotlib
- 辛皮
“python curve\u beam\u mrs.py”
您将看到该过程已经很慢了,主要是因为集成,由文件curved_beam.py
中的TODO
指示
如果删除文件curved\u beam\u mrs.py
中TODO
后指示的注释,速度会慢得多
集成的函数矩阵显示在print.txt
文件中
谢谢大家! 在实际情况下,积分没有精确解,你是说奇点吗?你能不能更精确地描述它,以及你想要整合的矩阵的大小。我不得不承认,在某些事情上,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(a*sin(bx+c)^n*cos(dx+e)^m)这样的东西,对于a,b,c,d,e,m,n的不同系数,我建议用解析的方法来做这些。(应该有一些公式,因为您可以将sin重写为复指数。)
在更好地检查这些函数时,我注意到的另一件事是sin(a*x+pi/2)和sin(a*x+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
这也简化了计算。如果你的公式不涉及大量的TXT文件,我会检查你需要积分的最一般的公式是什么,但我猜它类似于a*sin^n(bx+c)*cos^m(dx+e),m和n为01或2,这些东西可以简化为可以进行解析积分的东西。因此,如果你找到了你得到的最一般的解析函数,你可以很容易地
f=lambda x: [[s1(x),s2(x)],[s3(x),s4(x)]]
res=f(x2)-f(x1)
其中s1(x)等只是函数的分析集成版本
(实际上并不打算浏览整个代码,看看其余的代码都做了些什么,但它只是将这些函数从a到b或类似的东西集成到txt文件中吗?或者是否存在这样的情况,即取每个函数的平方或任何可能会破坏分析的可能性的东西?)
我想这会简化你的积分吧
和:第二个
嗯,第二个链接不起作用,但我想你是从第一个链接中得到这个想法的
编辑,因为您不需要分析解决方案:
改进之处在于消除Symphy:
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方法实际上更快,因为在本例中,我只在一个sin函数上尝试了它,而不是在它们的一系列函数上,但在比较较快方法的numpy版本和较快方法的symphy版本的时间时,舍弃symphy的点仍然存在)四元或四元的第一个参数必须是可调用的。
四元
的vec_func
参数是指此可调用的参数是否是(可能是多维的)向量。从技术上讲,您可以向量化四元
本身:
>>> 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
元素上显式循环。特别是,如果这是您所追求的,它不会给您带来任何性能提升。所以,总而言之,问题是为什么以及您到底想在这里实现什么。将梯形和辛普森积分规则矢量化。梯形只是复制和复制来自另一个使用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个点。对不起,我没有sympy:
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.
时间安排中需要指出的是,振亚的回答应该更加准确。我相信一切都是正确的,如果需要更改,请告诉我
如果你提供的功能和范围,你将使用我可能可以
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]]
1000 loops, best of 3: 527 µs per loop
[[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)