Passing a set of NumPy arrays into C function for input and output

落爺英雄遲暮 提交于 2019-12-03 11:13:28

To do this specifically with Numpy arrays, you could use:

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))

Where the C side of things might look like:

# function to multiply all arrays by 2
void foo(int count, float** array, int size)
{
   int ii,jj;
   for (ii=0;ii<count;ii++){
      for (jj=0;jj<size;jj++)
         array[ii][jj] *= 2;    
   }

}

In C, float** points to first element in a table/array of float* pointers.

Presumably each of those float* points to first element in a table/array of float values.

Your function declaration has 1 count, however it's not clear what this count applies to:

void compute (int count, float** input, float** output)
  • 2D matrix count x count in size?
  • count -sized array of float* each somehow terminated, e.g. with nan?
  • null-terminated array of float* each of count elements (reasonable assumption)?

Please clarify your question and I will clarify my answer :-)

Assuming the last API interpretation, here's my sample compute function:

/* null-terminated array of float*, each points to count-sized array
*/
extern void compute(int count, float** in, float** out)
{
    while (*in)
    {
        for (int i=0; i<count; i++)
        {
            (*out)[i] = (*in)[i]*42;
        }
        in++; out++;
    }
}

Test code for the sample compute function:

#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;
}

And how you use same via ctypes in Python for count == 10 float subarrays and size 2 float* array, containing 1 real subarray and NULL terminator:

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]

Numpy interface to ctypes is covered here http://www.scipy.org/Cookbook/Ctypes#head-4ee0c35d45f89ef959a7d77b94c1c973101a562f, arr.ctypes.shape[:] arr.ctypes.strides[:] and arr.ctypes.data are what you need; you might be able to feed that directly to your compute.

Here's an example:

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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!