2017-06-12 2 views
0

Je souhaite écrire une fonction avec la signature suivanteVectorize une matrice symétrique

VectorXd vectorize (const MatrixXd&); 

qui retourne le contenu d'une matrice symétrique en forme VectorXd, sans éléments répétés. Par exemple,

int n = 3; // n may be much larger in practice. 
MatrixXd sym(n, n); 
sym << 9, 2, 3, 
     2, 8, 4, 
     3, 4, 7; 

std::cout << vectorize(sym) << std::endl; 

REVERSE:

9 
2 
3 
8 
4 
7 

L'ordre des éléments dans vec n'a pas d'importance, à condition qu'il soit systématique. Ce qui est important à mes fins est de retourner les données de sym sans les éléments répétés, car sym est toujours supposé être symétrique. C'est-à-dire, je veux retourner les éléments de la "vue" triangulaire supérieure ou inférieure de sym sous la forme VectorXd.

J'ai naïvement implémenté vectorize avec des boucles for imbriquées, mais cette fonction peut être appelée très souvent dans mon programme (plus de 1 million de fois). Ma question est donc: quelle est la manière la plus efficace en termes de calcul pour écrire vectorize? J'espérais utiliser le triangularView d'Eigen, mais je ne vois pas comment.

Merci d'avance.

+1

Il semblerait que vous ayez besoin d'utiliser 'TriangularView' et' Map'. – TriskalJM

+1

Cette fonctionnalité-demande est liée: http://eigen.tuxfamily.org/bz/show_bug.cgi?id=42 (voir en particulier comment2 pour une alternative d'emballage - vous devriez aussi faire plus ou moins manuellement, cependant). – chtz

Répondre

1

En ce qui concerne l'efficacité, vous pourriez écrire une seule boucle avec copies sage colonne (et donc vectorisé):

VectorXd res(mat.rows()*(mat.cols()+1)/2); 
Index size = mat.rows(); 
Index offset = 0; 
for(Index j=0; j<mat.cols(); ++j) { 
    res.segment(offset,size) = mat.col(j).tail(size); 
    offset += size; 
    size--; 
} 

Dans la pratique, je pense que le compilateur déjà entièrement vectorisé votre boucle imbriquée, et donc la vitesse devrait être à peu près la même chose.

+0

Merci pour votre réponse. J'ai édité une petite erreur: 'size -' devrait venir après 'offset + = size'. – tmnol

+0

Pourriez-vous expliquer pourquoi vous utilisez 'Index' à la place de, disons,' int'? Je n'ai pas vu la classe 'Index' utilisée auparavant. – tmnol

+2

@tmnol 'Eigen :: Index' (par défaut) est juste un typedef pour' std :: ptrdiff_t', qui est un entier de 64 bits sur des plateformes de 64 bits. – chtz