2013-01-02 8 views
8

Eigen ist eine bekannte Matrix-Bibliothek in C++. Ich habe Probleme, eine eingebaute Funktion zu finden, um ein Element einfach an das Ende einer Matrix zu schieben. Zur Zeit weiß ich, dass es, wie dies getan werden kann:Eigen MatrixXd Push zurück in C++

Eigen::MatrixXd matrix(10, 3); 
long int count = 0; 
long int topCount = 10; 
for (int i = 0; i < listLength; ++i) { 
    matrix(count, 0) = list.x; 
    matrix(count, 1) = list.y; 
    matrix(count, 2) = list.z; 
    count++; 
    if (count == topCount) { 
     topCount *= 2; 
     matrix.conservativeResize(topCount, 3); 
    } 
} 
matrix.conservativeResize(count, 3); 

Und dies funktionieren wird (einige der Syntax sein kann aus). Aber es ist ziemlich kompliziert für eine einfache Sache zu tun. Gibt es bereits eine integrierte Funktion?

Antwort

13

Es gibt keine solche Funktion für Eigenmatrizen. Der Grund dafür ist, dass eine solche Funktion entweder sehr langsam ist oder übermäßigen Speicher verbraucht.

Für eine push_back Funktion, die nicht unerschwinglich teuer ist, muss sie die Kapazität der Matrix um einen Faktor erhöhen, wenn der Platz nicht mehr ausreicht, wie Sie es getan haben. Im Umgang mit Matrizen ist die Speichernutzung jedoch häufig ein Problem, so dass die Kapazität einer Matrix größer als notwendig sein kann. Wenn es stattdessen die Größe von rows() oder cols() jedes Mal erhöht, wäre der Vorgang O(n*m). Dies zu tun, um eine gesamte Matrix zu füllen, wäre O(n*n*m*m), was für Matrizen mit moderater Größe ziemlich langsam wäre.

Darüber hinaus sind in der linearen Algebra Matrix und Vektorgrößen fast immer konstant und im Voraus bekannt. Wenn Sie die Größe einer Matrix ändern, interessieren Sie sich oft nicht für die vorherigen Werte in der Matrix. Dies ist der Grund, warum die resize Funktion von Eigenen keine alten Werte beibehält, im Gegensatz zu std::vectors resize.

Der einzige Fall, in dem ich die Größe der Matrix nicht kennen würde, ist beim Lesen aus einer Datei. In diesem Fall würde ich entweder zuerst die Daten in einen Standardcontainer wie std::vector mit push_back laden und dann in eine bereits große Matrix kopieren oder, wenn der Speicher knapp ist, die Datei einmal durchlaufen, um die Größe zu erhalten, und ein zweites Mal kopieren die Werte.

+1

Mit "Wohlen Eigen" können Sie MaxRows MaxCols zur Kompilierzeit definieren. Selbst wenn Sie die genaue Größe bis zur Laufzeit nicht kennen, bleiben die Speicheranforderungen beschränkt (für die resize/push_back-Operationen sind keine Speicherzuweisungen erforderlich). Es wäre nett, wenn Sie push_back Elemente, Zeilen und Spalten so lange wie Größe gnzlbg

+1

"Außerdem sind in der linearen Algebra Matrix und Vektorgrößen fast immer konstant und vorher bekannt." In den meisten iterativen Algorithmen wissen Sie nicht, wie viele Iterationen erforderlich sind, bis ein Konvergenzkriterium erfüllt ist. – Lindon

+0

Modulo die Vorbehalte oben, wenn ich das wirklich brauchte, würde ich eine größere Matrix zuweisen und dann einen Block, der den verwendeten Teil der Matrix darstellt. Um zu pushen, geben Sie Werte der Speichermatrix ein und erstellen einen neuen erweiterten Block, der den neuen verwendeten Teil abdeckt. Wenn Sie die Größe Ihrer Speichermatrix ausgeschöpft haben, verteilen Sie sie neu, indem Sie jede Dimension verdoppeln. Dies ist eine amortisierte Konstante, genau wie std :: vector. Dies könnte einmal als benutzerdefinierte Klasse umbrochen werden. (Ich kenne die besonderen Einschränkungen von Blöcken im Vergleich zu Matrizen nicht. Ich habe sie nur ein paar Mal benutzt.) – THK

7

Es gibt keine solche Funktion, jedoch können Sie so etwas wie dieses selbst bauen:

using Eigen::MatrixXd; 
using Eigen::Vector3d; 

template <typename DynamicEigenMatrix> 
void push_back(DynamicEigenMatrix& m, Vector3d&& values, std::size_t row) 
{ 
    if(row >= m.rows()) { 
     m.conservativeResize(row + 1, Eigen::NoChange); 
    } 
    m.row(row) = values; 
} 


int main() 
{ 
    MatrixXd matrix(10, 3); 
    for (std::size_t i = 0; i < 10; ++i) { 
     push_back(matrix, Vector3d(1,2,3), i); 
    } 
    std::cout << matrix << "\n"; 
    return 0; 
} 

Wenn dies zu viele passt die Größe obwohl ausführen muss, es wird horrend langsam.