4

I have a library in c++ and I'm trying to wrap it for python using Cython. One function returns an array of 3D vectors (float (*x)[3]) and I want to access that data from python. I was able to do so 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 on that 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 is about three times slower than the list version.

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

The complete code is

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
  • 1
    did you try numpys frombuffer function? Commented Apr 22, 2011 at 16:55

2 Answers 2

2
  1. Define the type of res:

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

    res[i,0] = ...
    
  3. Turn off boundscheck & wraparound

    @cython.boundscheck(False)
    @cython.wraparound(False) 
    
Sign up to request clarification or add additional context in comments.

Comments

1

To summarize what HYRY said and to ensure Cython can generate fast indexing 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 I did was put the fast stuff inside a cdef method, put the right optimizing decorators on it, and called that inside the property's __get__(). You should also make sure to refer to self.thisptr.natoms inside the range() call rather than use the natoms property, which has lots of Python overhead associated with it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.