Contact Us!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

| Download

Math 208 Interactive Notebooks © 2024 by Soham Bhosale, Sara Billey, Herman Chau, Zihan Chen, Isaac Hartin Pasco, Jennifer Huang, Snigdha Mahankali, Clare Minerath, and Anna Willis is licensed under CC BY-ND 4.0

Views: 854
License: OTHER
Image: ubuntu2204
Kernel: SageMath 10.1

Chapter 5: Determinants

By: Soham Bhosale

The determinant of a matrix is a single numerical value which is used when calculating the inverse or when solving systems of linear equations. Let's look at some basic examples first.

A = Matrix(ZZ, [[-3,1,2],[5,5,-8],[4,2,-5]]) A
[-3 1 2] [ 5 5 -8] [ 4 2 -5]
A.det()
0
B = Matrix(ZZ, [[4, -1, 1, 0],[1, 7, 3, 5],[0,-3, -2, 1], [2, 4, 8, -1]]) B
[ 4 -1 1 0] [ 1 7 3 5] [ 0 -3 -2 1] [ 2 4 8 -1]
B.det()
-413

The determinants of 2x2 matrices can be generated using a special formula

var('a11', 'a12', 'a21', 'a22') A=matrix(2, 2, [a11, a12, a21, a22]) print(A) print("det of 2 x 2 ", det(A))
[a11 a12] [a21 a22] det of 2 x 2 -a12*a21 + a11*a22

Let's apply to an example matrix

A= random_matrix(ZZ, 2, 2) print(A) print("Sage determined determinant of A" , det(A)) d = A[0,0]*A[1,1]-A[0,1]*A[1,0] print("Determinant calculated by formula " , d)
[ 2 -1] [ -2 -11] Sage determined determinant of A -24 Determinant calculated by formula -24

Now we are going to look at some interesting properties of Determinants.

The first property of determinants we are going to look at is regarding multiplying determinants. Multiplying matrices and computing arithmetic operations requires a lot of computation. However, the relationship between the determinant of the product of matrices and the product of their individual determinants, it more simple.

det(AB)=det(A)det(B)det(A*B) = det(A) * det(B)

And

det(BA)=det(B)det(A)det(B*A) = det(B) * det(A)

C=random_matrix(ZZ,4,4) C
[ -1 3 0 -29] [ 1 -1 -1 7] [ 0 0 -1 -2] [ 1 -3 1 -1]
D=random_matrix(ZZ,4,4) D
[-2 -1 0 -8] [ 1 -4 27 1] [ 2 0 -1 -4] [ 4 -1 3 -3]
# Multiplying the two matrices C*D
[-111 18 -6 98] [ 23 -4 -5 -26] [ -10 2 -5 10] [ -7 12 -85 -12]
# Determinant of the product of the two matrices det(C*D)
29376
# Product of the determinants det(C) * det(D)
29376

This property holds commutatively as well!

D*C
[ -7 19 -7 59] [ -4 4 -22 -112] [ -6 18 -3 -52] [ -8 22 -5 -126]
det(D*C)
29376
det(D) * det(C)
29376

After seeing this neat property of multiplying determinants, it may be tempting to assume that adding determinants work the same way. Namely, that the determinant of the sum of two matrices is the same as the sum of their individual determinants. In math notation, det(A+B)=det(A)+det(B)det(A+B) = det(A)+det(B). However, this property is not true. Here's an example of when it is not true.

print("det(C+D) = ", det(C + D)) print("det(C) + det(D) = ", det(C) + det(D))
det(C+D) = -5430 det(C) + det(D) = -523

However, there are some instances where this property does hold true. Here is an example:

Determinants of matrices can be calculated using something called the cofactor expansion method.

Here is the formula:

det(A)=a11C11+a12C12+...a1nC1ndet(A) = a_{11}C_{11} + a_{12}C_{12} + ... a_{1n}C_{1n}

Where C11...C1nC_{11}...C_{1n} are the cofactors of a11...a1na_{11}...a_{1n}.

We can represent this using an example to see how sage calculates it

var('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i') A=matrix(3, 3, [a, b, c, d, e, f, g, h, i]) A
[a b c] [d e f] [g h i]
A.det()
-(f*h - e*i)*a + (c*h - b*i)*d - (c*e - b*f)*g

Elementary Matrices

Instead of using cofactor expansion to compute the determinant. It is more efficient to convert the matrix to echleon form using row operations and then multiply the terms along the diagnonal

First, let's see how elementary matrices change a matrix (row-operations)

Remember the three elementary operations are

  1. Interchanging two rows

  2. Multiplying a row by a constant c

  3. Adding a mulitple of one row to another

# Matrix representing adding a multiple of row 3 to row 2 E = elementary_matrix(3, row1 = 1, row2 = 2, scale = 4) E
[1 0 0] [0 1 4] [0 0 1]
#Effect of multiplying elementary matrix E by A E*A
[ a b c] [d + 4*g e + 4*h f + 4*i] [ g h i]
# Order of multiplication matters in linear algebra or else we get a completely different effect A*E
[ a b 4*b + c] [ d e 4*e + f] [ g h 4*h + i]

Affect of Elementary Matrices on the Determinant

Here is the affect of elementary matrices on the Determinant. This table from the textbook does a great job summarizing it.

#Adding a muliple of one row to the other does not change the determinant B=random_matrix(ZZ, 3, 3) print(B) print("Determinant Before", det(B)) E*B print("Determinant After Multiplying by elementary matrix", det(E*B))
[176 18 -1] [ -1 -1 -2] [ 1 -1 -2] Determinant Before -74 Determinant After Multiplying by elementary matrix -74

Elementary Matrix Switching Rows

The determinant of the matrix produced by interchanging two rows of the original matrix is -det(B)

F=elementary_matrix(3, row1=0, row2=2) print(F)
[0 0 1] [0 1 0] [1 0 0]
print(B) print("Determinant Before", det(B)) print('Matrix after row operation') print(F*B) print("Determinant After Multiplying by elementary matrix", det(F*B))
[176 18 -1] [ -1 -1 -2] [ 1 -1 -2] Determinant Before -74 Matrix after row operation [ 1 -1 -2] [ -1 -1 -2] [176 18 -1] Determinant After Multiplying by elementary matrix 74

Multiplying a row by a constant multiplies the determinant by that constnant c

G=elementary_matrix(3, row1=2, scale=5) print(G)
[1 0 0] [0 1 0] [0 0 5]
print(B) print("Determinant Before", det(B)) print('Matrix after row operation') print(G*B) print("Determinant After Multiplying by elementary matrix", det(G*B))
[176 18 -1] [ -1 -1 -2] [ 1 -1 -2] Determinant Before -74 Matrix after row operation [176 18 -1] [ -1 -1 -2] [ 5 -5 -10] Determinant After Multiplying by elementary matrix -370

Now here is a function I wrote that represents the recursive nature of finding determinants using cofactor expansion

def myDet(M): if M.ncols() != M.nrows(): return("not a square matrix so no determinant") else: col=M.ncols() if col==1: return M[0,0] else: D = 0 N=M.matrix_from_columns(range(1,col)) for i in range(col): D=D + (-1)^i * M[i,0] * myDet(N.matrix_from_rows(list(range(i)) + list(range(i+1, col)))) return D
A=random_matrix(ZZ, 5,5)
det(A)
147
myDet(A)
147

Some more properties!

A = Matrix(ZZ, [[3,1,0],[-1,2,1],[0,-1,2]]) print(A)
[ 3 1 0] [-1 2 1] [ 0 -1 2]

Determinant of the inverse of a matrix A is 1det(A)\dfrac{1}{det(A)}

B= A.inverse() print("A inverse") print(B) print("Determinant of matrix A", det(A)) print("Determinant of A inverse", det(B)) print("It can be seen that the determinant of the inverse is 1 over the determinant of the original matrix")
A inverse [ 5/17 -2/17 1/17] [ 2/17 6/17 -3/17] [ 1/17 3/17 7/17] Determinant of matrix A 17 Determinant of A inverse 1/17 It can be seen that the determinant of the inverse is 1 over the determinant of the original matrix

ATA^{T}has the same Determinant As A

print(A) B= A.transpose() print("Transposed Matrix") print(B) print("Original Determinant", det(A)) print("Determinant of Transposed Matrix", det(B))
[ 3 1 0] [-1 2 1] [ 0 -1 2] Transposed Matrix [ 3 -1 0] [ 1 2 -1] [ 0 1 2] Original Determinant 17 Determinant of Transposed Matrix 17

Inverses from Determinants

In the textbook, we learn that If A is an invertible matrix, then A1=1det(A)adj(A)A^{-1} = \dfrac{1}{det(A)} * adj(A)

A=random_matrix(ZZ, 5,5) print(A) C=A.adjugate() print("Adjugate matrix for A") print(C)
[-8 0 1 -1 56] [ 2 0 -1 0 0] [ 1 -2 -2 1 1] [-3 -1 1 1 7] [ 1 5 2 0 -3] Adjugate matrix for A [ 33 -732 312 -279 69] [ -36 474 -294 258 -168] [ 66 -954 624 -558 138] [ 32 -138 -192 -286 -134] [ -5 -90 30 -35 5]
D= 1/(det(A)) * C D
[-11/170 122/85 -52/85 93/170 -23/170] [ 6/85 -79/85 49/85 -43/85 28/85] [ -11/85 159/85 -104/85 93/85 -23/85] [-16/255 23/85 32/85 143/255 67/255] [ 1/102 3/17 -1/17 7/102 -1/102]
# We see that the formula holds true E = A.inverse() E
[-11/170 122/85 -52/85 93/170 -23/170] [ 6/85 -79/85 49/85 -43/85 28/85] [ -11/85 159/85 -104/85 93/85 -23/85] [-16/255 23/85 32/85 143/255 67/255] [ 1/102 3/17 -1/17 7/102 -1/102]
E== D
True

Cramer's Rule

Cramer's rule is a formula using determinants that can be used to find the solution to Ax = b where A is an n x n matrix and b is a vector.

If A = [a1,a2,...ana_1, a_2,...a_n] and b is in RnR^n, then let AiA_i denote the matrix A after replace aia_i with b

def mysolve(A, b): if A.nrows()!=A.ncols(): return "first matrix is not a square" else: if A.det() == 0: return "first matrix has determinant zero so Cramer's rule does not apply" else: if b.nrows()!=A.ncols() or b.ncols()!=1: return "second matrix is not a column matrix of the right side" else: n=A.ncols() x=matrix(QQ, n, 1) for j in range(n): Aj=copy(A) Aj[:,j]=b x[j] = Aj.det()/A.det() return x

A=random_matrix(ZZ, 3, 3) print(A) print("Determinant of A", A.det()) b=matrix(QQ, 3, 1, [5, 3, 7]) print(b) print("Using the Cramer Rule Calculator We get x=") print(mysolve(A,b))
[ 2 0 1] [ 5 -1 10] [ 0 1 0] Determinant of A -15 [5] [3] [7] Using the Cramer Rule Calculator We get x= [ 8/3] [ 7] [-1/3]
print("Using in built in sage functionality we get: ") print(A.solve_right(b))
Using in built in sage functionality we get: [ 8/3] [ 7] [-1/3]

Determinants Can Also Represent Area

Let T:

Example Problems

A functionality that computers provide is the ability to compute fast. Thus we can use this to our advantage to find examples of certain examples or counterxamples of matrices. Here are some practice problems from the book representing this

# Exercise 4 (c): Fill in entries for A and B to find a counterexample. A = Matrix(ZZ, [[_, _, _], [_, _, _], [_, _, _]]) B = Matrix(ZZ, [[_, _, _], [_, _, _], [_, _, _]]) A.determinant() - B.determinant() == (A-B).determinant()
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In [17], line 2 1 # Exercise 4 (c): Fill in entries for A and B to find a counterexample. ----> 2 A = Matrix(ZZ, [[_, _, _], [_, _, _], [_, _, _]]) 3 B = Matrix(ZZ, [[_, _, _], [_, _, _], [_, _, _]]) 5 A.determinant() - B.determinant() == (A-B).determinant()
File /ext/sage/10.1/src/sage/matrix/constructor.pyx:643, in sage.matrix.constructor.matrix() 641 """ 642 immutable = kwds.pop('immutable', False) --> 643 M = MatrixArgs(*args, **kwds).matrix() 644 if immutable: 645 M.set_immutable()
File /ext/sage/10.1/src/sage/matrix/args.pyx:668, in sage.matrix.args.MatrixArgs.matrix() 666 break 667 else: --> 668 M = self.space(self, coerce=convert) 669 670 # Also store the matrix to support multiple calls of matrix()
File /ext/sage/10.1/src/sage/structure/parent.pyx:903, in sage.structure.parent.Parent.__call__() 901 return mor._call_(x) 902 else: --> 903 return mor._call_with_args(x, args, kwds) 904 905 raise TypeError(_LazyString("No conversion defined from %s to %s", (R, self), {}))
File /ext/sage/10.1/src/sage/structure/coerce_maps.pyx:182, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_with_args() 180 print(type(C), C) 181 print(type(C._element_constructor), C._element_constructor) --> 182 raise 183 184
File /ext/sage/10.1/src/sage/structure/coerce_maps.pyx:172, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_with_args() 170 return C._element_constructor(x) 171 else: --> 172 return C._element_constructor(x, **kwds) 173 else: 174 if len(kwds) == 0:
File /ext/sage/10.1/src/sage/matrix/matrix_space.py:945, in MatrixSpace._element_constructor_(self, entries, **kwds) 835 def _element_constructor_(self, entries, **kwds): 836 """ 837 Construct an element of ``self`` from ``entries``. 838 (...) 943 False 944 """ --> 945 return self.element_class(self, entries, **kwds)
File /ext/sage/10.1/src/sage/matrix/matrix_integer_dense.pyx:309, in sage.matrix.matrix_integer_dense.Matrix_integer_dense.__init__() 307 ma = MatrixArgs_init(parent, entries) 308 cdef Integer z --> 309 for t in ma.iter(coerce, True): 310 se = <SparseEntry>t 311 z = <Integer>se.entry
File /ext/sage/10.1/src/sage/matrix/args.pyx:534, in iter() 532 x = next(it) 533 if convert and self.need_to_convert(x): --> 534 x = self.base(x) 535 if sparse: 536 yield make_SparseEntry(i, j, x)
File /ext/sage/10.1/src/sage/structure/parent.pyx:901, in sage.structure.parent.Parent.__call__() 899 if mor is not None: 900 if no_extra_args: --> 901 return mor._call_(x) 902 else: 903 return mor._call_with_args(x, args, kwds)
File /ext/sage/10.1/src/sage/structure/coerce_maps.pyx:163, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_() 161 print(type(C), C) 162 print(type(C._element_constructor), C._element_constructor) --> 163 raise 164 165 cpdef Element _call_with_args(self, x, args=(), kwds={}):
File /ext/sage/10.1/src/sage/structure/coerce_maps.pyx:158, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_() 156 cdef Parent C = self._codomain 157 try: --> 158 return C._element_constructor(x) 159 except Exception: 160 if print_warnings:
File /ext/sage/10.1/src/sage/rings/integer.pyx:710, in sage.rings.integer.Integer.__init__() 708 return 709 --> 710 raise TypeError("unable to coerce %s to an integer" % type(x)) 711 712 def __reduce__(self):
TypeError: unable to coerce <class 'sage.matrix.matrix_symbolic_dense.Matrix_symbolic_dense'> to an integer
#5.2 Question 41 for a in range(-10, 10): for b in range(-10, 10): for c in range(-10, 10): for d in range(-10, 10): A = Matrix(ZZ, [[a,b],[c,d]]) # Skip the all zeroes matrix. if a == 0 and b == 0 and c == 0 and d == 0: continue # In order for this to hold, we need det(A) == 0. if 3*det(A) == det(3*A) and det(A) != 0: print("Example found!\n", A)