我有一个c ++库,我正在尝试使用Cython将其包装为python。一个函数返回一个3D向量数组(float(* x)[3]),我想从python访问该数据。我能够通过做
这样的事情来做到这一点res = [
(self.thisptr.x[j][0],self.thisptr.x[j][1],self.thisptr.x[j][2])
for j in xrange(self.natoms)
]
但是我想将它作为一个numpy数组访问,所以我尝试了numpy.array,它的速度要慢得多。我也试过
cdef np.ndarray res = np.zeros([self.thisptr.natoms,3], dtype=np.float)
cdef int i
for i in range(self.natoms):
res[i][0] = self.thisptr.x[i][0]
res[i][1] = self.thisptr.x[i][1]
res[i][2] = self.thisptr.x[i][2]
但是比列表版本慢大约三倍。
有关如何更快地将矢量列表转换为numpy数组的任何建议?
完整的代码是
cimport cython
import numpy as np
cimport numpy as np
ctypedef np.float_t ftype_t
cdef extern from "ccxtc.h" namespace "ccxtc":
cdef cppclass xtc:
xtc(char []) except +
int next()
int natoms
float (*x)[3]
float time
cdef class pyxtc:
cdef xtc *thisptr
def __cinit__(self, char fname[]):
self.thisptr = new xtc(fname)
def __dealloc__(self):
del self.thisptr
property natoms:
def __get__(self):
return self.thisptr.natoms
property x:
def __get__(self):
cdef np.ndarray res = np.zeros([self.thisptr.natoms,3], dtype=np.float)
cdef int i
for i in range(self.natoms):
res[i][0] = self.thisptr.x[i][0]
res[i][1] = self.thisptr.x[i][1]
res[i][2] = self.thisptr.x[i][2]
return res
#return [ (self.thisptr.x[j][0],self.thisptr.x[j][1],self.thisptr.x[j][2]) for j in xrange(self.natoms)]
@cython.boundscheck(False)
def next(self):
return self.thisptr.next()
答案 0 :(得分:2)
定义res的类型:
cdef np.ndarray[np.float64_t, ndim=2] res = ...
使用完整索引:
res[i,0] = ...
关闭boundscheck&环绕
@cython.boundscheck(False)
@cython.wraparound(False)
答案 1 :(得分:1)
总结一下HYRY所说的内容并确保Cython能够生成快速索引代码,请尝试以下内容:
cimport cython
import numpy as np
cimport numpy as np
ctypedef np.float_t ftype_t
cdef extern from "ccxtc.h" namespace "ccxtc":
cdef cppclass xtc:
xtc(char []) except +
int next()
int natoms
float (*x)[3]
float time
cdef class pyxtc:
cdef xtc *thisptr
def __cinit__(self, char fname[]):
self.thisptr = new xtc(fname)
def __dealloc__(self):
del self.thisptr
property natoms:
def __get__(self):
return self.thisptr.natoms
@cython.boundscheck(False)
@cython.wraparound(False)
cdef _ndarray_from_x(self):
cdef np.ndarray[np.float_t, ndim=2] res = np.zeros([self.thisptr.natoms,3], dtype=np.float)
cdef int i
for i in range(self.thisptr.natoms):
res[i,0] = self.thisptr.x[i][0]
res[i,1] = self.thisptr.x[i][1]
res[i,2] = self.thisptr.x[i][2]
return res
property x:
def __get__(self):
return self._ndarray_from_x()
@cython.boundscheck(False)
def next(self):
return self.thisptr.next()
我所做的只是将快速的东西放在cdef
方法中,在其上放置正确的优化装饰器,并在属性的__get__()
内调用它。您还应该确保在self.thisptr.natoms
调用中引用range()
,而不是使用natoms
属性,该属性具有很多与之相关的Python开销。< / p>