2

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.

davidlowryduda
  • 2,404
  • 1
  • 25
  • 29
  • That question is from 2014. Maybe the API has changed since. The linked documentation does not mention kwarg, but it has "order": Row-major (C-style) or column-major (Fortran-style) order. – Thomas Weller Feb 14 '22 at 18:45

2 Answers2

2

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
ead
  • 32,758
  • 6
  • 90
  • 153
0

My guess is it's an equivalent to the order argument in the numpy ndarray docs.

J. Blackadar
  • 1,821
  • 1
  • 11
  • 18