O que é um algoritmo simples para calcular o SVD de matrizes?
Idealmente, eu gostaria de um algoritmo numericamente robusto, mas gostaria de ver implementações simples e não tão simples. Código C aceito.
Alguma referência a documentos ou código?
O que é um algoritmo simples para calcular o SVD de matrizes?
Idealmente, eu gostaria de um algoritmo numericamente robusto, mas gostaria de ver implementações simples e não tão simples. Código C aceito.
Alguma referência a documentos ou código?
Respostas:
Consulte /math/861674/decompose-a-2d-arbitrary-transform-into-only-scaling-and-rotation (desculpe, eu teria colocado isso em um comentário, mas me registrei apenas para postar isso, então eu não posso postar comentários ainda).
Mas, como estou escrevendo como resposta, também escreverei o método:
Isso decompõe a matriz da seguinte maneira:
A única coisa a ser evitada com esse método é queG = F= 0 ou H= E= 0 para atan2.
Duvido que possa ser mais robusto que isso( Atualização: veja a resposta de Alex Eftimiades!).A referência é: http://dx.doi.org/10.1109/38.486688 (fornecida por Rahul), que vem da parte inferior desta postagem do blog: http://metamerist.blogspot.com/2006/10/linear-algebra -para-gráficos-geeks-svd.html
Update: Como observado por @VictorLiu em um comentário,sy pode ser negativo. Isso acontece se, e somente se, o determinante da matriz de entrada também for negativo. Se for esse o caso e você desejar os valores singulares positivos, basta pegar o valor absoluto de sy .
fonte
@Pedro Gimeno
"Duvido que possa ser mais robusto que isso".
Desafio aceito.
Percebi que a abordagem usual é usar funções trigonométricas como atan2. Intuitivamente, não deve haver necessidade de usar funções trigonométricas. De fato, todos os resultados acabam em senos e cossenos de arctans - que podem ser simplificados para funções algébricas. Demorou um pouco, mas consegui simplificar o algoritmo de Pedro para usar apenas funções algébricas.
O seguinte código python faz o truque.
fonte
y1
= 0,x1
= 0,h1
= 0 et1
= 0/0 =NaN
.O GSL possui um solucionador SVD 2 por 2 subjacente à parte de decomposição QR do algoritmo SVD principal para
gsl_linalg_SV_decomp
. Veja osvdstep.c
arquivo e procure asvd2
função. A função tem alguns casos especiais, não é exatamente trivial e parece estar fazendo várias coisas para ser numericamente cuidadosa (por exemplo, usarhypot
para evitar estouros).fonte
ChangeLog
arquivo se você baixar o GSL. E você pode procurarsvd.c
por detalhes do algoritmo geral. A única documentação verdadeira parece ser para as funções de alto nível que podem ser chamadas pelo usuário, por exemplogsl_linalg_SV_decomp
,.Quando dizemos "numericamente robusto", geralmente queremos dizer um algoritmo no qual fazemos coisas como rotação para evitar a propagação de erros. No entanto, para uma matriz 2x2, é possível anotar o resultado em termos de fórmulas explícitas - ou seja, anotar fórmulas para os elementos SVD que indicam o resultado apenas em termos de entradas , e não em valores intermediários anteriormente calculados . Isso significa que você pode ter cancelamento, mas nenhuma propagação de erro.
O ponto simplesmente é que, para sistemas 2x2, não é necessário se preocupar com robustez.
fonte
Este código é baseado no papel de Blinn , papel Ellis , palestra SVD e adicionais cálculos. Um algoritmo é adequado para matrizes reais regulares e singulares. Todas as versões anteriores funcionam 100%, bem como esta.
fonte
Eu precisava de um algoritmo que tenha
Lembre-se que
O cálculo da rotação da diagonalização pode ser feito resolvendo a seguinte equação:
Onde
Ideias 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/
fonte
Eu usei a descrição em http://www.lucidarme.me/?p=4624 para criar esse código C ++. As matrizes são as da biblioteca Eigen, mas você pode criar facilmente sua própria estrutura de dados a partir deste exemplo:
Com a função de sinal padrão
Isso resulta exatamente nos mesmos valores que o
Eigen::JacobiSVD
(consulte https://eigen.tuxfamily.org/dox-devel/classEigen_1_1JacobiSVD.html ).fonte
S2 = hypot( a*a + b*b - c*c - d*d, 2*(a*c + b*d))
fonte
Para minha necessidade pessoal, tentei isolar o cálculo mínimo para um svd 2x2. Eu acho que é provavelmente uma das soluções mais simples e rápidas. Você pode encontrar detalhes no meu blog pessoal: http://lucidarme.me/?p=4624 .
Vantagens: simples, rápido e você só pode calcular uma ou duas das três matrizes (S, U ou D) se não precisar das três matrizes.
A desvantagem é o atan2, que pode ser impreciso e pode exigir uma biblioteca externa (tipo. Math.h).
fonte
Aqui está uma implementação de uma solução SVD 2x2. Baseei-o no código de Victor Liu. Seu código não estava funcionando para algumas matrizes. Usei esses dois documentos como referência matemática para a solução: pdf1 e pdf2 .
O
setData
método da matriz está na ordem das principais linhas. Internamente, represento os dados da matriz como uma matriz 2D dada pordata[col][row]
.fonte