Mag*_*n88 8 python numpy cython
如果它应该能够同时处理float和double,那么在cython中声明numpy数组的最佳方法是什么?
我想用内存视图是不可能的,因为数据类型是至关重要的,但是对于ndarray有什么方法可以给它一个通用浮点类型,这仍然有利于cython的快速性?
所以这就是我通常会做的事情:
def F( np.ndarray A):
A += 10
Run Code Online (Sandbox Code Playgroud)
我已经看到还有:
def F( np.ndarray[np.float32_t, ndim=2] A):
A += 10
Run Code Online (Sandbox Code Playgroud)
但这又会给这个类型增加一点尺寸.我还想过根据位大小(32或64)在函数内部创建内存视图.
任何想法都受到高度赞赏
非常感谢您对该floating
类型的提示.我试过这样的
import numpy as np
cimport numpy as np
import cython
cimport cython
from libc.math cimport sqrt, abs
from cython cimport floating
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
def Rot_Matrix(np.ndarray[floating, ndim=3] Fit_X,
np.ndarray[floating, ndim=3] Ref_X,
weight = None):
cdef:
unsigned int t, T = Fit_X.shape[0]
unsigned int n, N = Fit_X.shape[1]
np.ndarray[floating, ndim=3] Rot = np.empty((T,3,3))
return Rot
Run Code Online (Sandbox Code Playgroud)
当我现在用两个np.float32数组调用该函数时,我得到了错误
ValueError:Buffer dtype不匹配,预期'float'但得到'double'
如果我不在制动器中使用类型定义,Rot
那么它会读取np.ndarray[floating, ndim=3] Rot = np.empty((T,3,3))
然后我得到ndarray,它工作正常.你碰巧有一个指针,告诉我我做错了什么吗?
Vee*_*rac 12
Well this is actually really easy with fused types support:
This goes inside your code.
from cython cimport floating
def cythonfloating_memoryview(floating[:, :] array):
cdef int i, j
for i in range(array.shape[0]):
for j in range(array.shape[1]):
array[i, j] += 10
Run Code Online (Sandbox Code Playgroud)
Of course, there are loads of ways of doing this:
Name this fuzed.pyx. There's no need to compile or run
cython
on it; it's handled bypyximport
. Don't usepyximport
for production code, though, as you should typically only ship.c
files.
from cython cimport floating
from numpy import float32_t, float64_t, ndarray
ctypedef fused myfloating:
float32_t
float64_t
def cythonfloating_memoryview(floating[:, :] array):
# ...
def cythonfloating_buffer(ndarray[floating, ndim=2] array):
# ...
def myfloating_memoryview(myfloating[:, :] array):
# ...
def myfloating_buffer(ndarray[myfloating, ndim=2] array):
# ...
Run Code Online (Sandbox Code Playgroud)
and here's a little test script:
Name this test.py and run it as a normal Python script:
import pyximport
pyximport.install()
import fuzed
import numpy
functions = [
fuzed.cythonfloating_memoryview,
fuzed.cythonfloating_buffer,
fuzed.myfloating_memoryview,
fuzed.myfloating_buffer,
]
for function in functions:
floats_32 = numpy.zeros((100, 100), "float32")
doubles_32 = numpy.zeros((100, 100), "float64")
function(floats_32)
function(doubles_32)
print(repr(floats_32))
print(repr(doubles_32))
Run Code Online (Sandbox Code Playgroud)
It's worth noting that fused types are specialised at compilation, and are constant for a particular function invocation. The empty Numpy array you make is always of a double
type, but you assign it to either a 32-bit float or a 64-bit float. Here's what you should do:
from cython cimport floating
import numpy
def do_some_things(floating[:] input):
cdef floating[:] output
if floating is float:
output = numpy.empty(10, dtype="float32")
elif floating is double:
output = numpy.empty(10, dtype="float64")
else:
raise ValueError("Unknown floating type.")
return output
Run Code Online (Sandbox Code Playgroud)
and some tests to prove the point:
import pyximport
pyximport.install()
#>>> (None, None)
import floatingtest
import numpy
floatingtest.do_some_things(numpy.empty(10, dtype="float32"))
#>>> <MemoryView of 'ndarray' at 0x7f0a514b3d88>
floatingtest.do_some_things(numpy.empty(10, dtype="float32")).itemsize
#>>> 4
floatingtest.do_some_things(numpy.empty(10, dtype="float64"))
#>>> <MemoryView of 'ndarray' at 0x7f0a514b3d88>
floatingtest.do_some_things(numpy.empty(10, dtype="float64")).itemsize
#>>> 8
Run Code Online (Sandbox Code Playgroud)