Array of pointers from C ++ to NumPy via Cython

I have a library in C ++ and I'm trying to wrap it for python using Cython. One function returns an array of three-dimensional vectors (float (* x) [3]), and I want to access this data from python. I was able to do this by doing something like

res = [ (self.thisptr.x[j][0],self.thisptr.x[j][1],self.thisptr.x[j][2]) for j in xrange(self.natoms) ] 

but I would like to access this as a numpy array, so I tried numpy.array and it was much slower. I also tried

  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] 

But about three times slower than the list version.

Any suggestions on how to convert a list of vectors to a numpy array faster?

Full code

 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() 
+4
source share
2 answers
  • Define the res type:

     cdef np.ndarray[np.float64_t, ndim=2] res = ... 
  • Use full index:

     res[i,0] = ... 
  • Disable snapping and crop

     @cython.boundscheck(False) @cython.wraparound(False) 
+2
source

To summarize what HYRY said, and so that Cython can generate fast index code, try something like the following:

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

All that I did was put quick material inside the cdef method, it had right optimizing decorators on it and called it inside the __get__() property. You should also be sure to refer to self.thisptr.natoms inside the range() call, and not to the natoms property, which has a lot of Python overhead associated with it.

+1
source

All Articles