Gaussian elimination¶
We consider a linear system of size \(n\):
\[A_{ij} x_j = b_i,\]
or explicitly
\[\begin{split}\newcommand{\x}[2]{a_{#1,#2}}
\newcommand{\y}[1]{x_{#1}}
\newcommand{\z}[1]{b_{#1}}
\begin{bmatrix}
\x{ 0}{ 0} & \x{ 0}{ 1} & \cdots & \x{ 0}{i-1} & \x{ 0}{i } & \x{ 0}{i+1} & \cdots & \x{ 0}{n-2} & \x{ 0}{n-1} \\
\x{ 1}{ 0} & \x{ 1}{ 1} & \cdots & \x{ 1}{i-1} & \x{ 1}{i } & \x{ 1}{i+1} & \cdots & \x{ 1}{n-2} & \x{ 1}{n-1} \\
\vdots & \vdots & \ddots & \vdots & \vdots & \vdots & & \vdots & \vdots \\
\x{i-1}{ 0} & \x{i-1}{ 1} & \cdots & \x{i-1}{i-1} & \x{i-1}{i } & \x{i-1}{i+1} & \cdots & \x{i-1}{n-2} & \x{i-1}{n-1} \\
\x{i }{ 0} & \x{i }{ 1} & \cdots & \x{i }{i-1} & \x{i }{i } & \x{i }{i+1} & \cdots & \x{i }{n-2} & \x{i }{n-1} \\
\x{i+1}{ 0} & \x{i+1}{ 1} & \cdots & \x{i+1}{i-1} & \x{i+1}{i } & \x{i+1}{i+1} & \cdots & \x{i+1}{n-2} & \x{i+1}{n-1} \\
\vdots & \vdots & & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots \\
\x{n-2}{ 0} & \x{n-2}{ 1} & \cdots & \x{n-2}{i-1} & \x{n-2}{i } & \x{n-2}{i+1} & \cdots & \x{n-2}{n-2} & \x{n-2}{n-1} \\
\x{n-1}{ 0} & \x{n-1}{ 1} & \cdots & \x{n-1}{i-1} & \x{n-1}{i } & \x{n-1}{i+1} & \cdots & \x{n-1}{n-2} & \x{n-1}{n-1} \\
\end{bmatrix}
\begin{bmatrix}
\y{ 0} \\
\y{ 1} \\
\vdots \\
\y{i-1} \\
\y{i } \\
\y{i+1} \\
\vdots \\
\y{n-2} \\
\y{n-1} \\
\end{bmatrix}
=
\begin{bmatrix}
\z{ 0} \\
\z{ 1} \\
\vdots \\
\z{i-1} \\
\z{i } \\
\z{i+1} \\
\vdots \\
\z{n-2} \\
\z{n-1} \\
\end{bmatrix}.\end{split}\]
For notational simplicity, we consider the following augmented matrix:
\[\begin{split}\begin{bmatrix}
\x{ 0}{ 0} & \x{ 0}{ 1} & \cdots & \x{ 0}{i-1} & \x{ 0}{i } & \x{ 0}{i+1} & \cdots & \x{ 0}{n-2} & \x{ 0}{n-1} & \z{ 0} \\
\x{ 1}{ 0} & \x{ 1}{ 1} & \cdots & \x{ 1}{i-1} & \x{ 1}{i } & \x{ 1}{i+1} & \cdots & \x{ 1}{n-2} & \x{ 1}{n-1} & \z{ 1} \\
\vdots & \vdots & \ddots & \vdots & \vdots & \vdots & & \vdots & \vdots & \vdots \\
\x{i-1}{ 0} & \x{i-1}{ 1} & \cdots & \x{i-1}{i-1} & \x{i-1}{i } & \x{i-1}{i+1} & \cdots & \x{i-1}{n-2} & \x{i-1}{n-1} & \z{i-1} \\
\x{i }{ 0} & \x{i }{ 1} & \cdots & \x{i }{i-1} & \x{i }{i } & \x{i }{i+1} & \cdots & \x{i }{n-2} & \x{i }{n-1} & \z{i } \\
\x{i+1}{ 0} & \x{i+1}{ 1} & \cdots & \x{i+1}{i-1} & \x{i+1}{i } & \x{i+1}{i+1} & \cdots & \x{i+1}{n-2} & \x{i+1}{n-1} & \z{i+1} \\
\vdots & \vdots & & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots \\
\x{n-2}{ 0} & \x{n-2}{ 1} & \cdots & \x{n-2}{i-1} & \x{n-2}{i } & \x{n-2}{i+1} & \cdots & \x{n-2}{n-2} & \x{n-2}{n-1} & \z{n-2} \\
\x{n-1}{ 0} & \x{n-1}{ 1} & \cdots & \x{n-1}{i-1} & \x{n-1}{i } & \x{n-1}{i+1} & \cdots & \x{n-1}{n-2} & \x{n-1}{n-1} & \z{n-1} \\
\end{bmatrix}.\end{split}\]
Forward sweep¶
After forward-sweeping up to the \(i - 1\)-th row, we have
\[\begin{split}\begin{bmatrix}
\vdots & \vdots & \ddots & \vdots & \vdots & \vdots & & \vdots & \vdots & \vdots \\
0 & 0 & \cdots & 1 & a_{i-1,i } & a_{i-1,i+1} & \cdots & a_{i-1,n-2} & a_{i-1,n-1} & b_{i-1} \\
0 & 0 & \cdots & 0 & a_{i ,i } & a_{i ,i+1} & \cdots & a_{i ,n-2} & a_{i ,n-1} & b_{i } \\
0 & 0 & \cdots & 0 & a_{i+1,i } & a_{i+1,i+1} & \cdots & a_{i+1,n-2} & a_{i+1,n-1} & b_{i+1} \\
\vdots & \vdots & & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots \\
\end{bmatrix}.\end{split}\]
The \(i\)-th row is normalized (divided by \(\x{i}{i}\)) to obtain
\[\begin{split}\begin{bmatrix}
\vdots & \vdots & \ddots & \vdots & \vdots & \vdots & & \vdots & \vdots & \vdots \\
0 & 0 & \cdots & 1 & a_{i-1,i } & a_{i-1,i+1} & \cdots & a_{i-1,n-2} & a_{i-1,n-1} & b_{i-1} \\
0 & 0 & \cdots & 0 & 1 & a_{i ,i+1} := a_{i ,i+1} / a_{i ,i } & \cdots & a_{i ,n-2} := a_{i ,n-2} / a_{i ,i } & a_{i ,n-1} := a_{i ,n-1} / a_{i ,i } & b_{i } := b_{i } / a_{i ,i } \\
0 & 0 & \cdots & 0 & a_{i+1,i } & a_{i+1,i+1} & \cdots & a_{i+1,n-2} & a_{i+1,n-1} & b_{i+1} \\
\vdots & \vdots & & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots \\
\end{bmatrix}.\end{split}\]
13const double f = 1. / a[i * nitems + i];
14for (size_t j = i; j < nitems; j++) {
15 a[i * nitems + j] *= f;
16}
17x[i] *= f;
The new \(i\)-th row is utilized to eliminate the \(i\)-th column:
\[\begin{split}\begin{bmatrix}
\vdots & \vdots & \ddots & \vdots & \vdots & \vdots & & \vdots & \vdots & \vdots \\
0 & 0 & \cdots & 1 & a_{i-1,i } & a_{i-1,i+1} & \cdots & a_{i-1,n-2} & a_{i-1,n-1} & b_{i-1} \\
0 & 0 & \cdots & 0 & 1 & a_{i ,i+1} & \cdots & a_{i ,n-2} & a_{i ,n-1} & b_{i } \\
0 & 0 & \cdots & 0 & 0 & a_{i+1,i+1} := a_{i+1,i+1} - a_{i+1,i }a_{i ,i+1} & \cdots & a_{i+1,n-2} := a_{i+1,n-2} - a_{i+1,i }a_{i ,n-2} & a_{i+1,n-1} := a_{i+1,n-1} - a_{i+1,i }a_{i ,n-1} & b_{i+1} := b_{i+1} - a_{i+1,i }b_{i } \\
\vdots & \vdots & & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots \\
\end{bmatrix}.\end{split}\]
19for (size_t ii = i + 1; ii < nitems; ii++) {
20 const double f = a[ii * nitems + i];
21 for (size_t j = i + 1; j < nitems; j++) {
22 a[ii * nitems + j] -= f * a[i * nitems + j];
23 }
24 x[ii] -= f * x[i];
25}
Backward substitution¶
After the forward sweep, we have
\[\begin{split}\begin{bmatrix}
1 & \x{ 0}{ 1} & \cdots & \x{ 0}{i-1} & \x{ 0}{i } & \x{ 0}{i+1} & \cdots & \x{ 0}{n-2} & \x{ 0}{n-1} & \z{ 0} \\
0 & 1 & \cdots & \x{ 1}{i-1} & \x{ 1}{i } & \x{ 1}{i+1} & \cdots & \x{ 1}{n-2} & \x{ 1}{n-1} & \z{ 1} \\
\vdots & \vdots & \ddots & \vdots & \vdots & \vdots & & \vdots & \vdots & \vdots \\
0 & 0 & \cdots & 1 & \x{i-1}{i } & \x{i-1}{i+1} & \cdots & \x{i-1}{n-2} & \x{i-1}{n-1} & \z{i-1} \\
0 & 0 & \cdots & 0 & 1 & \x{i }{i+1} & \cdots & \x{i }{n-2} & \x{i }{n-1} & \z{i } \\
0 & 0 & \cdots & 0 & 0 & 1 & \cdots & \x{i+1}{n-2} & \x{i+1}{n-1} & \z{i+1} \\
\vdots & \vdots & & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots \\
0 & 0 & \cdots & 0 & 0 & 0 & \cdots & 1 & \x{n-2}{n-1} & \z{n-2} \\
0 & 0 & \cdots & 0 & 0 & 0 & \cdots & 0 & 1 & \y{n-1} \\
\end{bmatrix}.\end{split}\]
Starting from the bottom (\(n - 1\)-th) row, the upper-triangular elements are eliminated.
After backward-substituting up to the \(i + 1\)-th row, we have
\[\begin{split}\begin{bmatrix}
\vdots & \vdots & \ddots & \vdots & \vdots & \vdots & & \vdots & \vdots & \vdots \\
0 & 0 & \cdots & 1 & \x{i-1}{i } & \x{i-1}{i+1} & \cdots & \x{i-1}{n-2} & \x{i-1}{n-1} & \z{i-1} \\
0 & 0 & \cdots & 0 & 1 & \x{i }{i+1} & \cdots & \x{i }{n-2} & \x{i }{n-1} & \z{i } \\
0 & 0 & \cdots & 0 & 0 & 1 & \cdots & \x{i+1}{n-2} & \x{i+1}{n-1} & \y{i+1} \\
\vdots & \vdots & & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots \\
\end{bmatrix}.\end{split}\]
28for (size_t i = nitems - 1; ; i--) {
29 for (size_t j = i + 1; j < nitems; j++) {
30 x[i] -= a[i * nitems + j] * x[j];
31 }
32 if (0 == i) {
33 break;
34 }
35}