雑食性雑感雑記

知識の整理場。ため込んだ知識をブログ記事として再構築します。

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++化して高速化できそう。

参照