簡體   English   中英

將 Cython 中的 numpy 數組傳遞給需要動態分配數組的 C 函數

[英]Passing numpy arrays in Cython to a C function that requires dynamically allocated arrays

我有一些具有以下聲明的 C 代碼:

int myfunc(int m, int n, const double **a, double **b, double *c);

所以a是一個常量二維數組, b是一個二維數組, c是一個一維數組,都是動態分配的。 bc在傳遞給myfunc之前不需要是什么特別的東西,應該理解為輸出信息。 出於這個問題的目的,我不允許更改myfunc的聲明。

問題 1:如何將給定的 numpy 數組a_np轉換為具有此 C 函數所需格式的數組a ,以便我可以在 Cython 中使用a調用此 C 函數?

問題 2:下面bc的聲明是否正確,或者它們是否需要采用其他格式以便 C 函數將它們理解為 2D 和 1D 數組(分別)?

我的嘗試:

我的文件.pxd

cdef extern from "myfile.h":
    int myfunc(int p, int q, const double **a, double **b, double *c)

mytest.pyx

cimport cython
cimport myfile
import numpy as np
cimport numpy as np

p = 3
q = 4
cdef:
    double** a = np.random.random([p,q])
    double** b
    double* c

myfile.myfunc(p, q, a, b, c)

然后在 iPython 中我運行

import pyximport; pyximport.install()
import mytest

帶有a定義的行給了我錯誤消息Cannot convert Python object to 'double **' 我沒有收到關於bc任何錯誤消息,但由於此時我無法運行 C 函數,我不確定bc的聲明是否正確編寫(也就是說,以某種方式將使 C 函數分別輸出 2D 和 1D 數組)。

其他嘗試:我也嘗試遵循此處的解決方案,但這不適用於myfunc聲明中的雙星號類型的數組。 這里的解決方案不適用於我的任務,因為我無法更改myfunc的聲明。

在 cython 中創建一個輔助數組

要從 numpy 數組中獲取double** ,您可以在 *.pyx 文件中創建一個輔助指針數組。 此外,您必須確保 numpy 數組具有正確的內存布局。 (這可能涉及創建副本)

Fortran命令

如果您的 C 函數需要 fortran 順序(一個列表中的所有 x 坐標,另一個列表中的所有 y 坐標,第三個列表中的所有 z 坐標,如果您的數組 a 對應於 3D 空間中的點列表)

N,M = a.shape
# Make sure the array a has the correct memory layout (here F-order)
cdef np.ndarray[double, ndim=2, mode="fortran"] a_cython =
                         np.asarray(a, dtype = float, order="F")
#Create our helper array
cdef double** point_to_a = <double **>malloc(M * sizeof(double*))
if not point_to_a: raise MemoryError
try:
    #Fillup the array with pointers
    for i in range(M): 
        point_to_a[i] = &a_cython[0, i]
    # Call the C function that expects a double**
    myfunc(... &point_to_a[0], ...)
finally:
    free(point_to_a)

C-順序

如果您的 C 函數需要 C 順序([x1,y1,z1] 是第一個列表,[x2,y2,z2] 是 3D 點列表的第二個列表):

N,M = a.shape
# Make sure the array a has the correct memory layout (here C-order)
cdef np.ndarray[double, ndim=2, mode="c"] a_cython =
                         np.asarray(a, dtype = float, order="C")
#Create our helper array
cdef double** point_to_a = <double **>malloc(N * sizeof(double*))
if not point_to_a: raise MemoryError
try:
    for i in range(N): 
        point_to_a[i] = &a_cython[i, 0]
    # Call the C function that expects a double**
    myfunc(... &point_to_a[0], ...)
finally:
    free(point_to_a)

回復1:可以通過Cython 將NumPy 數組傳遞給C 使用數組開頭的位置(見下面代碼)。

回復2:你的聲明看起來是對的,但是我沒有使用這種顯式內存管理的方法。 您可以使用 NumPy 來聲明cdef -ed 數組。

cdef double[:,::1] a = np.random.random([p, q])
cdef double[:,::1] b = np.empty([p, q])
cdef double[::1] b = np.empty(q)

然后將&a[0] (數組開頭的位置)傳遞給您的 C 函數。 ::1是為了確保連續性。

對此的一個很好的參考是 Jake Vanderplas 的博客: https ://jakevdp.github.io/blog/2012/08/08/memoryview-benchmarks/

最后,通常在 Cython 中創建函數並在 Python 中調用它們,因此您的 Python 代碼將是:

import pyximport; pyximport.install()
import mytest
mytest.mywrappedfunc()

其中mywrappedfunc是在模塊中定義的 Python( def而不是cdef )函數,可以執行上面顯示的數組聲明。

暫無
暫無

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

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