I am trying to implement the below description from Ch. 11 of Heath's "Scientific Computing An Introductory Survey" of the Gauss-Seidel iterative method for solving a system of linear equations
however, I must be missing something because writing the equation exactly as is fails to produce the correct results. Please help!
using LinearAlgebra: lu
# From dicretization of Laplace equation
A = [
4.0 -1.0 -1.0 0.0
-1.0 4.0 0.0 -1.0
-1.0 0.0 4.0 -1.0
0.0 -1.0 -1.0 4.0]
# block diagonal matrix of A
D = [
4.0 -1.0 0.0 0.0
-1.0 4.0 0.0 0.0
0.0 0.0 4.0 -1.0
0.0 0.0 -1.0 4.0]
b = [0, 0, 1, 1] # rhs for laplace w/ Dirichlet boundary conditions
L, U = lu(A)
# gauss seidel using matrix terms
niters = 100
D_plus_L_inv = inv(D + L)
x = zeros(length(b))
for k in 1:niters
x = D_plus_L_inv*(b - U*x)
end
# clearly not equal
@show A \ b
# A \ b = [0.12499999999999999, 0.12499999999999999, #0.37499999999999994, 0.37499999999999994]
@show x
# x = [0.021795262674411238, 0.023610129063946845, 0.14893710589872386, 0.14211027447080438]
Per @Ian Bush comments, I was misinterpreting what L, U, and D were in the equations. L and U are strict lower and upper triangular matrices of A, while D is the diagonal entries of A. Here is the corrected function matching the described equation (even though computing the inverse D + L may not be done in practice).
using LinearAlgebra
"""
gauss_seidel_matrix_form_solver(
A_::Matrix, b::Vector, x0::Vector, niters::Int)
Return solution to linear system `Ax = b` via matrix Gauss-Seidel method.
# References
[1] : Ch. 11.5.3 Heath.
"""
function gauss_seidel_matrix_form_solver(
A_::Matrix, b::Vector, x0::Vector, niters::Int)
A = copy(A_)
# Get diagonal entries of A, store in matrix
D_vec = diag(A)
D = Diagonal(D_vec) # diagm(D_vec)
# Get the strict lower and upper triangular matrices
L = LowerTriangular(A)
L[diagind(L)] .= 0
U = UpperTriangular(A)
# Compute the inverse of D + L ahead of time
D_plus_L_inv = inv(D + L)
# initialize the guess
x = x0
# gauss seidel iterations
for k in 1:niters
x = D_plus_L_inv*(b - U*x)
end
return x
end
A = [
4.0 -1.0 -1.0 0.0
-1.0 4.0 0.0 -1.0
-1.0 0.0 4.0 -1.0
0.0 -1.0 -1.0 4.0]
b = [0, 0, 1, 1]
u_gs = gauss_seidel_matrix_form_solver(A, b, zeros(length(b)), 100)
u_builtin = A \ b
@show u_gs
# u_gs = [0.125, 0.125, 0.375, 0.375]
@show u_builtin
# u_builtin = [0.12499999999999999, 0.12499999999999999, 0.37499999999999994, 0.37499999999999994]