Posted at

Eigenの便利な機能あれこれ

機械学習を行う上で欠かせないのが行列演算ライブラリです。

pythonにnumpyがあるように、C++のデファクトスタンダードな行列計算ライブラリにEigenというものがあります。ヘッダのみのライブラリなのでプロジェクトに組み込みやすくSIMDとかも使って最適化してくれるので計算も速いです。

ここ最近でEigenを使った際に便利に感じた機能をまとめたいと思います。


Slicing and Indexing

v3.3.90から配列のSlicingとIndexingが便利に行えるようになりました。それまではblockAPIやhead/tail関数などを駆使していましたが、pythonのような要素指定が可能になりました。

以下にnumpyとEigenの要素指定方法の比較を載せました。

Eigen
numpy

A(seq(i,last), seqN(0,n))
A[i:, :n]

A(seqN(i,m), seqN(i,n))
A[i:i+m, i:i+n]

A(seq(i0,i1), seq(j0,j1))
A[i0:i1+1, j0:j0+1]

A(all, seq(0,last,2))
A[:, ::2]

A(last/2,all)
A[(A.shape[0]-1)/2, :]

v(lastN(n))
v[-n:]

A(all, seq(20, 10, fix<-2>))
A[:, 20:9:-2]

A(seqN(last, n, fix<-1>), all)
A[:-n:-1, :]

A(lastN(n).reverse(), all)
A[:-n:-1, :]

A(all,{4,2,5,5,3})
A[:, [4,2,5,5,3]]


最近傍点を見つけるコードを1行で書く

ドキュメントにも載っているのですが、これが1行で書けるのに少し感動したので紹介します。

#include <iostream>

#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
Eigen::MatrixXf m(2,4);
Eigen::VectorXf v(2);

m << 1, 23, 6, 9,
3, 11, 7, 2;

v << 2,
3;
MatrixXf::Index index;
// find nearest neighbour
(m.colwise() - v).colwise().squaredNorm().minCoeff(&index);
cout << "Nearest neighbour is column " << index << ":" << endl;
cout << m.col(index) << endl;
}

該当の部分は(m.colwise() - v).colwise().squaredNorm().minCoeff(&index);のところですが、行列mの中からベクトルvと最も近い列ベクトルのインデックスと距離を算出しています。


pybind11でpythonラッパにする

C++のコードのpythonラッパを作成するpybind11は標準でEigenとnumpyの変換を行ってくれます。

バインディングを行うコードでpybind11/eigen.hをインクルードするだけで、EigenのMatrix型をnumpyのndarrayに変換してくれます。


プラグインで機能拡張

EigenのMatrixやその他の型にはユーザが新たに関数追加を行うためのプラグイン機能があります。

プラグインと言っても以下のようにMatrixBase型などの中にマクロが埋め込まれており、ユーザ側で追加機能が書かれたファイルをEIGEN_MATRIX_BASE_PLUGINとして定義することでユーザが定義した関数や変数をクラスの中に追加することができます。

class MatrixBase {

// ...
#ifdef EIGEN_MATRIXBASE_PLUGIN
#include EIGEN_MATRIXBASE_PLUGIN
#endif
};

たとえばMatrixPlugin.hの中身を以下のように記述します。


MatrixPlugin.h

inline Scalar hoge() const { return this->operator()(0, 0); }


実際に使用するコードで、Eigenをインクルードする前に#define EIGEN_MATRIXBASE_PLUGIN "MatrixPlugin.h"を記述することで、Matrixからhoge関数を呼ぶことが可能になります。


Unsupported modules

公式にEigenがサポートしていないモジュールですが、色々入ってます。


  • Tensor(3次元以上の配列)の計算

  • 非線形最適化

  • オイラー角の計算

  • 自動微分


などなど。