8
votes

Eigen et C ++ 11 Type Inference échouent pour Crossky of Matrix Product

J'essaie de prendre la décomposition de la Groleky du produit d'une matrice avec sa transposition, en utilisant le type Eigen et C ++ 11 "Auto". Le problème vient lorsque j'essaie de faire xxx pré>

J'utilise Xcode 6.1, Eigen 3.2.2. L'erreur de type que je reçois est ici . P>

Cet exemple minimal montre le problème sur ma machine. Modifiez le type de C code> à partir de auto code> à matrixxd code> pour le voir fonctionner. P>

#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;
}


0 commentaires

4 Réponses :



2
votes

Je ne suis pas un expert à Eigen , mais les bibliothèques telles que ceci renvoient souvent des objets proxy des opérations, puis utilisent la conversion implicite ou les constructeurs pour forcer le travail réel. (Les modèles d'expression sont un exemple extrême de cela.) Cela évite de copier inutile de la matrice complète des données dans de nombreuses situations. Malheureusement, auto est assez heureux de simplement créer un objet du type de proxy, qui normalement, les utilisateurs de la bibliothèque ne déclareraient jamais expliquer explicitement. Depuis que vous devez finalement avoir les chiffres calculés, il n'y a pas de performance frappé par SE de casting à un matrixxd . (Scott Meyers, dans "Efficace moderne C ++", donne l'exemple associé d'utiliser auto avec vecteur , où opérateur [] (Taille_t i) < / code> retourne un proxy.)


0 commentaires

0
votes

Ne pas utiliser auto avec expressions d'Eigen. J'ai heurté des problèmes encore plus "dramatiques" avec cela avant, voir

Déduction de type auto Eigen en général

et a été conseillé par l'un des créateurs d'Eigen (GAEL) de ne pas utiliser auto avec expressions d'Eigen.

Le casting d'une expression à un type spécifique tel que matrixxd devrait être extrêmement rapide, sauf si vous voulez une évaluation paresseuse (puisque lorsque le résultat est évalué).


2 commentaires

Je pense que cela est légèrement différent du vôtre. Vous retournez un objet de ID à son tour référencé par AutoFeResult - alors l'objet à partir de ID disparaît et AutoSult Références Quelque chose qui ne quitte pas. c.transpose () références c , qui existe toujours donc mon auto CTC ne devrait pas faire référence à quelque chose qui n'existe pas - semblable à la façon dont GGAEL offre une solution à utiliser auto = id = id (foo, 4) . Je voulais tester si Eigen peut remarquer correctement que C.Transpose () * C = B.Transpose () *Transpose () * A * B qui simplifie le calcul, donc idéalement ce serait gardé comme une expression.


Oui, vous êtes correct, cependant, si je n'ai pas l'explication, je n'aurais absolument aucune idée de la raison pour laquelle le code s'est comporté anormalement. Et puisque Eigen a de nombreux types (fondamentalement, chaque expression est un type différent), plus le référencement indirect, auto rend les choses compliquées car vous n'êtes pas vraiment conscient de ce qui se passe sous la hotte et comment sont ces expressions évaluées.



4
votes

Permettez-moi de résumer ce qui se passe et pourquoi c'est faux. Tout d'abord, instanecons les mots-clés code> code> avec les types qu'ils prennent: xxx pré>

Notez que Eigen est une bibliothèque de modèles d'expression. Ici, GeneralProduct code> est un type de résumé représentant le produit. Aucun calcul n'est effectué. Par conséquent, si vous copiez CTC code> sur un matrixxd code> comme: p> xxx pré>

équivalent à: p> xxx pré>

puis le produit a * b code> sera effectué deux fois! Donc, dans tout cas, il est très préférable d'évaluer a * b code> dans un environnement temporaire explicite et identique pour c ^ t * C code>: p> xxx

La dernière ligne: p>

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


1 commentaires

Merci - c'est vraiment génial d'entendre un développeur de la bibliothèque! Ma raison pour cela était de voir si Eigen pourrait optimiser correctement M0.Transpose () * M1.Transpose () * M2 * M3 Quand ils ont des formes utiles - alors je voulais tout garder tout dans l'espace d'expression jusqu'à la dernière minute. Est-ce due à la manière dont les modèles fonctionnent que je ne peux pas prendre une décomposition de la Groleky d'un produit général, n'est-ce que personne n'a été suffisamment soignée pour l'ajouter à Eigen ou y a-t-il une raison pour laquelle il est stupide?