2017-05-31 1 views
2

を@jit、ここに値を返すためにポインタを使用して簡単なC関数である:は、例えば

void add(double x, double y, double *r) 
{ 
    *r = x + y; 
} 

は、私はすべての要素に対してadd()関数を呼び出したいですnumba @jit関数で結果を収集します。

!gcc -c -fpic func.c 
!gcc -shared -o func.so func.o 

をそしてctypesのことで、それをロードします:

は、最初のCコードをコンパイルし

lib = ctypes.cdll.LoadLibrary("./func.so") 
add = lib.add 
add.argtypes = ctypes.c_double, ctypes.c_double, ctypes.c_void_p 
add.restype = None 

その後、numba機能:

from numba import jit, float64 

@jit(float64(float64[:], float64[:])) 
def f(x, y): 
    z = np.zeros_like(x) 
    for i in range(x.shape[0]): 
     add(x[i], y[i], &z[i]) # here I want to pass the address of z[i] 
    return z 

しかしnumbaにはAddressOf演算子や関数を持っていません。

現在、以下の方法を使用しています。しかし、このメソッドはnopythonモードでは使用できません。forループのコードにPythonオブジェクトがあるかどうかはわかりません。

@jit(float64(float64[:], float64[:])) 
def f(x, y): 
    z = np.zeros_like(x) 
    tmp = ctypes.c_double(0.0) 
    addr = intp(ctypes.addressof(tmp)) 
    val = carray(ctypes.pointer(tmp), 1) 
    for i in range(x.shape[0]): 
     add(x[i], y[i], addr) 
     z[i] = val[0] 
    return z 
+0

配列全体で動作するCラッパー関数を記述すると、Numbaはまったく必要ありません。 –

+0

現在、私は仕事をするためにcythonを使用していますが、numbaに切り替えてこの問題を解決したいと思います。 – HYRY

+0

FYI: 'add.argtypes = ctypes.c_double、ctypes.c_double、ctypes.POINTER(ctypes.c_double)'はより正確になります。そのパラメータを渡すには 'tmp = ctypes.c_double()'と 'add(1.0,2.0、ctypes.byref(tmp))'があります。 'tmp.value'が結果になります。 –

答えて

3

私は、正確な要素の参照を渡すための正確な方法を見つけることができませんでしたが、次は仕事に表示されます。

@nb.jit(nb.float64[:](nb.float64[:], nb.float64[:])) 
def f(x, y): 
    z = np.zeros_like(x) 
    for i in range(x.shape[0]): 
     add(x[i], y[i], z[i:].ctypes.data) # here I want to pass the address of z[i] 
    return z 

基本的に、あなたはz.ctypes.dataを使用してzのデータポインタを取得することができますしかし、それはちょうどあなたに最初の要素を与えます。それはハック・アイを感じますが、基本的にスライスを取るので、私が望むメモリアドレスはスライスの先頭にあります。

もっと良い選択肢があるかどうかわかりません。

+0

「z.ctypes.data + i」と言うことはできませんか? –

+0

それは動作しますが、 'z.ctypes.data + i * z.itemsize'は行います。 – JoshAdel

+0

@eryksun numbaの 'nopython'モードで動作しないようです。 – JoshAdel