Почему Cython ожидает 0 измерений? - PullRequest
4 голосов
/ 18 февраля 2020

Я свел мою проблему к небольшому воспроизводимому контрольному примеру:

В файле 1 (custom_cython.pyx) у меня есть следующее:

import numpy as np
cimport numpy as np
cimport cython

ctypedef np.uint8_t DTYPE_B_t
ctypedef np.uint16_t CELL_ID_t
ctypedef np.int64_t DTYPE_INT64_t


cdef struct LOOKUPMEM_t:
    DTYPE_B_t filled_flag
    CELL_ID_t key_i
    CELL_ID_t key_j
    CELL_ID_t key_k
    DTYPE_INT64_t offset
    DTYPE_INT64_t num_elements  


cdef LOOKUPMEM_t[:] lookup_memory


my_dtype = [("filled_flag", np.uint8, 1),
            ("ijk", np.uint16, 3),
            ("offset_and_num", np.int64, 2)]

input_numpy_dtype = np.dtype(my_dtype, align=True)

lookup_memory = np.zeros(5000, dtype=input_numpy_dtype)

В файле 2 (custom_cython_test .py) У меня есть следующее:

from custom_cython import lookup_memory

print(lookup_memory)

Когда я запускаю python custom_cython_test.py, я получаю ValueError: Expected 0 dimension(s), got 1 в строке lookup_memory = np.zeros(5000, dtype=input_numpy_dtype)

В своем определении структуры я попытался использовать cdef packed struct LOOKUPMEM_t и align=False при создании dtype, и это приводит к той же ошибке.

Я на Python 3.7.3 с Cython версии 0.29.12 и Numpy 1.16.4.

Я успешно назначил просмотры памяти Cython для массивов 1-D numpy раньше, поэтому я озадачен тем, почему мой очевидный 1d cdef LOOKUPMEM_t[:] lookup_memory ожидает 0 измерений. Может кто-нибудь сказать мне, что происходит?

1 Ответ

3 голосов
/ 18 февраля 2020

Кажется, проблема в этой части вашей структуры:

    CELL_ID_t key_i
    CELL_ID_t key_j
    CELL_ID_t key_k

в сочетании с этой частью вашего dtype:

("ijk", np.uint16, 3)

и аналогично для вашего комбинированного поля offset_and_num.

Проблема в том, что когда интерфейс вида памяти видит поле типа кортежа, подобное ("ijk", np.uint16, 3), он хочет распаковать его в одномерный массив из 3 элементов, но следующий ключ в структуре - просто CELL_ID_t key_i, скаляр 0-D.

Если я изменю вашу структуру, чтобы она более точно соответствовала Numpy dtype, он работает:

cdef struct LOOKUPMEM_t:
    DTYPE_B_t filled_flag
    CELL_ID_t ijk[3]
    DTYPE_INT64_t offset_num_elements[2]

Так что у вас есть несколько вариантов действий , Если вы действительно хотите сохранить свою структуру таким же образом, вы можете сделать это и отформатировать dtype по-другому. Поскольку легко просматривать Numpy массивы с разными dtypes, вы также можете использовать другой dtype для инициализации просмотра памяти, если вы хотите сохранить существующий формат dtype для других случаев использования.

...