Notebook 1 – Math 2121, Fall 2020
This is a Pluto notebook, using the Julia programming language.
Julia is at the cutting edge of programming languages for scientific computing.
It combines many of the best features of Matlab and Python but is also very fast. The language has a lot of built-in functions that will be useful for demonstrating concepts in Math 2121.
xxxxxxxxxx
md"# Notebook 1 -- Math 2121, Fall 2020
Installing Pluto (optional)
Pluto is an interactive notebook for running Julia code.
You can access this notebook as a static HTML page on our course website. But if you install Julia and Pluto on your home computer, then you can also modify and run the code here yourself.
I can't improve upon the instructions at this link for installing both:
xxxxxxxxxx
md"## Installing Pluto (optional)
Running this Pluto notebook
Once you have Pluto up and running, you can access the notebook you we are currently viewing by entering this link (right click -> Copy Link) in the Open from file menu in Pluto.
xxxxxxxxxx
md"## Running *this* Pluto notebook
Working with matrices
The syntax for working with matrices in Julia is much like Matlab.
xxxxxxxxxx
md"## Working with matrices
3×5 Array{Int64,2}:
1 2 3 0 6
4 1 6 -1 8
7 8 1 2 200
xxxxxxxxxx
# constructs a 3-by-5 matrix called Y
Y = [1 2 3 0 6; 4 1 6 -1 8; 7 8 1 2 200]
-1
xxxxxxxxxx
# access entries in a matrix
Y[2, 4]
Make it interactive
row_index
=
col_index
=
xxxxxxxxxx
begin
3×5 Array{Int64,2}:
1 2 3 0 6
4 1 6 -1 8
7 8 1 2 200
xxxxxxxxxx
# here is Y again
Y
1
xxxxxxxxxx
Y[row_index, col_index]
xxxxxxxxxx
# we can also set entries in a matrix
Y[2, 4] = 60;
3×5 Array{Int64,2}:
1 2 3 0 6
4 1 6 60 8
7 8 1 2 200
xxxxxxxxxx
# this changes Y to be this matrix
Y
2×2 Array{Int64,2}:
3 0
6 60
xxxxxxxxxx
# create a submatrix, the slice notation is inclusive
Y[1:2,3:4]
1×2 Array{Int64,2}:
3 0
xxxxxxxxxx
Y[1:1,3:4]
3×1 Array{Int64,2}:
0
60
2
xxxxxxxxxx
Y[1:3,4:4]
3
5
xxxxxxxxxx
# we can get the dimensions of a matrix this way
(m, n) = size(Y)
3×4 Array{Float64,2}:
1.1 2.2 3.0 0.0
3.141592653589793 2.23606797749979 6.0 -1.0
7.0 8.0 1.0 2.0
xxxxxxxxxx
# we can also create matrices with non-integer entries
Z = [1.1 2.2 3 0; pi sqrt(5) 6 -1; 7 8 1 2]
Later in the course we will see many other operations involving matrices. Most of these will also be easily available in the Julia programming language.
xxxxxxxxxx
md"Later in the course we will see many other operations involving matrices. Most of these will also be easily available in the Julia programming language."
Augmented matrices
We can write our own functions to work with matrices.
(This requires some programming background, however.)
xxxxxxxxxx
md"## Augmented matrices
The next cell implements a function called print_linear_system
which takes a single input parameter. You can probably guess what it does.
(To see the code, click the Show/Hide icon on the left.)
xxxxxxxxxx
md"The next cell implements a function called `print_linear_system` which takes a single input parameter. You can probably guess what it does.
print_linear_system (generic function with 1 method)
xxxxxxxxxx
begin
x_1 + 2 x_2 + 3 x_3 = 6
4 x_1 + x_2 + 6 x_3 + 60 x_4 = 8
7 x_1 + 8 x_2 + x_3 + 2 x_4 = 200
xxxxxxxxxx
# prints something that looks like the linear system whose augmented matrix is Y
print_linear_system(Y)
0 = 0
0 = 60
0 = 2
xxxxxxxxxx
# what happens if Y has only one column?
print_linear_system(Y[1:3,4:4])
4 x_1 + x_2 + 6 x_3 = 60
7 x_1 + 8 x_2 + x_3 = 2
xxxxxxxxxx
# how about two rows
print_linear_system(Y[2:3,1:4])
Here's another function (code hidden) that returns true or false depending on whether a given list s is a solution to the linear system with augemented matrix A
xxxxxxxxxx
md"Here's another function (code hidden) that returns **true** or **false** depending on whether a given list **s** is a solution to the linear system with augemented matrix **A**"
is_solution (generic function with 2 methods)
xxxxxxxxxx
function is_solution(A, s, tolerance=10e-16)
3×4 Array{Int64,2}:
1 -2 1 0
0 2 -8 8
5 0 -5 10
xxxxxxxxxx
# we saw this matrix in lecture
T = [1 -2 1 0; 0 2 -8 8; 5 0 -5 10]
x_1 - 2 x_2 + x_3 = 0
2 x_2 - 8 x_3 = 8
5 x_1 - 5 x_3 = 10
xxxxxxxxxx
print_linear_system(T)
3×4 Array{Int64,2}:
1 -2 1 0
0 1 -4 4
0 0 1 -1
xxxxxxxxxx
# T is row equivalent to this triangular matrix
U = [1 -2 1 0; 0 1 -4 4; 0 0 1 -1]
x_1 - 2 x_2 + x_3 = 0
x_2 - 4 x_3 = 4
x_3 = -1
xxxxxxxxxx
print_linear_system(U)
true
xxxxxxxxxx
is_solution(U, [1; 0; -1])
true
xxxxxxxxxx
is_solution(T, [1; 0; -1])
Row operations
A handy feature of these notebooks is that we can very easily explore different ranges of inputs and parameters. Let's try this out with our elementary row operations.
xxxxxxxxxx
md"## Row operations
Set some parameters
a =
d =
g =
xxxxxxxxxx
begin
3×4 Array{Int64,2}:
1 2 3 -1
0 0 0 -2
3 8 12 0
xxxxxxxxxx
# now define a matrix with these parameters
A = [a b c p; d e f q; g h i r]
x_1 + 2 x_2 + 3 x_3 = -1
0 = -2
3 x_1 + 8 x_2 + 12 x_3 = 0
xxxxxxxxxx
# here's the linear system
print_linear_system(A)
Below are functions implementing our three row operations. Their syntax is:
rowop_replace(A, i, j, v)
: addsv
times rowi
in matrixA
to rowj
rowop_scale(A, i, v)
: multiplies rowi
in matrixA
by nonzero constantv
rowop_swap(A, i, j)
: swaps rowsi
andj
in matrixA
Each function returns a new matrix without modifying the matrix A.
xxxxxxxxxx
md"Below are functions implementing our three row operations. Their syntax is:
rowop_replace (generic function with 1 method)
xxxxxxxxxx
function rowop_replace(A, source_row, target_row, scalar_factor)
source_row != target_row
A = copy(A)
(m, n) = size(A)
for j=1:n
A[target_row,j] += A[source_row,j] * scalar_factor
end
A
end
rowop_scale (generic function with 1 method)
xxxxxxxxxx
function rowop_scale(A, target_row, scalar_factor)
scalar_factor != 0
A = copy(A)
(m, n) = size(A)
for j=1:n
A[target_row,j] *= scalar_factor
end
A
end
rowop_swap (generic function with 1 method)
xxxxxxxxxx
function rowop_swap(A, source_row, target_row)
A = copy(A)
(m, n) = size(A)
for j=1:n
A[target_row,j], A[source_row,j] = A[source_row,j], A[target_row,j]
end
A
end
Another parameter
v =
xxxxxxxxxx
begin
md"""**Another parameter**
v = $(@bind v Slider(-30:30, default=1, show_value=true))"""
end
3×4 Array{Int64,2}:
1 2 3 -1
0 0 0 -2
3 8 12 0
xxxxxxxxxx
# our original matrix
A
3×4 Array{Int64,2}:
1 2 3 -1
0 0 0 -2
4 10 15 -1
xxxxxxxxxx
# add v * row 1 to row 3
rowop_replace(A, 1, 3, v)
true
xxxxxxxxxx
# this row operation can be reversed
rowop_replace(rowop_replace(A, 1, 3, v), 1, 3, -v) == A
3×4 Array{Int64,2}:
1 2 3 -1
0 0 0 -2
3 8 12 0
xxxxxxxxxx
rowop_scale(A, 3, v)
true
xxxxxxxxxx
# also can be reversed
rowop_scale(rowop_scale(A, 3, v), 3, 1/v) == A
3×4 Array{Int64,2}:
1 2 3 -1
3 8 12 0
0 0 0 -2
xxxxxxxxxx
rowop_swap(A, 2, 3)
true
xxxxxxxxxx
# doing this one twice undoes everything
rowop_swap(rowop_swap(A, 2, 3), 2, 3) == A
Solving a linear system by row operations
By applying a sequence of row operations, we can transform the augmented matrix of a linear system to a simpler matrix, whose associated system has the same solutions as the one we started with.
xxxxxxxxxx
md"## Solving a linear system by row operations
3×4 Array{Int64,2}:
1 2 3 -1
0 9 0 -2
3 8 12 0
xxxxxxxxxx
M = [1 2 3 -1; 0 9 0 -2; 3 8 12 0]
x_1 + 2 x_2 + 3 x_3 = -1
9 x_2 = -2
3 x_1 + 8 x_2 + 12 x_3 = 0
xxxxxxxxxx
print_linear_system(M)
3×4 Array{Int64,2}:
1 2 3 -1
0 9 0 -2
0 2 3 3
xxxxxxxxxx
B = rowop_replace(M, 1, 3, -3)
3×4 Array{Int64,2}:
1 0 0 -4
0 9 0 -2
0 2 3 3
xxxxxxxxxx
C = rowop_replace(B, 3, 1, -1)
3×4 Array{Int64,2}:
1 0 0 -4
0 1 -12 -14
0 2 3 3
xxxxxxxxxx
D = rowop_replace(C, 3, 2, -4)
3×4 Array{Int64,2}:
1 0 0 -4
0 1 -12 -14
0 0 27 31
xxxxxxxxxx
E = rowop_replace(D, 2, 3, -2)
xxxxxxxxxx
# we would get an error here
# rowop_scale(E, 3, 1/27)
3×4 Array{Float64,2}:
1.0 0.0 0.0 -4.0
0.0 1.0 -12.0 -14.0
0.0 0.0 27.0 31.0
xxxxxxxxxx
# to avoid this we need to cast the matrix E to be a matrix of floating point numbers
F = float(E)
3×4 Array{Float64,2}:
1.0 0.0 0.0 -4.0
0.0 1.0 -12.0 -14.0
0.0 0.0 1.0 1.1481481481481481
xxxxxxxxxx
G = rowop_scale(F, 3, 1/27)
3×4 Array{Float64,2}:
1.0 0.0 0.0 -4.0
0.0 1.0 0.0 -0.22222222222222143
0.0 0.0 1.0 1.1481481481481481
xxxxxxxxxx
H = rowop_replace(G, 3, 2, 12)
x_1 = -4.0
x_2 = -0.22222222222222143
x_3 = 1.1481481481481481
xxxxxxxxxx
# our final matrix corresponds to a trivial linear system
print_linear_system(H)
-4.0
-0.222222
1.14815
xxxxxxxxxx
sol = H[1:3, 4]
true
xxxxxxxxxx
# this definitely should be a solution to the linear system of H
is_solution(H, sol)
true
xxxxxxxxxx
# as noted in class, it's also a solution to the linear system of M
is_solution(M, sol)