在cython中正确使用numpy recarray作为c结构数组

2024-09-29 23:19:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我想在cython中使用类似structurarray的东西,并且我希望这个structurarray在python中和在cython中一样容易访问。 基于一时兴起,我使用了一个重排,使用了一个看起来像我想要使用的结构的数据类型。奇怪的是,对于python来说,可以使用一个strucy数组。在

这是我的例子

# This is a "structarray in cython with numpy recarrays" testfile
import numpy as np
cimport numpy as np

# My structarray has nodes with fields x and y
# This also works without packed, but I have seen packed used in other places where people asked similar questions
# I assume that for two doubles that is equivalent but is necessary for in8s in between
cdef packed struct node:
    double x
    double y
# I suppose that would be the equivalent numpy dtype?
# Note: During compilation it warns me about double to float downcasts, but I do not see where
nodetype = [('x' , np.float64),('y', np.float64)]

def fun():
    # Make 10 element recarray
    # (Just looked it up. A point where 1-based indexing would save a look in the docs)
    mynode1 = np.recarray(10,dtype=nodetype)

    # Recarray with cdef struct
    mynode1 = np.recarray(10,dtype=nodetype)

    # Fill it with non-garbage somewhere
    mynode1[2].x=1.0
    mynode1[2].y=2.0

    # Brave: give recarray element to a c function assuming its equivalent to the struct
    ny = cfuny(mynode1[2])
    assert ny==2.0 # works!

    # Test memoryview, assuming type node
    cdef node [:] nview = mynode1
    ny = cfunyv(nview,2)
    assert ny==2.0 # works!

    # This sets the numpy recarray value with a c function the gts a memoryview
    cfunyv_set(nview,5,9.0)
    assert mynode1[5].y==9.0 # alsow works!

    return 0

# return node element y from c struct node
cdef double cfuny(node n):
    return n.y

# give element i from memoryview of recarray to c function expecting a c struct
cdef double cfunyv(node [:] n, int i):
    return cfuny(n[i])

# write into recarray with a function expecting a memoryview with type node
cdef int cfunyv_set(node [:] n,int i,double val):
    n[i].y = val
    return 0

当然我不是第一个尝试这个的人。在

例如,Here也做了同样的事情,它甚至声明这种用法是手册here的一部分,但是我在页面上找不到这个。我怀疑它在某个地方。还有一些讨论涉及到在这种自定义类型中使用字符串(例如here),从答案中我发现,对cstruct进行重新排列的可能性是预期行为,在讨论中,我们讨论了如何结合一个关于给定示例的回归测试,并在某个点上修复了字符串错误。在

我的问题

我找不到任何文件表明,除了论坛答案,这应该是有效的。有人能告诉我文件记录在哪里吗?在

而且,为了一些额外的好奇心

  • 在numpy或cython的发展过程中,这可能会在任何时候中断吗?在
  • 从其他关于这个主题的论坛条目来看,packaged对于这一点是必要的,因为有更多有趣的数据类型是结构的一部分。我不是编译器专家,也从来没有使用过结构打包,但我怀疑一个结构是否打包取决于编译器的设置。这是否意味着不使用打包结构编译numpy的人需要编译这个cython代码而不使用压缩的?在

Tags: theinnumpynodereturnwithnp结构
2条回答

回答最后一个问题:

From the other forum entries on the subject it seems that packed is necessary for this to work once more interesting datatypes are part of the struct. I am not a compiler expert and have never used structure packing myself, but I suspect that whether a structure gets packed or not depends on the compiler settings. Does that mean that someone who compiles numpy without packing structures needs to compile this cython code without the packed?

Numpy的行为是在运行时而不是在编译时决定的。它将计算一个结构可以需要的最小空间量并分配这些空间块。它不会被任何编译器设置更改,所以应该是可靠的。在

因此,总是需要cdef packed struct来匹配numpy。但是,它不会生成符合标准的C代码。相反,它使用GCCMSVC(以及其他)的扩展。因此,它在当前存在的主要C编译器上工作良好,但原则上可能在将来的编译器上失败。看起来应该可以使用C11标准alignas以符合标准的方式实现相同的功能,因此如果需要的话,可以对Cython进行修改。在

这似乎没有直接记录在案。我能给你的最好参考资料是这里的打字记忆视图docs。在

这似乎是支持PEP 3118缓冲区协议的结果,而不是对numpy结构化数据类型的特定cython支持。numpy为它的数组公开了一个Py_buffer结构,cython知道如何将它们转换成结构。在

包装是必要的。我的understandingis x86是在itemsize字节边界上对齐的,而作为numpy结构的数据类型则压缩到尽可能小的空间中。最清楚的例子是:

%%cython
import numpy as np

cdef struct Thing:
    char a
    # 7 bytes padding, double must be 8 byte aligned
    double b

thing_dtype = np.dtype([('a', np.byte), ('b', np.double)])
print('dtype size: ', thing_dtype.itemsize)
print('unpacked struct size', sizeof(Thing))
dtype size:  9
unpacked struct size 16

相关问题 更多 >

    热门问题