Anaconda 環境 で Boost.Python (Numpy)
Boost.Numpy
C++ と Python で データのやり取りをするには C++ と Python の間で types のコンバーションを書いてやります.
d.hatena.ne.jp
しかし,Numpy Array に変換する機能は標準の boost.python ではサポートしてないので,例えば C++ types から 一旦 python types に変換して Python 側で ndarray に突っ込むとか,或いは protobuf にシリアライズして Python 側で protobuf から ndarray に突っ込むとかそういう感じになります.
そういったときに,C++ types → ndarray へのアクセスをダイレクトに可能にするのが Boost.Numpy です.
詳しくは公式 doc を参照されたい.
Welcome to the documentation of the Boost.Python NumPy extension! - Boost.Python NumPy extension 1.0 documentation - master
boost 1.63 から boost.numpy が同梱になった
いままで自前で boost をビルドしたり boost.python をビルドしたり *1 boost.numpy をビルドしたり 面倒だなと感じていたのですが,boost1.63 から boost.numpy が本体同梱になったので とりあえず boost のビルドが成功すればまとめて使えるようになりました.後は任意の libpython で boost をビルドすればいいのですが,色々あって OS X だと Anaconda Cloud のパッケージを使うのが楽だというところに落ち着きました.
Anaconda の Python 向けに Boost.Python を導入する
Boost :: Anaconda Cloud
conda で boost (>=1.63) をインストールします.
$ conda install -c conda-forge boost=1.64.0
こうすると/path/to/anaconda/include
, /path/to/anaconda/lib
以下にヘッダとビルド済ライブラリが入ります.
とりあえず動くかテスト
適当になんか書きます.
├── CMakeLists.txt ├── include └── src └── sample_py.cc
sample_py.cc
C++側で ndarray を作って Python 側で貰ってみます.*2
#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wmissing-field-initializers" #include <boost/python.hpp> #include <boost/python/numpy.hpp> #pragma GCC diagnostic pop namespace py = boost::python; namespace np = boost::python::numpy; np::ndarray test() { py::tuple shape = py::make_tuple(3, 3); np::dtype dtype = np::dtype::get_builtin<float>(); np::ndarray a = np::zeros(shape, dtype); return a; } BOOST_PYTHON_MODULE(crfpp) { Py_Initialize(); np::initialize(); py::def("test", test); }
cmake を書きました.今回 find_package も使わないので Makefile と殆ど変わらないですが...*3
あと,add_library
すると勝手にターゲットの名前が libxxx にされてしまうので prefix をクリアしたのですが,これもなんとかならないのでしょうか.OS X だと .dylib
ができる( Python から読めない)ので suffix で .so
に変えたりもしたけどちょっと...
cmake_minimum_required(VERSION 3.3) project(crfpp) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib CACHE PATH "Output directory for libraries.") set(CMAKE_CXX_COMPILER clang++) set(CMAKE_CXX_FLAGS "-Wall -Wextra -std=c++11 -O3") set(CMAKE_SHARED_LINKER_FLAGS "-shared -fPIC") set(ANACONDA_ROOT "/path/to/anaconda2-2.4.1") include_directories(${ANACONDA_ROOT}/include ${ANACONDA_ROOT}/include/python2.7 "include") link_directories(${ANACONDA_ROOT}/lib) set(BOOST_LIBS python2.7 boost_python boost_numpy) add_library(crfpp SHARED src/sample_py.cc) target_link_libraries(crfpp ${BOOST_LIBS}) set_target_properties(crfpp PROPERTIES PREFIX "") set_target_properties(crfpp PROPERTIES SUFFIX ".so")
ビルド
$ mkdir build; cd build $ cmake .. $ make
実行
$ cd lib $ python -c "import crfpp; a=crfpp.test(); print(a)" [[ 0. 0. 0.] [ 0. 0. 0.] [ 0. 0. 0.]]
ちゃんと実行できてます.よかった.