将一组NumPy数组传递到C函数中进行输入和输出

2024-05-23 16:54:50 发布

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

假设我们有一个C函数,它接受一组或多个输入数组,对它们进行处理,并将其输出写入一组输出数组中。签名如下(其中count表示要处理的数组元素的数量):

void compute (int count, float** input, float** output)

我想通过ctypes从Python调用这个函数,并使用它对一组NumPy数组应用转换。对于定义为

^{pr2}$

以下工作:

import ctypes
import numpy

from numpy.ctypeslib import ndpointer

lib = ctypes.cdll.LoadLibrary('./block.so')
fun = lib.compute
fun.restype = None
fun.argtypes = [ctypes.c_int,
                ndpointer(ctypes.c_float),
                ndpointer(ctypes.c_float)]

data = numpy.ones(1000).astype(numpy.float32)
output = numpy.zeros(1000).astype(numpy.float32)
fun(1000, data, output)

但是,我不知道如何为多个输入(和/或输出)创建相应的指针数组。有什么想法吗?在

编辑:因此人们一直想知道compute如何知道预期的数组指针数量(因为count表示每个数组的元素数)。事实上,这是硬编码的;给定的compute精确地知道需要多少输入和输出。调用者的工作是验证input和{}是否指向正确数量的输入和输出。下面是一个示例compute获取2个输入并写入1个输出数组:

virtual void compute (int count, float** input, float** output) {
    float* input0 = input[0];
    float* input1 = input[1];
    float* output0 = output[0];
    for (int i=0; i<count; i++) {
        float fTemp0 = (float)input1[i];
        fRec0[0] = ((0.09090909090909091f * fTemp0) + (0.9090909090909091f * fRec0[1]));
        float fTemp1 = (float)input0[i];
        fRec1[0] = ((0.09090909090909091f * fTemp1) + (0.9090909090909091f * fRec1[1]));
        output0[i] = (float)((fTemp0 * fRec1[0]) - (fTemp1 * fRec0[0]));
        // post processing
        fRec1[1] = fRec1[0];
        fRec0[1] = fRec0[0];
    }
}

我无法影响compute的签名和实现。我可以验证(从Python!)需要多少输入和输出。关键问题是如何为函数提供正确的argtypes,以及如何在NumPy(指向NumPy数组的指针数组)中生成适当的数据结构。在


Tags: 函数numpyinputoutput数量count数组float
2条回答

在C中,float**指向float*指针的表/数组中的第一个元素。在

假设这些float*中的每一个都指向float值的表/数组中的第一个元素。在

您的函数声明有1个计数,但不清楚此计数适用于什么:

void compute (int count, float** input, float** output)
  • 二维矩阵countxcount大小?在
  • count-大小为float*的数组,每个数组都以某种方式终止,例如用nan?在
  • 以空结尾的数组float*每个count元素(合理假设)?在

请澄清您的问题,我将澄清我的答案:-)

假设最后一个API解释,下面是我的计算函数示例:

^{pr2}$

示例计算函数的测试代码:

#include <stdio.h>
extern void compute(int count, float** in, float** out);

int main(int argc, char** argv)
{
#define COUNT 3
    float ina[COUNT] = { 1.5, 0.5, 3.0 };
    float inb[COUNT] = { 0.1, -0.2, -10.0 };
    float outa[COUNT];
    float outb[COUNT];
    float* in[] = {ina, inb, (float*)0};
    float* out[] = {outa, outb, (float*)0};

    compute(COUNT, in, out);

    for (int row=0; row<2; row++)
        for (int c=0; c<COUNT; c++)
            printf("%d %d %f %f\n", row, c, in[row][c], out[row][c]);
    return 0;
}

以及如何通过Python中的ctypes为count==10float子数组和大小2float*数组使用相同的方法,其中包含1个实子数组和NULL终止符:

import ctypes

innertype = ctypes.ARRAY(ctypes.c_float, 10)
outertype = ctypes.ARRAY(ctypes.POINTER(ctypes.c_float), 2)

in1 = innertype(*range(10))
in_ = outertype(in1, None)
out1 = innertype(*range(10))
out = outertype(out1, None)

ctypes.CDLL("./compute.so").compute(10, in_, out)

for i in range(10): print in_[0][i], out[0][i]

这里介绍ctypes的Numpy接口http://www.scipy.org/Cookbook/Ctypes#head-4ee0c35d45f89ef959a7d77b94c1c973101a562f,arr.ctypes.shape形状[:] 前进的步伐[:]和arr.ctypes.data公司是您所需要的;您可以将其直接提供给您的compute。在

下面是一个例子:

In [55]: a = numpy.array([[0.0]*10]*2, dtype=numpy.float32)

In [56]: ctypes.cast(a.ctypes.data, ctypes.POINTER(ctypes.c_float))[0]
Out[56]: 0.0

In [57]: ctypes.cast(a.ctypes.data, ctypes.POINTER(ctypes.c_float))[0] = 1234

In [58]: a
Out[58]: 
array([[ 1234.,     0.,     0.,     0.,     0.,     0.,     0.,     0.,
            0.,     0.],
       [    0.,     0.,     0.,     0.,     0.,     0.,     0.,     0.,
            0.,     0.]], dtype=float32)

要特别针对Numpy数组执行此操作,可以使用:

import numpy as np
import ctypes

count = 5
size = 1000

#create some arrays
arrays = [np.arange(size,dtype="float32") for ii in range(count)] 

#get ctypes handles
ctypes_arrays = [np.ctypeslib.as_ctypes(array) for array in arrays]

#Pack into pointer array
pointer_ar = (ctypes.POINTER(C.c_float) * count)(*ctypes_arrays)

ctypes.CDLL("./libfoo.so").foo(ctypes.c_int(count), pointer_ar, ctypes.c_int(size))

其中C端可能看起来像:

^{pr2}$

相关问题 更多 >