Передача указателя numpy (dtype = np.bool) на С++

Я хотел бы использовать массив numpy типа bool в С++, передав его указатель через Cython. Я уже знаю, как это сделать с другими типами данных, такими как uint8. Выполнение этого метода аналогично логическому, это не сработает. Я могу скомпилировать, но во время выполнения есть следующее исключение:

Traceback (most recent call last):
  File "test.py", line 15, in <module>
    c = r.count(b, 4)
  File "rect.pyx", line 41, in rect.PyRectangle.count (rect.cpp:1865)
    def count(self, np.ndarray[bool, ndim=1, mode="c"] array not None, int size):
ValueError: Does not understand character buffer dtype format string ('?')

Вот мой метод С++:

void Rectangle::count(bool * array, int size)
{
    for (int i = 0; i < size; i++){
        std::cout << array[i] << std::endl;
    }
}

Файл Cython:

# distutils: language = c++
# distutils: sources = Rectangle.cpp

import numpy as np
cimport numpy as np

from libcpp cimport bool

cdef extern from "Rectangle.h" namespace "shapes":
    cdef cppclass Rectangle:
        Rectangle(int, int, int, int) except +
        int x0, y0, x1, y1
        void count(bool*, int)

cdef class PyRectangle:
    cdef Rectangle *thisptr      # hold a C++ instance which we're wrapping
    def __cinit__(self, int x0, int y0, int x1, int y1):
        self.thisptr = new Rectangle(x0, y0, x1, y1)
    def __dealloc__(self):
        del self.thisptr

    def count(self, np.ndarray[bool, ndim=1, mode="c"] array not None, int size):
        self.thisptr.count(&array[0], size)

И здесь python script, который вызывает этот метод и выдает ошибку:

import numpy as np
import rect

b = np.array([True, False, False, True])
c = r.count(b, 4)

Пожалуйста, дайте мне знать, если вам нужна дополнительная информация. Спасибо!

Ответ 1

Похоже, проблема связана с объявлением типа массива. Согласно документации на https://cython.readthedocs.org/en/latest/src/tutorial/numpy.html boolean arays еще не поддерживаются, но вы можете использовать их, отбросив их как массивы беззнаковых восьмибитных целых чисел, Вот простой пример, который берет сумму 1D массива логических значений (так же, как метод sum() для булевского массива NumPy)

from numpy cimport ndarray as ar
cimport numpy as np
cimport cython

@cython.boundscheck(False)
@cython.wraparound(False)
def cysum(ar[np.uint8_t,cast=True] A):
    cdef int i, n=A.size, tot=0
    for i in xrange(n):
        tot += A[i]
    return tot

В вашем коде на С++, в зависимости от того, что вы делаете, вам может потребоваться вернуть указатель обратно в bool, я не уверен в этом.

Изменить: вот пример того, как нарисовать указатель в Cython, который должен делать то, что вы хотите. Мне все еще приходилось вводить массив как неподписанное 8-битное целое число, но затем я возвращаю указатель обратно в bool.

from numpy cimport ndarray as ar
cimport numpy as np
from libcpp cimport bool
cimport cython

def cysum(ar[np.uint8_t,cast=True] A):
    cdef int i, n=A.size, tot=0
    cdef bool *bptr
    bptr = <bool*> &A[0]
    for i in xrange(n):
        tot += bptr[i]
    return tot

Если вы хотите передать массив в качестве указателя, вы можете просто использовать следующую функцию в вашем файле Cython:

cdef bool* arptr(np.uint8_t* uintptr):
    cdef bool *bptr
    bptr = <bool*> uintptr
    return bptr

Которое можно назвать

arptr(&A[0])