LoginSignup
13
14

More than 5 years have passed since last update.

C++のEigenで作ったライブラリをBoost.NumpyでPythonから使えるようにする。

Last updated at Posted at 2016-09-08

この記事は

札幌C++勉強会のオンラインもくもく会#36でやった内容をメモります。

インストール方法

他所をあたってください。がんばれ。

やること

簡単な例として、Pythonのnumpyで用意した2次元配列の和を
C++のEigenライブラリを使って計算し、それをまたPythonに返す、ということをします。

C++のソースコード

cpplib.cpp
#define EIGEN_DEFAULT_TO_ROW_MAJOR
#include<Eigen/Core>
#include<boost/numpy.hpp>
namespace py = boost::python;
namespace np = boost::numpy;

np::ndarray add_double(const np::ndarray lhs, const np::ndarray rhs) {
    using Stride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
    const auto
        lrows = lhs.shape(0),
        lcols = lhs.shape(1),
        rrows = rhs.shape(0),
        rcols = rhs.shape(1);

    const Stride
        lstride(lhs.strides(0)/sizeof(double), lhs.strides(1)/sizeof(double)),
        rstride(rhs.strides(0)/sizeof(double), rhs.strides(1)/sizeof(double));

    const Eigen::Map<const Eigen::MatrixXd, Eigen::Unaligned, Stride>
        lmat(reinterpret_cast<double*>(lhs.get_data()), lrows, lcols, lstride),
        rmat(reinterpret_cast<double*>(rhs.get_data()), rrows, rcols, rstride);

    np::ndarray ret = np::empty(
        py::make_tuple(lmat.rows(),lmat.cols()), 
        np::dtype::get_builtin<double>());

    Eigen::Map<Eigen::MatrixXd>
        ret_mat(reinterpret_cast<double*>(ret.get_data()), lmat.rows(), lmat.cols());

    ret_mat = lmat + rmat;
    return ret;
}

BOOST_PYTHON_MODULE(cpplib) {
    Py_Initialize();
    np::initialize();
    py::def("add_double",add_double); 
}

行列の足し算を目的にするだけならもっと簡単に書けるかもしれませんが、応用が効くように書いてます。型が double 限定なのは仕方ないです。やるとしたらdtype 調べて分岐ですが、実行時判定するしかない。

コンパイル方法

SConsでやります。例えばこんなかんじです。mingw環境でやってます。

SConstruct
# vim: filetype=python
# SConstruct

env = Environment(
    SHLIBPREFIX="",
    SHLIBSUFFIX=".pyd",
    CXX="/mingw64/bin/g++",
    CXXFLAGS=["-std=c++14"],
    LINKFLAGS=["-std=c++14"],
    CPPPATH=[
        "/mingw64/include/eigen3",
        "/mingw64/include/python3.5m", ],
    LIBPATH=["/mingw64/lib"])

env.SharedLibrary("cpplib", ["cpplib.cpp"],
    LIBS=["boost_numpy", "python3.5.dll", "boost_python3-mt"])

Pythonコード

usecpp.py
import numpy as np
from cpplib import add_double

a = np.array(
    [[1, 2, 3, 4],
     [5, 6, 7, 8],
     [9, 1, 2, 3],
     [4, 5, 6, 7], ], dtype=np.float64)
b = np.array(
    [[5, 6],
     [4, 5], ], dtype=np.float64)

result = add_double(a[1::2, 1::2], b[::1, ::1])
print(result)

結果は
[[6,8],[5,7]][[5,6],[4,5]]が足されるので

$ python3 usecpp.py
[[ 11.  14.]
 [  9.  12.]]

となります。ここでもくもく会時間切れ。

追記

13
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
14