2014-06-09 136 views
0

我想重写cython格式的类,并将其另存为demo.pyx。该类别的输入参数可以是具有Nx2形状的2D np.arraya=np.array([[0.2,-0.8],[3.7,0.02],..,[-0.92,-3.33]])instance a=[0.1,2.7]的列表。在cython中使用numpy.array

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 

我知道有一个与我所使用的指针的方式有问题,但如果我想保持的x类型和y含糊不清,我需要用这个。我怎么能让我的class工作?

+1

有没有这样的事情在C.浮点类型的'无符号double'总是签署。 –

回答

0

的答案,我在谷歌cython.group得到了完美的作品:

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 
0

&运算符取对象的地址。你想分配self.x作为地址positions[0]。所以它应该是self.x = &position[0]。这读取设置自己的成员x称为位置的第0个元素的地址。你试图做的是将x的地址设置为某些东西。但你不能这样做。 &只允许在方程的右边。

+0

但我需要在分配任何内容之前声明'x'和'y'的类型吗? – Dalek

0

用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. 

也许你应该保持一个参考positionshalo_positions类中。

+0

我没有声明类型和使用指针的目的是我想要给这个类提供一个列表,例如'a = [1,2]',并且它能够将它们分开并将它们分配给'x ''和'y'或像a = np.array([[1.0,2.0],[3.0,4.0]])这样的二维数组'',我可以将第一列分配给'x',第二列到'y'。但你举个例子,用** 1D数组** **。 – Dalek

+0

你可以发布一些例子来展示如何使用halo_positions类吗?我想要传递1-dim和2-dim数组,然后你应该将'positions'声明为'ndarray'对象。 – HYRY

+0

我更新了我写作班级的内容以及我希望传递给班级的哪种输入。提前致谢。 – Dalek

0

您的代码有几个问题。首先,也是最容易解决的问题是,不存在“无符号双精度”这样的事情,所以您应该先删除unsigned

另外,&positions[:,0]不是获取数组地址的正确语法,因为:将返回一个Python对象。你需要做&positions[0,0],它指向数组的最初元素。

需要指出的是,__init__只适用于Numpy数组,而不是列表,因为您声明您希望这样做。您必须事先将任何列表转换为数组。另外请记住,您需要保留对通过指针使用的任何数组的主动引用,否则您将遇到麻烦的麻烦。

尽管如此,取决于您想要对代码做什么,在您的类中使用指针变量可能并不是最安全的选择。

+0

但我应该如何初步定义'x'和'y'? – Dalek

+0

就像你做的,但没有无符号的,即'cdef double * x'和'cdef double * y' – Dologan

1

当你做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连续的二维数组。您不是将np.ndarray转换为double *,只是直接从内存访问其数据;

  • 我正在使用.copy()来保证你在内存中有连续的数据。如果positions是Fortran连续的,这将是不必要的。

+0

我得到这个错误信息'positions.pyx:16:26:无法将'double *'转换为Python对象'建立'职位'扩展' – Dalek

+0

@Dalek,但这个错误似乎是在别的地方,你是否已经通过了你原来的问题指出的问题? –

+0

以及我加了'def debug(self):print self.x,self.y'并试图调用它。 – Dalek