SymPy Demo 4: The Eigenvalue Problem#
Demo by Christian Mikkelstrup og Hans Henrik Hermansen, Karl Johan Måstrup Kristiansen, and Magnus Troen. Revised 11-11-24 by shsp.
from sympy import *
init_printing()
In this demo we wish to show how to manipulate a matrix for the purpose of solving the eigenvalue problem (finding eigenvectors and eigenvalues as well as other associated properties).
We will be working on the mapping matrix
which represents the linear map \(\boldsymbol f:\mathbb{R}^3\to \mathbb{R}^3\) with respect to the standard basis. See the course textbook for all the details about definitions, notation, terminology, and theorems, whcih we will be using freely in the following.
eFe = Matrix([[6,3,12],[4,-5,4],[-4,-1,-10]])
Eigenvalues#
The characteristic matrix \(\mathbf K(\lambda)= ~_e[\boldsymbol f]_e-\lambda\cdot \mathbf I_3\) is constructed as follows:
lamb = symbols('\lambda')
K = eFe - lamb * eye(3)
K
The characteristic polynomial is its determinant, \(p(\lambda)=\mathrm{det}(\mathbf K(\lambda))\):
charpoly = K.det()
charpoly

A SymPy command can do this in one step, but note that the sign here is different. This is not a problem, though, since we are interested in the roots of this polynomial.
eFe.charpoly()

The characteristic equation is the characteristic polynomial set equal to zero, \(\mathrm{det}(\mathbf K(\lambda))=0\):
chareq = Eq(charpoly, 0)
chareq

The eigenvalues of the original mapping matrix can now be found either by solving the characteristic equation or by using SymPy’s command .roots()
to find the roots in the characteristic polynomial:
roots(charpoly)

solveset(chareq, lamb)

Note that solveset()
does not catch the fact that \(-6\) has an algebraic multiplicity of \(2\)! If we do not want to miss the multiplicity, then we can ask SymPy for the factorisation as shown below, but often roots()
is more convenient in such cases.
factor(charpoly)

Eigenvectors#
Finding the eigenvectors belonging to the eigenvalue \(-6\) means solving the equation \(\mathbf K(-6)\,\mathbf x=\mathbf{0}\). We find \(\mathbf K(-6)\) as follows:
K.subs(lamb, -6)
We solve using the above coefficient matrix with a right-hand side of zeros:
K.subs(lamb, -6).gauss_jordan_solve(zeros(3,1))
We see from the output two linearly independent eigenvectors of our map. They span the eigenspace for the eigenvalue \(-6\). This eigenspace can hence be written as:
We count the geometric multiplicity to be \(2\) (the dimension of the eigenspace) for this eigenvalue of \(-6\).
Eigenvectors associated with the eigenvalue of \(3\) are likewise found by solving \(\mathbf K(3)\,x=\mathbf{0}\), which the readers might notice is the same is finding the kernel, \(\ker \mathbf K(3).\)
K.subs(lamb, 3).nullspace()
From this we see that \(E_3=\text{span}((-3,-1,1))\) and that the geometric multiplicity is equal to the algebraic multiplicity, namely \(1\).
Built-in Commands for finding Eigenvalues and -Vectors#
There actually is no need for dealing with characteristic matrices, characteristic polynomials, and characteristic equations etc. in a manual manner as we did above, because SymPy comes with built-in commands that you can apply directly on the mapping matrix. Typically, the only reason for the above would be if you need to meticulously look through the steps, or if you need an intermediate output. If that’s not relevant, then you can very quickly solve the eigenproblem with the following:
eFe.eigenvals()

eFe.eigenvects()
In fact, .eigenvects()
provides you with all data in one go - both the eigenvalues, their algebraic multiplicities, and associated (linearly independent) eigenvectors! The output format that you see above is the following:
Each bracket in the output displays info related to each unique eigenvalue.
You might infer that you still are missing one piece of info: what about the geometric multiplicity for each eigenvalue? But in fact that is also clear from the output, since that is just the number of (linearly independent) eigenvectors associated with an eigenvalue, which is easy to count from the output. And the eigenspaces can be written as the span of the shown eigenvectors for each eigenvalue.
You can automate the process of extracting this data from the output as follows:
eigen_info = eFe.eigenvects()
for lmb, am_lmb, list_of_v in eigen_info:
print(f'For the eigenvalue {lmb} with algebraic multiplicity {am_lmb}, the eigenspace is spanned by the eigenvectors')
display(list_of_v)
print(f'and the geometric multiplicity is {len(list_of_v)}' + '\n\n')
For the eigenvalue -6 with algebraic multiplicity 2, the eigenspace is spanned by the eigenvectors
and the geometric multiplicity is 2
For the eigenvalue 3 with algebraic multiplicity 1, the eigenspace is spanned by the eigenvectors
and the geometric multiplicity is 1
The data can be accessed directly via indexing. Be careful though! Sometimes this gets pretty confusing:
# Linearly independent eigenvectors associated with the eigenvalue -6
eigen_info[0][2]
Be aware that the order in the output (the order in which the eigenvalue-brackets are shown) might differ from time to time, even when running the command on the same matrix. But this of course will not matter for your mathematical results.