Iterative method to solve linear system
Note: Most of the code are copied from others. Not wrtitten by me.
[]: https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/	“Julia docs”
[]: https://jermwatt.github.io/machine_learning_refined/notes/16_Linear_algebra/16_5_Norms.html	“norm”
Prerequisite
Norms of Vectors and Matrices


Examples





Matrix norm:

Calculate the norm:
using LinearAlgebra
A = ##input matrix/vector
println(norm(A))
Eigenvalues and Eigenvectors => Spectral radius


Jacobi method
See: https://www.foopiew.com/spectral-radius-jacobi-method/
Pre: determine the spectral radius
using LinearAlgebra
A = [4 1 2; 3 5 1; 1 1 3];
D = Diagonal(A); # Diagonal matrix
R = A - D; # Off-diagonal matrix
G = -inv(D)*R; # Iteration matrix
eigenvalues=eigvals(G) # Compute the eigenvalues
spectral_radius = maximum(abs.(eigenvalues)) # Compute the spectral radius
println("Spectral Radius: ", spectral_radius)
Solve
using LinearAlgebra
using Plots
# ==============================
# Jacobi linear solver algorithm
# ==============================
function jacobi_solve(A::Matrix{Float64}, b::Vector{Float64}, 
    x0::Vector{Float64}, tol::Float64,
    zeroTolerance::Float64, max_iters::Int)
    
    # Number of unknowns
    # ------------------
    n = length(b)
    
    # Check for near-zero diagonal entries
    # ------------------------------------
    if any(abs.(diag(A)) .< zeroTolerance)
        error("Near-zero diagonal entry found in the matrix.")
    end
    # Solution vector initialisation
    # ------------------------------
    x = copy(x0)
    x_new = zeros(n)
    # Plot vector initialisation
    # --------------------------
    errors = Float64[]
    
    # Perform iteration
    # -----------------
    for iter = 1:max_iters
        # Loop rows
        for i = 1:n
            x_new[i] = (b[i] - dot(A[i, :], x) + A[i, i] * x[i]) / A[i, i]
        end
        
        # Evaluate error
        err = norm(x_new - x)
        push!(errors, err)  # Store the current error
        # Check for convergence
        if err < tol
            return x_new, iter, errors
        end
        # Update the solution vector
        x .= x_new
    end
    
    error("Maximum number of iterations reached without convergence.")
end
# =============
# Problem setup
# =============
# A = [4.0 1.0 2.0; 3.0 5.0 1.0; 1.0 1.0 3.0]
# b = [1.0; -2.0; 0.0]
## the following matrix is from the turorial 
A = [3.0 1.0 -1.0; 2.0 4.0 1.0; -1.0 2.0 5.0];
b = [4.0; 1.0; 1.0]
x0 = zeros(length(b)) # Initial guess for solution vector 
# ==================
# Numerical settings
# ==================
tolerance = 1E-8
zeroTolerance = 1E-12
iterMax = 500
# =====
# Solve
# =====
try
    x, niter, errors = jacobi_solve(A, b, x0, tolerance, zeroTolerance, iterMax)
    println("Converged in $niter iterations. Solution: $x")
    # Plotting error vs iteration number
    plot(1:niter, errors, yscale=:log10, xlabel="Iteration Number", ylabel="Error (log scale)", title="Convergence of Jacobi Method", legend=false, line=:line, marker=:circle)
    
catch error
    println(error)
end
Gauss Seidel method
See:https://www.foopiew.com/linear-solver-gauss-seidel-method/
Pre: determine the spectral radius
## for computing the spectral radius
using LinearAlgebra
A = [4 1 2; 3 5 1; 1 1 3];
D = Diagonal(A); # Diagonal part
L = tril(A, -1); # Strictly lower triangle part
U = triu(A, 1); # Strictly upper triangle part
G = -inv(L+D)*U; # Iteration Matrix
eigenvalues=eigvals(G) # Compute the eigenvalues
spectral_radius = maximum(abs.(eigenvalues)) # Compute the spectral radius
println("Spectral Radius: ", spectral_radius)
Solve
using LinearAlgebra
using Plots
# ====================================
# Gauss-Seidel linear solver algorithm
# ====================================
function gauss_seidel_solve(A::Matrix{Float64}, b::Vector{Float64}, x0::Vector{Float64}, tol::Float64, zeroTolerance::Float64, max_iters::Int)
    
    # Number of unknowns
    # ------------------
    n = length(b)
    
    # Check for near-zero diagonal entries
    # ------------------------------------
    if any(abs.(diag(A)) .< zeroTolerance)
        error("Near-zero diagonal entry found in the matrix.")
    end
    # Solution vector initialisation
    # ------------------------------
    x = copy(x0)
    # Plot vector initialisation
    # --------------------------
    errors = Float64[]
    
    # Perform iteration
    # -----------------
    for iter = 1:max_iters
        x_old = copy(x)
        
        # Loop rows
        for i = 1:n
            sum1 = dot(A[i, 1:i-1], x[1:i-1])
            sum2 = dot(A[i, i+1:end], x_old[i+1:end])
            x[i] = (b[i] - sum1 - sum2) / A[i, i]
        end
        
        # Evaluate error
        err = norm(x - x_old)
        push!(errors, err)  # Store the current error
        # Check for convergence
        if err < tol
            return x, iter, errors
        end
    end
    
    error("Maximum number of iterations reached without convergence.")
end
# =============
# Problem setup
# =============
# A = [4 1 2; 3 5 1; 1 1 3];
# b = [1.0; -2.0; 0.0]
A = [3 1 -1; 2 4 1; -1 2 5];
b = [4.0; 1.0; 1.0]
# Processing matrix and vectors 
A = convert(Matrix{Float64}, A) # Ensure they are not integers
x0 = zeros(length(b)) # Initial guess for solution Vector
# ==================
# Numerical settings
# ==================
tolerance = 1E-8
zeroTolerance = 1E-12
iterMax = 500
# =====
# Solve
# =====
try
    x, niter, errors = gauss_seidel_solve(A, b, x0, tolerance, zeroTolerance, iterMax)
    println("Converged in $niter iterations. Solution: $x")
    # Plotting error vs iteration number
    plot(1:niter, errors, yscale=:log10, xlabel="Iteration Number", ylabel="Error (log scale)", title="Convergence of Gauss-Seidel Method", legend=false, line=:line, marker=:circle, xticks=1:niter)
    
catch error
    println(error)
end
Successive over-relaxation method
See:https://www.foopiew.com/linear-solver-successive-over/
1
using LinearAlgebra
using Plots
# ==================================================
# Successive over-relaxation linear solver algorithm
# ==================================================
function SOR_solve(A::Matrix{Float64}, b::Vector{Float64}, x0::Vector{Float64}, ω::Float64, tol::Float64, zeroTolerance::Float64, max_iters::Int)
    
    # Number of unknowns
    # ------------------
    n = length(b)
    
    # Check for near-zero diagonal entries
    # ------------------------------------
    if any(abs.(diag(A)) .< zeroTolerance)
        error("Near-zero diagonal entry found in the matrix.")
    end
    # Solution vector initialisation
    # ------------------------------
    x = copy(x0)
    # Plot vector initialisation
    # --------------------------
    errors = Float64[]
    
    # Perform iteration
    # -----------------
    for iter = 1:max_iters
        x_old = copy(x)
        
        # Loop rows
        for i = 1:n
            sum1 = dot(A[i, 1:i-1], x[1:i-1])
            sum2 = dot(A[i, i+1:end], x_old[i+1:end])
            x[i] = (1-ω)*x[i] + ω*(b[i] - sum1 - sum2) / A[i, i]
        end
        
        # Evaluate error
        err = norm(x - x_old)
        push!(errors, err)  # Store the current error
        # Check for convergence
        if err < tol
            return x, iter, errors
        end
    end
    
    error("Maximum number of iterations reached without convergence.")
end
# =============
# Problem setup
# =============
A = [4 1 2; 3 5 1; 1 1 3];
b = [1.0; -2.0; 0.0]
# Processing matrix and vectors 
A = convert(Matrix{Float64}, A) # Ensure they are not integers
x0 = zeros(length(b)) # Initial guess for solution Vector
# ==================
# Numerical settings
# ==================
ω=1.05
tolerance = 1E-8
zeroTolerance = 1E-12
iterMax = 500
# =====
# Solve
# =====
try
    x, niter, errors = SOR_solve(A, b, x0, ω, tolerance, zeroTolerance, iterMax)
    println("Converged in $niter iterations. Solution: $x")
    # Plotting error vs iteration number
    plot(1:niter, errors, yscale=:log10, xlabel="Iteration Number", ylabel="Error (log scale)", title="Convergence of SOR Method", legend=false, line=:line, marker=:circle)
    
catch error
    println(error)
end
2
using LinearAlgebra
using Plots
# ==================================================
# Successive over-relaxation linear solver algorithm
# ==================================================
function SOR_solve(A::Matrix{Float64}, b::Vector{Float64}, 
    x0::Vector{Float64}, ω::Float64, tol::Float64, 
    zeroTolerance::Float64, max_iters::Int)
    
    # Number of unknowns
    # ------------------
    n = length(b)
    
    # Check for near-zero diagonal entries
    # ------------------------------------
    if any(abs.(diag(A)) .< zeroTolerance)
        error("Near-zero diagonal entry found in the matrix.")
    end
    # Solution vector initialisation
    # ------------------------------
    x = copy(x0)
    # Plot vector initialisation
    # --------------------------
    errors = Float64[]
    
    # Perform iteration
    # -----------------
    for iter = 1:max_iters
        x_old = copy(x)
        
        # Loop rows
        for i = 1:n
            sum1 = dot(A[i, 1:i-1], x[1:i-1])
            sum2 = dot(A[i, i+1:end], x_old[i+1:end])
            x[i] = (1-ω)*x[i] + ω*(b[i] - sum1 - sum2) / A[i, i]
        end
        
        # Evaluate error
        err = norm(x - x_old)
        push!(errors, err)  # Store the current error
        # Check for convergence
        if err < tol
            return x, iter, errors
        end
    end
    
    error("Maximum number of iterations reached without convergence.")
end
# =============
# Problem setup
# =============
A = [4 1 2; 3 5 1; 1 1 3];
b = [1.0; -2.0; 0.0]
# Processing matrix and vectors 
A = convert(Matrix{Float64}, A) # Ensure they are not integers
x0 = zeros(length(b)) # Initial guess for solution Vector
# ==================
# Numerical settings
# ==================
tolerance = 1E-8
zeroTolerance = 1E-12
iterMax = 500
# =====
# Solve
# =====
ω_list = range(start=0.1, step=0.05, stop=1.6)
niter_list = Float64[]
for iω in eachindex(ω_list)
    ω=ω_list[iω]
    try
        x, niter, errors = SOR_solve(A, b, x0, ω, tolerance, zeroTolerance, iterMax)
        println("Converged in $niter iterations. Solution: $x")
        push!(niter_list, niter)  # Store the number of iterations to converge
    catch error
        println(error)
    end
end
 # Plot ω-niter
 plot(ω_list, niter_list, xlabel="Relaxation Factor \\omega", ylabel="Number of Iterations to Converge", title="Effect of \\omega in SOR Method", legend=false, line=:line, marker=:circle)