Eigen バージョンでは、「真の」固定サイズの行列とベクトル、より優れたアルゴリズム (uBlas での LDLT と LU) を使用し、内部で SIMD 命令を使用します。では、次の例で uBlas よりも遅いのはなぜですか?
私は何か間違ったことをしていると確信しています.Eigenはより高速であるか、少なくとも同等である必要があります.
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/symmetric.hpp>
#include <boost/progress.hpp>
#include <Eigen/Dense>
#include <iostream>
using namespace boost;
using namespace std;
const int n=9;
const int total=100000;
void test_ublas()
{
using namespace boost::numeric::ublas;
cout << "Boost.ublas ";
double r=1.0;
{
boost::progress_timer t;
for(int j=0;j!=total;++j)
{
//symmetric_matrix< double,lower,row_major,bounded_array<double,(1+n)*n/2> > A(n,n);
matrix<double,row_major,bounded_array<double,n*n> > A(n,n);
permutation_matrix< unsigned char,bounded_array<unsigned char,n> > P(n);
bounded_vector<double,n> v;
for(int i=0;i!=n;++i)
for(int k=0;k!=n;++k)
A(i,k)=0.0;
for(int i=0;i!=n;++i)
{
A(i,i)=1.0+i;
v[i]=i;
}
lu_factorize(A,P);
lu_substitute(A,P,v);
r+=inner_prod(v,v);
}
}
cout << r << endl;
}
void test_eigen()
{
using namespace Eigen;
cout << "Eigen ";
double r=1.0;
{
boost::progress_timer t;
for(int j=0;j!=total;++j)
{
Matrix<double,n,n> A;
Matrix<double,n,1> b;
for(int i=0;i!=n;++i)
{
A(i,i)=1.0+i;
b[i]=i;
}
Matrix<double,n,1> x=A.ldlt().solve(b);
r+=x.dot(x);
}
}
cout << r << endl;
}
int main()
{
test_ublas();
test_eigen();
}
出力は次のとおりです。
Boost.ublas 0.50 s
488184
Eigen 2.66 s
488184
(Visual Studio 2010 x64 リリース)
編集:
為に
const int n=4;
const int total=1000000;
出力は次のとおりです。
Boost.ublas 0.67 s
1.25695e+006
Eigen 0.40 s
5.4e+007
このような動作は、uBlas バージョンがその場で因数分解を計算するのに対し、Eigen バージョンは行列の COPY (LDLT) を作成するためだと思います。そのため、キャッシュにうまく適合しません。
Eigenでインプレース計算を行う方法はありますか? それとも、それを改善する他の方法がありますか?
編集:
Fezvez のアドバイスに従って、LDLT の代わりに LLT を使用すると、次のようになります。
Eigen 0.16 s
488184
それは良いことですが、それでも不必要な行列スタック割り当てを行います:
sizeof(A.llt()) == 656
私はそれを避けることを好みます-それはさらに速くなるはずです。
編集:
LDLT (内部マトリックスは保護されています) からサブクラス化し、直接入力することにより、割り当てを削除しました。LDLT の結果は次のようになります。
Eigen 0.26 s
488209
それは機能しますが、回避策です-実際の解決策ではありません...
LLT からのサブクラス化も機能しますが、それほど大きな効果はありません。