簡體   English   中英

在cython中使用numpy.array

[英]Using numpy.array in cython

我想以cython格式重寫一個類,並將其另存為demo.pyx。 該類的輸入參數將是具有Nx2形狀的2D np.array ,例如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]

注意:

  • 是的 ,您可以獲取數組中元素的地址並將其用作double *數組,例如對於b=&positions[0,0] positions[0,0]==b[0]positions[0,0+1]==b[1] positions是C連續的2D數組時。 您不是將np.ndarray轉換為double * ,而是直接從內存訪問其數據;

  • 我正在使用.copy()來保證您的內存中有連續的數據。 如果positions是Fortran連續的,這將是不必要的。

&運算符采用對象的地址。 您想要將self.x分配為positions[0]的地址。 所以應該是self.x = &position[0] 這將設置為x的self成員讀取為位置的第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數組,不適用於列表,如您聲明的那樣。 您必須事先將任何列表轉換為數組。 還請記住,您需要保持對通過其指針使用的任何數組的有效引用,否則將遇到麻煩。

通常,根據您想對代碼執行的操作,在類中使用指針變量可能不是最安全的選擇。

我從google的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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM