私はいくつかのC関数を持っていますが、それらをpythonから呼び出したいと思います。 cythonが進むべき道のようですが、実際にこれがどのように行われるかの例を実際に見つけることはできません。私のC関数は次のようになります。
void calculate_daily ( char *db_name, int grid_id, int year,
double *dtmp, double *dtmn, double *dtmx,
double *dprec, double *ddtr, double *dayl,
double *dpet, double *dpar ) ;
私がやりたいのは、最初の3つのパラメーター(文字列と2つの整数)を指定し、8つのnumpy配列(またはpythonリスト。すべての二重配列にN要素がある)を復元することです。私のコードポインタがすでに割り当てられているメモリのチャンクを指していることを前提としていますまた、生成されたCコードはいくつかの外部ライブラリにリンクする必要があります。
以下は、numpy配列を外部C関数に論理的に渡す小さなしかし完全な例です。
fc( int N, double* a, double* b, double* z ) # z = a + b
cythonを使用します。 (これは確かにそれをよく知っている人にはよく知られています。コメントを歓迎します。最終変更:2011年2月23日、Cython 0.14用。)
Cython build と Cython with NumPy を最初に読み取るか、読み飛ばします。
2つのステップ:
python f-setup.py build_ext --inplace
f.pyx
およびfc.cpp
-> f.so
を返します、動的ライブラリpython test-f.py
import f
はf.so
をロードします。 f.fpy( ... )
はC fc( ... )
を呼び出します。python f-setup.py
はdistutils
を使用してcythonを実行し、コンパイルしてリンクします。cython f.pyx -> f.cpp
f.cpp
とfc.cpp
をコンパイルする
リンクf.o fc.o
-> f.so
、python import f
がロードする動的ライブラリ.
学生には、これらのステップの図を作成し、以下のファイルを確認してから、ダウンロードして実行することをお勧めします。
(distutils
は、配布用のPythonパッケージを作成してインストールするために使用される巨大な複雑なパッケージです。ここでは、コンパイルしてリンクするために、そのほんの一部を使用しています。 f.so
。このステップはCythonとは何の関係もありませんが、混乱を招く可能性があります。pyxの単純な間違いが原因で、g ++コンパイルおよびリンクからのあいまいなエラーメッセージのページが表示される場合があります。 distutils doc および/または distutils に関するSOの質問。)
make
と同様に、setup.py
がcython f.pyx
より新しい場合、g++ -c ... f.cpp
はf.pyx
およびf.cpp
を再実行します。
クリーンアップするには、rm -r build/
。
setup.py
の代わりに、スクリプトまたはMakefileでステップを個別に実行することもできます。cython --cplus f.pyx -> f.cpp # see cython -h
g++ -c ... f.cpp -> f.o
g++ -c ... fc.cpp -> fc.o
cc-lib f.o fc.o -> dynamic library f.so
。
以下のcc-lib-mac
ラッパーをプラットフォームとインストールに合わせて変更します。見栄えはよくありませんが、小さいです。
CythonのラッピングCの実際の例については、ほぼすべての SciKit の.pyxファイルを見てください。
関連項目: Cython for NumPy users および SO質問/タグ付き/ cython 。
次のファイルを解凍するには、ロットを1つの大きなファイル(cython-numpy-c-demo
など)にカットアンドペーストしてから、Unixで(クリーンな新しいディレクトリで)sh cython-numpy-c-demo
を実行します。
#--------------------------------------------------------------------------------
cat >f.pyx <<\!
# f.pyx: numpy arrays -> extern from "fc.h"
# 3 steps:
# cython f.pyx -> f.c
# link: python f-setup.py build_ext --inplace -> f.so, a dynamic library
# py test-f.py: import f gets f.so, f.fpy below calls fc()
import numpy as np
cimport numpy as np
cdef extern from "fc.h":
int fc( int N, double* a, double* b, double* z ) # z = a + b
def fpy( N,
np.ndarray[np.double_t,ndim=1] A,
np.ndarray[np.double_t,ndim=1] B,
np.ndarray[np.double_t,ndim=1] Z ):
""" wrap np arrays to fc( a.data ... ) """
assert N <= len(A) == len(B) == len(Z)
fcret = fc( N, <double*> A.data, <double*> B.data, <double*> Z.data )
# fcret = fc( N, A.data, B.data, Z.data ) grr char*
return fcret
!
#--------------------------------------------------------------------------------
cat >fc.h <<\!
// fc.h: numpy arrays from cython , double*
int fc( int N, const double a[], const double b[], double z[] );
!
#--------------------------------------------------------------------------------
cat >fc.cpp <<\!
// fc.cpp: z = a + b, numpy arrays from cython
#include "fc.h"
#include <stdio.h>
int fc( int N, const double a[], const double b[], double z[] )
{
printf( "fc: N=%d a[0]=%f b[0]=%f \n", N, a[0], b[0] );
for( int j = 0; j < N; j ++ ){
z[j] = a[j] + b[j];
}
return N;
}
!
#--------------------------------------------------------------------------------
cat >f-setup.py <<\!
# python f-setup.py build_ext --inplace
# cython f.pyx -> f.cpp
# g++ -c f.cpp -> f.o
# g++ -c fc.cpp -> fc.o
# link f.o fc.o -> f.so
# distutils uses the Makefile distutils.sysconfig.get_makefile_filename()
# for compiling and linking: a sea of options.
# http://docs.python.org/distutils/introduction.html
# http://docs.python.org/distutils/apiref.html 20 pages ...
# https://stackoverflow.com/questions/tagged/distutils+python
import numpy
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
# from Cython.Build import cythonize
ext_modules = [Extension(
name="f",
sources=["f.pyx", "fc.cpp"],
# extra_objects=["fc.o"], # if you compile fc.cpp separately
include_dirs = [numpy.get_include()], # .../site-packages/numpy/core/include
language="c++",
# libraries=
# extra_compile_args = "...".split(),
# extra_link_args = "...".split()
)]
setup(
name = 'f',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules,
# ext_modules = cythonize(ext_modules) ? not in 0.14.1
# version=
# description=
# author=
# author_email=
)
# test: import f
!
#--------------------------------------------------------------------------------
cat >test-f.py <<\!
#!/usr/bin/env python
# test-f.py
import numpy as np
import f # loads f.so from cc-lib: f.pyx -> f.c + fc.o -> f.so
N = 3
a = np.arange( N, dtype=np.float64 )
b = np.arange( N, dtype=np.float64 )
z = np.ones( N, dtype=np.float64 ) * np.NaN
fret = f.fpy( N, a, b, z )
print "fpy -> fc z:", z
!
#--------------------------------------------------------------------------------
cat >cc-lib-mac <<\!
#!/bin/sh
me=${0##*/}
case $1 in
"" )
set -- f.cpp fc.cpp ;; # default: g++ these
-h* | --h* )
echo "
$me [g++ flags] xx.c yy.cpp zz.o ...
compiles .c .cpp .o files to a dynamic lib xx.so
"
exit 1
esac
# Logically this is simple, compile and link,
# but platform-dependent, layers upon layers, gloom, Doom
base=${1%.c*}
base=${base%.o}
set -x
g++ -dynamic -Arch ppc \
-bundle -undefined dynamic_lookup \
-fno-strict-aliasing -fPIC -fno-common -DNDEBUG `# -g` -fwrapv \
-isysroot /Developer/SDKs/MacOSX10.4u.sdk \
-I/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6 \
-I${Pysite?}/numpy/core/include \
-O2 -Wall \
"$@" \
-o $base.so
# undefs: nm -gpv $base.so | egrep '^ *U _+[^P]'
!
# 23 Feb 2011 13:38
次の http://article.gmane.org/gmane.comp.python.cython.user/5625 のCythonコードは、明示的なキャストを必要とせず、非連続配列も処理します。
def fpy(A):
cdef np.ndarray[np.double_t, ndim=2, mode="c"] A_c
A_c = np.ascontiguousarray(A, dtype=np.double)
fc(&A_c[0,0])
基本的には、配列を割り当てるようにCython関数を記述できます(cimport numpy as np
):
cdef np.ndarray[np.double_t, ndim=1] rr = np.zeros((N,), dtype=np.double)
次に、.data
各C関数へのポインタ。うまくいくはずです。ゼロから始める必要がない場合は、np.empty
速度を少し上げます。
ドキュメントの Cython for NumPy Users チュートリアルを参照してください(正しいリンクに修正されています)。
あなたはチェックアウトする必要があります Ctypes 必要なのが1つの関数だけである場合、これはおそらく最も簡単に使用できるものです。