04 - Linear Transformations

485 days ago by jason3

%auto var('x,y,z,s,t'); 
       
(x, y, z, s, t)
(x, y, z, s, t)

2D Transformations

The code below illustrates how a matrix transforms objects in the plane.  It graphs both the unit square together with the image of the unit square under this transformation. Notice that lines are always mapped to lines, which is the reason for the word "linear" transformation. Notice the following:

  1. The columns of the matrix are the edges of transformed parallelogram
  2. The determinant of the matrix is the area increment. A negative determinant means that the image was flipped over through the transformation.
  3. The eigenvectors are the directions in which the map transforms objects radially outward.
  4. The product of the eigenvalues is the determinant of the matrix.
c(t)=(cos(t),sin(t)) origcircleplot=parametric_plot(c,(t,0,2*pi)) h(t)=((1 - sin(t))*cos(t)+1.5, (1 - sin(t))*sin(t)+2.5) h=h/3 origheart=parametric_plot( h, (t, pi/2, 3*pi/2),color='black', aspect_ratio=1,thickness=3) origheart+=parametric_plot( h, (t, -pi/2, pi/2),color='green',thickness=3) e1=vector([1,0]) e2=vector([0,1]) z=(0,0) origboxplot=arrow(z,e1,color='red',aspect_ratio=1) origboxplot+=arrow(z,e2,color='blue') origboxplot+=arrow(e2,e2+e1,color='red',linestyle='dashed') origboxplot+=arrow(e1,e1+e2,color='blue',linestyle='dashed') def draw(A=matrix(QQ, [[2,1], [0,3]])): EV=A.eigenvectors_right() c1,c2=A.columns() boxplot=arrow(z,c1,color='red') boxplot+=arrow(z,c2,color='blue') boxplot+=arrow(c2,c2+c1,color='red',linestyle='dashed') boxplot+=arrow(c1,c1+c2,color='blue',linestyle='dashed') #evplot=arrow(z,z) evplot=Graphics() for eval, evecs, mult in EV: print "eval, evecs",eval, evecs for evec in evecs: print eval print eval.conjugate() print evec print evec.norm() if eval==eval.conjugate(): unitevec=evec/evec.norm() evplot+=arrow(z, eval*unitevec, color='purple') evplot+=arrow(z, unitevec, color='green') evplot+=arrow(z, -eval*unitevec, color='purple') evplot+=arrow(z, -unitevec, color='green') return True if EV[0][2]==1: eval1,[evec1],_=EV[0] eval2,[evec2],_=EV[1] else: eval1,evecs,mult=EV[0] if len(evecs)==2: eval2=eval1 evec1,evec2=evecs else: evec1=evecs[0] eval2='' evec2='' circleplot=parametric_plot(A*c,(t,0,2*pi)) heart=parametric_plot( A*h, (t, pi/2, 3*pi/2),color='black',thickness=3) heart+=parametric_plot( A*h, (t, -pi/2, pi/2),color='green',thickness=3) html.table([[ origboxplot+boxplot+origheart+heart,origboxplot+boxplot+evplot+origcircleplot+circleplot ]]) html.table([["Matrix","Determinant", "Eval/Evec"], [A, A.det(), "%s: %s"%(eval1, evec1)],['','', "%s: %s"%(eval2,evec2)]]) 
       
c(t)=(cos(t),sin(t)) origcircleplot=parametric_plot(c,(t,0,2*pi)) h(t)=((1 - sin(t))*cos(t)+1.5, (1 - sin(t))*sin(t)+2.5) h=h/3 origheart=parametric_plot( h, (t, pi/2, 3*pi/2),color='black', aspect_ratio=1,thickness=3) origheart+=parametric_plot( h, (t, -pi/2, pi/2),color='green',thickness=3) e1=vector([1,0]) e2=vector([0,1]) z=(0,0) def draw(A=matrix(QQ, [[2,1], [0,3]])): EV=A.eigenvectors_right() c1,c2=A.columns() for eval, evecs, mult in EV: print "eval, evecs",eval, evecs for evec in evecs: print eval print eval.conjugate(), eval==eval.conjugate() print evec, evec.parent() print evec.norm() if eval==eval.conjugate(): unitevec=evec/evec.norm() print unitevec print eval arrow((0,0), list(eval*unitevec), color='purple') return True 
       
draw() 
       
eval, evecs 3 [
(1, 1)
]
3
3 True
(1, 1) Vector space of degree 2 and dimension 1 over Rational Field
User basis matrix:
[1 1]
sqrt(2)
(1/2*sqrt(2), 1/2*sqrt(2))
3
True
eval, evecs 3 [
(1, 1)
]
3
3 True
(1, 1) Vector space of degree 2 and dimension 1 over Rational Field
User basis matrix:
[1 1]
sqrt(2)
(1/2*sqrt(2), 1/2*sqrt(2))
3
True
A=matrix(QQ, [[2,1],[0,3]]) A 
       
[2 1]
[0 3]
[2 1]
[0 3]
EV=A.eigenvectors_right() EV 
       
[(3, [
(1, 1)
], 1), (2, [
(1, 0)
], 1)]
[(3, [
(1, 1)
], 1), (2, [
(1, 0)
], 1)]
c1,c2=A.columns() print c1,c2 
       
(2, 0) (1, 3)
(2, 0) (1, 3)
eval, evecs,mult=EV[0] eval, evecs, mult 
       
(3, [
(1, 1)
], 1)
(3, [
(1, 1)
], 1)
evec=evecs[0] evec 
       
(1, 1)
(1, 1)
unitevec=evec/evec.norm() unitevec 
       
parent(eval) 
       
parent(unitevec) 
       
eval*unitevec 
       
(3/2*sqrt(2), 3/2*sqrt(2))
(3/2*sqrt(2), 3/2*sqrt(2))
 
       
 
       
 
       
 
       
 
       

3D Transformations

This code repeats what was done in the 2D section. Now the determinant measures the increase in area.

A=matrix(QQ, [[1,0,0], [0,2,1], [0,1,2]]) EV=A.eigenvectors_right() e1=vector([1,0,0]) e2=vector([0,1,0]) e3=vector([0,0,1]) c1,c2,c3=A.columns() z=vector([0,0,0]) boxplot=arrow3d(z,e1,color='red',aspect_ratio=1) boxplot+=arrow3d(z,e2,color='blue') boxplot+=arrow3d(z,e3,color='green') boxplot+=arrow3d(e2,e2+e1,color='red',linestyle='dashed') boxplot+=arrow3d(e3,e3+e1,color='red',linestyle='dashed') boxplot+=arrow3d(e1,e1+e2,color='blue',linestyle='dashed') boxplot+=arrow3d(e3,e3+e2,color='blue',linestyle='dashed') boxplot+=arrow3d(e1,e1+e3,color='green',linestyle='dashed') boxplot+=arrow3d(e2,e2+e3,color='green',linestyle='dashed') boxplot+=arrow3d(z,c1,color='red',aspect_ratio=1) boxplot+=arrow3d(z,c2,color='blue') boxplot+=arrow3d(z,c3,color='green') boxplot+=arrow3d(c2,c2+c1,color='red',linestyle='dashed') boxplot+=arrow3d(c3,c3+c1,color='red',linestyle='dashed') boxplot+=arrow3d(c1,c1+c2,color='blue',linestyle='dashed') boxplot+=arrow3d(c3,c3+c2,color='blue',linestyle='dashed') boxplot+=arrow3d(c1,c1+c3,color='green',linestyle='dashed') boxplot+=arrow3d(c2,c2+c3,color='green',linestyle='dashed') evplot=arrow3d(z,z) for i in range(len(EV)): for j in range( len( EV[i][1] ) ): if EV[i][0]==EV[i][0].conjugate(): evplot+=arrow3d(z,EV[i][0]*(EV[i][1][j])/EV[i][1][j].norm(),color='black') evplot+=arrow3d(z,(EV[i][1][j])/EV[i][1][j].norm(),color='purple') evplot+=arrow3d(z,-EV[i][0]*(EV[i][1][j])/EV[i][1][j].norm(),color='black') evplot+=arrow3d(z,-(EV[i][1][j])/EV[i][1][j].norm(),color='purple') var('s,t') r=vector([sin(s)*cos(t),sin(s)*sin(t),cos(s)]) sphereplot=parametric_plot3d(r,(t,0,2*pi),(s,0,pi),opacity=.1) sphereplot+=parametric_plot3d(A*r,(t,0,2*pi),(s,0,pi),opacity=.1) r=1/2 * vector([cos(t)*cos(s)*sin(3*s),sin(t)*cos(s)*sin(3*s), sin(s)*sin(3*s)]) + vector([1/2, 1/2, 1/2]) flower=parametric_plot3d( r, (t, 0,2 *pi), (s,0,2*pi),color='red',opacity=.2) flower+=parametric_plot3d( A*r, (t, 0,2 *pi),(s,0,2*pi),color='red',opacity=.2) p=boxplot+evplot+sphereplot+flower p.show() html.table([["Matrix",A],["Determinant",A.det()],["Eigenvalues and Eigenvectors","Under the table" ]]) EV 
       

You can use the 3D code to create visualizations of transformations from 3D to 2D, and from 2D to 3D.  Just add on a row or column of zeros to make the matrix square.  This next example is from 3D to 2D so I added a row of zeros at the end).

A=matrix(QQ, [[1,0,0], [0,2,1], [0,0,0]]) EV=A.eigenvectors_right() e1=vector([1,0,0]) e2=vector([0,1,0]) e3=vector([0,0,1]) c1,c2,c3=A.columns() z=vector([0,0,0]) boxplot=arrow3d(z,e1,color='red',aspect_ratio=1) boxplot+=arrow3d(z,e2,color='blue') boxplot+=arrow3d(z,e3,color='green') boxplot+=arrow3d(e2,e2+e1,color='red',linestyle='dashed') boxplot+=arrow3d(e3,e3+e1,color='red',linestyle='dashed') boxplot+=arrow3d(e1,e1+e2,color='blue',linestyle='dashed') boxplot+=arrow3d(e3,e3+e2,color='blue',linestyle='dashed') boxplot+=arrow3d(e1,e1+e3,color='green',linestyle='dashed') boxplot+=arrow3d(e2,e2+e3,color='green',linestyle='dashed') boxplot+=arrow3d(z,c1,color='red',aspect_ratio=1) boxplot+=arrow3d(z,c2,color='blue') boxplot+=arrow3d(z,c3,color='green') boxplot+=arrow3d(c2,c2+c1,color='red',linestyle='dashed') boxplot+=arrow3d(c3,c3+c1,color='red',linestyle='dashed') boxplot+=arrow3d(c1,c1+c2,color='blue',linestyle='dashed') boxplot+=arrow3d(c3,c3+c2,color='blue',linestyle='dashed') boxplot+=arrow3d(c1,c1+c3,color='green',linestyle='dashed') boxplot+=arrow3d(c2,c2+c3,color='green',linestyle='dashed') evplot=arrow3d(z,z) for i in range(len(EV)): for j in range( len( EV[i][1] ) ): if EV[i][0]==EV[i][0].conjugate(): evplot+=arrow3d(z,EV[i][0]*(EV[i][1][j])/EV[i][1][j].norm(),color='black') evplot+=arrow3d(z,(EV[i][1][j])/EV[i][1][j].norm(),color='purple') evplot+=arrow3d(z,-EV[i][0]*(EV[i][1][j])/EV[i][1][j].norm(),color='black') evplot+=arrow3d(z,-(EV[i][1][j])/EV[i][1][j].norm(),color='purple') var('s,t') r=vector([sin(s)*cos(t),sin(s)*sin(t),cos(s)]) sphereplot=parametric_plot3d(r,(t,0,2*pi),(s,0,pi),opacity=.1) sphereplot+=parametric_plot3d(A*r,(t,0,2*pi),(s,0,pi),opacity=.1) r=1/2 * vector([cos(t)*cos(s)*sin(3*s),sin(t)*cos(s)*sin(3*s), sin(s)*sin(3*s)]) + vector([1/2, 1/2, 1/2]) flower=parametric_plot3d( r, (t, 0,2 *pi), (s,0,2*pi),color='red',opacity=.2) flower+=parametric_plot3d( A*r, (t, 0,2 *pi),(s,0,2*pi),color='red',opacity=.2) p=boxplot+evplot+sphereplot+flower p.show() html.table([["Matrix",A],["Determinant",A.det()],["Eigenvalues and Eigenvectors","Under the table" ]]) EV 
       
Matrix \left(\begin{array}{rrr} 1 & 0 & 0 \\ 0 & 2 & 1 \\ 0 & 0 & 0 \end{array}\right)
Determinant 0
Eigenvalues and Eigenvectors Under the table
[(2, [ (0, 1, 0) ], 1), (1, [ (1, 0, 0) ], 1), (0, [ (0, 1, -2) ], 1)]
Matrix \left(\begin{array}{rrr} 1 & 0 & 0 \\ 0 & 2 & 1 \\ 0 & 0 & 0 \end{array}\right)
Determinant 0
Eigenvalues and Eigenvectors Under the table
[(2, [ (0, 1, 0) ], 1), (1, [ (1, 0, 0) ], 1), (0, [ (0, 1, -2) ], 1)]

If I add a column of zeros on the right, then essentially this is like squashing 3D flat to 2D, and then mapping that into 3D. 

A=matrix(QQ, [[1,0,0], [0,2,0], [0,1,0]]) EV=A.eigenvectors_right() e1=vector([1,0,0]) e2=vector([0,1,0]) e3=vector([0,0,1]) c1,c2,c3=A.columns() z=vector([0,0,0]) boxplot=arrow3d(z,e1,color='red',aspect_ratio=1) boxplot+=arrow3d(z,e2,color='blue') boxplot+=arrow3d(z,e3,color='green') boxplot+=arrow3d(e2,e2+e1,color='red',linestyle='dashed') boxplot+=arrow3d(e3,e3+e1,color='red',linestyle='dashed') boxplot+=arrow3d(e1,e1+e2,color='blue',linestyle='dashed') boxplot+=arrow3d(e3,e3+e2,color='blue',linestyle='dashed') boxplot+=arrow3d(e1,e1+e3,color='green',linestyle='dashed') boxplot+=arrow3d(e2,e2+e3,color='green',linestyle='dashed') boxplot+=arrow3d(z,c1,color='red',aspect_ratio=1) boxplot+=arrow3d(z,c2,color='blue') boxplot+=arrow3d(z,c3,color='green') boxplot+=arrow3d(c2,c2+c1,color='red',linestyle='dashed') boxplot+=arrow3d(c3,c3+c1,color='red',linestyle='dashed') boxplot+=arrow3d(c1,c1+c2,color='blue',linestyle='dashed') boxplot+=arrow3d(c3,c3+c2,color='blue',linestyle='dashed') boxplot+=arrow3d(c1,c1+c3,color='green',linestyle='dashed') boxplot+=arrow3d(c2,c2+c3,color='green',linestyle='dashed') evplot=arrow3d(z,z) for i in range(len(EV)): for j in range( len( EV[i][1] ) ): if EV[i][0]==EV[i][0].conjugate(): evplot+=arrow3d(z,EV[i][0]*(EV[i][1][j])/EV[i][1][j].norm(),color='black') evplot+=arrow3d(z,(EV[i][1][j])/EV[i][1][j].norm(),color='purple') evplot+=arrow3d(z,-EV[i][0]*(EV[i][1][j])/EV[i][1][j].norm(),color='black') evplot+=arrow3d(z,-(EV[i][1][j])/EV[i][1][j].norm(),color='purple') var('s,t') r=vector([sin(s)*cos(t),sin(s)*sin(t),cos(s)]) sphereplot=parametric_plot3d(r,(t,0,2*pi),(s,0,pi),opacity=.1) sphereplot+=parametric_plot3d(A*r,(t,0,2*pi),(s,0,pi),opacity=.1) r=1/2 * vector([cos(t)*cos(s)*sin(3*s),sin(t)*cos(s)*sin(3*s), sin(s)*sin(3*s)]) + vector([1/2, 1/2, 1/2]) flower=parametric_plot3d( r, (t, 0,2 *pi), (s,0,2*pi),color='red',opacity=.2) flower+=parametric_plot3d( A*r, (t, 0,2 *pi),(s,0,2*pi),color='red',opacity=.2) p=boxplot+evplot+sphereplot+flower p.show() html.table([["Matrix",A],["Determinant",A.det()],["Eigenvalues and Eigenvectors","Under the table" ]]) EV 
       
Matrix \left(\begin{array}{rrr} 1 & 0 & 0 \\ 0 & 2 & 0 \\ 0 & 1 & 0 \end{array}\right)
Determinant 0
Eigenvalues and Eigenvectors Under the table
[(2, [ (0, 1, 1/2) ], 1), (1, [ (1, 0, 0) ], 1), (0, [ (0, 0, 1) ], 1)]
Matrix \left(\begin{array}{rrr} 1 & 0 & 0 \\ 0 & 2 & 0 \\ 0 & 1 & 0 \end{array}\right)
Determinant 0
Eigenvalues and Eigenvectors Under the table
[(2, [ (0, 1, 1/2) ], 1), (1, [ (1, 0, 0) ], 1), (0, [ (0, 0, 1) ], 1)]