IntroLinearAlgebra.jl Tutorial

Accompanying this course is a package which is designed to help you with elementary row operations row reducing matrices, and other operations. The package is written in Julia, which is a new (2012) and beautiful scientific programming language which combines speed with convenience and expressiveness. You can use it as a calculation tool without aiming to develop any programming skills, but any skills you do develop along the way are likely to be valuable to you in the future.

My intention is that you use this package to reduce the matrix calculation workload. There will be far more matrices to row reduce in this course than you need to develop that skill, and being able to quickly have arithmetic performed for you will allow you to focus on higher order concepts.

This package provides advantages over other systems. Chiefly, you have direct access to the package developer, and the tools made available to you are tailored to your use case. When you need technical assistance, I will be able to efficiently help you out. Advantages over calculators include improved input and display, as well as support for precision arithmetic (i.e., fractions instead of decimals). Finally, Julia's syntax and programming style are very similar to those of many other popular scientific computing languages, like Python and MATLAB.

Installation and updating

The first step is to install the package. Copy-paste the next command, put it into a cell, and do shift+enter.

In [1]:
Pkg.clone("git://github.com/sswatson/IntroLinearAlgebra.jl.git")
INFO: Initializing package repository /home/juser/.julia/v0.5
INFO: Cloning METADATA from https://github.com/JuliaLang/METADATA.jl
INFO: Cloning IntroLinearAlgebra from git://github.com/sswatson/IntroLinearAlgebra.jl.git
INFO: Computing changes...
INFO: No packages to install, update or remove

To update the package (when changes are introduced, later), run one of the following two lines (the green text after a hashtag is a comment, i.e., it isn't run and is just there to help you understand what's going on):

In [2]:
Pkg.update("IntroLinearAlgebra") # Update just this package
#Pkg.update() # Update all packages
INFO: Updating METADATA...
INFO: Updating IntroLinearAlgebra master...
INFO: Computing changes...
INFO: No packages to install, update or remove

The cloning and updating above need to be done only once and occasionally, respectively. The following one needs to be done for each session. It loads up the package so its functions are available to us.

In [3]:
using IntroLinearAlgebra
INFO: Precompiling module IntroLinearAlgebra.

Doing matrix calculations

We enter matrices in Julia by rows, using spaces to separate entries and semicolons to separate rows. Any fractions, say $\frac{2}{7}$, need to be entered with a double-slash to ensure they're encoded as fractions, like 2//7. Otherwise, the computer uses floating point encoding that it displays as a decimal (like you're used to with a calculator).

In [4]:
M = [1 2 3 4; 5 6 7 8; 9//2 10//2 11//2 12//2]
Out[4]:
$\left[\begin{array}{cccc}1 & 2 & 3 & 4 \\ 5 & 6 & 7 & 8 \\ \frac{9}{2} & 5 & \frac{11}{2} & 6 \\ \end{array}\right]$

We can row reduce with the function rref.

In [5]:
rref(M)
Out[5]:
$\left[\begin{array}{cccc}1 & 0 & -1 & -2 \\ 0 & 1 & \hphantom{-}2 & \hphantom{-}3 \\ 0 & 0 & \hphantom{-}0 & \hphantom{-}0 \\ \end{array}\right]$

Getting help

If we want to do particular row operations, we can do that with the functions rowswitch, rowscale, and rowadd. If we forget how the functions work, we can run ?rowadd (for example) to get the documentation.

In [6]:
?rowadd
search: rowadd

Out[6]:
rowadd(M,i,j,x)

Return matrix obtained by adding x times row j to row i in matrix M

julia> M = [1 2 3; 4 5 6]
julia> rowadd(M,1,2,-1)
2×3 Array{Int64,2}:
 -3  -3  -3
  4   5   6

Performing row operations

Here are some random row operations.

In [7]:
# switch the first and second row, and save the new matrix to the name M
M = rowswitch(M,1,2)
# scale the third row by 3//2 and save 
M = rowswitch(M,3,2)
# Replace the **third** row with itself plus the **first** row times -1//5
M = rowadd(M,3,1,-1//5)
Out[7]:
$\left[\begin{array}{cccc}5 & 6 & 7 & 8 \\ \frac{9}{2} & 5 & \frac{11}{2} & 6 \\ 0 & \frac{4}{5} & \frac{8}{5} & \frac{12}{5} \\ \end{array}\right]$

If you want to drop particular columns, you can do that by indexing the matrix. The way it works is that you do

M[row_instruction,column_instruction]

where the two instructions can be :, which makes take all of them, or just a range like 2:7 which means take the second through the seventh and drop the rest, or a list of true/false values, like [true, true, false, true, false, true] that says exactly which ones you want to keep. Here's an example:

In [8]:
A = M[:,[true,false,true,true]] # drop second column
Out[8]:
$\left[\begin{array}{ccc}5 & 7 & 8 \\ \frac{9}{2} & \frac{11}{2} & 6 \\ 0 & \frac{8}{5} & \frac{12}{5} \\ \end{array}\right]$
In [9]:
B = M[2:3,2:4]
Out[9]:
$\left[\begin{array}{ccc}5 & \frac{11}{2} & 6 \\ \frac{4}{5} & \frac{8}{5} & \frac{12}{5} \\ \end{array}\right]$

That's all you'll need most of the time! The next section is optional: you'll only need it if you want to do matrix manipulations with symbols.

SymPy

If we want to use variables as well as numbers, we need another package.

In [10]:
Pkg.add("SymPy")
INFO: Cloning cache of BaseTestNext from https://github.com/JuliaCI/BaseTestNext.jl.git
INFO: Cloning cache of BinDeps from https://github.com/JuliaLang/BinDeps.jl.git
INFO: Cloning cache of Compat from https://github.com/JuliaLang/Compat.jl.git
INFO: Cloning cache of Conda from https://github.com/JuliaPy/Conda.jl.git
INFO: Cloning cache of JSON from https://github.com/JuliaIO/JSON.jl.git
INFO: Cloning cache of MacroTools from https://github.com/MikeInnes/MacroTools.jl.git
INFO: Cloning cache of PyCall from https://github.com/JuliaPy/PyCall.jl.git
INFO: Cloning cache of RecipesBase from https://github.com/JuliaPlots/RecipesBase.jl.git
INFO: Cloning cache of SHA from https://github.com/staticfloat/SHA.jl.git
INFO: Cloning cache of SymPy from https://github.com/JuliaPy/SymPy.jl.git
INFO: Cloning cache of URIParser from https://github.com/JuliaWeb/URIParser.jl.git
INFO: Installing BaseTestNext v0.2.2
INFO: Installing BinDeps v0.4.7
INFO: Installing Compat v0.23.0
INFO: Installing Conda v0.5.3
INFO: Installing JSON v0.9.0
INFO: Installing MacroTools v0.3.6
INFO: Installing PyCall v1.11.1
INFO: Installing RecipesBase v0.1.0
INFO: Installing SHA v0.3.2
INFO: Installing SymPy v0.5.1
INFO: Installing URIParser v0.1.8
INFO: Building Conda
INFO: Building PyCall
INFO: PyCall is using python (Python 2.7.6) at /usr/bin/python, libpython = libpython2.7
INFO: /home/juser/.julia/v0.5/PyCall/deps/deps.jl has been updated
INFO: /home/juser/.julia/v0.5/PyCall/deps/PYTHON has been updated
INFO: Package database updated

Now we can load SymPy, declare some variables, and get started. The second line is special syntax for telling Julia we want it to treat x, y and z like symbols.

In [11]:
using SymPy
@vars x y z
INFO: Precompiling module SymPy.
WARNING: using SymPy.rref in module Main conflicts with an existing identifier.
Out[11]:
(x,y,z)
In [12]:
M = [1 2 3 x; 4 5 6 y]
Out[12]:
\begin{bmatrix}1&2&3&x\\4&5&6&y\end{bmatrix}
In [13]:
rref(M)
Out[13]:
\begin{bmatrix}1&0&-1&- \frac{5 x}{3} + \frac{2 y}{3}\\0&1&2&\frac{4 x}{3} - \frac{y}{3}\end{bmatrix}

Interact

If you want to see the individual steps of our row reduction algorithm, you can use the Interact package. It's preinstalled on JuliaBox; if you're using a local installation you'd want to run Pkg.add("Interact").

In [14]:
using Interact
In [15]:
steps = rref([1 2 3 4; 5 6 7 8];showsteps=true);
In [16]:
@manipulate for i=1:length(steps)
    steps[i]
end
Out[16]:
$\left[\begin{array}{cccc}1 & \hphantom{-}2 & \hphantom{-}3 & \hphantom{-}4 \\ 0 & -4 & -8 & -12 \\ \end{array}\right]$

Visualizing Transformations

Let's make a movie to visualize how the matrix [0 1; -2 0] acts on the plane. We need the Graphics2D package.

In [17]:
Pkg.clone("git://github.com/sswatson/Graphics2D.jl.git")
INFO: Cloning Graphics2D from git://github.com/sswatson/Graphics2D.jl.git
INFO: Computing changes...
INFO: Cloning cache of Cairo from https://github.com/JuliaGraphics/Cairo.jl.git
INFO: Cloning cache of ColorTypes from https://github.com/JuliaGraphics/ColorTypes.jl.git
INFO: Cloning cache of Colors from https://github.com/JuliaGraphics/Colors.jl.git
INFO: Cloning cache of FixedPointNumbers from https://github.com/JuliaMath/FixedPointNumbers.jl.git
INFO: Cloning cache of Graphics from https://github.com/JuliaGraphics/Graphics.jl.git
INFO: Cloning cache of NaNMath from https://github.com/mlubin/NaNMath.jl.git
INFO: Cloning cache of Reexport from https://github.com/simonster/Reexport.jl.git
INFO: Installing Cairo v0.3.0
INFO: Installing ColorTypes v0.4.0
INFO: Installing Colors v0.7.3
INFO: Installing FixedPointNumbers v0.3.6
INFO: Installing Graphics v0.2.0
INFO: Installing NaNMath v0.2.4
INFO: Installing Reexport v0.0.3
INFO: Building Cairo
In [18]:
using IntroLinearAlgebra
using Interact
movie = transformation_movie([0 1; -2 0]);
@manipulate for i=1:length(movie)
    movie[i]
end
INFO: Precompiling module Graphics2D.
Out[18]:

Eigenspaces

In [19]:
A = [1 5; 6 2]
Out[19]:
$\left[\begin{array}{cc}1 & 5 \\ 6 & 2 \\ \end{array}\right]$
In [20]:
eigenspaces(A)
Out[20]:
$$\begin{bmatrix}\mathrm{eigenspace}\left(λ = -4, \mathrm{mult} = 1, \mathrm{Col}\left(\begin{bmatrix}-1\\1\end{bmatrix}\right)\right)\\\mathrm{eigenspace}\left(λ = 7, \mathrm{mult} = 1, \mathrm{Col}\left(\begin{bmatrix}\frac{5}{6}\\1\end{bmatrix}\right)\right)\\\end{bmatrix}$$
In [ ]: