如何使用 CFFI 将多维 Numpy 数组传递给 C 函数?
How to pass multidimensional Numpy arrays to C function using CFFI?
我试图通过在 C++ 中实现一个函数并使用 CFFI 将其嵌入我的代码来加速我的 Python 程序。该函数采用两个 3x3 数组并计算距离。
Python 代码如下:
import cffi
import numpy as np
ffi = cffi.FFI()
ffi.cdef("""
extern double dist(const double s[3][3], const double t[3][3]);
""")
lib = ffi.dlopen("./dist.so")
S = np.array([[-1.63538, 0.379116, -1.16372],[-1.63538, 0.378137, -1.16366 ],[-1.63193, 0.379116, -1.16366]], dtype=np.float32)
T = np.array([[-1.6467834, 0.3749715, -1.1484985],[-1.6623441, 0.37410975, -1.1647063 ],[-1.6602284, 0.37400728, -1.1496595 ]], dtype=np.float32)
Sp = ffi.cast("double(*) [3]", S.ctypes.data)
Tp = ffi.cast("double(*) [3]", T.ctypes.data)
dd = lib.dist(Sp,Tp);
此解决方案未按预期工作。实际上,C 函数打印的参数是:
Sp=[[0.000002, -0.270760, -0.020458]
[0.000002, 0.000000, 0.000000]
[0.000000, 0.000000, 0.000000]]
Tp=[[0.000002, -0.324688, -0.020588]
[0.000002, 0.000000, 0.000000]
[0.000000, 0.000000, -nan]]
我还尝试了以下方法来初始化指针:
Sp = ffi.new("double *[3]")
for i in range(3):
Sp[i] = ffi.cast("double *", S[i].ctypes.data)
Tp = ffi.new("double *[3]")
for i in range(3):
Tp[i] = ffi.cast("double *", T[i].ctypes.data)
dd = lib.dist(Sp,Tp);
但此解决方案在 dist(Sp,Tp)
中出现错误:
TypeError: initializer for ctype 'double(*)[3]' must be a pointer to same type, not cdata 'double *[3]'
你知道如何让它发挥作用吗?谢谢。
类型double[3][3]
和double *[3]
不等价。前者是double 3x3的二维数组,存储为9个连续的double。后者是一个包含 3 个双指针的数组,这不是 2D 静态数组在 C 或 C++ 中的实现方式。
numpy 数组和 C++ 静态数组在内存中都表示为连续的元素块,只是中间的 double *[3]
类型在工作中造成了麻烦。您想要的是正确使用 double[3][3]
或 double[3]*
(指向一行三个双打的指针)。请注意,如果您使用后者,您可能需要更改函数原型以采用 double [][3]
.
我试图通过在 C++ 中实现一个函数并使用 CFFI 将其嵌入我的代码来加速我的 Python 程序。该函数采用两个 3x3 数组并计算距离。 Python 代码如下:
import cffi
import numpy as np
ffi = cffi.FFI()
ffi.cdef("""
extern double dist(const double s[3][3], const double t[3][3]);
""")
lib = ffi.dlopen("./dist.so")
S = np.array([[-1.63538, 0.379116, -1.16372],[-1.63538, 0.378137, -1.16366 ],[-1.63193, 0.379116, -1.16366]], dtype=np.float32)
T = np.array([[-1.6467834, 0.3749715, -1.1484985],[-1.6623441, 0.37410975, -1.1647063 ],[-1.6602284, 0.37400728, -1.1496595 ]], dtype=np.float32)
Sp = ffi.cast("double(*) [3]", S.ctypes.data)
Tp = ffi.cast("double(*) [3]", T.ctypes.data)
dd = lib.dist(Sp,Tp);
此解决方案未按预期工作。实际上,C 函数打印的参数是:
Sp=[[0.000002, -0.270760, -0.020458]
[0.000002, 0.000000, 0.000000]
[0.000000, 0.000000, 0.000000]]
Tp=[[0.000002, -0.324688, -0.020588]
[0.000002, 0.000000, 0.000000]
[0.000000, 0.000000, -nan]]
我还尝试了以下方法来初始化指针:
Sp = ffi.new("double *[3]")
for i in range(3):
Sp[i] = ffi.cast("double *", S[i].ctypes.data)
Tp = ffi.new("double *[3]")
for i in range(3):
Tp[i] = ffi.cast("double *", T[i].ctypes.data)
dd = lib.dist(Sp,Tp);
但此解决方案在 dist(Sp,Tp)
中出现错误:
TypeError: initializer for ctype 'double(*)[3]' must be a pointer to same type, not cdata 'double *[3]'
你知道如何让它发挥作用吗?谢谢。
类型double[3][3]
和double *[3]
不等价。前者是double 3x3的二维数组,存储为9个连续的double。后者是一个包含 3 个双指针的数组,这不是 2D 静态数组在 C 或 C++ 中的实现方式。
numpy 数组和 C++ 静态数组在内存中都表示为连续的元素块,只是中间的 double *[3]
类型在工作中造成了麻烦。您想要的是正确使用 double[3][3]
或 double[3]*
(指向一行三个双打的指针)。请注意,如果您使用后者,您可能需要更改函数原型以采用 double [][3]
.