\(\newcommand{\re}{\mathbb{R}}\)
Triangular systems#
Given \(L \in \re^{m \times m}\) lower-triangular, non-singular matrix, we want to solve
\[
L x = b
\]
The \(i\)’th equation is
\[
\sum_{j=0}^{m-1} L_{ij} x_j = b_i, \qquad 0 \le i \le m-1
\]
and since \(L\) is lower-triangular, this simplifies to
\[
\sum_{j=0}^{i} L_{ij} x_j = b_i
\]
which can be solved for \(x_i\)
\[
x_i = \frac{1}{L_{ii}} \left[b_i - \sum_{j=0}^{i-1} L_{ij} x_j\right]
\]
We can solve using forward-substitution, i.e., solve for \(x_0\), then \(x_1\), and so on.
Forward-substitution: For \(i=0,1,2,\ldots,m-1\)
\[
x_i = \frac{1}{L_{ii}} \left[b_i - \sum_{j=0}^{i-1} L_{ij} x_j\right]
\]
Since \(L\) is non-singular, the diagonal entries are non-zero, \(L_{ii} \ne 0\).
import numpy as np
We can compute the sum
\[
\sum_{j=0}^{i-1} L_{ij} x_j
\]
using a for
loop, but this is slow in Python. Instead, we can compute it as a dot product
\[
\sum_{j=0}^{i-1} L_{ij} x_j = \texttt{np.dot(L[i,0:i], x[0:i])}
\]
def LSolve(L,b):
m = L.shape[0]
# solve Lx = b
x = np.empty_like(b)
for i in range(m):
x[i] = (b[i] - np.dot(L[i,0:i], x[0:i])) / L[i,i]
return x
Create a random matrix and right hand side vector \(b\) and solve \(L x = b\).
m = 10
A = np.random.rand(m,m) # random matrix
L = np.tril(A) # lower-triangular part
b = np.random.rand(m)
x = LSolve(L,b)
print('||Lx-b|| = ',np.linalg.norm(L@x - b,np.inf))
||Lx-b|| = 8.881784197001252e-16
Exercise#
Write a code to solve an upper-triangular, non-singular system and test it.