2011-04-21 72 views
4

我在C++中有一个库,我试图用Cython将它包装为python。一个函数返回一个3D向量数组(float(* x)[3]),我想从python访问这些数据。我能够做这样的事情从C++指针到数组指针的数组Cython

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() 
+1

你尝试numpys frombuffer函数吗? – tillsten 2011-04-22 16:55:12

回答

2
  1. 定义资源的类型:

    cdef np.ndarray[np.float64_t, ndim=2] res = ... 
    
  2. 使用完整的索引:

    res[i,0] = ... 
    
  3. 关闭boundscheck &环绕

    @cython.boundscheck(False) 
    @cython.wraparound(False) 
    
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__()内调用该装饰器。您还应该确保在range()调用中参考self.thisptr.natoms,而不是使用natoms属性,该属性具有与其关联的Python开销批次