07 In-Class Assignment: Transformations#


1. Review of Pre-Class Assignment#

  • View multiplication by \(A\) as a function from \(\mathbb R^n\) to \(\mathbb R^n\) and \(A^{-1}\) (if it exists) as it inverse function.

  • When might \(A^{-1}\) not exist for a given square matrix?

    • row picture and a row that is a linear combination of the rest (what does this mean about the corresponding linear equations, depending on the right hand side?)

    • column picture and a column that is a linear combination of the rest (what does this mean about being able to represent a given vector \(b\) as a linear combination of the columns?)

  • Calculating \(A^{-1}\) by Gauss-Jordan Elimination using Augmented Matrix \([A | I] = [A |e_1 e_2 e_3]\) (if working in \(\mathbb R^3\))

    • Provide an example how we transform this to \([I | A^{-1}]\) and explain how then \(A^{-1}\) is the product of elementary matrices.


2. Calculating an Inverse Matrix#

DO THIS: Consider the matrix \(A\) given by $\( A=\left[ \begin{array}{rrr} 2 & -1 & 0\\ -1 & 2 & -1\\ 0 & -1 & 2 \end{array} \right]. \)$

Use the Gauss-Jordan Elimination to find \(A^{-1}\) by row reducing \(\begin{bmatrix}A | I\end{bmatrix}\) to \(\begin{bmatrix}I | A^{-1}\end{bmatrix}\). The first step is

\[\begin{split} \left[ \begin{array}{rrr|rrr} 2 & -1 & 0& 1 & 0 &0 \\ -1 & 2 & -1 & 0 & 1 &0 \\ 0 & -1 & 2 & 0 & 0 &1 \end{array} \right] \end{split}\]

\(\frac{1}{2}\) (row 1) + (row 2) - what is the corresponding elementary matrix \(E_1\)? $\( \left[ \begin{array}{rrr|rrr} 2 & -1 & 0& 1 & 0 &0 \\ 0 & \frac{3}{2} & 0 & \frac{1}{2} & 1 &0 \\ 0 & -1 & 2 & 0 & 0 &1 \end{array} \right] \)\( Complete the rest of the steps to find \)A^{-1}\( by hand (on paper) and compare your result with Python's \)A^{-1}$.

Put your result for \(A^{-1}\) when working by hand: $\( A^{-1}=\left[ \begin{array}{rrr} a & b & c\\ d & e & f\\ g & h & i \end{array} \right]. \)$

## Use Python code to find A^{-1}

3. Affine Transforms#

In this section, we are going to explore different types of transformation matrices. The following code is designed to demonstrate the properties of some different transformation matrices.

DO THIS: Review the following code.

#Some python packages we will be using
%matplotlib inline
import numpy as np
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D # Lets make 3D plots
import numpy as np
import sympy as sym
sym.init_printing(use_unicode=True) # Trick to make matrixes look nice in jupyter
# Define some points
x = [0.0,  0.0,  2.0,  8.0, 10.0, 10.0, 8.0, 4.0, 3.0, 3.0, 4.0, 6.0, 7.0, 7.0, 10.0, 
     10.0,  8.0,  2.0, 0.0, 0.0, 2.0, 6.0, 7.0,  7.0,  6.0,  4.0,  3.0, 3.0, 0.0]
y = [0.0, -2.0, -4.0, -4.0, -2.0,  2.0, 4.0, 4.0, 5.0, 7.0, 8.0, 8.0, 7.0, 6.0,  6.0,
     8.0, 10.0, 10.0, 8.0, 4.0, 2.0, 2.0, 1.0, -1.0, -2.0, -2.0, -1.0, 0.0, 0.0]
con = [ 1.0 for i in range(len(x))] 

p = np.matrix([x,y,con])


mp = p.copy()

#Plot Points
plt.plot(mp[0,:].tolist()[0],mp[1,:].tolist()[0], color='green');
plt.axis('scaled');
plt.axis([-10,20,-15,15]);
plt.title('Start Location');

Example Scaling Matrix#

#Example Scaling Matrix

#Define Matrix
scale = 0.5  #The amount that coordinates are scaled.
S = np.matrix([[scale,0,0], [0,scale,0], [0,0,1]])

#Apply matrix

mp = p.copy()
mp = S*mp

#Plot points after transform
plt.plot(mp[0,:].tolist()[0],mp[1,:].tolist()[0], color='green')
plt.axis('scaled')
plt.axis([-10,20,-15,15])
plt.title('After Scaling')
#plt.plot([p[0,14],mp[0,14]],[p[1,14],mp[1,14]], color='blue');

#Uncomment the next line if you want to see the original.
# plt.plot(p[0,:].tolist()[0],p[1,:].tolist()[0], color='blue',alpha=0.3);

sym.Matrix(S)

Example Translation Matrix#

#Example Translation Matrix

#Define Matrix
dx = 10  #The amount shifted in the x-direction
dy = -5 #The amount shifted in the y-direction
T = np.matrix([[1,0,dx], [0,1,dy], [0,0,1]])

#Apply matrix

mp = p.copy()

mp = T*mp

#Plot points after transform
plt.plot(mp[0,:].tolist()[0],mp[1,:].tolist()[0], color='green')
plt.axis('scaled')
plt.axis([-10,20,-15,15])
plt.title('After Translation')

#Uncomment the next line if you want to see the original.
# plt.plot(p[0,:].tolist()[0],p[1,:].tolist()[0], color='blue',alpha=0.3);

sym.Matrix(T)

Example Reflection Matrix#

#Example Reflection Matrix

#Define Matrix
Re = np.matrix([[1,0,0],[0,-1,0],[0,0,1]]) ## Makes all y-values opposite so it reflects over the x-axis.

#Apply matrix

mp = p.copy()

mp = Re*mp

#Plot points after transform
plt.plot(mp[0,:].tolist()[0],mp[1,:].tolist()[0], color='green')
plt.axis('scaled')
plt.axis([-10,20,-15,15])
plt.title('After Reflection Along x-axis')


#Uncomment the next line if you want to see the original.
# plt.plot(p[0,:].tolist()[0],p[1,:].tolist()[0], color='blue',alpha=0.3);

sym.Matrix(Re)

Example Rotation Matrix#

#Example Rotation Matrix

#Define Matrix
degrees = 30
theta = degrees * np.pi / 180  ##Make sure to always convert from degrees to radians. 

# Rotates the points 30 degrees counterclockwise.
R = np.matrix([[np.cos(theta),-np.sin(theta),0],[np.sin(theta), np.cos(theta),0],[0,0,1]]) 

#Apply matrix
mp = p.copy()

mp = R*mp

#Plot points after transform
plt.plot(mp[0,:].tolist()[0],mp[1,:].tolist()[0], color='green')
plt.axis('scaled')
plt.axis([-10,20,-15,15])
plt.title('After Rotation')

#Uncomment the next line if you want to see the original.
# plt.plot(p[0,:].tolist()[0],p[1,:].tolist()[0], color='blue',alpha=0.3);

sym.Matrix(R)

Example Shear Matrix#

#Example Shear Matrix

#Define Matrix
shx=0.5 # shear in the x-direction
SHx =   np.matrix([[1,shx,0], [0,1,0], [0,0,1]])

#Apply matrix
mp = p.copy()

mp = SHx*mp

#Plot points after transform
plt.plot(mp[0,:].tolist()[0],mp[1,:].tolist()[0], color='green')
plt.axis('scaled')
plt.axis([-10,20,-15,15])
plt.title('After Shear along x-axis')

#Uncomment the next line if you want to see the original.
# plt.plot(p[0,:].tolist()[0],p[1,:].tolist()[0], color='blue',alpha=0.3);

sym.Matrix(SHx)
#Example Shear Matrix

#Define Matrix
shy=0.3 #shear in the y-direction
SHy =   np.matrix([[1,0,0], [shy,1,0], [0,0,1]])

#Apply matrix
mp = p.copy()

mp = SHy*mp

#Plot points after transform
plt.plot(mp[0,:].tolist()[0],mp[1,:].tolist()[0], color='green')
plt.axis('scaled')
plt.axis([-10,20,-15,15])
plt.title('After Shear along y-axis')

#Uncomment the next line if you want to see the original.
# plt.plot(p[0,:].tolist()[0],p[1,:].tolist()[0], color='blue',alpha=0.3);

sym.Matrix(SHy)

DO THIS: Experiment with different values of shx and shy to see their effect.

Combine Transforms#

We have six transforms R, S, T, Re, SHx, and SHy.

DO THIS: Construct a (\(3 \times 3\)) transformation Matrix (called M) which combines these six transforms into a single matrix. You can choose different orders for these six matrices, then compare your result with other students.

#Put your code here
#Plot combined transformed points
mp = p.copy()
mp = M*mp
plt.plot(mp[0,:].tolist()[0],mp[1,:].tolist()[0], color='green');
plt.axis('scaled');
plt.axis([-10,20,-15,15]);
plt.title('Start Location');

Questions: Did you can get the same result with others? You can compare the matrix M to see the difference. If not, can you explain why it happens?

Put your answer here

Interactive Example#

from ipywidgets import interact,interact_manual

def affine_image(angle=0.0,scale=1.0,dx=0,dy=0, shx=0, shy=0):
    theta = -angle/180  * np.pi
    
    plt.plot(p[0,:].tolist()[0],p[1,:].tolist()[0], color='green')
    
    S = np.matrix([[scale,0,0], [0,scale,0], [0,0,1]])
    SH1 = np.matrix([[1,shx,0], [0,1,0], [0,0,1]])
    SH2 = np.matrix([[1,0,0], [shy,1,0], [0,0,1]])
    T = np.matrix([[1,0,dx], [0,1,dy], [0,0,1]])
    R = np.matrix([[np.cos(theta),-np.sin(theta),0],[np.sin(theta), np.cos(theta),0],[0,0,1]])
    
    #Full Transform
    FT = T*SH2*SH1*R*S;
    #Apply Transforms
    p2 =  FT*p;
    
    #Plot Output
    plt.plot(p2[0,:].tolist()[0],p2[1,:].tolist()[0], color='black')
    plt.axis('equal')
    plt.axis([-20,30,-15,15])
    return sym.Matrix(FT)
interact(affine_image, angle=(-180,180), scale_manual=(0.01,2), dx=(-5,15,0.5), dy=(-15,15,0.5), shx = (-1,1,0.1), shy = (-1,1,0.1)); ##TODO: Modify this line of code

The following command can also be used but it may be slow on some peoples computers.

interact(affine_image, angle=(-180,180), scale=(0.01,2), dx=(-5,15,0.5), dy=(-15,15,0.5), shx = (-1,1,0.1), shy = (-1,1,0.1)); ##TODO: Modify this line of code

DO THIS: Using the above interactive enviornment to see if you can figure out the transformation matrix to make the following image:

Questions: What where the input values?

Put your answer here:

r =

scale =

dx =

dy =

shx =

shy =


3. Fractals#

In this section we are going to explore using transformations to generate fractals. Consider the following set of linear equations. Each one takes a 2D point as input, applies a \(2 \times 2\) transform, and then also translates by a \(2 \times 1\) translation matrix

\[\begin{split} T_1:\left[ \begin{matrix} x_1 \\ y_1 \end{matrix} \right] = \left[ \begin{matrix} 0.86 & 0.03 \\ -0.03 & 0.86 \end{matrix} \right] \left[ \begin{matrix} x_0 \\ y_0 \end{matrix} \right] + \left[\begin{matrix} 0\\ 1.5 \end{matrix} \right] : probability = 0.83 \end{split}\]
\[\begin{split} T_2: \left[ \begin{matrix} x_1 \\ y_1 \end{matrix} \right] = \left[ \begin{matrix} 0.2 & -0.25 \\ 0.21 & 0.23 \end{matrix} \right] \left[ \begin{matrix} x_0 \\ y_0 \end{matrix} \right] + \left[\begin{matrix} 0\\ 1.5 \end{matrix} \right] : probability = 0.08 \end{split}\]
\[\begin{split} T_3 : \left[ \begin{matrix} x_1 \\ y_1 \end{matrix} \right] = \left[ \begin{matrix} 0.15 & 0.27 \\ 0.25 & 0.26 \end{matrix} \right] \left[ \begin{matrix} x_0 \\ y_0 \end{matrix} \right] + \left[\begin{matrix} 0\\ 0.45 \end{matrix} \right] : probability = 0.08 \end{split}\]
\[\begin{split} T_4: \left[ \begin{matrix} x_1 \\ y_1 \end{matrix} \right] = \left[ \begin{matrix} 0 & 0 \\ 0 & 0.17 \end{matrix} \right] \left[ \begin{matrix} x_0 \\ y_0 \end{matrix} \right] + \left[\begin{matrix} 0\\ 0 \end{matrix} \right] : probability = 0.01 \end{split}\]

We want to write a program that uses the above transformations to “randomly” generate an image. We start with a point at the origin (0,0) and then randomly pick one of the above transformation based on their probabilities, update the point position and then randomly pick another point. Each matrix adds a bit of rotation and translation with \(T_4\) as a kind of restart.

To try to make our program a little easier, let’s rewrite the above equations to make a system of “equivalent” equations of the form \(Ax=b\) with only one matrix. We do this by adding an additional variable variable \(z=1\). For example, verify that the following equation is the same as equation for \(T_1\) above:

\[\begin{split} T_1: \left[ \begin{matrix} x_1 \\ y_1 \end{matrix} \right] = \left[ \begin{matrix} 0.86 & 0.03 & 0 \\ -0.03 & 0.86 & 1.5 \end{matrix} \right] \left[ \begin{matrix} x_0 \\ y_0 \\ 1 \end{matrix} \right] \end{split}\]

Please NOTE that we do not change the value for \(z\), and it is always be \(1\).

DO THIS: Verify that the \(Ax=b\) format will generate the same answer as the \(T_1\) equation above.

The following is some pseudocode that we will be using to generate the Fractals:

  1. Let \(x = 0\), \(y = 0\), \(z=1\)

  2. Use a random generator to select one of the affine transformations \(T_i\) according to the given probabilities.

  3. Let \((x',y') = T_i(x,y,z)\).

  4. Plot \((x', y')\)

  5. Let \((x,y) = (x',y')\)

  6. Repeat Steps 2, 3, 4, and 5 one thousand times.

The following python code implements the above pseudocode with only the \(T_1\) matrix:

%matplotlib inline

import numpy as np
import matplotlib.pylab as plt
import sympy as sym
sym.init_printing(use_unicode=True) # Trick to make matrixes look nice in jupyter

T1 = np.matrix([[0.86, 0.03, 0],[-0.03, 0.86, 1.5]])
#####Start your code here #####
T2 = T1 
T3 = T1
T4 = T1
#####End of your code here#####       

prob = [0.83,0.08,0.08,0.01]

I = np.matrix([[1,0,0],[0,1,0],[0,0,1]])

fig = plt.figure(figsize=[10,10])
p = np.matrix([[0.],[0],[1]])
plt.plot(p[0],p[1], 'go');
for i in range(1,1000):
    ticket = np.random.random();
    if (ticket < prob[0]):
        T = T1
    elif (ticket < sum(prob[0:2])):
        T = T2
    elif (ticket < sum(prob[0:3])):
        T = T3
    else:
        T = T4
    p[0:2,0] = T*p    
    plt.plot(p[0],p[1], 'go');
plt.axis('scaled');

DO THIS: Modify the above code to add in the \(T_2\), \(T_3\) and \(T_4\) transforms.

QUESTION: Describe in words for the actions performed by \(T_1\), \(T_2\), \(T_3\), and \(T_4\).

\(T_1\): Put your answer here

\(T_2\): Put your answer here

\(T_3\): Put your answer here

\(T_4\): Put your answer here

DO THIS: Using the same ideas to design and build your own fractal. You are welcome to get inspiration from the internet. Make sure you document where your inspiration comes from. Try to build something fun, unique and different. Show what you come up with with your instructors.

#Put your code here. 

Written by Dr. Dirk Colbry, Michigan State University Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.

###STARTFOOTER###


Congratulations, we’re done!#