Was ist ein einfacher Algorithmus zur Berechnung der SVD von Matrizen?
Idealerweise hätte ich gerne einen numerisch robusten Algorithmus, aber ich würde gerne sowohl einfache als auch nicht so einfache Implementierungen sehen. C-Code akzeptiert.
Verweise auf Papiere oder Code?
Antworten:
Siehe https://math.stackexchange.com/questions/861674/decompose-a-2d-arbitrary-transform-into-only-scaling-and-rotation (Entschuldigung, das hätte ich in einen Kommentar eingefügt, aber ich habe mich registriert nur um dies zu posten, damit ich noch keine Kommentare posten kann).
Da ich es aber als Antwort schreibe, schreibe ich auch die Methode:
Das zerlegt die Matrix wie folgt:
Das einzige, wovor man sich bei dieser Methode hüten muss, ist, dassG=F=0 oder H=E=0 für atan2 ist.
Ich bezweifle, dass es robuster sein kann( Update: siehe Antwort von Alex Eftimiades!)Die Referenz lautet: http://dx.doi.org/10.1109/38.486688 (von Rahul dort angegeben) und befindet sich am Ende dieses Blogposts: http://metamerist.blogspot.com/2006/10/linear-algebra -für-Grafik-Geeks-svd.html
Update: Wie von @VictorLiu in einem Kommentar vermerkt, kannsy negativ sein. Dies geschieht genau dann, wenn die Determinante der Eingangsmatrix ebenfalls negativ ist. Wenn dies der Fall ist und Sie die positiven Singularwerte wollen, nehmen Sie einfach den absoluten Wert von sy .
quelle
@ Pedro Gimeno
"Ich bezweifle, dass es robuster sein kann."
Herausforderung angenommen.
Mir ist aufgefallen, dass der übliche Ansatz darin besteht, Triggerfunktionen wie atan2 zu verwenden. Intuitiv sollte es nicht erforderlich sein, Triggerfunktionen zu verwenden. In der Tat enden alle Ergebnisse als Sinus und Cosinus von Arctanen - was zu algebraischen Funktionen vereinfacht werden kann. Es hat eine Weile gedauert, aber ich habe es geschafft, den Algorithmus von Pedro so zu vereinfachen, dass er nur algebraische Funktionen verwendet.
Der folgende Python-Code erledigt den Trick.
quelle
y1
= 0,x1
= 0,h1
= 0 undt1
= 0/0 =NaN
.Die GSL verfügt über einen 2-mal-2-SVD-Löser, der dem QR-Zerlegungsteil des SVD-Hauptalgorithmus für zugrunde liegt
gsl_linalg_SV_decomp
. Sehen Sie sich diesvdstep.c
Datei an und suchen Sie nach dersvd2
Funktion. Die Funktion hat einige Sonderfälle, ist nicht gerade trivial und scheint verschiedene Dinge zu tun, um numerisch vorsichtig zu sein (z. B.hypot
um Überläufe zu vermeiden).quelle
ChangeLog
Datei befindet sich ein Teil, wenn Sie die GSL herunterladen. Und Sie können schauen ,svd.c
um Details des gesamten Algorithmus. Die einzig wahre Dokumentation scheint für die vom Benutzer aufrufbaren Funktionen auf hoher Ebene zu sein, zgsl_linalg_SV_decomp
.Wenn wir "numerisch robust" sagen, meinen wir normalerweise einen Algorithmus, bei dem wir Dinge wie das Schwenken tun, um eine Fehlerausbreitung zu vermeiden. Bei einer 2x2-Matrix können Sie das Ergebnis jedoch in Form expliziter Formeln aufschreiben, dh Formeln für die SVD-Elemente, die das Ergebnis nur anhand der Eingaben und nicht anhand der zuvor berechneten Zwischenwerte angeben . Das bedeutet, dass Sie möglicherweise eine Stornierung, aber keine Fehlerweitergabe haben.
Der Punkt ist einfach, dass bei 2x2-Systemen die Sorge um die Robustheit nicht erforderlich ist.
quelle
Dieser Code basiert auf Blinns Artikel , Ellis-Artikel , SVD-Vorlesung und zusätzlichen Berechnungen. Ein Algorithmus eignet sich für reguläre und singuläre reelle Matrizen. Alle vorherigen Versionen funktionieren zu 100% so gut wie diese.
quelle
Ich brauchte einen Algorithmus, der hat
Wir wollen berechnenc1,s1,c2,s2,σ1 σ2
Erinnere dich daran
Die Berechnung der Diagonalisierungsdrehung kann durch Lösen der folgenden Gleichung erfolgen:
woher
andt2 is the tangent of angle of V . This can be derived by expanding VATAVT and making its off-diagonal elements equal to zero (they are equal to each other).
The problem with this method is that it loses significant floating point precision when calculatingβ−α and γ for certain matrices, because of the subtractions in the calculations. The solution for this is to do an RQ decomposition (A=RQ , R upper triangular and Q orthogonal) first, then use the algorithm to factorize USV′=R . This gives USV=USV′Q=RQ=A . Notice how setting d to 0 (as in R ) eliminates some of the additions/subtractions. (The RQ decomposition is fairly trivial from the expansion of the matrix product).
The algorithm naively implemented this way has some numerical and logical anomalies (e.g. isS +D−−√ or −D−−√ ), which I fixed in the code below.
I threw about 2000 million randomized matrices at the code, and the largest numerical error produced was around6⋅10−7 (with 32 bit floats, error=||USV−M||/||M|| ). The algorithm runs in about 340 clock cycles (MSVC 19, Ivy Bridge).
Ideen von:
http://www.cs.utexas.edu/users/inderjit/public_papers/HLA_SVD.pdf
http://www.math.pitt.edu/~sussmanm/2071Spring08/lab09/index.html
http: // www.lucidarme.me/singular-value-decomposition-of-a-2x2-matrix/
quelle
Ich habe die Beschreibung unter http://www.lucidarme.me/?p=4624 verwendet , um diesen C ++ - Code zu erstellen. Die Matrizen sind die der Eigen-Bibliothek, aber Sie können aus diesem Beispiel leicht Ihre eigene Datenstruktur erstellen:
Mit der Standardzeichenfunktion
Daraus ergeben sich genau dieselben Werte wie für
Eigen::JacobiSVD
(siehe https://eigen.tuxfamily.org/dox-devel/classEigen_1_1JacobiSVD.html ).quelle
S2 = hypot( a*a + b*b - c*c - d*d, 2*(a*c + b*d))
Ich habe reinen C - Code für die 2x2 echte SVD hier . Siehe Zeile 559. Sie berechnet im Wesentlichen die Eigenwerte vonEINTEIN durch das Lösen eines Quadrats ist es nicht unbedingt das robusteste, aber es scheint in der Praxis für nicht zu pathologische Fälle gut zu funktionieren. Es ist relativ einfach.
quelle
Aus persönlichen Gründen habe ich versucht, die Mindestberechnung für eine 2x2-DVD zu isolieren. Ich denke, es ist wahrscheinlich eine der einfachsten und schnellsten Lösungen. Details finden Sie in meinem persönlichen Blog: http://lucidarme.me/?p=4624 .
Vorteile: einfach, schnell und Sie können nur eine oder zwei der drei Matrizen (S, U oder D) berechnen, wenn Sie die drei Matrizen nicht benötigen.
Nachteil: Es wird atan2 verwendet, was möglicherweise ungenau ist und eine externe Bibliothek erfordert (typ. Math.h).
quelle
Hier ist eine Implementierung eines 2x2 SVD zu lösen. Ich habe es auf Victor Lius Code aufgebaut. Sein Code funktionierte für einige Matrizen nicht. Ich habe diese beiden Dokumente als mathematische Referenz für die Lösung verwendet: pdf1 und pdf2 .
Die Matrixmethode
setData
ist in der Hauptreihenfolge. Intern repräsentiere ich die Matrixdaten als 2D-Array vondata[col][row]
.quelle