¿Qué es un algoritmo simple para calcular la SVD de matrices ?
Idealmente, me gustaría un algoritmo numéricamente robusto, pero me gustaría ver implementaciones simples y no tan simples. Código C aceptado.
¿Alguna referencia a documentos o código?
¿Qué es un algoritmo simple para calcular la SVD de matrices ?
Idealmente, me gustaría un algoritmo numéricamente robusto, pero me gustaría ver implementaciones simples y no tan simples. Código C aceptado.
¿Alguna referencia a documentos o código?
Respuestas:
Ver /math/861674/decompose-a-2d-arbitrary-transform-into-only-scaling-and-rotation (lo siento, lo habría puesto en un comentario pero me he registrado solo para publicar esto para que no pueda publicar comentarios todavía).
Pero como lo escribo como respuesta, también escribiré el método:
Eso descompone la matriz de la siguiente manera:
Lo único contra lo que debe protegerse con este método es que o para atan2.G = F= 0 H= E= 0
Dudo que pueda ser más robusto que eso( Actualización: ¡ vea la respuesta de Alex Eftimiades!).La referencia es: http://dx.doi.org/10.1109/38.486688 (dada por Rahul allí) que viene del final de esta publicación de blog: http://metamerist.blogspot.com/2006/10/linear-algebra -for-graphics-geeks-svd.html
Actualización: como señaló @VictorLiu en un comentario, puede ser negativo. Eso sucede si y solo si el determinante de la matriz de entrada también es negativo. Si ese es el caso y desea los valores singulares positivos, simplemente tome el valor absoluto de .sy sy
fuente
@Pedro Gimeno
"Dudo que pueda ser más robusto que eso".
Desafío aceptado.
Noté que el enfoque habitual es utilizar funciones trigonométricas como atan2. Intuitivamente, no debería ser necesario usar funciones trigonométricas. De hecho, todos los resultados terminan como senos y cosenos de arctanos, que pueden simplificarse a funciones algebraicas. Me llevó bastante tiempo, pero logré simplificar el algoritmo de Pedro para usar solo funciones algebraicas.
El siguiente código de Python hace el truco.
fuente
y1
= 0,x1
= 0,h1
= 0, yt1
= 0/0 =NaN
.El GSL tiene un solucionador SVD de 2 por 2 subyacente a la parte de descomposición QR del algoritmo SVD principal para
gsl_linalg_SV_decomp
. Vea elsvdstep.c
archivo y busque lasvd2
función. La función tiene algunos casos especiales, no es exactamente trivial y parece estar haciendo varias cosas para ser numéricamente cuidadoso (por ejemplo, usarhypot
para evitar desbordamientos).fuente
ChangeLog
archivo si descarga el GSL. Y puede consultar lossvd.c
detalles del algoritmo general. La documentación sólo es cierto parece ser para las funciones se puede llamar de usuario de alto nivel, por ejemplo,gsl_linalg_SV_decomp
.Cuando decimos "numéricamente robusto" usualmente nos referimos a un algoritmo en el que hacemos cosas como pivotar para evitar la propagación de errores. Sin embargo, para una matriz de 2x2, puede escribir el resultado en términos de fórmulas explícitas, es decir, escribir fórmulas para los elementos SVD que expresan el resultado solo en términos de las entradas , en lugar de en términos de valores intermedios previamente calculados . Eso significa que puede tener cancelación pero no propagación de errores.
El punto simplemente es que para sistemas 2x2, no es necesario preocuparse por la robustez.
fuente
Este código se basa en el artículo de Blinn , papel Ellis , conferencia SVD , y otros cálculos. Un algoritmo es adecuado para matrices reales regulares y singulares. Todas las versiones anteriores funcionan al 100% tan bien como esta.
fuente
Necesitaba un algoritmo que tenga
Recordar que
Se puede calcular la rotación de diagonalización resolviendo la siguiente ecuación:
dónde
Ideas de:
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/
fuente
He usado la descripción en http://www.lucidarme.me/?p=4624 para crear este código C ++. Las matrices son las de la biblioteca Eigen, pero puede crear fácilmente su propia estructura de datos a partir de este ejemplo:
Con la función de signo estándar
Esto da como resultado exactamente los mismos valores que el
Eigen::JacobiSVD
(consulte https://eigen.tuxfamily.org/dox-devel/classEigen_1_1JacobiSVD.html ).fuente
S2 = hypot( a*a + b*b - c*c - d*d, 2*(a*c + b*d))
fuente
Para mi necesidad personal, traté de aislar el cálculo mínimo para un svd de 2x2. Supongo que es probablemente una de las soluciones más simples y rápidas. Puede encontrar detalles en mi blog personal: http://lucidarme.me/?p=4624 .
Ventajas: simple, rápido y solo puede calcular una o dos de las tres matrices (S, U o D) si no necesita las tres matrices.
La desventaja es que utiliza atan2, que puede ser impreciso y puede requerir una biblioteca externa (típ. Math.h).
fuente
Aquí hay una implementación de una resolución SVD 2x2. Lo basé en el código de Victor Liu. Su código no funcionaba para algunas matrices. Usé estos dos documentos como referencia matemática para la resolución: pdf1 y pdf2 .
El
setData
método de la matriz está en orden de fila mayor. Internamente, represento los datos de la matriz como una matriz 2D dada pordata[col][row]
.fuente