2017-03-25 15 views
0

入力としてコールバック関数をとるCライブラリを使用する必要があります。このコールバック関数は配列をとり、値を返します。したがって、たとえばC配列をnumpy配列にキャスト/ CythonコードのCython型のメモリビュー

double candidate(double[] x); 

は有効なコールバックになります。

Nymphyを使用して実装を単純化するために、Cythonをコールバック関数を使用して使いたいと考えています。

だから私は、関数に

cdef double cythonCandidate(double[] x): 

を実装するために、今、私はすぐにnumpyの配列としてXを「キャスト」したいとして、numpyのを使用して操作を行うだろうしようとしています。

cdef double euclideanNorm(double[] x): 
    # cast x into a numpy array nx here - dont know how!! 
    return np.sum(x * x) 

Q1:

例えば、私のような何かを書きたいと思うかもしれません。これはどうすればいいですか?明示的なコピーをせずに、基になるバッファを参照するだけで、C配列を数値配列にキャストするにはどうすればよいですか?

質問2:私のようにnumpyを使用すると、Pythonのオーバーヘッドはありますか? Q1については

答えて

1

%%cython -f 
import numpy as np 

def test_cast(): 
    cdef double *x = [1, 2, 3, 4, 5] 
    cdef double[:1] x_view = <double[:5]>x # cast to memoryview, refer to the underlying buffer without copy 
    xarr = np.asarray(x_view)    # numpy array refer to the underlying buffer without copy 
    x_view[0] = 100 
    xarr[1] = 200 
    x[2] = 300 
    print(xarr.flags)      # OWNDATA flag should be False 
    return x[0],x[1],x[2],x[3],x[4]   # (100.0, 200.0, 300.0, 4.0, 5.0) 

:あなたはx_viewを宣言し、このxarr = np.asarray(<double[:5]>x)をしない場合は、cythonコンパイラは、エラーメッセージを表示してをクラッシュすることがあります:AttributeError: 'CythonScope' object has no attribute 'viewscope' .Thisが可能

%%cython -f 
from cython cimport view # comment this line to see what will happen 
import numpy as np 

def test_error_cast(): 
    cdef double *x = [1, 2, 3, 4, 5] 
    xarr = np.asarray(<double[:5]>x) 
    xarr[0] = 200 
    return x[0],x[1],x[2],x[3],x[4] 

私は分かりませんこれは機能やバグです。

Q2の場合: 配列が小さい場合は、numpyオーバーヘッドが重要です。以下のベンチマークを参照してください。

%%cython -a 
from cython cimport view 
import numpy as np 

cdef inline double euclideanNorm(double *x, size_t x_size): 
    xarr = np.asarray(<double[:x_size]>x) 
    return np.sum(xarr*xarr) 

cdef inline double euclideanNorm_c(double *x, size_t x_size): 
    cdef double ss = 0.0 
    cdef size_t i 
    for i in range(x_size): 
     ss += x[i] * x[i] 
    return ss 

def c_norm(double[::1] x): 
    return euclideanNorm_c(&x[0], x.shape[0]) 

def np_norm(double[::1] x): 
    return euclideanNorm(&x[0], x.shape[0]) 
私のPCで

小さな配列:

import numpy as np 
small_arr = np.random.rand(100) 
print(c_norm(small_arr)) 
print(np_norm(small_arr)) 
%timeit c_norm(small_arr) # 1000000 loops, best of 3: 864 ns per loop 
%timeit np_norm(small_arr) # 100000 loops, best of 3: 8.51 µs per loop 
私のPCで

ビッグ配列:

big_arr = np.random.rand(1000000) 
print(c_norm(big_arr)) 
print(np_norm(big_arr)) 
%timeit c_norm(big_arr) # 1000 loops, best of 3: 1.46 ms per loop 
%timeit np_norm(big_arr) # 100 loops, best of 3: 4.93 ms per loop