Boolean numpy arrays with Cython
Asked Answered
W

3

8

I have a numpy boolean array:

myarr = np.array([[False, True], [True, False]])

If I try to initialise a Cython MemoryView with it, like this:

cdef bint[:,:] mymem = myarr

I get this error:

ValueError: Does not understand character buffer dtype format string ('?')

If I do this instead, it works fine:

cdef np.int_t[:,:] mymem = np.int_(myarr)

How can I store a boolean numpy array using Cython MemoryViews?

Wards answered 1/3, 2018 at 20:28 Comment(0)
I
6

I ran into the same problem some time ago. Unfortunately I did not find a direct solution to this. But there is another approach: Since an array of boolean vales has the same data type size as uint8, you could use a memory view with this type as well. Values in the uint8 memory view can also be compared to boolean values, so the behavior is mostly equal to an actual bint memory view:

cimport cython
cimport numpy as np
import numpy as np
ctypedef np.uint8_t uint8

cdef int i
cdef np.ndarray array = np.array([True,False,True,True,False], dtype=bool)
cdef uint8[:] view = np.frombuffer(array, dtype=np.uint8)
for i in range(view.shape[0]):
    if view[i] == True:
        print(i)

Output:

0
2
3
Imbrue answered 2/3, 2018 at 10:49 Comment(0)
F
9

This information seems to be not easy to find, my reference is pretty old (2011), but not much seems to have changed since then.

Numpy's bool-array uses a 8bit-value for False/True (this is not obvious per se - C++'s std::vector<bool> uses for example 1 bit per value) with 0-meaning False and 1-meaning True. You can use cast=True for an unit8-array in order to use it as a bool-array, for example:

 %%cython
 import numpy as np
 cimport numpy as np
 def to_bool_array(lst):
    cdef np.ndarray[np.uint8_t, ndim = 1, cast=True] res
    res=np.array(lst, dtype=bool)
    return res

And now:

 >>> to_bool_array([True,False,True,False])
 array([ True, False,  True, False], dtype=bool)

Setting cast=True gives some slack to Cython's type-checking, so the numpy-arrays with the same element-size (for example uint8, int8 and bool) can be reinterpreted. This however would not work if element-sizes were different: for example np.int8(1byte) and np.int16 (2bytes).

Fullmouthed answered 6/3, 2018 at 7:1 Comment(0)
I
6

I ran into the same problem some time ago. Unfortunately I did not find a direct solution to this. But there is another approach: Since an array of boolean vales has the same data type size as uint8, you could use a memory view with this type as well. Values in the uint8 memory view can also be compared to boolean values, so the behavior is mostly equal to an actual bint memory view:

cimport cython
cimport numpy as np
import numpy as np
ctypedef np.uint8_t uint8

cdef int i
cdef np.ndarray array = np.array([True,False,True,True,False], dtype=bool)
cdef uint8[:] view = np.frombuffer(array, dtype=np.uint8)
for i in range(view.shape[0]):
    if view[i] == True:
        print(i)

Output:

0
2
3
Imbrue answered 2/3, 2018 at 10:49 Comment(0)
S
0

I found it simplest to do:

cdef uint8_t[:] arr_memview8 = data.astype(np.uint8)
bool* ptr = <bool*>&arr_memview8[0]
Sing answered 30/7, 2018 at 17:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.