Der effizienteste Weg, um eine Eigenmatrix zu durchlaufen

7

Ich erstelle einige Funktionen, um Dinge wie die "getrennte Summe" von negativer und positiver Zahl, kahan, paarweise und andere Sachen zu machen, wo es egal ist, in welcher Reihenfolge ich die Elemente aus der Matrix nehme, zum Beispiel:

%Vor%

Nun möchte ich das so effizient wie möglich machen, also ist es meine Frage, wäre es besser, jede Spalte jeder Zeile wie oben beschrieben zu durchlaufen oder das Gegenteil zu tun, wie das Folgende:

%Vor%

(Ich nehme an, das hängt von der Reihenfolge ab, in der die Matrixelemente im Speicher zugewiesen sind, aber ich konnte dies in Eigens Handbuch nicht finden).

Gibt es noch andere alternative Möglichkeiten wie die Verwendung von Iteratoren (existieren sie in Eigen?), die etwas schneller sein könnten?

    
random_user 29.04.2013, 15:55
quelle

4 Antworten

6

Eigen vergibt standardmäßig Matrizen in der Reihenfolge Groß (Fortran) ( Dokumentation ).

Der schnellste Weg, um über eine Matrix zu iterieren, ist die Speicherreihenfolge. Wenn Sie die falsche Richtung wählen, erhöht sich die Anzahl der Cache-Misses (wenn Ihre Matrix nicht in L1 passt, wird Ihre Rechenzeit dominieren Rechenzeit) um einen Faktor cacheline / elemsize (wahrscheinlich 64/8 = 8).

Wenn Ihre Matrix in den L1-Cache passt, macht das keinen Unterschied, aber ein guter Compiler sollte in der Lage sein, die Schleife zu vektorisieren, was Ihnen mit AVX (auf einem glänzenden neuen Core i7) eine Beschleunigung von so viel geben könnte als 4 mal. (256 Bits / 64 Bits).

Erwarte schließlich nicht, dass irgendwelche eingebauten Funktionen dir eine Beschleunigung geben (ich glaube nicht, dass es Iteratoren gibt, aber ich kann mich irren), sie werden dir nur das gleiche geben (sehr einfacher) Code.

TLDR: Tauschen Sie die Iterationsreihenfolge, Sie müssen den Zeilenindex am schnellsten variieren.

    
jleahy 29.04.2013, 19:22
quelle
15

Ich habe einige Benchmarks zum Auschecken gemacht, welcher Weg ist schneller, ich habe folgende Ergebnisse (in Sekunden):

%Vor%

Die erste Zeile führt eine Iteration durch, wie von @jleahy vorgeschlagen. Die zweite Zeile führt eine Iteration durch, wie ich es in meinem Code in der Frage gemacht habe (die umgekehrte Reihenfolge von @jleahy). Die dritte Zeile führt eine Iteration mit PlainObjectBase::data() wie dieser for (int i = 0; i < matrixObject.size(); i++) durch. Die anderen 3 Zeilen wiederholen das gleiche wie oben, aber mit einem temporären, wie von @ lucas92 vorgeschlagen

Ich habe auch die gleichen Tests gemacht, aber mit Ersetzen von / sonst. * / für / else / (keine spezielle Behandlung für spärliche Matrix) und ich habe Folgendes (in Sekunden):

%Vor%

Durch die Wiederholung der Tests waren die Ergebnisse ziemlich ähnlich. Ich habe g++ 4.7.3 mit -O3 benutzt. Der Code:

%Vor%     
random_user 29.04.2013 20:50
quelle
3

Ich stelle fest, dass der Code der Summe aller Einträge in der Matrix entspricht, d. h. Sie können einfach Folgendes tun:

%Vor%

Ich würde annehmen, dass dies eine bessere Leistung bringen würde, da es nur ein einziger Durchgang ist, und außerdem sollte Eigen "wissen", wie man die Durchgänge für optimale Leistung anordnet.

Wenn Sie jedoch die beiden Durchläufe beibehalten möchten, können Sie dies mithilfe der Koeffizienten-Reduktionsmechanismen wie folgt ausdrücken:

%Vor%

verwendet den booleschen Koeffizienten, um die positiven und negativen Einträge auszuwählen. Ich weiß nicht, ob es die handgewalzten Schleifen übertreffen würde, aber in der Theorie, die es auf diese Weise codiert, kann Eigen (und der Compiler) mehr über Ihre Absicht wissen und möglicherweise die Ergebnisse verbessern.

    
Jeff Trull 20.08.2015 01:10
quelle
1

Versuchen Sie, xs (i, j) innerhalb einer temporären Variablen innerhalb der Schleife zu speichern, so dass Sie die Funktion nur einmal aufrufen.

    
lucas92 29.04.2013 17:15
quelle

Tags und Links