2016-12-08 18 views
1

私はcythonで単純な補間関数を書いて、他のcythonコードから(たくさんの)呼び出されます。パラメータの1つがnumpyの配列です:numpy配列のCythonオーバヘッド

@cython.boundscheck(False) 
@cython.cdivision(True) 
@cython.wraparound(False) 
cdef double interpU_cython(double kX,double kY,int iX,int iY, int iTheta,int nbX,int nbY,np.ndarray[double, ndim=3] u, double outVal): 
    cdef double uPt, u0, u1 
    if (iX >= 0 and iY >= 0 and iX < nbX-1 and iY < nbY-1): 
     u0 = u[iX,iY,iTheta] + (u[iX+1,iY,iTheta]-u[iX,iY,iTheta]) * kX 
     u1 = u[iX,iY+1,iTheta] + (u[iX+1,iY+1,iTheta]-u[iX,iY+1,iTheta]) * kX 
     uPt = u0 + (u1-u0) * kY 
    else: 
     uPt = outVal 
    return uPt 

私は-a cython とPythonの呼び出しをチェックし、関数呼び出しがいくつかのPythonの呼び出しに依存しているように見えます:

+01: cimport cython 
02: cimport numpy as np 
+03: import numpy as np 
04: 
05: @cython.boundscheck(False) 
06: @cython.cdivision(True) 
07: @cython.wraparound(False) 
+08: cdef double interpU_cython(double kX,double kY,int iX,int iY, int iTheta,int nbX,int nbY,np.ndarray[double, ndim=3] u, double outVal): 
static double __pyx_f_10FSM_cython_interpU_cython(double __pyx_v_kX, double __pyx_v_kY, int __pyx_v_iX, int __pyx_v_iY, int __pyx_v_iTheta, int __pyx_v_nbX, int __pyx_v_nbY, PyArrayObject *__pyx_v_u, double __pyx_v_outVal) { 
    double __pyx_v_uPt; 
    double __pyx_v_u0; 
    double __pyx_v_u1; 
    __Pyx_LocalBuf_ND __pyx_pybuffernd_u; 
    __Pyx_Buffer __pyx_pybuffer_u; 
    double __pyx_r; 
    __Pyx_RefNannyDeclarations 
    __Pyx_RefNannySetupContext("interpU_cython", 0); 
    __pyx_pybuffer_u.pybuffer.buf = NULL; 
    __pyx_pybuffer_u.refcount = 0; 
    __pyx_pybuffernd_u.data = NULL; 
    __pyx_pybuffernd_u.rcbuffer = &__pyx_pybuffer_u; 
    { 
    __Pyx_BufFmt_StackElem __pyx_stack[1]; 
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_u.rcbuffer->pybuffer, (PyObject*)__pyx_v_u, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 3, 0, __pyx_stack) == -1)) __PYX_ERR(0, 8, __pyx_L1_error) 
    } 
    __pyx_pybuffernd_u.diminfo[0].strides = __pyx_pybuffernd_u.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_u.diminfo[0].shape = __pyx_pybuffernd_u.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_u.diminfo[1].strides = __pyx_pybuffernd_u.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_u.diminfo[1].shape = __pyx_pybuffernd_u.rcbuffer->pybuffer.shape[1]; __pyx_pybuffernd_u.diminfo[2].strides = __pyx_pybuffernd_u.rcbuffer->pybuffer.strides[2]; __pyx_pybuffernd_u.diminfo[2].shape = __pyx_pybuffernd_u.rcbuffer->pybuffer.shape[2]; 
/* … */ 
    /* function exit code */ 
    __pyx_L1_error:; 
    { PyObject *__pyx_type, *__pyx_value, *__pyx_tb; 
    __Pyx_PyThreadState_declare 
    __Pyx_PyThreadState_assign 
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb); 
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_u.rcbuffer->pybuffer); 
    __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);} 
    __Pyx_WriteUnraisable("FSM_cython.interpU_cython", __pyx_clineno, __pyx_lineno, __pyx_filename, 0, 0); 
    __pyx_r = 0; 
    goto __pyx_L2; 
    __pyx_L0:; 
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_u.rcbuffer->pybuffer); 
    __pyx_L2:; 
    __Pyx_RefNannyFinishContext(); 
    return __pyx_r; 
} 
09:  cdef double uPt, u0, u1 
+10:  if (iX >= 0 and iY >= 0 and iX < nbX-1 and iY < nbY-1): 
+11:   u0 = u[iX,iY,iTheta] + (u[iX+1,iY,iTheta]-u[iX,iY,iTheta]) * kX 
+12:   u1 = u[iX,iY+1,iTheta] + (u[iX+1,iY+1,iTheta]-u[iX,iY+1,iTheta]) * kX 
+13:   uPt = u0 + (u1-u0) * kY 
14:  else: 
+15:   uPt = outVal 
+16:  return uPt 

がありますかなりのオーバーヘッドなしでnumpy配列を渡して使用するための効率的な方法、またはコードのコンパイルされた部分にあるすべてのものに対してc配列を使うだけですか?

numpy配列の最初の要素へのポインタを使用し、配列サイズをパラメータに追加して1次元配列として使用するのは安全ですか?

おかげ

答えて

1

https://jakevdp.github.io/blog/2012/08/08/memoryview-benchmarks/

を見てくださいこのブログの記事は、Cythonでnumpyのアレイを使用するためにいくつかの可能性を比較します。

短い答えは、あなたがdouble[:,:,:] u代わりのnp.ndarray[double, ndim=3] uとして宣言されている型付けmemoryviewsを使用する必要があるということです。ドキュメント:http://docs.cython.org/en/latest/src/userguide/memoryviews.html

編集:あなたはmemoryview

の形状を照会することができます