Numpy-> Cython conversion: Ошибка компиляции: невозможно преобразовать 'npy_intp *' в объект Python

У меня есть следующий код, который должен быть непосредственно преобразован в cython:

from numpy import *

## returns winning players or [] if undecided. 
def score(board):
    scores = []
    checked = zeros(board.shape)
    for i in xrange(len(board)):
        for j in xrange(len(board)):
            if checked[i,j] == 0 and board[i,j] !=0:
                ... do stuf

моя попытка преобразования в cython:

import numpy as np
cimport numpy as np

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)

## returns winning players or [] if undecided. 
def score(np.ndarray[int, ndim=2] board):
    scores = []
    cdef np.ndarray[int, ndim = 2 ] checked
    checked = np.zeros(board.shape)
    for i in xrange(len(board)):
        for j in xrange(len(board)):
            if checked[i,j] == 0 and board[i,j] !=0:
                ... do stuf

Но когда я компилирую, я получаю:

$ python setup.py build_ext --inplace
running build_ext
cythoning newgox.pyx to newgox.c


## returns winning players or [] if undecided. 
def score(np.ndarray[int, ndim=2] board):
    scores = []
    cdef np.ndarray[int, ndim = 2 ] checked
    checked = np.zeros(board.shape)
                       ^
------------------------------------------------------------

newgox.pyx:58:28: Cannot convert 'npy_intp *' to Python object 
building 'newgox' extension

Кроме того, я не уверен, что это правильный способ работы со списками в cython:

scores = []
if some_stuff_is_true:
    scores.append(some_integer)

EDIT:

Спасибо, код теперь компилируется, но когда я его запускаю, я получаю сообщение об ошибке:

File "newgox.pyx", line 63, in newgox.score (newgox.c:1710)
    def score(np.ndarray[np.int, ndim=2] board):
ValueError: Buffer dtype mismatch, expected 'int object' but got 'long'

Я связал эти два варианта:

ctypedef np.int_t DTYPE_t
DTYPE = np.int

а затем продолжайте:

board = zeros((5,5), dtype = DTYPE)
def score(np.ndarray[DTYPE, ndim=2] board):

или просто в обеих объявлениях:

    ...  np.int ...

Это приводит к той же ошибке, но с сигнатурой:

 ValueError: Buffer dtype mismatch, expected 'int' but got 'long'

Спасибо bellamyj, но ваш предложенный код не будет компилироваться,

$ python setup.py build_ext --inplace
running build_ext
cythoning newgox.pyx to newgox.c
building 'newgox' extension
gcc-4.2 -fno-strict-aliasing -fno-common -dynamic -arch i386 -arch x86_64 -g -O2 -DNDEBUG -g -O3 -I/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c newgox.c -o   build/temp.macosx-10.6-intel-2.7/newgox.o

newgox.c:238:31: error: numpy/arrayobject.h: No such file or directory
newgox.c:239:31: error: numpy/ufuncobject.h: No such file or directory
newgox.c:356: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘__pyx_t_5numpy_int8_t’
newgox.c:365: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘__pyx_t_5numpy_int16_t’
newgox.c:374: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘__pyx_t_5numpy_int32_t’

И он продолжает перечислять все другие типы.

Тогда мне это говорит:

newgox.c:978: error: expected ‘)’ before ‘*’ token
newgox.c:979: error: expected ‘)’ before ‘*’ token
newgox.c:980: error: expected ‘)’ before ‘*’ token
newgox.c:983: error: expected declaration specifiers or ‘...’ before ‘PyArrayObject’
newgox.c:984: error: expected declaration specifiers or ‘...’ before ‘PyArrayObject’
newgox.c:985: error: expected ‘)’ before ‘*’ token
newgox.c:987: error: ‘__pyx_t_5numpy_int32_t’ undeclared here (not in a function)
newgox.c: In function ‘__pyx_pf_6newgox_7score’:
newgox.c:1638: error: ‘PyArrayObject’ undeclared (first use in this function)
newgox.c:1638: error: (Each undeclared identifier is reported only once
newgox.c:1638: error: for each function it appears in.)
newgox.c:1638: error: ‘__pyx_v_checked’ undeclared (first use in this function)
newgox.c:1659: error: ‘__pyx_t_5’ undeclared (first use in this function)
newgox.c:1721: error: expected expression before ‘)’ token
newgox.c:1723: error: expected expression before ‘)’ token
newgox.c:1747: error: expected expression before ‘)’ token
newgox.c:1766: error: expected expression before ‘)’ token
newgox.c:1813: error: expected expression before ‘)’ token
newgox.c:1846: error: expected expression before ‘)’ token
newgox.c:1846: error: too many arguments to function ‘__pyx_f_6newgox_check_life’
newgox.c:2009: error: expected expression before ‘)’ token
newgox.c:2009: warning: assignment makes pointer from integer without a cast
newgox.c:2012: error: expected expression before ‘)’ token
newgox.c:2032: error: expected expression before ‘)’ token
newgox.c: At top level:
newgox.c:2088: error: expected declaration specifiers or ‘...’ before ‘PyArrayObject’
newgox.c: In function ‘__pyx_f_6newgox_check_life’:
newgox.c:2124: error: ‘__pyx_v_board’ undeclared (first use in this function)
newgox.c:2160: error: ‘PyArrayObject’ undeclared (first use in this function)
newgox.c:2160: error: expected expression before ‘)’ token
newgox.c:2160: error: too many arguments to function ‘__pyx_f_6newgox_liberty’
newgox.c:2420: error: too many arguments to function ‘__pyx_f_6newgox_check_life’
newgox.c: At top level:
newgox.c:2583: error: expected declaration specifiers or ‘...’ before ‘PyArrayObject’
newgox.c: In function ‘__pyx_f_6newgox_liberty’:
newgox.c:2610: error: ‘__pyx_v_board’ undeclared (first use in this function)
newgox.c: At top level:
newgox.c:2859: error: expected ‘)’ before ‘*’ token
newgox.c: In function ‘__pyx_pf_5numpy_7ndarray___getbuffer__’:
newgox.c:2999: error: ‘PyArray_Descr’ undeclared (first use in this function)
newgox.c:2999: error: ‘__pyx_v_descr’ undeclared (first use in this function)
newgox.c:3062: error: ‘PyArrayObject’ undeclared (first use in this function)
newgox.c:3062: error: expected expression before ‘)’ token
newgox.c:3071: error: ‘npy_intp’ undeclared (first use in this function)
newgox.c:3114: error: expected expression before ‘)’ token
newgox.c:3114: error: ‘NPY_C_CONTIGUOUS’ undeclared (first use in this function)
newgox.c:3154: error: expected expression before ‘)’ token
newgox.c:3154: error: ‘NPY_F_CONTIGUOUS’ undeclared (first use in this function)
newgox.c:3184: error: expected expression before ‘)’ token
newgox.c:3184: warning: assignment makes pointer from integer without a cast
newgox.c:3240: error: expected expression before ‘)’ token
newgox.c:3240: error: subscripted value is neither array nor pointer
newgox.c:3249: error: expected expression before ‘)’ token
newgox.c:3249: error: subscripted value is neither array nor pointer
newgox.c:3262: error: expected expression before ‘)’ token
newgox.c:3271: error: expected expression before ‘)’ token
newgox.c:3291: error: expected expression before ‘)’ token

И еще несколько.

Обратите внимание:

newgox.c:2160: error: too many arguments to function ‘__pyx_f_6newgox_liberty’
newgox.c:2420: error: too many arguments to function ‘__pyx_f_6newgox_check_life’

Но мой вызов от счета /1 до check_life:

life, newly_checked = check_life(i,j,board,[])

И он получен следующим образом:

# helper functions of score/1
cdef check_life(int i, int j, np.ndarray[int, ndim=2] board, checked):
    ...
    return life, checked

Наконец, какой тип данных является "i4", который вы используете?

Ответ 1

Я не думаю, что распаковка распаковки работает в Cython, как в Python. Вы должны указать размер checked с помощью (board.shape[0], board.shape[1]).

Вам также необходимо указать тип данных checked. По умолчанию np.zeros возвращает a float64. Вы должны изменить это на int32, чтобы быть совместимым с объявленным типом.

Здесь будет изменена версия, которая должна работать.

def score(np.ndarray[int, ndim=2] board):

    cdef np.ndarray[np.int32_t, ndim = 2] checked
    checked = np.zeros((board.shape[0], board.shape[1]), dtype='i4')

    for i in xrange(len(board)):
        for j in xrange(len(board)):
            if checked[i,j] == 0 and board[i,j] !=0:
                ... do stuff

Чтобы ответить на вторую часть вашего вопроса - да, вы можете добавлять в списки в функциях Cython. Однако, как я понимаю, это включает вызовы функций Python, поэтому он не будет быстрее, чем те же операции в Python.

Обновление 1:

Я считаю, что эти ошибки связаны с тем, что компилятор не может найти заголовочные файлы NumPy. Обновите файл setup.py, чтобы указать путь к этим файлам. Путь должен быть выведен функцией np.get_include().

import numpy as np
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

setup(
      cmdclass={'build_ext': build_ext},
      ext_modules = [
              Extension("new_gox",
                        ["new_gox.pyx"],
                        include_dirs=[np.get_include()])
                    ]
     )

dtype i4 - это 32-битное целое число. Это эквивалентно np.int32.

Я не уверен, что происходит с ошибками "слишком много аргументов". Если вы вызываете эту функцию из Python, ее нужно объявить либо как def или cpdef. Функции, объявленные с помощью cdef, могут быть вызваны только из Cython. Это описано здесь в документах Cython.

Ответ 2

np.intp аналогичен (void *)

определите его тип следующим образом:

ctypedef np.npy_intp SIZE_t              # Type for indices and counters

Источник:

NPY_INTP == Значение перечисления для целочисленного типа со знаком, который имеет тот же размер, что и указатель (void *). Это тип, используемый всеми массивами индексов.

Так, например, в cython...

Структура в файле header file.h:

struct Cudamat_Struct1 {
    float * dataHost;
    float * dataDevice;
    int onDevice;
    int onHost;
    (void *) shape;
    int size;
    int isTrans; // 0 or 1
    int ownsData;

};

В файле cython file.pxd:

cdef extern from "file.h":
    cdef cppclass c_Cudamat_Struct "Cudamat_Struct":
        float *dataHost
        float *dataDevice
        bint onDevice
        bint onHost
        SIZE_t * shape
        int size
        bint isTrans
        bint ownsData

Наконец, в функции cython:

cdef pycublas_thrust_2d():
    cdef c_Cudamat_Struct1* mat = new c_Cudamat_Struct1()

    cdef int N = 10

    cdef np.ndarray[ndim=2, dtype=F32t] arrHost = np.ones((1,10),dtype=F32)

    cdef int size = 10

    cdef F32t[:,:] arrHost_ = arrHost

    cdef F32t * arrHostPtr = &arrHost[0,0]

    mat.dataHost = arrHostPtr
    mat.shape = arrHost.shape
    mat.size = size