Boost.numpy ことはじめ その2 (戻り値)
前回まででPythonからサンプルを使ってみることができるようになった。
今回は、2次元numpy配列をC++側で作成し、Python側に戻せるようにしてみる。
サンプル
「行列サイズを指定し、そのサイズにあった2次元numpy行列を返す」サンプルを作ってみる。
ディレクトリ構成
<root directory> - sample.cpp - CMakeLists.txt
sample.cpp
np::zeros を使ってゼロ配列を作成し、そこに値を入れ込む形で実装する。(場合によってはもっと高速な方法あるかもだけどとりあえず。)
2次元ができてしまえば、1次元はもっと簡単なので省略。
ポイント :
- np::zeros の引数は「shape のサイズ、shape、タイプ」。基本的にはPythonのものと同じ。
- 1次元vectorでデータを用意し、std::copyでデータを移す。
#include "boost/python/numpy.hpp" #include <stdexcept> #include <algorithm> namespace p = boost::python; namespace np = boost::python::numpy; std::vector<double> func(int row, int col) { std::vector<double> v; int count = 0; for (int y = 0; y < row; y++) { for (int x = 0; x < col; x++) { v.push_back(count++); } } return v; } np::ndarray retvec(int row, int col) { std::vector<double> v = func(row, col); Py_intptr_t shape[2] = {row, col}; np::ndarray result = np::zeros(2, shape, np::dtype::get_builtin<double>()); std::copy(v.begin(), v.end(), reinterpret_cast<double*>(result.get_data())); return result; } /* BOOST_PYTHON_MODULE の引数は .so 名 */ BOOST_PYTHON_MODULE(libsample) { Py_Initialize(); np::initialize(); p::def("retvec", retvec); }
ビルド
CMakeLists.txtは前回と同じなので割愛。
mkdir build cd build cmake .. make
実行
ipython3で実行
ipython3 In [1]: import libsample as s In [2]: import numpy as np In [3]: a = s.retvec(3, 2) In [4]: a Out[4]: array([[0., 1.], [2., 3.], [4., 5.]])
3行2列の配列ができた!!
まとめ
前回と合わせて、
・ Boost.Numpy の実行
・ (C++で処理して) numpy 配列を戻す
ところまでできた。
ここまでで大体の処理はC++化して高速化できそう。
参照
- 1. how to return numpy.array from boost::python?
- stackoverflow。Boost.Numpyで戻り値取ってくるためのQ&A。