I am modifying cython code that makes plots of complex-valued functions. This code includes something equivalent to the following:
cimport numpy as cnumpy
def do_something():
# Buffer types only allowed as function local variables, so put
# this inside a function.
cdef cnumpy.ndarray[cnumpy.float_t, ndim=3, mode='c'] rgb
pass
What does the mode='c'
kwarg do? I don't see this as an option on the numpy.ndarray documentation (or anywhere else in the numpy documentation), or mentioned in the cython for numpy users documentation/tutorial, or mentioned in cython's working with numpy documentation/tutorial.
I am not fluent in cython, but I do know python and C. I see from other questions here that this is not a rare argument, but I can't find documentation or explanation for what this does.
Argument mode
maps to Python's buffer protocol's flags:
"c"
means PyBUF_C_CONTIGUOUS
"fortran"
means PyBUF_F_CONTIGUOUS
"strided"
means PyBUF_STRIDES
there is also "full"
which maps to PyBUF_INDIRECT
and thus doesn't make sense for numpy-arrays.
Knowing, that the memory layout/mode is "c" or "fortran" would lead to generation of a more performant code, but then only numpy arrays with this layout (flags of the array must be either C_CONTIGUOUS=true
for mode="c"
or F_CONTIGUOUS=true
for mode="fortran"
) would be accepted.
On the other hand mode="strided"
would accept any numpy ndarray, but the generated C-code would be less performant.
The gory details:
To access the content of a numpy array Cython uses Python's buffer protocol. Whenever there is a np.ndarray
in the Cython code, there will be a corresponding __Pyx_Buffer
variable in the C-code, for generation of which the class BufferEntry
is responsible.
To get the buffer from the array object, the C-function __Pyx_GetBufferAndValidate
will be emitted. The mode
-argument will be translated into the buffer-protocol flags used by the above function in BufferEntry.get_flags
:
def get_flags(buffer_aux, buffer_type):
flags = 'PyBUF_FORMAT'
mode = buffer_type.mode
if mode == 'full':
flags += '| PyBUF_INDIRECT'
elif mode == 'strided':
flags += '| PyBUF_STRIDES'
elif mode == 'c':
flags += '| PyBUF_C_CONTIGUOUS'
elif mode == 'fortran':
flags += '| PyBUF_F_CONTIGUOUS'
else:
assert False
if buffer_aux.writable_needed: flags += "| PyBUF_WRITABLE"
return flags