使用来自其他 Cython 代码的自定义 Cython 代码

发布于 2024-10-22 19:49:57 字数 2386 浏览 2 评论 0原文

我目前正在尝试优化我的 Python 程序,并开始使用 Cython 以减少函数调用开销,也许稍后会包含优化的 C 库函数。

所以我遇到了第一个问题:

我在代码中使用组合来创建一个更大的类。到目前为止,我已经将我的一个 Python 类转换为 Cython(这已经足够困难了)。代码如下:

import numpy as np
cimport numpy as np
ctypedef np.float64_t dtype_t
ctypedef np.complex128_t cplxtype_t
ctypedef Py_ssize_t index_t

cdef class bendingForcesClass(object):
    cdef dtype_t bendingRigidity
    cdef np.ndarray matrixPrefactor
    cdef np.ndarray bendingForces

    def __init__(self, dtype_t bendingRigidity, np.ndarray[dtype_t, ndim=2] waveNumbersNorm):
        self.bendingRigidity = bendingRigidity
        self.matrixPrefactor = -self.bendingRigidity * waveNumbersNorm ** 2

    cpdef np.ndarray calculate(self, np.ndarray membraneHeight):
        cdef np.ndarray bendingForces
        bendingForces = self.matrixPrefactor * membraneHeight
        return bendingForces

在我的组合 Python/Cython 类中,我调用类方法 calculate,因此在我的组合类中,我有以下(简化的)代码:

from bendingForcesClass import bendingForcesClass

cdef class membraneClass(object):
    def  __init__(self, systemSideLength, lowerCutoffLength, bendingRigidity):
        self.bendingForces = bendingForcesClass(bendingRigidity, self.waveNumbers.norm)

    def calculateForces(self, heightR):
        return self.bendingForces.calculate(heightR)

我发现 cpdef 使方法/函数可以从 Python 和 Cython 调用,这很棒并且有效,只要我不尝试事先定义 self.bendingForces 的类型 - 根据为了消除函数调用开销,文档(早期绑定速度)是必要的。我尝试了以下方法,但不起作用:

from bendingForcesClass import bendingForcesClass
from bendingForcesClass cimport bendingForcesClass

    cdef class membraneClass(object):
        cdef bendingForcesClass bendingForces

        def  __init__(self, systemSideLength, lowerCutoffLength, bendingRigidity):
            self.bendingForces = bendingForcesClass(bendingRigidity, self.waveNumbers.norm)

        def calculateForces(self, heightR):
            return self.bendingForces.calculate(heightR)

在尝试使用 Cython 构建 membraneClass.pyx 时,我收到此错误:

membraneClass.pyx:18:6: 'bendingForcesClass' is not a type identifier
building 'membraneClass' extension

请注意,声明位于两个单独的文件中,这使得这变得更加困难。

那么我该如何完成这件事呢?如果有人能给我指点,我将非常感激,因为除了上面给出的链接之外,我找不到任何有关此的信息。

谢谢并致以诚挚的问候!

I am currently trying to optimize my Python program and got started with Cython in order to reduce the function calling overhead and perhaps later on include optimized C-libraries functions.

So I ran into the first problem:

I am using composition in my code to create a larger class. So far I have gotten one of my Python classes converted to Cython (which was difficult enough). Here's the code:

import numpy as np
cimport numpy as np
ctypedef np.float64_t dtype_t
ctypedef np.complex128_t cplxtype_t
ctypedef Py_ssize_t index_t

cdef class bendingForcesClass(object):
    cdef dtype_t bendingRigidity
    cdef np.ndarray matrixPrefactor
    cdef np.ndarray bendingForces

    def __init__(self, dtype_t bendingRigidity, np.ndarray[dtype_t, ndim=2] waveNumbersNorm):
        self.bendingRigidity = bendingRigidity
        self.matrixPrefactor = -self.bendingRigidity * waveNumbersNorm ** 2

    cpdef np.ndarray calculate(self, np.ndarray membraneHeight):
        cdef np.ndarray bendingForces
        bendingForces = self.matrixPrefactor * membraneHeight
        return bendingForces

From my composed Python/Cython class I am calling the class-method calculate, so that in my composed class I have the following (reduced) code:

from bendingForcesClass import bendingForcesClass

cdef class membraneClass(object):
    def  __init__(self, systemSideLength, lowerCutoffLength, bendingRigidity):
        self.bendingForces = bendingForcesClass(bendingRigidity, self.waveNumbers.norm)

    def calculateForces(self, heightR):
        return self.bendingForces.calculate(heightR)

I have found out that cpdef makes the method/functions callable from Python and Cython, which is great and works, as long as I don't try to define the type of self.bendingForces beforehand - which according to the documentation (Early Binding For Speed) is necessary in order to remove the function-calling overhead. I have tried the following, which does not work:

from bendingForcesClass import bendingForcesClass
from bendingForcesClass cimport bendingForcesClass

    cdef class membraneClass(object):
        cdef bendingForcesClass bendingForces

        def  __init__(self, systemSideLength, lowerCutoffLength, bendingRigidity):
            self.bendingForces = bendingForcesClass(bendingRigidity, self.waveNumbers.norm)

        def calculateForces(self, heightR):
            return self.bendingForces.calculate(heightR)

With this I get this error, when trying to build membraneClass.pyx with Cython:

membraneClass.pyx:18:6: 'bendingForcesClass' is not a type identifier
building 'membraneClass' extension

Note that the declarations are in two separate files, which makes this more difficult.

So I how do I get this done? I would be very thankful if someone could give me a pointer, as I can't find any information about this, besides the link given above.

Thanks and best regards!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

耶耶耶 2024-10-29 19:49:57

免责声明:这个问题很老了,我不确定当前的解决方案是否适用于 2011 Cython 代码。

为了从另一个文件导入扩展类(cdef 类),您需要提供 .pxd 文件(也称为定义文件)声明所有 C 类、属性和方法。请参阅文档中的共享扩展类型供参考。

对于您的示例,您需要一个文件 bendingForcesClass.pxd,它声明您想要共享的类,以及所有 cimport、模块级变量、typedef 等:

bendingForcesClass .pxd

# cimports
cimport numpy as np

# typedefy you want to share
ctypedef np.float64_t dtype_t
ctypedef np.complex128_t cplxtype_t
ctypedef Py_ssize_t index_t

cdef class bendingForcesClass:
    # declare C attributes
    cdef dtype_t bendingRigidity
    cdef np.ndarray matrixPrefactor
    cdef np.ndarray bendingForces

    # declare C functions
    cpdef np.ndarray calculate(self, np.ndarray membraneHeight)

    # note that __init__ is missing, it is not a C (cdef) function

所有导入、变量和现在在 .pxd 文件中声明的属性可以(并且必须)从 .pyx 文件中删除:

bendingForcesClass .pyx

import numpy as np

cdef class bendingForcesClass(object):

    def __init__(self, dtype_t bendingRigidity, np.ndarray[dtype_t, ndim=2] waveNumbersNorm):
        self.bendingRigidity = bendingRigidity
        self.matrixPrefactor = -self.bendingRigidity * waveNumbersNorm ** 2

    cpdef np.ndarray calculate(self, np.ndarray membraneHeight):
        cdef np.ndarray bendingForces
        bendingForces = self.matrixPrefactor * membraneHeight
        return bendingForces

现在您的 cdef 类 bendingForcesClass可以从其他 Cython 模块导入,使其成为有效的类型标识符,这应该可以解决您的问题。

Disclaimer: This question is very old and I am not sure the current solution would work for 2011 Cython code.

In order to cimport an extension class (cdef class) from another file you need to provide a .pxd file (also known as a definitions file) declaring all C classes, attributes and methods. See Sharing Extension Types in the documentation for reference.

For your example, you would need a file bendingForcesClass.pxd, which declares the class you want to share, as well as all cimports, module level variables, typedefs, etc.:

bendingForcesClass .pxd

# cimports
cimport numpy as np

# typedefy you want to share
ctypedef np.float64_t dtype_t
ctypedef np.complex128_t cplxtype_t
ctypedef Py_ssize_t index_t

cdef class bendingForcesClass:
    # declare C attributes
    cdef dtype_t bendingRigidity
    cdef np.ndarray matrixPrefactor
    cdef np.ndarray bendingForces

    # declare C functions
    cpdef np.ndarray calculate(self, np.ndarray membraneHeight)

    # note that __init__ is missing, it is not a C (cdef) function

All imports, variables, and attributes that now are declared in the .pxd file can (and have to be) removed from the .pyx file:

bendingForcesClass .pyx

import numpy as np

cdef class bendingForcesClass(object):

    def __init__(self, dtype_t bendingRigidity, np.ndarray[dtype_t, ndim=2] waveNumbersNorm):
        self.bendingRigidity = bendingRigidity
        self.matrixPrefactor = -self.bendingRigidity * waveNumbersNorm ** 2

    cpdef np.ndarray calculate(self, np.ndarray membraneHeight):
        cdef np.ndarray bendingForces
        bendingForces = self.matrixPrefactor * membraneHeight
        return bendingForces

Now your cdef class bendingForcesClass can be cimported from other Cython modules, making it a valid type identifier, which should solve your problem.

网名女生简单气质 2024-10-29 19:49:57

您需要使用声明“.pxd”文件和 cimport。 (本质上,cimport 发生在编译时,而 import 发生在运行时,因此 Cython 无法利用任何重要的内容)。

创建“utils.pxd”:

cdef class MyClass:
    cdef readonly int field
    cdef void go(self, int i)

“utils.pyx”现在读取

cdef class MyClass:
    def __init__(self, field):
    self.field = field

cdef void go(self, int i):
    self.field = i

pyx 文件中的所有声明读取到 .pxd 文件中。

然后在mymodule.pyx中

from utils import MyClass
from utils cimport MyClass
# other code follows...

// 这里的扩展答案:
Cython:在类型声明中使用导入的类

You need to use a declaration ".pxd" file and cimport. (Essentially, cimport happens at compile time, while import happens at run time so Cython can't make use of anything important).

Create "utils.pxd":

cdef class MyClass:
    cdef readonly int field
    cdef void go(self, int i)

"utils.pyx" now reads

cdef class MyClass:
    def __init__(self, field):
    self.field = field

cdef void go(self, int i):
    self.field = i

all declarations which have been in the pyx file go into the .pxd file.

Then in mymodule.pyx

from utils import MyClass
from utils cimport MyClass
# other code follows...

// Extended answer from here:
Cython: using imported class in a type declaration

So尛奶瓶 2024-10-29 19:49:57

这些可能不是错误的根源,但为了缩小问题范围,您可以尝试更改以下内容:

是否您在此处使用 bendingForces 作为变量的名称:

cpdef np.ndarray calculate( self, np.ndarray membraneHeight ) :
      cdef np.ndarray bendingForces
      bendingForces = self.matrixPrefactor * membraneHeight
      return bendingForces

以及也是此处成员对象的名称:

cdef class membraneClass( object ):
    cdef bendingForcesClass bendingForces

此外,bendingForcesClass 是模块和类的名称。最后,从类 bendingForcesClass 中创建一个 ctypedef 怎么样?

These are probably not the source of the error, but just to narrow down the problem, you might try to change the following:

Could it be that you are using bendingForces as the name of the variable here:

cpdef np.ndarray calculate( self, np.ndarray membraneHeight ) :
      cdef np.ndarray bendingForces
      bendingForces = self.matrixPrefactor * membraneHeight
      return bendingForces

and also the name of the member object here:

cdef class membraneClass( object ):
    cdef bendingForcesClass bendingForces

Also, bendingForcesClass is the name of the module as well as the class. Finally, how about making a ctypedef from the class bendingForcesClass?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文