13

1つ以上の入力配列のセットを受け取り、それらを処理し、その出力を出力配列のセットに書き込むC関数があると仮定します。シグニチャは次のようになります(count処理される配列要素の数を表します)。

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

この関数をPythonからctypesを介して呼び出し、それを使用してNumPy配列のセットに変換を適用したいと思います。1入力/1出力関数の場合、次のように定義されます。

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

次の作品:

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のは、呼び出し元の仕事です。次に、2つの入力を受け取り、1つの出力配列に書き込むoutput例を示します。compute

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配列へのポインターの配列)で適切なデータ構造を生成する方法です。

4

2 に答える 2

9

特に 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 側は次のようになります。

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

}
于 2013-01-16T10:23:35.460 に答える
4

C では、ポインターfloat**のテーブル/配列の最初の要素をfloat*指します。

おそらく、これらのそれぞれは、値float*のテーブル/配列の最初の要素を指していfloatます。

関数宣言には 1 つのカウントがありますが、このカウントが何に適用されるかは明確ではありません。

void compute (int count, float** input, float** output)
  • 2D 行列countxcountのサイズは?
  • count-サイズのそれぞれの配列は、たとえば?float*で何らかの形で終了します。nan
  • float*各要素のヌル終了配列count(合理的な仮定)?

あなたの質問を明確にしてください、私は私の答えを明確にします:-)

最後の API 解釈を前提として、サンプルの計算関数を次に示します。

/* 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++;
    }
}

サンプル計算関数のテスト コード:

#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サブ配列とサイズ2 float*配列 (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.strides[:] および 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)
于 2013-01-15T19:37:13.960 に答える