Autovalores de uma matriz

11

Dada uma matriz quadrada, produza os autovalores da matriz. Cada valor próprio deve ser repetido um número de vezes igual à sua multiplicidade algébrica.

Os valores próprios de uma matriz Asão valores escalares λde tal modo que, por algum vector de coluna v, A*v = λ*v. Eles também são as soluções para o polinômio característico de A: det(A - λ*I) = 0(onde Ié a matriz de identidade com as mesmas dimensões que A).

As saídas devem ter precisão de 3 dígitos significativos. Todas as entradas e saídas estarão dentro do intervalo representável de valores numéricos para o idioma escolhido.

Construções internas são aceitáveis, mas você deve incluir soluções que não usam construções internas.

Casos de teste

Nestes casos de teste, Irepresenta a unidade imaginária. Números complexos são escritos no formulário a + b*I. Todas as saídas têm 3 dígitos significativos de precisão.

[[42.0]] -> [42.0]
[[1.0, 0.0], [0.0, 1.0]] -> [1.00, 1.00]
[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]] -> [16.1, -1.12, -1.24e-15]
[[1.2, 3.4, 5.6, 7.8], [6.3, 0.9, -5.4, -2.3], [-12.0, -9.7, 7.3, 5.9], [-2.5, 7.9, 5.3, 4.4]] -> [7.20 + 5.54*I, 7.20 - 5.54*I, -4.35, 3.75]
[[-3.22 - 9.07*I, 0.193 + 9.11*I, 5.59 + 1.33*I, -3.0 - 6.51*I, -3.73 - 6.42*I], [8.49 - 3.46*I, -1.12 + 6.39*I, -8.25 - 0.455*I, 9.37 - 6.43*I, -6.82 + 8.34*I], [-5.26 + 8.07*I, -6.68 + 3.72*I, -3.21 - 5.63*I, 9.31 + 3.86*I, 4.11 - 8.82*I], [-1.24 + 9.04*I, 8.87 - 0.0352*I, 8.35 + 4.5*I, -9.62 - 2.21*I, 1.76 - 5.72*I], [7.0 - 4.79*I, 9.3 - 2.31*I, -2.41 - 7.3*I, -7.77 - 6.85*I, -9.32 + 2.71*I]] -> [5.18 + 16.7*I, -24.9 - 2.01*I, -5.59 - 13.8*I, 0.0438 - 10.6*I, -1.26 + 1.82*I]
[[-30.6 - 73.3*I, 1.03 - 15.6*I, -83.4 + 72.5*I, 24.1 + 69.6*I, 52.3 + 2.68*I, 23.8 + 98.0*I, 96.8 + 49.7*I, -26.2 - 5.87*I, -52.4 + 98.2*I, 78.1 + 6.69*I], [-59.7 - 66.9*I, -26.3 + 65.0*I, 5.71 + 4.75*I, 91.9 + 82.5*I, -94.6 + 51.8*I, 61.7 + 82.3*I, 54.8 - 27.8*I, 45.7 + 59.2*I, -28.3 + 78.1*I, -59.9 - 54.5*I], [-36.0 + 22.9*I, -51.7 + 10.8*I, -46.6 - 88.0*I, -52.8 - 32.0*I, -75.7 - 23.4*I, 96.2 - 71.2*I, -15.3 - 32.7*I, 26.9 + 6.31*I, -59.2 + 25.8*I, -0.836 - 98.3*I], [-65.2 - 90.6*I, 65.6 - 24.1*I, 72.5 + 33.9*I, 1.47 - 93.8*I, -0.143 + 39.0*I, -3.71 - 30.1*I, 60.1 - 42.4*I, 55.6 + 5.65*I, 48.2 - 53.0*I, -3.9 - 33.0*I], [7.04 + 0.0326*I, -12.8 - 50.4*I, 70.1 - 30.3*I, 42.7 - 76.3*I, -3.24 - 64.1*I, 97.3 + 66.8*I, -11.0 + 16.5*I, -40.6 - 90.7*I, 71.5 - 26.2*I, 83.1 - 49.4*I], [-59.5 + 8.08*I, 74.6 + 29.1*I, -65.8 + 26.3*I, -76.7 - 83.2*I, 26.2 + 99.0*I, -54.8 + 33.3*I, 2.79 - 16.6*I, -85.2 - 3.64*I, 98.4 - 12.4*I, -27.6 - 62.3*I], [82.6 - 95.3*I, 55.8 - 73.6*I, -49.9 + 42.1*I, 53.4 + 16.5*I, 80.2 - 43.6*I, -43.3 - 3.9*I, -2.26 - 58.3*I, -19.9 + 98.1*I, 47.2 + 62.4*I, -63.3 - 54.0*I], [-88.7 + 57.7*I, 55.6 + 70.9*I, 84.1 - 52.8*I, 71.3 - 29.8*I, -3.74 - 19.6*I, 29.7 + 1.18*I, -70.6 - 10.5*I, 37.6 + 99.9*I, 87.0 + 19.0*I, -26.1 - 82.0*I], [69.5 - 47.1*I, 11.3 - 59.0*I, -84.3 - 35.1*I, -3.61 - 35.7*I, 88.0 + 88.1*I, -47.5 + 0.956*I, 14.1 + 89.8*I, 51.3 + 0.14*I, -78.5 - 66.5*I, 2.12 - 53.2*I], [0.599 - 71.2*I, 21.7 + 10.8*I, 19.9 - 97.1*I, 20.5 + 37.4*I, 24.7 + 40.6*I, -82.7 - 29.1*I, 77.9 + 12.5*I, 94.1 - 87.4*I, 78.6 - 89.6*I, 82.6 - 69.6*I]] -> [262. - 180.*I, 179. + 117.*I, 10.3 + 214.*I, 102. - 145.*I, -36.5 + 97.7*I, -82.2 + 89.8*I, -241. - 104.*I, -119. - 26.0*I, -140. - 218.*I, -56.0 - 160.*I]
Mego
fonte
Sandbox
Mego
Relacionado ? Provavelmente relacionado ? (Depende da abordagem)
user202729 27/11

Respostas:

12

Haskell , 576 554 532 507 bytes

Sem built-ins!

import Data.Complex
s=sum
l=length
m=magnitude
i=fromIntegral
(&)=zip
t=zipWith
(x!a)b=x*a+b
a#b=[[s$t(*)x y|y<-foldr(t(:))([]<$b)b]|x<-a]
f a|let c=[1..l a];g(u,d)k|m<-[t(+)a b|(a,b)<-a#u&[[s[d|x==y]|y<-c]|x<-c]]=(m,-s[s[b|(n,b)<-c&a,n==m]|(a,m)<-a#m&c]/i k)=snd<$>scanl g(0<$c<$c,1)c
p?x|let f=foldl1(x!);c=l p-1;n=i c;q p=init$t(*)p$i<$>[c,c-1..];o=f(q p)/f p;a|d<-sqrt$(n-1)*(n*(o^2-f(q$q p)/f p)-o^2)=n/last(o-d:[o+d|m(o-d)<m(o+d)])=last$p?(x-a):[x|m a<1e-9]
z[a,b]=[-b/a]
z p=p?0:z(init$scanl1(p?0!)p)

Experimente online!

Muito obrigado @ ØrjanJohansen por um total de -47 bytes!

Explicação

Primeiro, calcula o polinômio característico com o algoritmo Faddeev – LeVerrier, que é a função f. Então a função zcalcula todas as raízes desse polinômio iterando o gque implementa o Método de Laguerre para encontrar uma raiz, uma vez que uma raiz é encontrada, ela é removida e gchamada novamente até que o polinômio tenha o grau 1, o qual é resolvido trivialmente z[a,b]=[-b/a].

Ungolfed

Eu re-inlined as funções sum, length, magnitude, fromIntegral, zipWithe (&), assim como o pequeno ajudante (!). A função faddeevLeVerriercorresponde a f, rootspara ze gpara laguerrerespectivamente.

-- Transpose a matrix/list
transpose a = foldr (zipWith(:)) (replicate (length a) []) a

-- Straight forward implementation for matrix-matrix multiplication
(#) :: [[Complex Double]] -> [[Complex Double]] -> [[Complex Double]]
a # b = [[sum $ zipWith (*) x y | y <- transpose b]|x<-a]


-- Faddeev-LeVerrier algorithm
faddeevLeVerrier :: [[Complex Double]] -> [Complex Double]
faddeevLeVerrier a = snd <$> scanl go (zero,1) [1..n]
  where n = length a
        zero = replicate n (replicate n 0)
        trace m = sum [sum [b|(n,b)<-zip [1..n] a,n==m]|(m,a)<-zip [1..n] m]
        diag d = [[sum[d|x==y]|y<-[1..n]]|x<-[1..n]]
        add as bs = [[x+y | (x,y) <- zip a b] | (b,a) <- zip as bs]
        go (u,d) k = (m, -trace (a#m) / fromIntegral k)
          where m = add (diag d) (a#u)


-- Compute roots by succesively removing newly computed roots
roots :: [Complex Double] -> [Complex Double]
roots [a,b] = [-b/a]
roots   p   = root : roots (removeRoot p)
  where root = laguerre p 0
        removeRoot = init . scanl1 (\a b -> root*a + b)

-- Compute a root of a polynomial p with an initial guess x
laguerre :: [Complex Double] -> Complex Double -> Complex Double
laguerre p x = if magnitude a < 1e-9 then x else laguerre p new_x
  where evaluate = foldl1 (\a b -> x*a+b)
        order' = length p - 1
        order  = fromIntegral $ length p - 1
        derivative p = init $ zipWith (*) p $ map fromIntegral [order',order'-1..]
        g  = evaluate (derivative p) / evaluate p
        h  = (g ** 2 - evaluate (derivative (derivative p)) / evaluate p)
        d  = sqrt $ (order-1) * (order*h - g**2)
        ga = g - d
        gb = g + d
        s = if magnitude ga < magnitude gb then gb else ga
        a = order /s
        new_x = x - a
ბიმო
fonte
1
Como o único envio que não usa built-in, essa deve ser a resposta mais votada.
Esolanging Fruit
+1 para calcular algo relacionado a determinante em tempo menor que n!!
user202729
Obrigado rapazes! @ user202729: Inicialmente supervisionei !e fiquei realmente confuso: D
#:
6

Oitava , 4 bytes

@eig

Experimente online!

Apenas dois bytes a mais que o equivalente ao idioma de golfe MATL!

Define um identificador de função anônimo para o eiginterno. Curiosamente, a filosofia de design do MATLAB vai contra muitas linguagens de ponta, que gostam de usar DescripteFunctionNamesTakingArguments(), enquanto o MATLAB e, consequentemente, o Octave tendem a obter o menor nome de função inequívoco possível. Por exemplo, para obter um s ubset de valores próprios (por exemplo, o menor nem valor absoluto), você usa eigs.

Como um bônus, aqui está uma função (funciona no MATLAB e, em teoria, poderia funcionar no Octave, mas solvea tarefa não está realmente preparada) que não usa built-ins, mas resolve simbolicamente o problema de autovalor det(A-λI)=0e o converte para a forma numérica usandovpa

@(A)vpa(solve(det(A-sym('l')*eye(size(A)))))
Sanchises
fonte
3

MATL , 2 bytes

Yv

Experimente online!

Explicação

Eu segui o conselho usual em álgebra linear numérica: em vez de escrever sua própria função, use um built-in projetado especificamente para evitar instabilidades numéricas.

Aliás, é mais curto. ¯ \ _ (ツ) _ / ¯

Luis Mendo
fonte
Isso levanta a questão: quanto tempo ficaria sem Yv?
Sanchises
@ Sanches, não tenho certeza. Provavelmente, encontraria as raízes ( ZQ) do polinômio característico. Mas computar explicitamente os coeficientes do polinômio pode ser muito trabalhoso
Luis Mendo
2

Mathematica, 11 bytes

Eigenvalues

Experimente online!

J42161217
fonte
Sim, esperava uma resposta interna antes de clicar em "1 nova resposta a esta pergunta". Vamos esperar por uma resposta não incorporada ... / Basicamente, a solução Mathematica geralmente é <primeira palavra no título> #
user202729 27/17/17
O mais curto não-puro embutido I obtido é First@Eigensystem@#&(20 bytes)
Sr. Xcoder
7
Na verdade, eu concordo com o user202729 aqui. Embora seja divertido brincar sobre o Mathematica ter um builtin para tudo, é muito irritante tanto como um pôster de desafio quanto como responder a ver uma resposta embutida equivalente a algo que você tentou relativamente difícil de fazer. O golfe (IMO) consiste em tentar encontrar o algoritmo mais curto e a implementação do referido algoritmo, mas uma resposta embutida tira isso do "esporte".
caird coinheringaahing
2
@cairdcoinheringaahing Deveríamos realmente começar a colocar a proposta do xnor em prática .
Martin Ender
1

R , 22 bytes

function(m)eigen(m)$va

Experimente online!

Toma mcomo uma matriz. Frustrantemente, a eigenfunção em R retorna um objeto de classe eigen, que possui dois campos: valuesos autovalores e vectorsos autovetores.

No entanto, mais irritantemente, o argumento opcional only.valuesretorna a listcom dois campos, valuescontendo os valores próprios e vectors, definido como NULL, mas como eigen(m,,T)também tem 22 bytes, é uma lavagem.

Giuseppe
fonte
1

Julia , 12 bytes

n->eig(n)[1]

Experimente online!

Infelizmente, eigretorna os valores próprios e os vetores próprios, como uma tupla, portanto, desperdiçamos outros 9 bytes para identificá-lo e capturar o primeiro item.

Uriel
fonte
0

Python + numpy, 33 bytes

from numpy.linalg import*
eigvals
Uriel
fonte