1

我正在尝试将 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.]]))
4

3 回答 3

2

您可以创建一个临时缓冲区,该缓冲区将接收 的值,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()如果您使用 anp.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
于 2014-05-23T12:01:04.797 回答
1

这不是由视图或 Cython 引起的。B = la.inv(A)创建一个新数组并Btestfunc1. 这不会影响名称为Bin的数组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.]])
>>> 
于 2014-05-23T11:54:55.340 回答
0

如果我在上创建 mememoryview,la.inv(A)我可以执行 1 步,并且可能是高效的,memoryview 到 memoryview 的副本:

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

我猜 memoryview 副本会更快,但样本数组对于有意义的时间测试来说太小了。

我在https://stackoverflow.com/a/30418448/901925上对此进行了测试作为响应的一部分


Python您可以重新分配data数组的缓冲区(尽管有一定风险):

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

cython使用此语句在编译阶段引发有关不安全指针的错误。

受我为https://stackoverflow.com/a/28855962/901925 using找到的示例的启发np.PyArray_SimpleNewFromData,我尝试使用其他PyArray...函数进行相同类型的base重新分配:

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

目前我正在尝试解决一个AttributeError: 'module' object has no attribute 'PyArray_SetBaseObject'错误。

于 2015-05-23T23:04:39.553 回答