使用numpy.cython中的数组



我想以cython格式重写一个类,并将其保存为demo.pyx。该类的输入参数可以是2D np。具有Nx2形状的数组,例如a=np.array([[0.2,-0.8],[3.7,0.02],..,[-0.92,-3.33]]),或instance a=[0.1,2.7]的列表。

cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef unsigned double *x 
    cdef unsigned double *y 
    def __init__(self, np.ndarray[np.float64_t,ndim=2,mode='c'] positions):
        self.x = &positions[:,0]
        self.y = &positions[:,1]

我尝试写的内容导致错误消息如下:

running build_ext
cythoning demo.pyx to demo.c
Error compiling Cython file:
------------------------------------------------------------
...
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef unsigned double *x 
        ^
------------------------------------------------------------
demo.pyx:5:9: Unrecognised type modifier combination
Error compiling Cython file:
------------------------------------------------------------
...
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef unsigned double *x 
    cdef unsigned double *y 
        ^
------------------------------------------------------------
demo.pyx:6:9: Unrecognised type modifier combination
Error compiling Cython file:
------------------------------------------------------------
...
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef unsigned double *x 
    cdef unsigned double *y 
    def __init__(self, np.ndarray[np.float64_t,ndim=2,mode='c'] positions):
        self.x = &positions[:,0]
                ^
------------------------------------------------------------
demo.pyx:8:17: Cannot take address of Python variable
Error compiling Cython file:
------------------------------------------------------------
...
cdef class halo_positions(object):
    cdef unsigned double *x 
    cdef unsigned double *y 
    def __init__(self, np.ndarray[np.float64_t,ndim=2,mode='c'] positions):
        self.x = &positions[:,0]
        self.y = &positions[:,1]
                ^
------------------------------------------------------------
demo.pyx:9:17: Cannot take address of Python variable

我知道我使用指针的方式有问题,但是如果我想保持xy的类型不明确,我需要使用它。我怎样才能使我的class工作?

当您执行positions[:,0]positions[:,1]时,您正在Cython中创建一个新的,1D和未声明的缓冲区。这不是一个可以从中获取地址的元素。该地址将对应于数组中的单个值,因此您应该这样做:

cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef double *x 
    cdef double *y 
    def __init__(self, np.ndarray[np.float64_t, ndim=2, mode='c'] positions):
        cdef np.ndarray[np.float64_t, ndim=1] buffx, buffy
        buffx = positions[:,0].copy()
        buffy = positions[:,1].copy()
        self.x = &buffx[0]
        self.y = &buffy[0]

注意:

  • YES,您可以将数组中元素的地址用作double *数组,例如对于b=&positions[0,0];positions[0,0]==b[0]positions[0,0+1]==b[1];当positions是c连续的2D数组时。您没有将np.ndarray转换为double *,只是直接从内存访问其数据;

  • 我使用.copy()来保证内存中有连续的数据。

  • 如果positions是fortrans -连续的,则不需要这样做。

&操作符接受对象的地址。将self.x指定为positions[0]的地址。所以应该是self.x = &position[0]。这读起来就像将self的成员x设置为position的第0个元素的地址。你要做的就是把x的地址设为。但你不能这么做。&只允许出现在等式的右边

Cython无法将numpy数组转换为double *,您可以使用double[:]代替,例如:

cimport numpy as np
cdef class halo_positions(object):
    cdef double *x 
    cdef double *y 
    def __init__(self, double[:] positions):
        self.x = &positions[0]
        self.y = &positions[1]
    def debug(self):
        print self.x[0], self.y[0]

但这很危险:

a = np.array([1.0, 2.0, 3.0, 4.0])
hp = halo_positions(a)
hp.debug()
del a
hp.debug() # x and y is wild pointer now.

也许你应该在halo_positions类中保留对positions的引用。

您的代码有几个问题。首先,也是最容易修复的,是没有"unsigned double"这样的东西,所以你应该删除unsigned作为开始。

同样,&positions[:,0]不是获取数组地址的正确语法,因为:将返回一个Python对象。您需要执行&positions[0,0],它指向数组的初始元素。

应该指出的是,你的__init__只适用于Numpy数组,而不是列表,正如你所说的那样。您必须事先将任何列表转换为数组。还要记住,你需要通过指针对你使用的任何数组保持一个活动引用,否则你会遇到麻烦。

根据你想对代码做什么,在类中使用指针变量可能不是最安全的选择。

我从cython得到的答案。Group in Google works perfect:

import cython
cimport cython
import numpy as np
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef double [:] _x
    property x:
        def __get__(self):
            return np.array(self._x)
        def __set__(self, np.ndarray[DTYPE_t, ndim=1] x):
            self._x = x
    cdef double [:] _y
    property y:
        def __get__(self):
            return np.array(self._y)
        def __set__(self, np.ndarray[DTYPE_t, ndim=1] y):
            self._y = y
    def __init__(self, np.ndarray[DTYPE_t,ndim=2] positions):
        self._x = positions[:,0]
        self._y = positions[:,1]
    def debug(self):
        print self.x, self.y

相关内容

  • 没有找到相关文章

最新更新