Search code examples
pythoncythonmemoryview

Initialize slices of memoryview in cython from numpy.ndarray


I am trying to initialize a slice (not not whole) of a memoryview. Suppose that I have memoryview A as an attribute of a class (Extension Type)

from cython.view cimport array as cvarray

N = 1000
cdef double[:,:,::1] A = cvarray(shape=(2,N,N),itemsize=sizeof(double),format='d')

Now, I am trying to initialize it in a cdef function. I have no problem initializing the whole memoryview like this

# From elsewhere we have loaded a numpy.ndarray B of size (2,N,N)
A[:,:,:] = B

This is fine when the initializer B is 3D array (2,N,N) so that we do not have to slice A. But now, the problem is here: suppose that I have 2D arrays B1 and B2 of size (N,N), and trying to initialize as

A[0,:,:] = B1
A[1,:,:] = B2

This gives me the following error:

TypeError: only length-1 arrays can be converted to Python scalars

Of course I can copy all data one-by-one from B1 and B2 to A, but this would not be efficient. This process is in a loop and the size N is large. B1 and B2 come form loading netcdf files as numpy.ndarray type.

Also, I am defining A to be as a memoryview so that somewhere else in the code I can use nogil functions over accessing A.

I am wondering if there is an efficient way to initialize the memoryview as above, or at least, somehow play with pointers of B1 and B2 and put them together into an iterable array. Thanks.


Solution

  • I can find two options:

    1. It works if you type B1 and B2 as a memoryview.
    2. You can access the base attribute of the memoryview to get the cvarray and index that:

      A.base[0,:,:] = B1
      A.base[1,:,:] = B2
      

      I don't think this will necessarily work for all memoryview compatible objects (they are required to define the buffer interface rather than a useful __getitem__) but it should work for most of them, including cvarray.