2017-01-30 2 views
0

Sei A eine symmetrische Matrix und sei v ein Vektor. Ich Auszug aus einem Block von n Spalten von j beginnen und durch v multiplizierenC++ Eigenes Kopieren?

VectorXd a; 
a = A.middleCols(j,n).selfadjointView<Lower>() * v // does not compile 

Da dies mit nicht kompiliert, während dies

a = MatrixXd(A.middleCols(j,n).selfadjointView<Lower>()) * v 

tut, ich frage mich, ob die zweite Version macht eine Kopie von

A.middleCols(j,n).selfadjointView<Lower>() 

oder führt die Berechnung direkt aus?

Danke für jeden Hinweis.

EDIT: Ich vermute, dass das Problem etwas mit dem Argument-Typen zu tun hat, wie ich den Fehler:

invalid argument type 'typename ConstSelfAdjointViewReturnType.... to unary expression' 

Tatsächlich A ist das Argument einer durch konstante Referenz übergibt Funktion entweder von

mit Hier
const MatrixXd& A 
const Ref<const MatrixXd>& A 

ist ein Beispiel:

// this version doesn't compile 
MatrixXd returnSymmetricMatrix(const MatrixXd& A, const VectorXd& v, const MatrixXd& B){ 
// B is a symmetric matrix 

VectorXd a; 
a = A.middleCols(3, 4).selfadjointView<Lower>() * v; 
MatrixXd M(code_fill(){...}); 
// code_fill is the function filling the lower triangular part of a symmetric matrix 
M.block(1, 2, 3, 4).triangularView<Lower>() += B.selfadjointView<Lower>(); 

return M; 
} 

// this version compiles 
MatrixXd returnSymmetricMatrix(const MatrixXd& A, const VectorXd& v, const MatrixXd& B){ 
// B is a symmetric matrix 

VectorXd a; 
a = MatrixXd(A.middleCols(3, 4).selfadjointView<Lower>()) * v; 
MatrixXd M(code_fill(){...}); 
// code_fill is the function filling the lower triangular part of a symmetric matrix 
Matrix(M.block(1, 2, 3, 4).triangularView<Lower>()) += B.selfadjointView<Lower>(); 

return M; 
} 

EDIT2 In Bezug auf meine anfängliche Frage und das Beispiel, das ich im Abschnitt Bearbeiten hinzugefügt habe, bin ich ein wenig verwirrt in Bezug auf das Kopieren. Als ich den Unterschied zwischen der Arbeits- und der nicht arbeitenden Versionen, die Linie

Matrix(M.block(1, 2, 3, 4).triangularView<Lower>()) += B.selfadjointView<Lower>(); 

funktioniert, weil seine linke Skala sagt zu Eigen, dass M.block (1, 2, 3, 4) .triangularView() zu verstehen ist eigentlich eine Matrix und keine Referenz auf eine Matrix. Andernfalls würde der Operator + = durch einen Fehler, dass dieser Operator nicht für .block() überladen wird. Meine ursprüngliche Frage ist also, ob Matrix (...) nur sagt, dass es eine Matrix ist, um die Berechnung zu ermöglichen, oder vielmehr die ... in eine Matrix zu kopieren? Vielen Dank!

+0

Der Ausdruck kompiliert (und läuft) gut für mich. Können Sie zusätzliche Informationen überprüfen und hinzufügen? –

+0

Ja, die erste sollte gut funktionieren, ich sehe es mit 'M' anstelle von' A' ... – ggael

+0

Kannst du es zu einem [MCVE] ausmalen? –

Antwort

1

Der folgende Ausdruck:

A.middleCols(j,n).selfadjointView<Lower>() 

schafft keine Kopie.

Auf der anderen Seite, einen temporären für das Ergebnis des Produkts zu vermeiden, können Sie .noalias() hinzufügen:

a.noalias() = M.middleCols(j,n).selfadjointView<Lower>() * v; 

Dies ist nur für die unmittelbare Zuordnung von dichtem Produkt benötigt Code zu ermöglichen, wie:

a = M * a; 

verhalten sich wie erwartet.

EDIT:

bezüglich Ihrer Compilation Ausgabe, die folgenden kompiliert fein:

#include <Eigen/Dense> 
using namespace Eigen; 
int main() 
{ 
    int n = 10; 
    MatrixXd M = MatrixXd::Random(n,2*n); 
    VectorXd v = VectorXd::Random(n); 
    VectorXd a; 
    a.noalias() = M.middleCols(2,n).selfadjointView<Upper>() * v; 

    const Ref<const MatrixXd>& A = M; 
    a.noalias() = A.middleCols(2,n).selfadjointView<Upper>() * v; 
} 

EDIT2

Die folgende Zeile:

MatrixXd(M.block(1, 2, 3, 4).triangularView<Lower>()) += B.selfadjointView<Lower>(); 

macht keinen Sinn, da Sie eine temporäre Kopie erstellen, der Sie zuweisen. Daran erinnern, dass hier MatrixXd(whatever) ruft die Eigen::Matrix Konstruktor. Auch das Zuweisen einer selbstadjungierten Ansicht zu einer Dreiecksansicht macht keinen Sinn. Ich kann nicht einmal darüber nachdenken, was ein vernünftiges Verhalten dafür sein könnte. Wenn Sie nur den unteren Dreiecks Teil aktualisieren möchten, dann tun:

M.block(1, 2, 3, 4).triangularView<Lower>() += B; 

In diesem Fall triangularView verhält sich als Schreibmaske.

+0

Vielen Dank für die .noalias() Erinnerung, aber in diesem Fall verstehe ich nicht wirklich, warum die .noalias() benötigt wird, da ich a = M * v (statt a = M * a) berechne. Ich versuche nicht, die Speicherung eines zu vermeiden, wie ich es wirklich für zukünftige Berechnungen brauche. Ich versuche jedoch, die Kopie von A.MiddleCols (j, n) .selfadjointView (()) zu vermeiden und ich bin immer noch verwirrt, warum die erste Version für Sie funktioniert, wie es nicht für mich (und ja das M statt A ist hier ein Tippfehler, nicht in meinem Code). – itQ

+0

Das liegt daran, dass wir zur Kompilierzeit nicht wissen können, ob Sie a = Mv oder a = Ma machen, und das ist selbst zur Laufzeit im allgemeinen Fall sehr schwierig. Standardmäßig wird also a = Mv so ausgewertet, als ob zwischen a und M oder v ein Alias ​​auftritt, also: 'tmp = M * v; a = tmp; '. – ggael

+0

Vielen Dank! Ich habe die .noalias() Angelegenheit! – itQ