5.11. Egenværdier og -vektorer#

En central problemstilling i Linær algebra er at finde egenvædier og -vektorer af en matrice. Dette gøres relativt enkelt i SymPy.

import sympy as sp
from sympy import Matrix

For en matrix findes egenværdier og -vektorer med A.eigenvals() og A.eigenvects().

A.eigenvals() giver os blot alle egenværdierne til en bestemt matrix i sorteret rækkefølge:

A = Matrix([[2, 0, 0], [0, 3, 4], [0, 4, 9]])
display(A)
\[\begin{split}\displaystyle \left[\begin{matrix}2 & 0 & 0\\0 & 3 & 4\\0 & 4 & 9\end{matrix}\right]\end{split}\]
A.eigenvals()
{11: 1, 2: 1, 1: 1}

Dette giver os nu en liste over egenværdierne (altså, 1, 2 og 11) og deres algebraiske multiplicitet, altså hvor mange gange den pågældende egenværdi er rod i det karakteristiske polynomium (her har alle egenværdierne algebraiske multiplicitet 1). For at illustrere hvordan resultaterne vises, “beregner” vi her egenværdierne for et trivielt eksempel:

from sympy.matrices import eye
B = Matrix([[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 5]])
display(B)
\[\begin{split}\displaystyle \left[\begin{matrix}2 & 0 & 0 & 0\\0 & 2 & 0 & 0\\0 & 0 & 2 & 0\\0 & 0 & 0 & 5\end{matrix}\right]\end{split}\]
B.eigenvals()
{2: 3, 5: 1}

Funktionen .eigenvects virker på samme måde og giver både egenværdier og -vektorerne. Hvis man bruger sp.init_printing(), kan man kalde dette direkte ved blot at skrive A.eigenvects().

A.eigenvects()
[(1,
  1,
  [Matrix([
   [ 0],
   [-2],
   [ 1]])]),
 (2,
  1,
  [Matrix([
   [1],
   [0],
   [0]])]),
 (11,
  1,
  [Matrix([
   [  0],
   [1/2],
   [  1]])])]

Hvis vi vil vise resultatet i matematisk notation, er nogle krumspring nødvendige. Vi benytter sp.latex() til at konvertere det hele til LaTeX og viser derefter LaTeX-koden ved display(Math()).

from IPython.display import Math
display(Math(sp.latex(A.eigenvects())))
\[\begin{split}\displaystyle \left[ \left( 1, \ 1, \ \left[ \left[\begin{matrix}0\\-2\\1\end{matrix}\right]\right]\right), \ \left( 2, \ 1, \ \left[ \left[\begin{matrix}1\\0\\0\end{matrix}\right]\right]\right), \ \left( 11, \ 1, \ \left[ \left[\begin{matrix}0\\\frac{1}{2}\\1\end{matrix}\right]\right]\right)\right]\end{split}\]

Her er resultatet altså givet som en liste med (egenværdi, multiplicitet, egenvektorer). Vi kan igen bruge det trivielle eksempel med B for at vise hvad der sker, når en egenværdi har flere tilhørende egenvektorer:

display(Math(sp.latex(B.eigenvects())))
\[\begin{split}\displaystyle \left[ \left( 2, \ 3, \ \left[ \left[\begin{matrix}1\\0\\0\\0\end{matrix}\right], \ \left[\begin{matrix}0\\1\\0\\0\end{matrix}\right], \ \left[\begin{matrix}0\\0\\1\\0\end{matrix}\right]\right]\right), \ \left( 5, \ 1, \ \left[ \left[\begin{matrix}0\\0\\0\\1\end{matrix}\right]\right]\right)\right]\end{split}\]

I matematikkurser har matricerne gerne pæne (ofte heltallige) egenværdier, mens man i praksis sjældent oplever matricer med så velopdragne egenværdier. Dertil kommer, at store matricer kan gøre det meget hårdt for computeren at regne det hele symbolsk. Derfor vil man (når man eksempelvis beregner egenværdier i kvantemekanik) i stedet bruge NumPy, da der her er nogle ret hurtige implementeringer til at give gode numeriske løsninger. Heldigvis ligner metoderne meget hinanden, og hvis man skulle komme ud for at skulle løse et problem, der er for krævende med sumbolske beregninger, kan man finde NumPys LinAlg værktøjer i den relevante dokumentation.

Når man beregner egenværdier i hånden, findes de som rødderne til det karakteristiske polynomium. Ovenfor har vi sprunget dette trin over, idet de indbyggede funktioner bestemmer egenværdier og -vektorer uden først eksplicit at beregne karakteristiske polynomium. Det karakteristiske polynomium kan imidlertid nemt beregnes med A.charpoly(x), hvor x blot er den variabel vi vil lave polynomiet med:

Tager vi blot B matricen fra overstående eksempel:

from sympy.abc import x
B.charpoly(x)
\[\displaystyle \operatorname{PurePoly}{\left( x^{4} - 11 x^{3} + 42 x^{2} - 68 x + 40, x, domain=\mathbb{Z} \right)}\]

Som vi selvfølgelig kan løse ved at finde rødderne. I nedenstående eksempel bliver polynomiet løst numerisk, her svarer tallet i nroots(n) til, hvor mange decimaler vi ønsker på vores løsning.

B.charpoly(x).nroots(5)
[2.0000, 2.0000, 2.0000, 5.0000]

5.11.1. Diagonalisering#

En afgørende pointe i kurset er at undersøge hvornår der kan findes en basis hvor en matrix \(A\) er på diagonalform, altså hvornår der findes en matrix \(P\), der opfylder at \(D = P^{-1}AP\), hvor \(D\) er en diagonalmatrix. For at finde \(P\) og \(D\) kan vi benytte A.diagonalize(). Vi regner videre med matricen A defineret ovenfor:

display(A)
\[\begin{split}\displaystyle \left[\begin{matrix}2 & 0 & 0\\0 & 3 & 4\\0 & 4 & 9\end{matrix}\right]\end{split}\]
display(*A.diagonalize())
\[\begin{split}\displaystyle \left[\begin{matrix}0 & 1 & 0\\-2 & 0 & 1\\1 & 0 & 2\end{matrix}\right]\end{split}\]
\[\begin{split}\displaystyle \left[\begin{matrix}1 & 0 & 0\\0 & 2 & 0\\0 & 0 & 11\end{matrix}\right]\end{split}\]

Outputtet for denne funktion er matricerne \(P\) og \(D\). Vi genkender at matricen \(D\) netop indeholder egenværdierne langs diagonalen og at \(P\) består at (multipla af) egenvektorerne. Vi kan få de pågældende matricer ud så vi kan regne videre med dem på følgende måde:

(P, D) = A.diagonalize()
display(P, D)
\[\begin{split}\displaystyle \left[\begin{matrix}0 & 1 & 0\\-2 & 0 & 1\\1 & 0 & 2\end{matrix}\right]\end{split}\]
\[\begin{split}\displaystyle \left[\begin{matrix}1 & 0 & 0\\0 & 2 & 0\\0 & 0 & 11\end{matrix}\right]\end{split}\]

Og vi demonstrerer endelig at matricerne sammensættes som forventet. Først \(D = P^{-1}AP\):

P.inv() * A * P
\[\begin{split}\displaystyle \left[\begin{matrix}1 & 0 & 0\\0 & 2 & 0\\0 & 0 & 11\end{matrix}\right]\end{split}\]

Eller omvendt \(A = P D P^{-1}\)

P * D * P.inv()
\[\begin{split}\displaystyle \left[\begin{matrix}2 & 0 & 0\\0 & 3 & 4\\0 & 4 & 9\end{matrix}\right]\end{split}\]