C++でpythonを拡張する(Boost.NumPy)

  • 30
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

何故C++のクラス・関数をPythonにバインドするか?

C++11は非常に便利になった。Boost使えばさらに便利だ。
しかし、pythonはもっと使いやすい。
NumPyをベースにしたプロジェクト群(SciPy, matplotlib, pandas, ...)
は共通の基盤の上に非常に使い易く整備されている上に、そこそこ高速に動作する。
C++を使うべきか、Pythonにバインドして使うべきか、
また私の中で結論はでていないが、とりあえずバインドするための情報をまとめる。

どうやってバインドするか?

問題は2つある。

  • 単純にPythonにバインドする方法
  • NumPyにバインドする方法

Pythonを使う理由の一つにNumPyのベースのライブラリを使用する事があるので、
NumPyのndarray等に変換できる必要がある。

基本となるのはPython C APINumPy C APIである。
これらを通してC++の関数やクラスをPythonにバインドする。
C++は当然Python C APIを直接呼びだせるが、
参照カウントを自分で制御しないといけない。
これは無理ゲーすぎるので、その辺をC++らしくラップしたのがBoost.Pythonである。
スマートポインタで参照カウントは管理してくれる。

一方で、NumPy C APIはPython C APIとは別物であるため、
Boost.Python自体にはNumPyのAPIのラッパーは含まれていない。
そこでBoost.PythonをベースにNumPyのためのインターフェイスを
実装したものがBoost.NumPyである。
現在Boost sandboxに入ってると書いているが、
Boost本体の開発がGithubに移ってからSandboxは運用されていないようだ。
開発はgithubで行われている。
Boostとしての立ち位置はよく分らない。

Install

git clone https://github.com/ndarray/Boost.NumPy
cd Boost.NumPy

した事前提で話を進める。

documentのビルド

cd libs/numpy/doc
make

としてlibs/numpy/doc/_build/html/index.htmlを開けばドキュメントが見れる

cmakeによるインストール

上述のドキュメントに詳しくある(略)
python3環境でコンパイルするには少し変更が必要となる。

使い方

SciPyの各種アルゴリズムを使うためには
numpy.ndarray を引数にして同じndarrayを返す関数が必須。

NumPyの肝であるndarrayをC++で作る

project/CMakeLists.txt
        numpy.cpp
numpy.cpp
#include "boost/numpy.hpp"

namespace p = boost::python;
namespace np = boost::numpy;

np::ndarray new_zero1(unsigned int N) {
  p::tuple shape = p::make_tuple(N);
  np::dtype dtype = np::dtype::get_builtin<double>();
  return np::zeros(shape, dtype);
}

BOOST_PYTHON_MODULE(mymodule) {
  Py_Initialize();
  np::initialize();

  p::def("new_zero", new_zero1);
}

こんな感じで書く。かなり直感的に書ける。

CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
# set(CMAKE_VERBOSE_MAKEFILE 1)

find_package(Boost COMPONENTS python3 REQUIRED) # for python3
find_package(PythonLibs REQUIRED)
include_directories(${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})

add_library(mymodule SHARED numpy.cpp)
target_link_libraries(mymodule ${Boost_LIBRARIES} ${PYTHON_LIBRARY} boost_numpy)
set_target_properties(mymodule PROPERTIES PREFIX "") # 接頭辞'lib'を省略するため
cmake .
make

これでmymodule.soができる。
set_target_propertiesを書かないとlibmymodule.soとなる。
LIBRARYだったりLIBRARIESだったりするので注意する。

もっと詳しい使い方は次回。