如何使用通用浮点类型在cython中声明一个ndarray

时间:2014-04-28 21:53:40

标签: python numpy cython

如果它能够同时处理float和double,那么在cython中声明numpy数组的最佳方法是什么?

我想因为数据类型是至关重要的,但是对于内存视图来说它是不可能的,但是对于一个ndarray,有没有办法给它一个通用浮点类型,这仍然可以从cython的快速性中受益? / p>

所以这就是我通常会做的事情:

def F( np.ndarray A):
    A += 10

我已经看到还有:

def F( np.ndarray[np.float32_t, ndim=2] A):
    A += 10

但是这又会为该类型提供一点尺寸。我还想到了根据位大小(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

当我现在用两个np.float32数组调用该函数时,我得到了错误

  

ValueError:缓冲区dtype不匹配,预期'浮动'但得到了双倍的'

如果我没有在Rot的制动器中使用类型定义,那么它会读取np.ndarray[floating, ndim=3] Rot = np.empty((T,3,3))然后我得到ndarray,它运行正常。你碰巧有一个指针告诉我我做错了吗?

2 个答案:

答案 0 :(得分:12)

对于融合类型支持,这实际上非常简单:

  

这会进入你的代码。

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

当然,有很多方法可以做到这一点:

  

将此 fuzed.pyx 命名为。没有必要在其上编译或运行cython;它由pyximport处理。但是,不要将pyximport用于生产代码,因为您通常只应提供.c个文件。

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):
    # ...

这是一个小测试脚本:

  

将此 test.py 命名为普通Python脚本:

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))

值得注意的是,融合类型专门用于编译,并且对于特定的函数调用是常量。您创建的空Numpy数组始终为double类型,但您可以将其分配给32位浮点数或64位浮点数。这是你应该做的:

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

和一些测试来证明这一点:

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

答案 1 :(得分:2)

融合类型只能在函数声明中使用。我能想出的最好的比喻是C ++中的模板。

创建一个可以与float32 / 64一起使用的函数

from cython import floating, numeric
cimport cython

def func_float(floating a):
    print cython.typeof(a)

但是,您只能在已经出现在函数声明中的函数中使用Fused Types