6.2. Solving systems of linear equations using LU decomposition#
Systems of linear equations often appear in the topics of numerical analysis and numerical solutions to differential equations. Examples include the solution of the stage values of an implicit Runge-Kutta method and the solution to a boundary value problem using the finite-difference method. The methods that are applied to solve systems of linear equations fall into one of two categories: direct methods that use an algebraic approach and indirect methods that use an iterative approach. Here we will look at some common direct methods.
6.2.1. Systems of linear equations#
A system of linear equations with
where
where
The solution (if it exists) is the vector
The system has infinitely many solutions. This usually occurs when the number of unknown variables exceeds the number of equations in the system.
The system has a single unique solution.
The system has no solution. This usually occurs where one equation in the system contradicts another such that not value of the variables could satisfy both.
6.2.2. Solving systems of linear equations using LU decomposition#
Given a system of linear equations of the form
Let
The advantage of using LU decomposition to solve systems of linear equations is that once the LU decomposition of the coefficient matrix has been calculated it can be used for any values of the constant vector
Algorithm 6.2 (Solving systems of linear equations using LU decomposition)
Inputs: A system of linear equations expressed using the coefficient matrix
Inputs: The variable vector
Calculate the LU decomposition of
to determine and such that .For
doFor
doReturn
.
Example 6.2
Solve the following system using LU decomposition
Solution (click to show)
We saw in the Example 6.1 above that the LU decomposition of the coefficient matrix is
Solving
gives
Solving
gives
So the solution is
6.2.3. Code#
The code below defines two functions called forward_substitution()
and back_substitution()
that calculate perform forward and back substitution. These are used to solve the system of linear equations from Example 6.2.
def forward_substitution(L, b):
n = L.shape[0]
x = np.zeros(n)
for i in range(n):
sum_ = 0
for j in range(i):
sum_ += L[i,j] * x[j]
x[i] = (b[i] - sum_) / L[i,i]
return x
def back_substitution(U, b):
n = U.shape[0]
x = np.zeros(n)
x[-1] = b[-1] / U[-1,-1]
for i in range(n - 2, -1, -1):
sum_ = 0
for j in range(i + 1, n):
sum_ += U[i,j] * x[j]
x[i] = (b[i] - sum_) / U[i,i]
return x
# Define system
A = np.array([[1, 3, 0],
[2, -4, -1],
[-3, 1, 2]])
b = np.array([-7, 11, 1])
# Calculate LU decomposition
L, U = lu(A)
# Solve system
y = forward_substitution(L, b)
x = back_substitution(U, y)
print(f"x = {x}")
% Define system
A = [1, 3, 0 ;
2, -4, -1 ;
-3, 1, 2 ];
b = [-7 ; 11 ; 1];
% Calculate LUP decomposition
P = partial_pivot(A);
[L, U] = lu(P * A);
% Solve system
y = forward_substitution(L, P * b);
x = back_substitution(U, y)
% --------------------------------------------------------------
function x = forward_substitution(L, b)
n = size(L, 1);
x = zeros(n, 1);
for i = 1 : n
sum_ = 0;
for j = 1 : i - 1
sum_ = sum_ + L(i,j) * x(j);
end
x(i) = (b(i) - sum_) / L(i,i);
end
end
% --------------------------------------------------------------
function x = back_substitution(U, b)
n = size(U, 1);
x = zeros(n, 1);
x(n) = b(n) / U(n,n);
for i = n - 1 : -1 : 1
sum_ = 0
for j = i + 1 : n
sum_ = sum_ + U(i,j) * x(j);
end
x(i) = (b(i) - sum_) / U(i,i);
end
end