我试图将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.]]))
答案 0 :(得分: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()
而不是MemoryView,则可以使用np.ndarray
:
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
答案 1 :(得分: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.]])
>>>
答案 2 :(得分: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
我猜测内存视图副本会更快,但样本数组太小而无法进行有意义的时间测试。
我在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使用np.PyArray_SimpleNewFromData
找到的示例的启发,我尝试使用其他PyArray...
函数执行相同类型的base
重新分配:
np.PyArray_SetBaseObject(B, np.PyArray_BASE(la.inv(A)))
目前我正在尝试解决AttributeError: 'module' object has no attribute 'PyArray_SetBaseObject'
错误。