HW 2
HW 2
1 Homework 2
Start by solving Exercises 3.6, 3.15 and 3.17.
Let us start by recalling the code for the LU factorization given in the second tutorial.
[ ]: function LU(A)
n, m = size(A) # A is supposed to be a square matrix, so hopefully n and m␣
↪will be equal.
for k in 1:n
L[k,k] = 1
for i in (k+1):n
L[i,k] = U[i,k]/U[k,k]
U[i,:] = U[i,:] - L[i,k]*U[k,:]
end
end
return L, U
end
1.1 Exercise
Find one matrix 𝐴 ∈ ℝ3×3 , which is invertible and has no diagonal element equal to zero, so that
the function LU(A) fails. You can tell it fails because it will return matrices 𝐿 and 𝑈 for which
some entries are NaN (Not A Number).
1
LU(A)
[ ]: ([1.0 0.0 0.0; 1.0 1.0 0.0; 1.0 NaN 1.0], [1.0 1.0 1.0; 0.0 0.0 0.0; NaN NaN
NaN])
1.2 Exercise
Implement the forward sustitution algorithm to solve 𝐿𝑥 = 𝑦 when 𝐿 is lower triangular.
[ ]: function forward_substitute(L,y)
n, m = size(L)
r, = size(y)
@assert n == m == r
x = copy(y)
x[1] = y[1]/L[1,1]
for i in 2:n
x[i] = (y[i] - sum(L[i,1:i-1].*x[1:i-1]))/L[i,i]
end
return x
end
[ ]: A = [1. 0. 0
1. 1. 0.
1. 1. 1.]
y = [1,2,3]
forward_substitute(A, y)
[ ]: 3-element Vector{Int64}:
1
1
1
1.3 Exercise
Implement the backward sustitution algorithm to solve 𝑈 𝑥 = 𝑦 when 𝑈 is upper triangular.
Suggestion. The range n:-1:1 corresponds to the numbers {𝑛, 𝑛 − 1, 𝑛 − 2, … , 2, 1} in backward
order.
[ ]: function backward_substitute(U,y)
n, m = size(U)
r, = size(y)
@assert n == m == r
2
x = similar(y)
x[n] = y[n]/U[n,n]
for i in (n-1):-1:1
x[i] = (y[i] - sum(U[i,i+1:n].*x[i+1:n]))/U[i,i]
end
return x
end
[ ]: A = [1. 1. 1.
0. 1. 1.
0. 0. 1.]
y = [1., 2., 3.]
backward_substitute(A, y)
2
1
[ ]: 3-element Vector{Float64}:
-1.0
-1.0
3.0
1.4 Exercise
Write a function that solves a linear system 𝐴𝑥 = 𝑓 using Gaussian elimination.
If you want, you can use the LU function above and implement backward substitution. Otherwise,
you can re-implement Gaussian elimination modifying the right-hand side 𝑓 along the way.
[ ]: function solve(A,f)
n, m = size(A)
r, = size(f)
@assert n == m == r
L, U = LU(A)
y = forward_substitute(L,f)
x = backward_substitute(U,y)
return(x)
end
3
[ ]: A = [1. 2. 3.
4. 5. 6.
0. 9. 15.]
y = [1.
2.
4.]
x = solve(A,y)
A*x - y
[ ]: 3-element Vector{Float64}:
-1.1102230246251565e-16
-2.220446049250313e-16
-4.440892098500626e-16
Let us try the algorithm with the Hilbert matrix to see how things can go unexpectedly wrong.
Recall the Hilbert matrix which has a very high condition number
4
2-element Vector{Float64}:
-1.0
1.0
But we wanted to get
2-element Vector{Float64}:
-1.0
1.0
# of round-off arithmetic.
solvewithH(15)
5
1.0
-1.0
Let us now construct the 𝑛2 × 𝑛2 matrix corresponding to the elastic membrane problem that we
discussed in class.
[ ]: function big_matrix(n)
A = zeros(n^2,n^2)
for i in 1:n^2
A[i,i] = 4
if mod(i,n)!=0
A[i+1,i] = -1
A[i,i+1] = -1
end
if i<=n^2-n
A[i,i+n] = -1
A[i+n,i] = -1
end
end
return A
end
Recall that we wanted to make a system 𝐴𝑥 = 𝑦, with the large matrix 𝐴 defined above, in order to
compute the position of all points in an ellastic membrane with a prescripe shape on the boundary.
The right-hand side 𝑦 depends on this boundary value. Let us set it with the following function. It
takes a function 𝑓(𝑥, 𝑦) that determines the vertical displacement of the membrane for any x,y on
the boundary of the unit square. We are discretizing the unit square with points from 0 to N+1
on each side.
This is the function that produces the right-hand side. Don’t worry if you do not understand how
it works.
[ ]: function big_rhs(n, f)
y = zeros(n^2)
for i in 1:n
y[i] += f(i/(n+1),0.)
y[n^2-n+i] += f(i/(n+1),1.)
end
for i in 1:n
y[n*i] += f(1.,i/(n+1))
y[n*i-n+1] += f(0.,i/(n+1))
end
return y
end
6
So, it is time to try it. If everything goes well, the following code should produce a pretty picture
of an elastic membrane as if it was being pulled down on two opposing edges, with the other two
edgest fixed to the boundary.
[ ]: n = 10
y = big_rhs(n,(x,y)->1 - sin(pi*x))
A = big_matrix(n)
x = solve(A,y)
membrane = reshape(x,n,n)
partition = 1/(n+1) : 1/(n+1) : 1-1/(n+1)
using CairoMakie
surface(partition,partition,membrane)
[ ]:
[ ]: n = 40
y = big_rhs(n,(x,y)->1 - sin(pi*x))
A = big_matrix(n)
x = solve(A,y)
membrane = reshape(x,n,n)
partition = 1/(n+1) : 1/(n+1) : 1-1/(n+1)
using CairoMakie
surface(partition,partition,membrane)
7
[ ]:
Try changing the value of 𝑛 for a larger one. The shape should look smoother and more realistic for
large 𝑛. But the computation will also take longer. Eventually it will be too long and you would
not want to wait for it. If we want to solve an equation like this with a very fine mesh, we should
rethink how we solve the linear system.