Valores propios de una matriz


11

Dada una matriz cuadrada, genera los valores propios de la matriz. Cada valor propio debe repetirse varias veces igual a su multiplicidad algebraica.

Los valores propios de una matriz Ason valores escalares λde tal manera que, por alguna vector columna v, A*v = λ*v. También son las soluciones al polinomio característico de A: det(A - λ*I) = 0(donde Iestá la matriz de identidad con las mismas dimensiones que A).

Las salidas deben tener una precisión de 3 dígitos significativos. Todas las entradas y salidas estarán dentro del rango representable de valores numéricos para el idioma elegido.

Las incorporaciones son aceptables, pero le recomendamos que incluya soluciones que no las utilicen.

Casos de prueba

En estos casos de prueba, Irepresenta la unidad imaginaria. Los números complejos se escriben en el formulario a + b*I. Todas las salidas tienen 3 dígitos significativos de precisión.

[[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]



Respuestas:


12

Haskell , 576 554 532 507 bytes

No hay incorporados!

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)

Pruébalo en línea!

¡Muchas gracias @ ØrjanJohansen por un total de -47 bytes!

Explicación

Primero, calcula el polinomio característico con el algoritmo Faddeev-LeVerrier, que es la función f. Luego, la función zcalcula todas las raíces de ese polinomio mediante la iteración gque implementa el Método de Laguerre para encontrar una raíz, una vez que se encuentra una raíz, se elimina y se gvuelve a llamar hasta que el polinomio tenga un grado 1 que se resuelve trivialmente z[a,b]=[-b/a].

Sin golf

Me re-inline las funciones sum, length, magnitude, fromIntegral, zipWithy (&)así como el pequeño ayudante (!). La función faddeevLeVerriercorresponde a f, rootsa zy ga laguerre, respectivamente.

-- 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

1
Como la única sumisión que no usa builtins, esta debería ser la respuesta más votada.
Esolanging Fruit

+1 para calcular algo relacionado con un determinante en un tiempo menor que n!!
user202729

¡Gracias chicos! @ user202729: Inicialmente supervisé !y estaba realmente confundido: D
ბიმო

6

Octava , 4 bytes

@eig

Pruébalo en línea!

¡Solo dos bytes más que el equivalente de lenguaje de golf MATL!

Define un identificador de función anónimo para el eigincorporado. Curiosamente, la filosofía de diseño de MATLAB va en contra de muchos lenguajes de alta gama, que les gusta usar DescripteFunctionNamesTakingArguments(), mientras que MATLAB y, en consecuencia, Octave tienden a obtener el nombre de función más breve e inequívoco posible. Por ejemplo, para obtener una s ubset de valores propios (por ejemplo, el más pequeño nen magnitud absoluta), se utiliza eigs.

Como beneficio adicional, aquí hay una función (funciona en MATLAB, y en teoría podría funcionar en Octave pero solverealmente no está a la altura de la tarea) que no utiliza incorporados, sino que resuelve simbólicamente el problema de valor propio det(A-λI)=0y lo convierte a forma numérica usandovpa

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

3

MATL , 2 bytes

Yv

Pruébalo en línea!

Explicación

Seguí los consejos habituales en álgebra lineal numérica: en lugar de escribir su propia función, use una función incorporada que esté específicamente diseñada para evitar inestabilidades numéricas.

Por cierto, es más corto. ¯ \ _ (ツ) _ / ¯


Esto plantea la pregunta, ¿cuánto tiempo pasaría sin Yv?
Sanchises

@Sanchises No estoy seguro. Probablemente lo haría buscando las raíces ( ZQ) del polinomio característico. Pero calcular explícitamente los coeficientes del polinomio puede ser mucho trabajo
Luis Mendo

2

Mathematica, 11 bytes

Eigenvalues

Pruébalo en línea!


Sí, esperaba una respuesta integrada antes de hacer clic en "1 nueva respuesta a esta pregunta". Esperemos una respuesta no integrada ... / Básicamente, la solución de Mathematica es a menudo <primera palabra en el título>
usuario202729

El más corto no puro incorporado que obtuve es First@Eigensystem@#&(20 bytes)
Sr. Xcoder

77
De hecho, estoy de acuerdo con el usuario202729 aquí. Si bien es divertido bromear acerca de que Mathematica tiene una función incorporada para todo, es muy molesto tanto como un póster de desafío como para responder a ver una respuesta integrada equivalente a algo que trataste de hacer relativamente difícil. El golf (IMO) se trata de intentar encontrar el algoritmo más corto y la implementación de dicho algoritmo, pero una respuesta integrada lo quita del "deporte".
caird coinheringaahing

2
@cairdcoinheringaahing Realmente deberíamos comenzar a poner en práctica la propuesta de xnor .
Martin Ender

1

R , 22 bytes

function(m)eigen(m)$va

Pruébalo en línea!

Toma mcomo una matriz. Frustrantemente, la eigenfunción en R devuelve un objeto de clase eigen, que tiene dos campos: valueslos valores propios y vectorslos vectores propios.

Sin embargo, de manera más molesta, el argumento opcional only.valuesdevuelve un listcon dos campos, que valuescontiene los valores propios y vectors, establecido en NULL, pero como eigen(m,,T)también tiene 22 bytes, es un lavado.


1

Julia , 12 bytes

n->eig(n)[1]

Pruébalo en línea!

Desafortunadamente, eigdevuelve tanto los valores propios como los vectores propios, como una tupla, por lo que desperdiciamos otros 9 bytes para lambdificarlo y tomar el primer elemento.


0

Python + numpy, 33 bytes

from numpy.linalg import*
eigvals

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.