2014-06-09 132 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