Jon Olav Vik wrote:
> If I may make a wish, I would like Cython to find more declarations 
> automatically. For instance, having
> 
> cdef extern * from "cvode/cvode.h"
> 
> or, if that is impractical,
> 
> cdef extern from "cvode/cvode.h":
>     CVodeCreate, CVRhsFn, CVodeMalloc, CVodeFree, CVode, CV_ADAMS, CV_BDF

Yes, we all would. If you find a decent CS student at your institution 
who would like to do this as his or her master thesis then drop us a 
note :-)

I think there's a script someone posted on the mailing list to try to 
autogenerate pxds, though I don't remember enough to find it -- anyone?

> I haven't benchmarked anything yet, but the relative ease of adapting the C 
> tutorial for CVODE [3] is uplifting. As a last question, what is the cleanest 
> way to transfer arrays of double between realtype* and Numpy vectors (one-
> dimensional arrays)?

OK here it is. Note that this sets up the ndarray to point to the *same* 
memory. Modifications to the resulting NumPy array will happen directly 
in the NVector!

Case A: If you are 100% sure that you do not call N_VDestroy_Serial 
before all references to the ndarray created are gone, you can simply do 
this:

cdef extern from "numpy/arrayobject.h":
     # These are simply missing from numpy.pxd due to laziness;
     # so declare manually for now
     void import_array()
     object PyArray_SimpleNewFromData(int nd,
                                      np.npy_intp* dims,
                                      int typenum,
                                      void* data)



import_array() # Needed because we call the raw NumPy C API below!

def some_func():
     cdef np.npy_intp* shape = [somehow_extract_length_of(some_nvector)]
     # Create ndarray. Assume realtype is double.
     assert sizeof(realtype) == sizeof(double)
     yourarray = PyArray_SimpleNewFromData(
       1, shape, np.NPY_DOUBLE,
       <void*>self.nvector.whatever_to_get_buffer_pointer)
     ...

But this is dangerous as the resulting yourarray will address 
nonallocated memory if you free the underlying NVector.

Case B: Proper memory handling:

First, create a C header file (workaround.h), because Cython cannot 
handle expressions of the form "foo(x) = y" so we need to "reformulate" 
the NumPy C API a bit:

#include <numpy/arrayobject.h>
#define PyArray_Set_BASE(arr, obj) PyArray_BASE(arr) = obj

Then, this Cython code should do the job. Note that we need to create a 
class because Python needs an object to associate with the memory, so 
that the memory gets freed at the right time.

cimport numpy as np

cdef extern from "workaround.h":
     void PyArray_Set_BASE(np.ndarray arr, object obj)

cdef extern from "numpy/arrayobject.h":
     # These are simply missing from numpy.pxd due to laziness;
     # so declare manually for now
     void import_array()
     object PyArray_SimpleNewFromData(int nd,
                                      np.npy_intp* dims,
                                      int typenum,
                                      void* data)



import_array() # Needed because we call the raw NumPy C API below!

cdef class CythonNVector:
     cdef N_Vector nvector
     def __init__(self, length):
         self.nvector = N_VNew_Serial(length)

     def __dealloc__(self):
         # Called when the object is being destroyed (normally there's
         # no need for this in Python, but here it is, as we need to
         # free C memory explicitly).
         #
         # Note: The "Python parts" of the object might already
         # be gone in this method -- only touch C attributes.
         N_VDestroy_Serial(self.nvector)

     cpdef toarray(self):
         cdef np.npy_intp* shape = \
[somehow_extract_length_of(self.nvector)]
         # Create ndarray. Assume realtype is double.
         assert sizeof(realtype) == sizeof(double)
         cdef np.ndarray result = PyArray_SimpleNewFromData(
   1, shape, np.NPY_DOUBLE,
   <void*>self.nvector.whatever_to_get_buffer_pointer)
         # Make the ndarray keep a reference to this object
         PyArray_Set_BASE(result, self)
         return result


Just modify this general scheme for your usecase (i.e. you can set 
nvector manually rather than allocate it the constructor, etc.)



-- 
Dag Sverre
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev

Reply via email to