1Reading¶
Material related to this page, as well as additional exercises, can be found in ALA 1.9.
2Learning Objectives¶
By the end of this page, you should know:
- some key facts of the determinant,
- several ways to find the determinant of a matrix,
- (optional) the formal definition of a determinant.
3Determinants¶
We assume that you have already seen determinants in Math 1410, and focus here on reviewing the key properties. Before proceeding, we pause to note that determinants have very deep meanings, especially in differential calculus, as they keep track of volumes as they are transformed via (linear or otherwise) functions. They are indeed very useful theoretical tools, but much like matrix inverses, are rarely computed by hand, except for cases. Below is a helpful link if you need a refresher on the determinant.
3.1Key Properties of the Determinant¶
First, we’ll state a couple of key facts about the determinant.
These facts (and more) are all derivable from a basic principles of the determinant, but, as with many other topics in mathematics, the rabbit hole goes incredibly deep. For the purpose of studying eigenvalues and eigenvectors this is all we need, but for sake of completeness we included the rest of this page as further information on determinants.
3.2Optional: An Algebraic Definition of the Determinant¶
As mentioned above, we don’t really spend much time working with determinants in this course aside from for computing eigenvalues/vectors. However, for interested students, we will give an algebraic definition of the determinant as well as some methods of finding the determinant of a matrix. This definition is taken from these notes, which explain the connection between the geometric and algebraic interpretations of the determinant.
From this definition, we can compute the determinants of the elementary matrices!
To see why, note that the determinants of scaling and switching follow immediately from the multilinear and alternating properties of the determinant, respectively. To prove that the determinant of a row addition matrix is 1, we’ll show this is the case for a specific elementary matrix, and then you should convince yourself this is true for all row addition matrices:
Using the alternating property, you can show that . Therefore, we have that .
Equipped with these results, we can see how right multiplying by an elementary matrix changes the determinant. Recall that right multiplication by an elementary matrix defines a column operation; we’ll also extend these results to left multiplication by an elementary matrix (which defines a row operation).
The proof of these properties is not hard, and follows from a few applications of the defining properties of the determinant. Try to prove these yourself!
Now, we are ready to prove a lot of useful facts about determinants! We’ll state and prove them one by one.
To prove this theorem, start by proving it for just upper triangular matrices with all nonzero pivots. Try to come up with a series of row addition operations to reduce to diagonal form, and then apply multilinearity to easily find the determinant of a diagonal matrix!
The case where has a zero on its diagonal is trickier. One way is to show that you can come up with a series of row addition and column scaling operations to reduce to a form with two identical columns, then apply the alternating property of the determinant to prove that must have zero determinant!
Next, we’ll state and prove the key property of the determinant used for computing eigenvalues.
To prove this statement, we’ll use the row echelon form of a matrix, in combination with our result on triangular matrices (recall that any matrix can be written as a product of elementary matrices followed by a matrix in row echelon form):
If is singular, then its row echelon form will have a zero on its diagonal. By our result on triangular matices, this implies that (since row echelon matrices are triangular).
If is nonsingular, then its row echelon will have nonzero pivots (which must be diagonal elements). By our result on triangular matrices, and the fact that the product of nonzero numbers is nonzero, this implies that .
Next, we’ll prove another extremely important property of determinants!
First, we’ll prove that this holds for invertible matrices. To prove this, recall that any invertible square matrix can be factored as a product of elementary matrices:
Then, we can cleverly use our knowledge of how elementary operations change the determinant:
Next, we’ll consider the case where or , or both, is noninvertible. In this case, the result follows easily because a matrix product with a noninvertible factor is also noninvertible, and thus has zero determinant.
Try to prove this yourself! As a start, observe from the determinants of elementary matrices that transposing an elementary matrix does not change its determinant. Then, just like we did for matrix products, either write and as products of elementary matrices or show that is noninvertible.
To prove this, start from the condition that , then apply this theorem!
Try to prove this yourself using the properties we have already proven!
3.3Optional: Methods of Computing the Determinant¶
In the section, we will review/introduce two way of computing the determinant: the Laplace expansion and the PLU-factorization.
This is quite an abstract definition, so let’s see it at work!
Note that in the Laplace expansion, the row or column chosen to compute the expansion is arbitrary! Thus, it makes sense to expand along rows and columns with lots of zeros; if the coefficient multiplying a submatrix determinant is zero, then we don’t have to actually compute that submatrix determinant!
For small matrices, the Laplace expansion works fine. However, for larger matrices (even with ), this method of naively applying the Laplace will require a HUGE number of addition and multiplication operations (on the order of , or factorial)!
However, by applying our results for triangular matrices, we can come up with a much more computationally efficient method for computing the determinant.
Python Break!¶
Below are 3 code snippets demonstrating a few ways to compute the determinant. First, we run an implementation of the Laplace expansion (taken from this article). Second, we implement a determinant function based on the PLU factorization. Finally, we show how to use the built in determinant function from the scipy.linalg
library.
import numpy as np
from scipy import linalg
import time
np.random.seed(2030)
# This code is from https://en.wikipedia.org/wiki/Laplace_expansion#Computational_expense
def laplace_det(M):
# Base case of recursive function: 1x1 matrix
if M.shape[0] == 1:
return M[0, 0]
total = 0
for column, element in enumerate(M[0]):
# Exclude first row and current column.
K = np.stack([np.concatenate((x[:column], x[column + 1 :]), axis=0) for x in M[1:]], axis=1)
s = 1 if column % 2 == 0 else -1
total += s * element * laplace_det(K)
return total
# Generate a random matrix
A = np.random.rand(9, 9)
B = np.random.rand(10, 10)
# Find the determinant of A and B using Laplace expansion; also time how long it takes
start_time_A = time.time()
det_A = laplace_det(A)
end_time_A = time.time()
start_time_B = time.time()
det_B = laplace_det(B)
end_time_B = time.time()
print(f"Determinant (for 9x9): {det_A}")
print(f"Elapsed time (for 9x9): {end_time_A - start_time_A} seconds")
print(f"Determinant (for 10x10): {det_B}")
print(f"Elapsed time (for 10x10): {end_time_B - start_time_B} seconds")
Determinant (for 9x9): -0.007502281817950991
Elapsed time (for 9x9): 4.375511169433594 seconds
Determinant (for 10x10): -0.0334246928386742
Elapsed time (for 10x10): 40.4918212890625 seconds
Above is a recursive implementation of the Laplace expansion. As you can see, this implementation isn’t very fast! On this specific machine, it took ~4s to find the determinant for a matrix; and ~40s to find the determinant for a matrix!
For anything longer, this implementation will take forever to finish. Luckily, using our linear algebra knowledge, we can give a much more efficient implementation of the determinant!
import numpy as np
from scipy import linalg
import time
np.random.seed(2030)
def sign(P):
sign = 1
visited = [0 for _ in range(len(P))]
for i in range(len(P)):
if visited[i] == 1:
continue
if P[i] == i:
continue
curr = P[i]
visited[curr] = 1
cycle_length = 1
while curr != i:
curr = P[curr]
visited[curr] = 1
cycle_length += 1
if cycle_length % 2 == 0:
sign = -sign
return sign
def plu_det(M):
P, L, U = linalg.lu(M, p_indices=True)
return sign(P) * np.prod(np.diag(L)) * np.prod(np.diag(U))
# Generate a random matrix
A = np.random.rand(9, 9)
B = np.random.rand(10, 10)
# Find the determinant of A and B using Laplace expansion; also time how long it takes
start_time_A = time.time()
det_A = plu_det(A)
end_time_A = time.time()
start_time_B = time.time()
det_B = plu_det(B)
end_time_B = time.time()
print(f"Determinant (for 9x9): {det_A}")
print(f"Elapsed time (for 9x9): {end_time_A - start_time_A} seconds")
print(f"Determinant (for 10x10): {det_B}")
print(f"Elapsed time (for 10x10): {end_time_B - start_time_B} seconds")
Determinant (for 9x9): -0.007502281817951028
Elapsed time (for 9x9): 0.0 seconds
Determinant (for 10x10): -0.033424692838674074
Elapsed time (for 10x10): 0.0 seconds
As you can see, with the PLU method, this method is much quicker; as you can see, for smaller matrices it was near instantaneous. A few notes; to find the PLU decomposition of , we used the scipy.linalg.lu
function, which returns the and matrices, as well as either the matrix or its representation in one-line notation (this is because permutation matrices are mostly zeros, and can be encoded as just a list of numbers). Also, note the sign
function we defined; the details aren’t important, but this function is essentially a fast way to compute the determinant of a permutation matrix given in one-line notation.
Finally, let’s see how to use the built in functions from scipy.linalg
(or numpy.linalg
) to find determinants!
import numpy as np
from scipy import linalg
import time
np.random.seed(2030)
# Generate a random matrix
A = np.random.rand(9, 9)
B = np.random.rand(10, 10)
# Find the determinant of A and B using Laplace expansion; also time how long it takes
start_time_A = time.time()
det_A = linalg.det(A)
end_time_A = time.time()
start_time_B = time.time()
det_B = linalg.det(B)
end_time_B = time.time()
print(f"Determinant (for 9x9): {det_A}")
print(f"Elapsed time (for 9x9): {end_time_A - start_time_A} seconds")
print(f"Determinant (for 10x10): {det_B}")
print(f"Elapsed time (for 10x10): {end_time_B - start_time_B} seconds")
Determinant (for 9x9): -0.007502281817951028
Elapsed time (for 9x9): 0.0 seconds
Determinant (for 10x10): -0.033424692838674094
Elapsed time (for 10x10): 0.0 seconds
As you can see, it’s really easy, just a single call to the scipy.linalg.det
function!