python – 使用cython将numpy数组列表传递给C.
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了python – 使用cython将numpy数组列表传递给C.,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3387字,纯文字阅读大概需要5分钟。
内容图文
![python – 使用cython将numpy数组列表传递给C.](/upload/InfoBanner/zyjiaocheng/822/4158963030824274b23cca426ced2c18.jpg)
我有一个列表list_of_arrays的3D numpy数组,我想用模板传递给C函数
int my_func_c(double **data, int **shape, int n_arrays)
这样的
data[i] : pointer to the numpy array values in list_of_arrays[i]
shape[i] : pointer to the shape of the array in list_of_arrays[i] e.g. [2,3,4]
如何使用cython接口函数调用my_func_c?
我的第一个想法是做类似下面的事情(有效),但我觉得有一个更好的方法就是使用numpy数组而不需要mallocing和freeing.
# my_func_c.pyx
import numpy as np
cimport numpy as np
cimport cython
from libc.stdlib cimport malloc, free
cdef extern from "my_func.c":
double my_func_c(double **data, int **shape, int n_arrays)
def my_func(list list_of_arrays):
cdef int n_arrays = len(list_of_arrays)
cdef double **data = <double **> malloc(n_arrays*sizeof(double *))
cdef int **shape = <int **> malloc(n_arrays*sizeof(int *))
cdef double x;
cdef np.ndarray[double, ndim=3, mode="c"] temp
for i in range(n_arrays):
temp = list_of_arrays[i]
data[i] = &temp[0,0,0]
shape[i] = <int *> malloc(3*sizeof(int))
for j in range(3):
shape[i][j] = list_of_arrays[i].shape[j]
x = my_func_c(data, shape, n_arrays)
# Free memory
for i in range(n_arrays):
free(shape[i])
free(data)
free(shape)
return x
注:
要查看一个工作示例,我们可以使用一个非常简单的函数来计算列表中所有数组的乘积.
# my_func.c
double my_func_c(double **data, int **shape, int n_arrays) {
int array_idx, i0, i1, i2;
double prod = 1.0;
// Loop over all arrays
for (array_idx=0; array_idx<n_arrays; array_idx++) {
for (i0=0; i0<shape[array_idx][0]; i0++) {
for (i1=0; i1<shape[array_idx][1]; i1++) {
for (i2=0; i2<shape[array_idx][2]; i2++) {
prod = prod*data[array_idx][i0*shape[array_idx][1]*shape[array_idx][2] + i1*shape[array_idx][2] + i2];
}
}
}
}
return prod;
}
创建setup.py文件,
# setup.py
from distutils.core import setup
from Cython.Build import cythonize
import numpy as np
setup(
name='my_func',
ext_modules = cythonize("my_func_c.pyx"),
include_dirs=[np.get_include()]
)
编
python3 setup.py build_ext --inplace
最后我们可以进行一个简单的测试
# test.py
import numpy as np
from my_func_c import my_func
a = [1+np.random.rand(3,1,2), 1+np.random.rand(4,5,2), 1+np.random.rand(1,2,3)]
print('Numpy product: {}'.format(np.prod([i.prod() for i in a])))
print('my_func product: {}'.format(my_func(a)))
运用
python3 test.py
解决方法:
另一种选择是让numpy为你管理你的记忆.您可以使用nump.nintp的numpy数组来完成此操作,该数组是一个unsigned int,其大小与任何指针相同.
不幸的是,这确实需要一些类型转换(在“指针大小的int”和指针之间),这是隐藏逻辑错误的好方法,所以我不是百分之百满意.
def my_func(list list_of_arrays):
cdef int n_arrays = len(list_of_arrays)
cdef np.uintp_t[::1] data = np.array((n_arrays,),dtype=np.uintp)
cdef np.uintp_t[::1] shape = np.array((n_arrays,),dtype=np.uintp)
cdef double x;
cdef np.ndarray[double, ndim=3, mode="c"] temp
for i in range(n_arrays):
temp = list_of_arrays[i]
data[i] = <np.uintp_t>&temp[0,0,0]
shape[i] = <np.uintp_t>&(temp.shape[0])
x = my_func_c(<double**>(&data[0]), <np.intp_t**>&shape[0], n_arrays)
(我应该指出,我只是确认它编译而不是进一步测试,但基本的想法应该没问题)
你这样做的方式可能是一种非常明智的方式.对原始代码的一个简单的简化应该有效
shape[i] = <np.uintp_t>&(temp.shape[0])
而不是malloc和副本.我还建议将frees放在finally块中以确保它们运行.
编辑:@ead有助于指出numpy shape is stored as as np.intp_t – 即一个大小足以适合指针的有符号整数,大多数是64位 – 而int通常是32位.因此,要在不复制的情况下传递形状,您需要更改C api.施法帮助使这个错误难以发现(“隐藏逻辑错误的好方法”)
内容总结
以上是互联网集市为您收集整理的python – 使用cython将numpy数组列表传递给C.全部内容,希望文章能够帮你解决python – 使用cython将numpy数组列表传递给C.所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。