python中的矢量化球形bessel函数?

前端之家收集整理的这篇文章主要介绍了python中的矢量化球形bessel函数?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我注意到,顺序n和参数x jv(n,x)的 scipy.special贝塞尔函数在x中被矢量化:

在[14]中:将scipy.special导入sp
在[16]中:sp.jv(1,范围(3))#n = 1,[x = 0,1,2]
Out [16]:array([0.,0.44005059,0.57672481])

但是没有相应的矢量化形式的球形贝塞尔函数,sp.sph_jn:

  1. In [19]: sp.sph_jn(1,range(3))
  2.  
  3. ---------------------------------------------------------------------------
  4. ValueError Traceback (most recent call last)
  5. <ipython-input-19-ea59d2f45497> in <module>()
  6. ----> 1 sp.sph_jn(1,range(3)) #n=1,3 value array
  7.  
  8. /home/glue/anaconda/envs/fibersim/lib/python2.7/site-packages/scipy/special/basic.pyc in sph_jn(n,z)
  9. 262 """
  10. 263 if not (isscalar(n) and isscalar(z)):
  11. --> 264 raise ValueError("arguments must be scalars.")
  12. 265 if (n != floor(n)) or (n < 0):
  13. 266 raise ValueError("n must be a non-negative integer.")
  14.  
  15. ValueError: arguments must be scalars.

此外,球形贝塞尔函数在一次通过中计算N的所有阶数.因此,如果我想要参数x = 10的n = 5 Bessel函数,则返回n = 1,2,3,4,5.它实际上在一次传递中返回jn及其衍生物:

  1. In [21]: sp.sph_jn(5,10)
  2. Out[21]:
  3. (array([-0.05440211,0.07846694,0.07794219,-0.03949584,-0.10558929,-0.05553451]),array([-0.07846694,-0.0700955,0.05508428,0.09374053,0.0132988,-0.07226858]))

为什么API中存在这种不对称性,并且有没有人知道一个库将返回矢量化的球形贝塞尔函数,或者至少更快(即在cython中)?

解决方法

你可以编写一个cython函数来加速计算,你要做的第一件事是获取fortran函数SPHJ的地址,这里是如何在Python中执行此操作:
  1. from scipy import special as sp
  2. sphj = sp.specfun.sphj
  3.  
  4. import ctypes
  5. addr = ctypes.pythonapi.PyCObject_AsVoidPtr(ctypes.py_object(sphj._cpointer))

然后你可以直接在Cython中调用fortran函数,注意我使用prange()来使用multicore来加速计算:

  1. %%cython -c-Ofast -c-fopenmp --link-args=-fopenmp
  2. from cpython.mem cimport PyMem_Malloc,PyMem_Free
  3. from cython.parallel import prange
  4. import numpy as np
  5. import cython
  6. from cpython cimport PyCObject_AsVoidPtr
  7. from scipy import special
  8.  
  9. ctypedef void (*sphj_ptr) (const int *n,const double *x,const int *nm,const double *sj,const double *dj) nogil
  10.  
  11. cdef sphj_ptr _sphj=<sphj_ptr>PyCObject_AsVoidPtr(special.specfun.sphj._cpointer)
  12.  
  13.  
  14. @cython.wraparound(False)
  15. @cython.boundscheck(False)
  16. def cython_sphj2(int n,double[::1] x):
  17. cdef int count = x.shape[0]
  18. cdef double * sj = <double *>PyMem_Malloc(count * sizeof(double) * (n + 1))
  19. cdef double * dj = <double *>PyMem_Malloc(count * sizeof(double) * (n + 1))
  20. cdef int * mn = <int *>PyMem_Malloc(count * sizeof(int))
  21. cdef double[::1] res = np.empty(count)
  22. cdef int i
  23. if count < 100:
  24. for i in range(x.shape[0]):
  25. _sphj(&n,&x[i],mn + i,sj + i*(n+1),dj + i*(n+1))
  26. res[i] = sj[i*(n+1) + n] #choose the element you want here
  27. else:
  28. for i in prange(count,nogil=True):
  29. _sphj(&n,dj + i*(n+1))
  30. res[i] = sj[i*(n+1) + n] #choose the element you want here
  31. PyMem_Free(sj)
  32. PyMem_Free(dj)
  33. PyMem_Free(mn)
  34. return res.base

比较一下,这是在forloop中调用sphj()的Python函数

  1. import numpy as np
  2. def python_sphj(n,x):
  3. sphj = special.specfun.sphj
  4. res = np.array([sphj(n,v)[1][n] for v in x])
  5. return res

以下是10个元素的%timit结果:

  1. x = np.linspace(1,10)
  2. r1 = cython_sphj2(4,x)
  3. r2 = python_sphj(4,x)
  4. assert np.allclose(r1,r2)
  5. %timeit cython_sphj2(4,x)
  6. %timeit python_sphj(4,x)

结果:

  1. 10000 loops,best of 3: 21.5 µs per loop
  2. 10000 loops,best of 3: 28.1 µs per loop

以下是100000个元素的结果:

  1. x = np.linspace(1,100000)
  2. r1 = cython_sphj2(4,x)

结果:

  1. 10 loops,best of 3: 44.7 ms per loop
  2. 1 loops,best of 3: 231 ms per loop

猜你在找的Python相关文章