8

Eigen と C++11 の "auto" 型を使用して、行列の積をその転置でコレスキー分解しようとしています。私がやろうとすると問題が発生します

auto c = a * b
auto cTc = c.tranpose() * c;
auto chol = cTc.llt();

XCode 6.1、Eigen 3.2.2 を使用しています。私が得る型エラーはhereです。

この最小限の例は、私のマシンの問題を示しています。の型をcからautoに変更して、動作するMatrixXdことを確認します。

#include <iostream>
#include <Eigen/Eigen>
using namespace std;
using namespace Eigen;


int main(int argc, const char * argv[]) {
    MatrixXd a = MatrixXd::Random(100, 3);
    MatrixXd b = MatrixXd::Random(3, 100);
    auto c = a * b;
    auto cTc = c.transpose() * c;
    auto chol = cTc.llt();
    return 0;
}

まだ自動を使用している間にこれを機能させる方法はありますか?

副次的な質問として、行列がMatrixXd各段階で a であると主張しないパフォーマンス上の理由はありますか? auto を使用すると、Eigen は、それが空想する奇妙なテンプレート表現として答えを保持することができます。MatrixXd と入力すると問題が発生するかどうかはわかりません。

4

4 に答える 4

4

何が起こっているのか、なぜそれが間違っているのかを要約しましょう。まず、auto取得する型でキーワードをインスタンス化しましょう。

typedef GeneralProduct<MatrixXd,MatrixXd> Prod;
Prod c = a * b;
GeneralProduct<Transpose<Prod>,Prod> cTc = c.transpose() * c;

Eigen は式テンプレート ライブラリであることに注意してください。ここでGeneralProduct<>は、製品を表す抽象型です。計算は実行されません。cTcしたがって、次のようにコピーする場合MatrixXd:

MatrixXd d = cTc;

これは次と同等です:

MatrixXd d = c.transpose() * c;

その後、製品a*bは2回実行されます! したがって、いずれにせよa*b、明示的なテンポラリ内で評価することが非常に望ましいですc^T*c

MatrixXd c = a * b;
MatrixXd cTc = c.transpose() * c;

最後の行:

auto chol = cTc.llt();

もかなり間違っています。cTc が抽象積タイプの場合、抽象積タイプで動作するコレスキー分解をインスタンス化しようとしますが、これは不可能です。cTcが の場合、コードは機能するはずですが、メソッドは次のようなワンライナー式を実装するためMatrixXd、これはまだ推奨される方法ではありません。llt()

VectorXd b = ...;
VectorXd x = cTc.llt().solve(b);

名前付きの Cholesky オブジェクトが必要な場合は、代わりにそのコンストラクターを使用します。

LLT<MatrixXd> chol(cTc);

あるいは:

LLT chol(c.transpose() * c);

c.transpose() * c他の計算で使用する必要がない限り、これは同等です。

a最後に、とのサイズによっては、次のbように計算することが望ましい場合がありますcTc

MatrixXd cTc = b.transpose() * (a.transpose() * a) * b;

将来 (つまり、Eigen 3.3)、Eigen は以下を確認できるようになります。

auto c = a * b;
MatrixXd cTc = c.transpose() * c;

4 つの行列の積としてm0.transpose() * m1.transpose() * m2 * m3、括弧を適切な場所に置きます。m0==m3ただし、それはとを知ることができないため、一時的m1==m2に評価することが好ましい方法である場合でも、自分で行う必要があります。a*b

于 2014-11-25T08:57:23.700 に答える
2

私は の専門家ではありませんEigenが、このようなライブラリは多くの場合、操作からプロキシ オブジェクトを返し、暗黙的な変換またはコンストラクタを使用して実際の作業を強制します。(式テンプレートはこの極端な例です。) これにより、多くの状況でデータの完全なマトリックスを不必要にコピーすることが回避されます。残念ながら、auto通常はライブラリのユーザーが明示的に宣言することのないプロキシ型のオブジェクトを作成するだけで十分です。最終的に数値を計算する必要があるため、 へのキャストによるパフォーマンス ヒット自体はありませんMatrixXd。(Scott Meyers は、「Effective Modern C++」で、autowithを使用する関連例を示しています。 vector<bool>whereoperator[](size_t i)はプロキシを返します。)

于 2014-11-24T21:21:59.540 に答える
0

autoEigen 式と一緒に使用しないでください。以前、これでさらに「劇的な」問題に遭遇しました。

一般積における固有自動車型控除

また、Eigen 作成者の 1 人 (Gael) からauto、Eigen 式を使用しないようにアドバイスされました。

MatrixXd遅延評価が必要でない限り、式から特定の型へのキャストは非常に高速である必要があります (キャストを実行すると結果が評価されるため)。

于 2014-11-24T23:09:46.737 に答える