Назначение пустых данных в Cython представлению

Я пытаюсь назначить вывод обратной функции linalg (la.inv) для представления в Cython. К сожалению, это не работает. Я всегда могу назначить вывод la.inv() временному объекту ndarray, а затем скопировать его содержимое в представление.

Есть ли лучший способ сделать это.

cpdef int testfunc1(np.ndarray[np.float_t, ndim=2] A,
                    double [:,:] B) except -1:

    print("inverse of A:", la.inv(A))
    if np.isnan(A).any():
        return -1
    else:
        B = la.inv(A)
        return 1


cpdef int testfunc2(np.ndarray[np.float_t, ndim=2] A) except -1:
    cdef long p = np.shape(A)[0], status
    cdef B = np.zeros(shape=(p, p), dtype=float)
    cdef double[:,:] BView = B
    print("before inverse. B: ", B)
    status = testfunc1(A, BView)
    print("after inverse. B: ", B)
    if status == -1:
        return -1
    else:
        return 1

Выход:

A = np.random.ranf(4).reshape(2, 2)
        status = testfunc2(A)
        if status == -1:
            raise ValueError("nan cell.")
        else:
            print("pass")

('before inverse. B: ', array([[ 0.,  0.],
       [ 0.,  0.]]))
('inverse of A:', array([[ 4.4407987 , -0.10307341],
       [-2.26088593,  1.19604499]]))
('after inverse. B: ', array([[ 0.,  0.],
       [ 0.,  0.]]))

3 ответа

Вы можете создать временный буфер, который будет получать значение la.inv() а затем заполните представление памяти:

import numpy as np
cimport numpy as np
import numpy.linalg as la

cpdef int testfunc1(np.ndarray[np.float_t, ndim=2] A,
                    double [:,:] B) except -1:
    cdef np.ndarray[np.float_t, ndim=2] buff
    cdef int i, j

    print("inverse of A:", la.inv(A))
    if np.isnan(A).any():
        return -1
    else:
        buff = la.inv(A)
        for i in range(buff.shape[0]):
            for j in range(buff.shape[1]):
                B[i, j] = buff[i, j]
        return 1

cpdef int testfunc2(np.ndarray[np.float_t, ndim=2] A) except -1:
    cdef long p = np.shape(A)[0], status
    cdef B = np.zeros(shape=(p, p), dtype=float)
    cdef double[:,:] BView = B
    print("before inverse. B: ", B)
    status = testfunc1(A, BView)
    print("after inverse. B: ", B)
    if status == -1:
        return -1
    else:
        return 1

Как указывает @MrE, вы можете использовать np.copyto() если вы используете np.ndarray вместо MemoryView:

cpdef int testfunc1(np.ndarray[np.float_t, ndim=2] A,
                    np.ndarray[np.float_t, ndim=2] B) except -1:
    cdef int i, j
    print("inverse of A:", la.inv(A))
    if np.isnan(A).any():
        return -1
    else:
        np.copyto(B, la.inv(A))
        return 1

cpdef int testfunc2(np.ndarray[np.float_t, ndim=2] A) except -1:
    cdef long p = np.shape(A)[0], status
    cdef np.ndarray[np.float_t, ndim=2] B, BView
    B = np.zeros(shape=(p, p), dtype=float)
    BView = B
    print("before inverse. B: ", B)
    status = testfunc1(A, BView)
    print("after inverse. B: ", B)
    if status == -1:
        return -1
    else:
        return 1

Это не вызвано взглядами или Cython. B = la.inv(A) создает новый массив и дает ему имя B в объеме testfunc1, Это не влияет на массив с именем B в testfunc2,

Имейте в виду, что ваш код, где тяжелая работа выполняется функциями NumPy, вряд ли выиграет от Cython.

Один из способов сделать эту работу - это сделать:

np.copyto(B, la.inv(A))

в testfunc1, @SaulloCastro упоминает, что это не работает в Cython как B имеет тип представления памяти, однако вы можете сделать это, объявив аргумент B как ndarray (не уверен в этом). В противном случае без Cython:

>>> import numpy as np
>>> X = np.zeros((5, 5))
>>> B = X[:3, :3]
>>> A = np.ones((3, 3))
>>> np.copyto(B, A)
>>> X
array([[ 1.,  1.,  1.,  0.,  0.],
       [ 1.,  1.,  1.,  0.,  0.],
       [ 1.,  1.,  1.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])
>>> 

Если я создаю воспоминания о la.inv(A) Я могу выполнить один шаг, и, по-видимому, эффективный, просмотр из памяти в копию с просмотром памяти:

cpdef int testfunc1c(np.ndarray[np.float_t, ndim=2] A,
                    double [:,:] BView) except -1:
    cdef double[:,:] CView
    print("inverse of A:", la.inv(A))
    if np.isnan(A).any():
        return -1
    else:
        CView = la.inv(A)
        BView[...] = CView
        return 1

производство:

In [4]: so23827902.testfunc2(A)
('before inverse. B: ', array([[ 0.,  0.],
       [ 0.,  0.]]))
('inverse of A:', array([[ 1.04082818, -0.14530117],
       [-0.24050511,  1.13292585]]))
('after inverse. B: ', array([[ 1.04082818, -0.14530117],
       [-0.24050511,  1.13292585]]))
Out[4]: 1

Я предполагаю, что копия памяти будет быстрее, но выборочные массивы слишком малы для значимых временных тестов.

Я проверил это как часть ответа на /questions/2572988/skopirujte-massiv-numpy-v-pamyat/2572995#2572995


В Python Вы можете переназначить data буфер массива (хотя и с некоторым риском):

B = np.zeros_like(A)
C = la.inv(A)
B.data = C.data

cython с этим оператором выдает ошибки о небезопасных указателях на этапе компиляции.

Вдохновленный примерами, которые я нашел для /questions/33731496/cython-sozdat-obekt-ndarray-bez-vyideleniya-pamyati-dlya-dannyih/33731506#33731506 используя np.PyArray_SimpleNewFromDataЯ пытался использовать другие PyArray... функции, чтобы сделать такой же вид base переназначение:

np.PyArray_SetBaseObject(B, np.PyArray_BASE(la.inv(A)))

В настоящее время я пытаюсь решить AttributeError: 'module' object has no attribute 'PyArray_SetBaseObject' ошибка.

Другие вопросы по тегам