PyUblas を使う

PyUblasはBoost.PythonとNumpyの間のデータ受け渡しをサポートする素敵ライブラリーだ.
かなり便利. インストール方法は, 公式ドキュメントを参照.

ただ, インストール過程で何箇所か戸惑う所があった. まず, コンパイルエラーが出たことと(const変数から非const関数が呼び出されていた), ライブラリの配置先がよくわからなかったこと.
前者の問題は, コードを書き換えて, 後者の問題はlocateで見つけた該当ファイルをパスが通った所にコピーして解決した. あんまりLinux使ってない人だと解決できないかも.

使ってみると結構便利, python側はpyublasをimportするだけでだいたい使えるし, C++側も

#include <Python.h>

#include <numpy/arrayobject.h>
#include <boost/python.hpp>
#include <pyublas/numpy.hpp>

using namespace std;
using namespace boost;
using namespace boost::python;

//numpy_matrixはscipy.arrayとメモリ空間を共有しているため, 
//変更は元のscipy.arrayに反映される
pyublas::numpy_matrix<double> doublify(pyublas::numpy_matrix<double> x)
{
  return 2*x;
}

//BOOST_PYTHON_MODULE()の引数がmodule名
BOOST_PYTHON_MODULE(simple_array){
  //import_array();
  //numeric::array::set_module_and_type("numpy", "ndarray");
  def("doublify",doublify);
  def("test",test);
}

これだけでOK! 解説する必要も無さそう. Python側からは

#!/usr/bin/python

from scipy import *
import simple_array
import pyublas

vec = array([[1,2],[3,4]],dtype=double)
print simple_array.doublify(vec)

という風に使う.

import pyublas

を忘れるとBoost.Pythonの型変換テーブルにscipy.array <=> pyublas::numpy_matrixの対応が登録されないためエラーが発生する.

numpy_vector, numpy_matrixの最大の特徴は色々な操作でデータのコピーが発生しないこと. numpy_vectorもndarray(scipy.array)のメモリ空間を直接操作してるらしい. だからin-place処理も可能.

注意すべき点

pyublassはPythonのndarrayを, C++のnumpy_arrayかnumpy_matrixに変換できる. ただしnumpy_arrayはおそらく何次元のarrayを受け取っても全部1次元に変換してしまう.

また, 重要なのはcontiguousでないarray, つまり

A = eye(3)
A[:2,:2]

みたいにメモリが連続していないarrayはnumpy_matrixでは扱えない.

また, indexを介してアクセスする処理が遅いっぽくて, コンパイル時にBOOST_UBLAS_USE_ITERATINGというフラグを立てれば解決するらしい. (自分のコードにもいる). iteratorを介したアクセスなら大丈夫らしいけど.
これは, 要素が連続しているって仮定を使ってないからなのかな? そうだとしたらnumpy_matrixでは同じ現象は起こらない筈だけどまだ検証してない.

あとpyublasの返り値は左辺値として使えるものしか返せない(参照やポインタは返せない)とか, 引数は右辺値としてしか使えるものしか認めないとかあるらしいけどドキュメント読んで下さい.

まとめ

とりあえず便利なのでしばらく使ってみようと思っている.