MAT 232 Chapter Three

587 days ago by kcrisman

What are isomorphisms, homomorphisms, linear transformations?

Chapter Three takes us through a fairly abstract world of changes in vector spaces.  But underlying it all is a basic concept:

Vectors have information.  We might want only some of that information, or want to change it in some way, while getting a vector back.

Doing this consistently is the focus of this chapter.

Motivating Examples

Let's start with some motivating examples before we try to really do more.

Voting

Recall the example I've done several times where we imagine 27 voters if the election this fall is between Sanders, Bloomberg, and Trump.  We have represented this as a vector.

vector([5,14,8]) 
       
(5, 14, 8)
(5, 14, 8)

We can use a basis to get the average number of votes, or ... we can just formally add up all the votes.

sum(vector([5,14,8])) 
       
27
27

Let's make this a little more formal.  If $S=5$, $B=14$, and $T=8$, we could make this a formula.

S = 5 B = 14 T = 8 S+B+T 
       
27
27

This is a nice linear equation.  If we change the numbers, we just change the numbers.

@interact def _(S = 5, B = 14, T = 8): return S+B+T 
       

Click to the left again to hide and once more to show the dynamic interactive window

I want us to note three things about this.

  • If we multiply all the individual votes by the same number, the final number of votes is multiplied by that number.
  • If we add two smaller votes together, the total number of votes will be the sum of the totals for the smaller votes.
  • Both the input and the output seem to be vectors.
@interact(layout=[['S','B','T'],['S2','B2','T2'],['constant'],['mul','add']]) def _(S = input_box(5,width=20),B = input_box(14,width=20),T = input_box(8,width=20),S2 = input_box(1,width=20),B2 = input_box(1,width=20),T2 = input_box(1,width=20),constant=input_box(2,width=20),add=False,mul=False): print 'First voter total is ',S+B+T print 'Second voter total is ',S2+B2+T2 if add and not mul: print 'Added is ', (S+B+T)+(S2+B2+T2) elif mul and not add: print 'Multiply first by a constant is', constant*(S+B+T) elif mul and add: print 'Please select just one' 
       

Click to the left again to hide and once more to show the dynamic interactive window

Notice that this behaves very "linearly".

Graphics

Imagine that you are trying to do some basic computer graphics manipulations.  Maybe you have a line or circle you want to move around... or maybe a rectangular box.

def Box(a,b,color='red'): return line([(0,0),(a,0),(a,b),(0,b),(0,0)],color=color,figsize=3,aspect_ratio=1)+point((a,b),color='green',size=20) 
       
Box(2,1) 
       
Box(1,2,'green') 
       

These two boxes are nice.  Pretty clearly I've just flipped them:

Box(1,2)+Box(2,1,color='blue')+plot(x,(x,0,2),linestyle='--') 
       

Can I flip other boxes?

@interact def _(a=1,b=2): show(Box(a,b)+Box(b,a,color='blue')+plot(x,(x,0,max(a,b)),linestyle='--')) 
       

Click to the left again to hide and once more to show the dynamic interactive window

Really the relationship here is $$x'=y\qquad y'=x$$ which we can think of as something more interesting: $$\begin{align} x' & = 0x+1y \\ y'& = 1x+0y \end{align}$$ or $$\left(\begin{matrix} 0 & 1 \\ 1 & 0 \end{matrix}\right)$$  How about a rotation?

@interact def _(a=1,b=2): show(Box(a,b)+Box(-b,a,color='blue')) 
       

Click to the left again to hide and once more to show the dynamic interactive window

The same thing seems to work.  $$\begin{align} x' & = 0x-1y \\ y'& = 1x+0y \end{align}$$ or $$\left(\begin{matrix} 0 & -1 \\ 1 & 0 \end{matrix}\right)$$  Really, we're just moving the corner around.  So we can think of this as taking a vector $(a,b)$ in $\mathbb{R}^2$ and just moving it to another vector in $\mathbb{R}^2$, given by the linear equations given in shorthand by the matrix.  (We can imagine more complicated ones too, but this is enough for now.)  And the actions are clearly behaving linearly in terms of the starting vector.

Population

Many applications have two (or more) populations that fluctuate with the other.

Boston = .1 Beverly = .9 
       
Boston, Beverly 
       
(0.100000000000000, 0.900000000000000)
(0.100000000000000, 0.900000000000000)

We can imagine that there is an equation saying how people move around: $$\begin{align} Boston & = .2*Beverly+.3*Boston \\ Beverly& = .8*Beverly+.7*Boston \end{align}$$

Boston, Beverly = .2*Beverly + .3*Boston, .8*Beverly + .7*Boston 
       
Boston, Beverly 
       
(0.222210000000000, 0.777790000000000)
(0.222210000000000, 0.777790000000000)

We can follow this for quite a while, but maybe we should change a few things.

@interact def _(Boston=100,Beverly=900,years=[1..20]): for i in range(years): Boston,Beverly = .2*Beverly + .3*Boston, .8*Beverly + .7*Boston print 'Final percentages after ',years,'years' print 'Boston:',Boston print 'Beverly:',Beverly 
       

Click to the left again to hide and once more to show the dynamic interactive window

Huh!  That's ... weird.

  • But what if I made a mistake, and the inputs were twice as much?
  • But what if I made a mistake, and there were two years of graduates to follow?
 
       

Visualizing Linear Transformations (and other homomorphisms)

Let's see what can happen in a linear transformation. We will use the convention that $a,b,c$ are variable names for the domain, and $x,y,z$ in the codomain - it will be clear how to input them.

This first setup is taking vectors from $\mathbb{R}^2$ and sending them to $\mathbb{R}^3$.  What happens if we make the transformation have nontrivial linear relations?  Can we get every possible vector?

@interact(layout=[['A','Myvect']]) def _(A = matrix([[1,-3],[3,5],[-1,7]]),Myvect=matrix([[2,-1]])): V = vector([1,3]) W = A*V V1 = vector([-1,2]) W1 = A*V1 Myvect = vector(Myvect[0]) Wyvect = A*Myvect pretty_print(html("We apply the linear transformation")) pretty_print(html("$x={}a+{}b".format(A[0,0],A[0,1]))) pretty_print(html("$y={}a+{}b".format(A[1,0],A[1,1]))) pretty_print(html("$z={}a+{}b".format(A[2,0],A[2,1]))) pretty_print(html("To the vectors $(1,3)$, $(-1,2)$, and $({},{})$".format(Myvect[0],Myvect[1]))) show(plot(V)+plot(V1,color='red')+plot(Myvect,color='green')) show(plot(W,thickness=10)+plot(W1,color='red',thickness=10)+plot(Wyvect,color='green',thickness=10)) 
       

Click to the left again to hide and once more to show the dynamic interactive window

We could also try the opposite, linear transformations from $\mathbb{R}^3$ to $\mathbb{R}^2$.

@interact(layout=[['A','Myvect']]) def _(A = matrix([[1,-3,3],[5,-1,7]]),Myvect=matrix([[2,-1,0]])): V = vector([1,3,0]) W = A*V V1 = vector([-1,2,1]) W1 = A*V1 Myvect = vector(Myvect[0]) Wyvect = A*Myvect pretty_print(html("We apply the linear transformation")) pretty_print(html("$x={}a+{}b+{}c".format(A[0,0],A[0,1],A[0,2]))) pretty_print(html("$y={}a+{}b+{}c".format(A[1,0],A[1,1],A[1,2]))) pretty_print(html("To the vectors $(1,3,0)$, $(-1,2,1)$, and $({},{},{})$".format(Myvect[0],Myvect[1],Myvect[2]))) show(plot(V,thickness=10)+plot(V1,color='red',thickness=10)+plot(Myvect,color='green',thickness=10)) show(plot(W)+plot(W1,color='red')+plot(Wyvect,color='green')) 
       

Click to the left again to hide and once more to show the dynamic interactive window

Linear Transformations

The book calls a linear map a linear transformation if it is a map from a vector space $V$ to itself.  Here is what linear transformations from $\mathbb{R}^3$ to $\mathbb{R}^3$ might look like.

@interact(layout=[['A','Myvect']]) def _(A = matrix([[1,-3,3],[5,-1,7],[0,1,2]]),Myvect=matrix([[2,-1,0]])): V = vector([1,3,2]) W = A*V V1 = vector([-1,2,1]) W1 = A*V1 Myvect = vector(Myvect[0]) Wyvect = A*Myvect pretty_print(html("We apply the linear transformation")) pretty_print(html("$x={}a+{}b+{}c".format(A[0,0],A[0,1],A[0,2]))) pretty_print(html("$y={}a+{}b+{}c".format(A[1,0],A[1,1],A[1,2]))) pretty_print(html("$z={}a+{}b+{}c".format(A[2,0],A[2,1],A[2,2]))) pretty_print(html("To the vectors $(1,3,0)$, $(-1,2,1)$, and $({},{},{})$".format(Myvect[0],Myvect[1],Myvect[2]))) show(plot(V,thickness=10)+plot(V1,color='red',thickness=10)+plot(Myvect,color='green',thickness=10)+plot(W,thickness=3)+plot(W1,color='red',thickness=3)+plot(Wyvect,color='green',thickness=3)) 
       

Click to the left again to hide and once more to show the dynamic interactive window

The thick vectors are the original ones, the skinny ones are the "transformed" vectors.  What are the possibilities?  For instance, what of projection to the $xy$-plane, as on page 291?

@interact(layout=[['A','Myvect']]) def _(A = matrix([[1,0,0],[0,1,0],[0,0,0]]),Myvect=matrix([[2,-1,0]])): V = vector([1,3,2]) W = A*V V1 = vector([-1,2,1]) W1 = A*V1 Myvect = vector(Myvect[0]) Wyvect = A*Myvect pretty_print(html("We apply the linear transformation")) pretty_print(html("$x={}a+{}b+{}c".format(A[0,0],A[0,1],A[0,2]))) pretty_print(html("$y={}a+{}b+{}c".format(A[1,0],A[1,1],A[1,2]))) pretty_print(html("$z={}a+{}b+{}c".format(A[2,0],A[2,1],A[2,2]))) pretty_print(html("To the vectors $(1,3,0)$, $(-1,2,1)$, and $({},{},{})$".format(Myvect[0],Myvect[1],Myvect[2]))) show(plot(V,thickness=10)+plot(V1,color='red',thickness=10)+plot(Myvect,color='green',thickness=10)+plot(W,thickness=3)+plot(W1,color='red',thickness=3)+plot(Wyvect,color='green',thickness=3)) 
       

Click to the left again to hide and once more to show the dynamic interactive window

Here is the one from the online response.

t = var('t') @interact def _(box=matrix(RDF,[[1,2]]), lin_trans=matrix(RDF,[[1,0],[0,1]]),auto_update=False): a = box[0][0] b = box[0][1] P = line([(0,0),(a,0),(a,b),(0,b),(0,0)],color='red')+point((a,b),color='green',size=20) A,B,C,D = lin_trans[0,0],lin_trans[0,1],lin_trans[1,0],lin_trans[1,1] P += line([(0,0),(A*a,C*a),(A*a+B*b,C*a+D*b),(B*b,D*b),(0,0)],color='blue')+point((a,b),color='green',size=20) pretty_print(html('box to $({},{})$'.format(box[0][0],box[0][1]))) pretty_print(html('transformed by $x={}a+{}b$ and $y={}a+{}b$'.format(lin_trans[0,0],lin_trans[0,1],lin_trans[1,0],lin_trans[1,1]))) P.show(aspect_ratio=1,figsize=4) 
       

Click to the left again to hide and once more to show the dynamic interactive window

There are many types of linear transformations in $\mathbb{R}^2$.  We can see all of them in the following activity. It's due to Jane Long, based on an activity of Tom Judson, both at Stephen F. Austin State in Nacogdoches, TX.

t = var('t') @interact def _(auto_update=False,A=matrix(RDF,[[1,0],[0,1]])): pll=A*vector((-0.5,0.5)) plr=A*vector((-0.3,0.5)) prl=A*vector((0.3,0.5)) prr=A*vector((0.5,0.5)) left_eye=line([pll,plr])+point(pll,size=5)+point(plr,size=5) right_eye=line([prl,prr],color='green')+point(prl,size=5,color='green')+point(prr,size=5,color='green') mouth=parametric_plot(A*vector([t, -0.15*sin(2*pi*t)-0.5]), (t, -0.5, 0),color='red')+parametric_plot(A*vector([t, -0.15*sin(2*pi*t)-0.5]), (t,0,0.5),color='orange') face=parametric_plot(A*vector([cos(t),sin(t)]), (t,0,pi/2),color='black')+parametric_plot(A*vector([cos(t),sin(t)]), (t,pi/2,pi),color='lavender')+parametric_plot(A*vector([cos(t),sin(t)]), (t,pi,3*pi/2),color='cyan')+parametric_plot(A*vector([cos(t),sin(t)]),(t,3*pi/2,2*pi),color='sienna') P=right_eye+left_eye+face+mouth pretty_print(html('smiley guy transformed by $x={}a+{}b$ and $y={}a+{}b$'.format(A[0,0],A[0,1],A[1,0],A[1,1]))) P.show(aspect_ratio=1,figsize=6) 
       

Click to the left again to hide and once more to show the dynamic interactive window

Finally, we can start using and multiplying vectors and matrices!

Here's how you make a vector.

V = vector([1,2]) 
       

Here's how you make a matrix, recall.

M = matrix([[4,-4],[1,-4],[-5,4]]) 
       
show(M) 
       

Here's how you multiply them:

M*V 
       
(-4, -7, 3)
(-4, -7, 3)

Didn't catch that? Let's do another. This time, we try to use Sage to compute them.

A = matrix([[8,-4],[-12,6]]) 
       
A.column_space() # this is the image, remember 
       
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[ 4 -6]
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[ 4 -6]
A.kernel() 
       
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[3 2]
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[3 2]

Oops!  Why does WeBWorK not like it?

A.kernel? 
       

I see.  We need right_kernel, because our equations have the vector on the right.  Huh.

A.right_kernel() 
       
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[1 2]
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[1 2]

Phew!

And in case you were worried, we can do more than that.

A.row_space() 
       
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[ 4 -2]
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[ 4 -2]
A.column_space() 
       
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[ 4 -6]
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[ 4 -6]

The Algebra of Matrices

We can do all the things with matrices we can do with vectors.  Also we can multiply them (if they're the right size).

A = matrix([[0,-1],[1,0]]); show(A) 
       
M = matrix([[1,2],[3,4]]); show(M) 
       
A+M 
       
[1 1]
[4 4]
[1 1]
[4 4]
M+A 
       
[1 1]
[4 4]
[1 1]
[4 4]
2*A 
       
[ 0 -2]
[ 2  0]
[ 0 -2]
[ 2  0]
2*A-3*M 
       
[ -3  -8]
[ -7 -12]
[ -3  -8]
[ -7 -12]

Multiplication

What about doing a linear map again and again?  Recall this situation:

Beverly = .1 Boston = .9 
       
Beverly, Boston = .8*Beverly + .7*Boston, .2*Beverly + .3*Boston 
       
Beverly, Boston 
       
(0.777100000000000, 0.222900000000000)
(0.777100000000000, 0.222900000000000)

And we can keep doing this again and again.

But is there an easier way?

Trans = matrix(RDF,[[.8,.7],[.2,.3]]) 
       
Trans*(Trans*vector([.9,.1])) 
       
(0.7790000000000001, 0.22100000000000003)
(0.7790000000000001, 0.22100000000000003)
(Trans^2 ) * vector([.9,.1]) 
       
(0.7790000000000001, 0.22100000000000003)
(0.7790000000000001, 0.22100000000000003)
t = var('t') @interact(layout=[['box','auto_update'],['lin_trans_1','lin_trans_2']]) def _(box=matrix(RDF,[[1,2]]), lin_trans_1=matrix(RDF,[[1,0],[0,1]]),lin_trans_2=matrix(RDF,[[1,0],[0,1]]),auto_update=False): ID = matrix(RDF,[[1,0],[0,1]]) def makebox(M,figsize=[4,4]): A,B,C,D = M[0,0],M[0,1],M[1,0],M[1,1] P = line([(0,0),M*vector([box[0][0],0]),M*box[0],M*vector([0,box[0][1]]),(0,0)],color='blue',figsize=figsize)+point(M*box[0],color='green',size=20) return P pretty_print(html('box, first transformed by first matrix, and next by next one')) G = graphics_array([[makebox(ID),makebox(lin_trans_1),makebox(lin_trans_2*lin_trans_1)]]) G.show(figsize=[4,2]) 
       

Click to the left again to hide and once more to show the dynamic interactive window

Try doing this with a shear or flip and then rotation, and then the opposite direction.

t = var('t') @interact(layout=[['A','B'],['auto_update']]) def _(A=matrix(RDF,[[1,0],[0,1]]),B=matrix(RDF,[[1,0],[0,1]]),auto_update=False): ID = matrix(RDF,[[1,0],[0,1]]) def makeface(M): pll=M*vector((-0.5,0.5)) plr=M*vector((-0.3,0.5)) prl=M*vector((0.3,0.5)) prr=M*vector((0.5,0.5)) left_eye=line([pll,plr])+point(pll,size=5)+point(plr,size=5) right_eye=line([prl,prr],color='green')+point(prl,size=5,color='green')+point(prr,size=5,color='green') mouth=parametric_plot(M*vector([t, -0.15*sin(2*pi*t)-0.5]), (t, -0.5, 0),color='red')+parametric_plot(M*vector([t, -0.15*sin(2*pi*t)-0.5]), (t,0,0.5),color='orange') face=parametric_plot(M*vector([cos(t),sin(t)]), (t,0,pi/2),color='black')+parametric_plot(M*vector([cos(t),sin(t)]), (t,pi/2,pi),color='lavender')+parametric_plot(M*vector([cos(t),sin(t)]), (t,pi,3*pi/2),color='cyan')+parametric_plot(M*vector([cos(t),sin(t)]),(t,3*pi/2,2*pi),color='sienna') return right_eye+left_eye+face+mouth pretty_print(html('smiley guy, then transformed by $A$, and next by $B$')) G = graphics_array([[makeface(ID),makeface(A),makeface(B*A)]]) G.show(aspect_ratio=1) 
       

Click to the left again to hide and once more to show the dynamic interactive window

t = var('t') @interact def _(theta=pi/2,phi=pi/3,auto_update=False): A=matrix(RDF,[[cos(theta),-sin(theta)],[sin(theta),cos(theta)]]) B=matrix(RDF,[[cos(phi),-sin(phi)],[sin(phi),cos(phi)]]) ID = matrix(RDF,[[1,0],[0,1]]) def makeface(M): pll=M*vector((-0.5,0.5)) plr=M*vector((-0.3,0.5)) prl=M*vector((0.3,0.5)) prr=M*vector((0.5,0.5)) left_eye=line([pll,plr])+point(pll,size=5)+point(plr,size=5) right_eye=line([prl,prr],color='green')+point(prl,size=5,color='green')+point(prr,size=5,color='green') mouth=parametric_plot(M*vector([t, -0.15*sin(2*pi*t)-0.5]), (t, -0.5, 0),color='red')+parametric_plot(M*vector([t, -0.15*sin(2*pi*t)-0.5]), (t,0,0.5),color='orange') face=parametric_plot(M*vector([cos(t),sin(t)]), (t,0,pi/2),color='black')+parametric_plot(M*vector([cos(t),sin(t)]), (t,pi/2,pi),color='lavender')+parametric_plot(M*vector([cos(t),sin(t)]), (t,pi,3*pi/2),color='cyan')+parametric_plot(M*vector([cos(t),sin(t)]),(t,3*pi/2,2*pi),color='sienna') return right_eye+left_eye+face+mouth pretty_print(html('smiley guy, then transformed by $A$, and next by $B$')) G = graphics_array([[makeface(ID),makeface(A),makeface(B*A)]]) G.show(aspect_ratio=1) 
       

Click to the left again to hide and once more to show the dynamic interactive window

Here we go with multiplication:

show(A*M) 
       
show(M*A) 
       

Hey, we could multiply both ways!  Although the answers were different... is that a problem?

B = matrix([[1,2,3],[4,5,6]]); show(B) 
       

But we have to be careful:

A*B 
       
[-4 -5 -6]
[ 1  2  3]
[-4 -5 -6]
[ 1  2  3]
B*A 
       
Traceback (click to the left of this block for traceback)
...
TypeError: unsupported operand parent(s) for '*': 'Full MatrixSpace of 2
by 3 dense matrices over Integer Ring' and 'Full MatrixSpace of 2 by 2
dense matrices over Integer Ring'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_84.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("QipB"),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))
  File "", line 1, in <module>
    
  File "/tmp/tmpZvExEy/___code___.py", line 2, in <module>
    exec compile(u'B*A
  File "", line 1, in <module>
    
  File "sage/structure/element.pyx", line 2949, in sage.structure.element.Matrix.__mul__ (/usr/local/sage-6.9/src/build/cythonized/sage/structure/element.c:23250)
  File "sage/structure/coerce.pyx", line 1070, in sage.structure.coerce.CoercionModel_cache_maps.bin_op (/usr/local/sage-6.9/src/build/cythonized/sage/structure/coerce.c:9739)
TypeError: unsupported operand parent(s) for '*': 'Full MatrixSpace of 2 by 3 dense matrices over Integer Ring' and 'Full MatrixSpace of 2 by 2 dense matrices over Integer Ring'
M = matrix([[1,-1],[-1,1]]) N1 = matrix([[2,1],[2,1]]) N2 = matrix([[3,-1],[3,-1]]) 
       

We have the following unusual situation (well, unusual to us so far in our experience):

pretty_print(html('$M\cdot N1$ is')) show(M*N1) pretty_print(html('$M\cdot N2$ is')) show(M*N2) pretty_print(html("But $N1$ and $N2$ are not the same! Here's their difference:")) show(N1-N2) 
       
 is

 is

But  and  are not the same!  Here's their difference:
 is

 is

But  and  are not the same!  Here's their difference:

So you definitely can't cancel if $M*N1 = M*N2$ but $N1\neq N2$.

 
       

Projective Coordinates

We can do transformation and elementary transformations at the same time using projective coordinates, and matrix multiplication still acts like composing transformations.

t = var('t') @interact(layout=[['box','auto_update','two_times'],['move_matrix','move_matrix2']]) def _(box=matrix(RDF,[[1,2]]), move_matrix=matrix(RDF,[[1,0,0],[0,1,0],[0,0,1]]), move_matrix2=matrix(RDF,[[1,0,0],[0,1,0],[0,0,1]]),auto_update=False,two_times=False): ID = matrix(RDF,[[1,0,0],[0,1,0],[0,0,1]]) def makebox(M,figsize=[4,4],color='red'): pt_list = [M*vector([0,0,1]), M*vector([box[0][0],0,1]), M*vector([box[0][0],box[0][1],1]),M*vector([0,box[0][1],1]),M*vector([0,0,1])] pt_list = [V[:-1] for V in pt_list] P = line(pt_list,color=color,figsize=figsize) return P pretty_print(html('box, transformed in projective coordinates')) G = makebox(ID,color='blue')+makebox(move_matrix) if two_times: G += makebox(move_matrix2*move_matrix,color='green') G.show(aspect_ratio=1) 
       

Click to the left again to hide and once more to show the dynamic interactive window

Inverse Matrices

This is pretty easy to do in Sage.  But watch out that your matrix is invertible!

M = matrix([[2,1],[1,-1]]) 
       
M^-1 
       
[ 1/3  1/3]
[ 1/3 -2/3]
[ 1/3  1/3]
[ 1/3 -2/3]
M^-1 * vector([5,1]) 
       
(2, 1)
(2, 1)
var('a,b') 
       
(a, b)
(a, b)
M^-1*vector([a,b]) 
       
(1/3*a + 1/3*b, 1/3*a - 2/3*b)
(1/3*a + 1/3*b, 1/3*a - 2/3*b)
M = matrix([[1,0,0],[0,1,0],[0,0,0]]); M 
       
[1 0 0]
[0 1 0]
[0 0 0]
[1 0 0]
[0 1 0]
[0 0 0]
M^-1 
       
Traceback (click to the left of this block for traceback)
...
ZeroDivisionError: Matrix is singular
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_10.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("TV4tMQ=="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))
  File "", line 1, in <module>
    
  File "/tmp/tmpmZKIp0/___code___.py", line 3, in <module>
    exec compile(u'M**-_sage_const_1 
  File "", line 1, in <module>
    
  File "sage/matrix/matrix_integer_dense.pyx", line 1042, in sage.matrix.matrix_integer_dense.Matrix_integer_dense.__pow__ (/usr/local/sage-6.9/src/build/cythonized/sage/matrix/matrix_integer_dense.c:11506)
  File "sage/matrix/matrix_integer_dense.pyx", line 3851, in sage.matrix.matrix_integer_dense.Matrix_integer_dense.__invert__ (/usr/local/sage-6.9/src/build/cythonized/sage/matrix/matrix_integer_dense.c:33250)
  File "sage/matrix/matrix_integer_dense.pyx", line 3812, in sage.matrix.matrix_integer_dense.Matrix_integer_dense._invert_flint (/usr/local/sage-6.9/src/build/cythonized/sage/matrix/matrix_integer_dense.c:33084)
ZeroDivisionError: Matrix is singular

Let's do it in three dimensions.

M = matrix([[1,2,3],[2,0,5],[0,1,0]]); show(M) 
       

N = M^-1; show(N) 
       
show(M*N) 
       

And yes, the original is the product of the inverses of the elementary matrices that get you from $M$ to $I$.  Note we use Python numbering - rows start being counted at 0.

E = elementary_matrix(3,row1=1,row2=0,scale=2)*elementary_matrix(3,row1=1,row2=2)*elementary_matrix(3,row1=2,row2=1,scale=-4)*elementary_matrix(3,row1=2,scale=-1)*elementary_matrix(3,row1=0,row2=2,scale=3)*elementary_matrix(3,row1=0,row2=1,scale=2) 
       
E == M; E 
       
True
[1 2 3]
[2 0 5]
[0 1 0]
True
[1 2 3]
[2 0 5]
[0 1 0]
E^-1 
       
[-5  3 10]
[ 0  0  1]
[ 2 -1 -4]
[-5  3 10]
[ 0  0  1]
[ 2 -1 -4]
matrix([[1,0,0],[0,1,0],[3,0,1]])*matrix([[1,0,0],[2,1,0],[0,0,1]])*matrix([[1,0,0],[0,-5,0],[0,0,1]])*matrix([[1,0,0],[0,1,0],[0,-5,1]])*matrix([[1,0,0],[0,1,0],[0,0,2]])*matrix([[1,2,0],[0,1,0],[0,0,1]]) 
       
[ 1  2  0]
[ 2 -1  0]
[ 3  1  2]
[ 1  2  0]
[ 2 -1  0]
[ 3  1  2]

Projection and Orthogonality

The final topic in Chapter Three is about direction and angles - caring about orthogonality.  Let's see this with two examples.

t = var('t') @interact def _(A=matrix(RDF,[[1,0],[0,1]]),auto_update=False): ID = matrix(RDF,[[1,0],[0,1]]) def makeface(M): pll=M*vector((-0.5,0.5)) plr=M*vector((-0.3,0.5)) prl=M*vector((0.3,0.5)) prr=M*vector((0.5,0.5)) left_eye=line([pll,plr])+point(pll,size=5)+point(plr,size=5) right_eye=line([prl,prr],color='green')+point(prl,size=5,color='green')+point(prr,size=5,color='green') mouth=parametric_plot(M*vector([t, -0.15*sin(2*pi*t)-0.5]), (t, -0.5, 0),color='red')+parametric_plot(M*vector([t, -0.15*sin(2*pi*t)-0.5]), (t,0,0.5),color='orange') face=parametric_plot(M*vector([cos(t),sin(t)]), (t,0,pi/2),color='black')+parametric_plot(M*vector([cos(t),sin(t)]), (t,pi/2,pi),color='lavender')+parametric_plot(M*vector([cos(t),sin(t)]), (t,pi,3*pi/2),color='cyan')+parametric_plot(M*vector([cos(t),sin(t)]),(t,3*pi/2,2*pi),color='sienna') return right_eye+left_eye+face+mouth pretty_print(html('smiley guy, then transformed by $A$')) pretty_print(html('which makes him {} times bigger!'.format(det(A)))) pretty_print(html('But did we preserve all lengths too? {}'.format(A.is_unitary()))) G = makeface(ID)+makeface(A) G.show(aspect_ratio=1,figsize=5) 
       

Click to the left again to hide and once more to show the dynamic interactive window

In this example, we want Smiley Guy to not just preserve his size, but also to preserve "shape", which we can guarantee by asking whether the linear map doesn't change any lengths.

We can also ask about something seemingly completely different.  Namely, can we try to see about how to analyze data with linear algebra? 

Let's do an experiment.  I have fifteen multicolored dice, and I want to see how many green dice I get, on average.  Hopefully 2.5!  But what if they are weighted toward the green?  (We assume the dice are actually identical, just to avoid the tedium of rolling the dice a lot.)

my_green_rolls=[4,1,1,1,2,4,5,3,1] 
       
list2 = [15*i for i in range(1,len(my_green_rolls)+1)]; list2 
       
[15, 30, 45, 60, 75, 90, 105, 120, 135]
[15, 30, 45, 60, 75, 90, 105, 120, 135]
list3 = [sum(my_green_rolls[:i]) for i in range(1,len(my_green_rolls)+1)]; list3 
       
[4, 5, 6, 7, 9, 13, 18, 21, 22]
[4, 5, 6, 7, 9, 13, 18, 21, 22]
points([(0,0)]+zip(list2,list3),figsize=5) 
       
@interact def _(m=1/6): show(points([(0,0)]+zip(list2,list3))+plot(m*x,(x,0,list2[-1]),color='red'),figsize=5) 
       

Click to the left again to hide and once more to show the dynamic interactive window

Well - what slope will make the most sense?  This one seems plausible, but maybe another is better?  And this was just one simulation.

In order to answer this better, we will need to talk about lengths of vectors and angles again.

import pylab A_image = pylab.mean(pylab.imread(DATA + 'gordon_college_medium.png'), 2) @interact def svd_image(i=(20,(1..100)),display_axes=True): u,s,v = pylab.linalg.svd(A_image) A = sum(s[j]*pylab.outer(u[0:,j],v[j,0:]) for j in range(i)) g = graphics_array([matrix_plot(A),matrix_plot(A_image)]) show(g,axes=display_axes, figsize=[8,3]) pretty_print(html('<h2>Compressed using %s eigenvalues</h2>'%i)) 
       
display_axes 

Click to the left again to hide and once more to show the dynamic interactive window

This example shows us that image compression also can happen using orthogonal vectors, though we won't be able to see how this kind of thing might be approached until the last day of lecture.

Data analysis uses similar tools as well... and so forth!