2013年1月10日木曜日

Scipy.WeaveでPythonにC++埋め込み 1 Hello world

Pythonって超便利ですね。非常に多様な目的に使われる言語ですが、Numpy・Scipyによる数値計算ライブラリがあるので数値計算・グラフ描画もできます。Matlabなんかもういらないのではないかとおもいますね。しかし、MatlabやPythonのようなインタープリタ言語でループを回したりすると一気に実行速度が激遅になります。そこで、開発者(研究者)はプログラムの高速化が必要な部分をC/C++(以下、C)で書いて呼び出したりします。MatlabではMexによってこれが実現できます。Pythonでもctypes, SWIG, Boost.Python, Cython, Scipy.WeaveによってCによる高速化ができます。今回はWeaveを使った例をお見せします。(Cythonもいずれ紹介します。)

誰もが最初にやるやつ

そう、Hello worldです。WeaveはPythonのコードの中にCコードを直接埋め込むことができます。
from scipy import weave

def test_hello_world():
    print "----- Print ----"
    code = r"""
    printf("Hello world!!\n");
    """
    weave.inline(code)

if __name__ == '__main__':
    test_hello_world()
Cコードを埋め込むための一つのメソッドがweave.inlineです。上のように、第1引数にCのコードを書いた文字列を取ります。出力は、
----- Print ----
Hello world!!
となります。
inlineメソッドは呼び出されたときに第一引数の文字列codeのCコードを実行時コンパイルして呼び出します。これだと呼び出す度にコンパイルが行われ余計に計算時間がかかってしまうと思うかもしれません。しかし実際には、inlineは一度コンパイル済みのものと同じ内容のcodeが渡された時にはコンパイル済みのものを使うため、高速にCコードを呼び出すことができます。 何が起こっているか確認するために、verbose=2と強制的に同じcodeでもコンパイルするためのforce=Trueをオプション引数に追加するように変更してみます。
weave.inline(code, verbose=2, force=True)
いろいろverboseされます。
----- Print ----
<weave: compiling>
running build_ext
running build_src
build_src
building extension "sc_de155a42ad0378e80d2e4d68a547cce52" sources
build_src: building npy-pkg config files
customize UnixCCompiler
customize UnixCCompiler using build_ext
customize UnixCCompiler
customize UnixCCompiler using build_ext
building 'sc_de155a42ad0378e80d2e4d68a547cce52' extension
compiling C++ sources
C compiler: c++ -fno-strict-aliasing -fno-common -dynamic -arch i386 -arch x86_64 -I/usr/local/include -DNDEBUG -g -O3 -Wall

compile options: '-I/usr/local/lib/python2.7/site-packages/scipy/weave -I/usr/local/lib/python2.7/site-packages/scipy/weave/scxx -I/usr/local/lib/python2.7/site-packages/numpy/core/include -I/usr/local/Cellar/python/2.7.3/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'
c++: /usr/local/lib/python2.7/site-packages/scipy/weave/scxx/weave_imp.cpp
c++: /Users/USERNAME/.python27_compiled/sc_de155a42ad0378e80d2e4d68a547cce52.cpp
c++ -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -isysroot / -L/usr/local/lib /var/folders/jp/rhc_v7hn46g05j5v678bjbfm0000gn/T/USERNAME/python27_intermediate/compiler_f217358f4c5a874fd8a2d639e1b28c86/Users/USERNAME/.python27_compiled/sc_de155a42ad0378e80d2e4d68a547cce52.o /var/folders/jp/rhc_v7hn46g05j5v678bjbfm0000gn/T/USERNAME/python27_intermediate/compiler_f217358f4c5a874fd8a2d639e1b28c86/usr/local/lib/python2.7/site-packages/scipy/weave/scxx/weave_imp.o -o /Users/USERNAME/.python27_compiled/sc_de155a42ad0378e80d2e4d68a547cce52.so
running scons
Hello world!!
ごちゃごちゃとありますが、
c++: /Users/USERNAME/.python27_compiled/sc_de155a42ad0378e80d2e4d68a547cce52.cpp
を見るとCコードが生成されている場所がわかります。僕はMac OSX Lionなので、ホームの.python27_compliedにソースコードが自動生成されているのがわかります。Windwosなどでもverbose=2にすれば、どこにソースが生成されたかを知ることができます。このソースを覗いてみるとweaveがどのようにcodeをCコードに変換しているかがわかります(compiled_func関数)。
今回はまったく実用的でないプログラムでしたが、次はweave.inlineに引数を渡す例をお見せします。
変数を渡す編

0 件のコメント:

コメントを投稿