Кажется, что Cython использует неправильный шаг всякий раз, когда я присваиваю одно значение срезу многомерного представления памяти, за исключением случаев, когда срез находится по первому измерению. Я привожу полный пример ниже:
# bug.py
import numpy as np
def bug():
#cdef int[:, ::1] a
a = 2*np.ones((2, 2), dtype=np.intc)
a[:, :1] = 1
print(np.asarray(a))
Если мы запустим это в Python (например, python3 -c 'import bug; bug.bug()'
), мы получим
[[1 2]
[1 2]]
распечатано, как и ожидалось. Теперь я скомпилирую его с Cython, переименовав файл в bug.pyx
, сохранив следующее в Makefile
в том же каталоге,
# Makefile
python = python3
python_config = $(python)-config
CC = gcc
CFLAGS = $(shell $(python_config) --cflags) -fPIC
CFLAGS += $(shell $(python_config) --includes)
python_libdir = $(shell $(python) -c "import sysconfig; \
print(sysconfig.get_config_var('LIBDIR'));")
LDLIBS = -L$(python_libdir) -Wl,-rpath=$(python_libdir)
LDLIBS += $(shell $(python_config) --libs)
LDFLAGS = $(shell $(python_config) --ldflags) -shared
bug.so: bug.c; $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o bug.so bug.c
bug.c: bug.pyx; $(python) -m cython -3 $<
и запустите make
. Снова запустив python3 -c 'import bug; bug.bug()'
, он теперь подбирает скомпилированный bug.so
, который снова выводит
[[1 2]
[1 2]]
Если мы теперь раскомментируем объявление cdef
, снова запустим make
и python3 -c 'import bug; bug.bug()'
, мы получим
[[1 1]
[2 2]]
что неправильно. Я не считаю, что декларация int[:, ::1]
неверна, поскольку Cython будет жаловаться. Если я заменю его только на int[:, :]
, он сработает. Кроме того, если я назначу первому измерению a
, a[:1, :] = 1
, это сработает.
Это известная проблема, или я как-то неправильно понимаю это, казалось бы, базовое использование представлений памяти Cython?
print(a.flags)
(в чистом Python, без компиляции), мы увидим, чтоa
действительно является C-непрерывным, поэтомуint[:, ::1] a
правильно. Однакоprint(a[:, :1].flags)
нет! Я предполагаю, что это источник проблемы. - person jmd_dk   schedule 07.05.2019