Course Webpage

Linear systems: direct methods

In [13]:
import numpy as np

We set the format

In [14]:
np.set_printoptions(precision = 2)  
np.set_printoptions(suppress = True)

In this lab we tackle the problem of solving linear systems of equations

$$ \begin{array}{cll} a_{11}x_{1}+a_{12}x_{2}+\ldots+a_{1n}x_{n} & = & b_{1},\\ a_{21}x_{1}+a_{22}x_{2}+\ldots+a_{2n}x_{n} & = & b_{2},\\ \vdots\\ a_{n1}x_{1}+a_{n2}x_{2}+\ldots+a_{nn}x_{n} & = & b_{n}. \end{array} $$

We assume that the matrix $A=(a_{ij})$ is non-singular, i.e. det$(A)$ does not vanish, and therefore, the system has a unique solution.


Backward substitution

Similarly, for the system

$$ U\mathbf{x}=\mathbf{b} $$

with $U$ of the form

$$ U=\left(\begin{array}{ccccc} u_{11} & u_{12} & u_{13} & \ldots & u_{1n}\\ 0 & u_{22} & u_{23} & \ldots & u_{2n}\\ 0 & 0 & u_{33} & \ldots & u_{3n}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & 0 & 0 & u_{nn} \end{array}\right) $$

the $i$-th equation is, for $i=1,2,\ldots,n$,

$$ u_{ii}x_{i}+u_{ii+1}x_{i+1}+\cdots+u_{in}x_{n}=b_{i} $$

Therefore, for $i=1,2,\ldots,n$, if $l_{ii}$ does not vanish then

$$ x_{i}=\frac{b_{i}-u_{ii+1}x_{i+1}-\cdots-u_{in}x_{n}}{u_{ii}}= \frac{1}{u_{ii}}\left(b_{i}-\sum_{j=i+1}^{n}u_{ij}x_{j}\right), $$

Algorithm

  • $x_{n}=\dfrac{b_{n}}{u_{nn}}$
  • For $i=n-1,\ldots,1$
    • If $u_{ii}=0$, exit
    • Else, set
$$ x_{i}=\frac{1}{u_{ii}}\left(b_{i}-\sum_{j=i+1}^{n}u_{ij}x_{j}\right). $$

Exercise 1

Write a function subs_backward(U,b) whose output $x$ is the solution of the system $Ux=b$, being U a upper triangular matriz and b a column matrix.

Use it to solve the system

$$\left(\begin{array}{rrr} 2 & 1 & 1\\ 0 & 2 & 1\\ 0 & 0 & 2 \end{array}\right) \left(\begin{array}{c} x_1\\ x_2\\ x_3 \end{array}\right)= \left(\begin{array}{r} 9\\ 4\\ 4 \end{array}\right) $$
U = np.array([[2., 1, 1], [0, 2, 1], [0, 0, 2]])
b = np.array([9., 4, 4])
  • Check the solution computing $Ux$ and comparing it with $b$.
  • Check that the function also works well with the $Ux=b$ system with matrices $L$ and $b$ generated as follows
    n = 5
    np.random.seed(2)           
    U = np.random.random((n,n)) 
    U = np.triu(U) # make zero elements under the diagonal
    b = np.random.random(n)
    

Hints

  • We can obtain the number of rows and columns of a matrix A with n_rows, n_columns = A.shape
  • The number of elements of b can be obtained with n = len(b).
  • We initialize a vector of zeros x with the same shape as b with
    • x = np.zeros(len(b)) or x = np.zeros_like(b)
In [15]:
%run Exercise1.py
------------- SYSTEM 1 -------------

--- Data ---
U
[[2 1 1]
 [0 2 1]
 [0 0 2]]
b
[9 4 4]

--- Solution ---
x
[3 1 2]

------------- SYSTEM 2 -------------

--- Data ---
U
[[0.44 0.03 0.55 0.44 0.42]
 [0.   0.2  0.62 0.3  0.27]
 [0.   0.   0.13 0.51 0.18]
 [0.   0.   0.   0.85 0.08]
 [0.   0.   0.   0.   0.13]]
b
[0.6  0.23 0.11 0.22 0.35]

--- Solution ---
x
[ 2.08  6.54 -2.98  0.    2.75]

Gaussian elimination

Idea of Gauss' method is to transform the original system into an upper triangular system with the same solution. To do this, we may use the following operations:

  • We add a row multiplied by a constant to other $r_i\rightarrow r_i +\lambda r_k,\quad i\ne k$
  • We can interchange rows.

Once the matrix is triangular we can solve the system with backward elimination.

In general, it is necessary to allow the swapping of rows, but we will code first the algorithm without it.

Algorithm

  • For $k=1,\ldots,n-1$
    • If $a_{kk}=0$, exit
    • Else, for $i=k+1,\ldots,n,$
      • $f = \dfrac{a_{ik}}{a_{kk}}$
      • $b_{i}=b_{i}-f\,b_{k}$
      • $a\,\mathrm{row}_i \leftarrow a\,\mathrm{row}_i - f\times a\,\mathrm{row}_k$

Exercise 2

Write a function triang(A,b) whose output are the transformed upper triangular matrix U and vector c of a given matrix A and right hand side of the system b.

Use it for the matrices of the system $Ax=b$

$$\left(\begin{array}{rrr} 2 & 1 & 1\\ 1 & 2 & 1\\ 1 & 1 & 2 \end{array}\right) \left(\begin{array}{c} x_1\\ x_2\\ x_3 \end{array}\right)= \left(\begin{array}{r} 2\\ 4\\ 6 \end{array}\right) $$
  • Print the matrices U and c.
  • Solve the equivalent system $Ux=c$ and check the solution computing $Ax$ and comparing it with $b$.
  • Check that the function also works well with the $Ax=b$ system with matrices $A$ and $b$ generated as follows
    n = 5
    np.random.seed(3)           
    A = np.random.random((n,n)) 
    b = np.random.random((n,))
    

Hint

  • We can extract the row i from matrix A with A[i,:] or just A[i].
In [16]:
%run Exercise2.py
------------- System 1 -------------

              --DATA--       
A
[[2. 1. 1.]
 [1. 2. 1.]
 [1. 1. 2.]]
b
[2. 4. 6.]

         --TRIANGULARIZATION--       

 U
[[2.   1.   1.  ]
 [0.   1.5  0.5 ]
 [0.   0.   1.33]]

 c
[2. 3. 4.]

        --BACKWARD SUBSTITUTION--       

 x
[-1.  1.  3.]

------------- System 2 -------------

              --DATA--       
A
[[0.55 0.71 0.29 0.51 0.89]
 [0.9  0.13 0.21 0.05 0.44]
 [0.03 0.46 0.65 0.28 0.68]
 [0.59 0.02 0.56 0.26 0.42]
 [0.28 0.69 0.44 0.16 0.54]]
b
[0.78 0.31 0.22 0.39 0.94]

         --TRIANGULARIZATION--       

 U
[[ 0.55  0.71  0.29  0.51  0.89]
 [ 0.   -1.03 -0.27 -0.78 -1.01]
 [ 0.    0.    0.52 -0.07  0.22]
 [ 0.    0.   -0.    0.33  0.  ]
 [ 0.    0.   -0.    0.   -0.32]]

 c
[ 0.78 -0.96 -0.21  0.42  0.73]

        --BACKWARD SUBSTITUTION--       

 x
[ 0.95  2.02  0.7   1.31 -2.29]

Inverse matrix with Gauss-Jordan method

To compute $A_{n\times n}$ by Gauss-Jordan method, we will follow the steps:

  1. Write a $n\times 2n$ matrix $M$, built concatenating matrices $A$ and $I$ (identity matrix) $n\times n$. That is, $M = [A\,|\,I]$

  2. Operating by rows, we transform matrix $A$ into matrix $I$. Then, the right hand matrix will be the inverse of $A$. That is, from $M = [A\,|\,I]$ we arrive to $M = [I\,|\,A^{-1}]$ with the following operations:

For $k = 1,\ldots,n$

  • If $m_{kk}=0$, exit.
  • Else,
    • $m\,\mathrm{row}_k \leftarrow \dfrac{m\,\mathrm{row}_k}{m_{kk}}$
    • For $i = 1,\ldots,n \quad i \ne k$

      $m\,\mathrm{row}_i \leftarrow m\,\mathrm{row}_i - m_{ik}\times m\,\mathrm{row}_k$


Exercise 3

Write a function gaussjordan(A) with input parameter the square matrix A and output the inverse of A and that computes this inverse using Gauss-Jordan method without pivoting.

Compute the inverse of the matrices from the previous exercise.

Hints

  • The identity matrix $n \times n$ can be obtained with I = np.eye(n).
  • We can concatenate two matrices A and B horizontally (if the number of rows in both matrices is the same) with M = np.concatenate((A,B),axis=1).
  • We can extract row i of matrix M with M[i,:] or just M[i].
  • We can extract the last columns from column n with M[:,n:].
In [17]:
%run Exercise3.py
Matrix
[[2. 1. 1.]
 [1. 2. 1.]
 [1. 1. 2.]]

Inverse matriz
[[ 0.75 -0.25 -0.25]
 [-0.25  0.75 -0.25]
 [-0.25 -0.25  0.75]]

Matrix
[[0.55 0.71 0.29 0.51 0.89]
 [0.9  0.13 0.21 0.05 0.44]
 [0.03 0.46 0.65 0.28 0.68]
 [0.59 0.02 0.56 0.26 0.42]
 [0.28 0.69 0.44 0.16 0.54]]

Inverse matriz
[[ 0.05  0.25 -1.49  0.94  0.86]
 [ 0.11 -1.08 -1.83  0.32  2.72]
 [-1.17 -0.8  -0.01  1.69  1.28]
 [ 2.12 -3.27 -2.59  3.1   0.03]
 [ 0.17  2.83  3.85 -3.16 -3.12]]

More exercises

Forward substitution

For the system $$ L\mathbf{x}=\mathbf{b}, $$ with $L$ of the form $$ L=\left(\begin{array}{ccccc} l_{11} & 0 & 0 & \ldots & 0\\ l_{21} & l_{22} & 0 & \ldots & 0\\ l_{31} & l_{32} & l_{33} & \ldots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ l_{n1} & l_{n2} & l_{n3} & \ldots & l_{nn} \end{array}\right) $$ the $i$-th equation is, for $i=1,2,\ldots,n$, $$ l_{i1}x_{1}+l_{i2}x_{2}+\cdots+l_{ii}x_{i}=b_{i}. $$

Therefore, for $i=1,2,\ldots,n$, if $l_{ii}$ does not vanish, then $$ x_{i}=\frac{b_{i}-l_{i1}x_{1}-\cdots-l_{ii-1}x_{i-1}}{l_{ii}}= \frac{1}{l_{ii}}\left(b_{i}-\sum_{j=1}^{i-1}l_{ij}x_{j}\right). $$

Algorithm

  • If $l_{11}=0$, exit
  • Else, set $x_{1}=\dfrac{b_{1}}{l_{11}}$
  • For $i=2,\ldots,n$
  • If $l_{ii}= 0$, exit.

  • Else, set $$ x_{i}=\frac{1}{l_{ii}}\left(b_{i}-\sum_{j=1}^{i-1}l_{ij}x_{j}\right). $$


Exercise 4

Write a function subs_forward(L,b) whose output x is the solution of the system $Lx=b$, being L a lower triangular matriz and b a column matrix.

Use it to solve the system

$$\left(\begin{array}{rrr} 2 & 0 & 0\\ 1 & 2 & 0\\ 1 & 1 & 2 \end{array}\right) \left(\begin{array}{c} x_1\\ x_2\\ x_3 \end{array}\right)= \left(\begin{array}{r} 2\\ -1\\ 0 \end{array}\right) $$

Check the solution computing $Lx$ and comparing it with $b$.

Check that the function also works well with the $Lx=b$ system with matrices $L$ and $b$ generated as follows

n = 5
np.random.seed(1)           
L = np.random.random((n,n)) 
L = np.tril(L) # hace cero los elementos por encima de la diagonal
b = np.random.random(n)
In [19]:
%run Exercise4.py
------------- System 1 -------------

--- Data ---
L
[[2 0 0]
 [1 2 0]
 [1 1 2]]
b
[ 2 -1  0]

--- Solution ---
x
[ 1 -1  0]

------------- System 2 -------------

--- Data ---
L
[[0.42 0.   0.   0.   0.  ]
 [0.09 0.19 0.   0.   0.  ]
 [0.42 0.69 0.2  0.   0.  ]
 [0.67 0.42 0.56 0.14 0.  ]
 [0.8  0.97 0.31 0.69 0.88]]
b
[0.89 0.09 0.04 0.17 0.88]

--- Solution ---
x
[ 2.15 -0.61 -2.17  1.42 -0.63]

LU decomposition

We express $A$ as a matrix multiplication of two matrices: a Lower triangular matrix, $L$, and an Upper triangular matrix, $U$,

$$ A=LU. $$

Consider the system

$$ A\mathbf{x}=\mathbf{b}, $$

where $A$ admits the $LU$ decomposition. Then

$$ A\mathbf{x}=\mathbf{b}\Longleftrightarrow LU\mathbf{x}=\mathbf{b} $$

Solving $Ax=b$ is done in two steps

  • Solve $L\mathbf{y}=\mathbf{b}$, by forward substitution, to get $\mathbf{y}$.
  • Solve $U\mathbf{x}=\mathbf{y}$, by backward substitution, to get $\mathbf{x}$.

For the time being, we are not considering swapping rows.


Exercise 5

Use the $LU$ decomposition of $A$ to solve the system $Ax=b$, with

$$ A=\left(\begin{array}{rrr} 2 & 1 & 1\\ 1 & 2 & 1\\ 1 & 1 & 2 \end{array}\right)\quad\quad b=\left(\begin{array}{c} 2\\ 4\\ 6 \end{array}\right) $$
  • Create a function LU(A) that gives the $LU$ decomposition of $A$.
  • Obtain and print the matrices $L$ and $U$.
  • Use the subs_backward and subs_forward functions to solve the resulting systems.
  • Check the solution computing $Ax$ and comparing it with $b$.
  • You can initialize the matrices:
    • U = np.zeros((n,n)) (matrix of zeros with the same shape as $A$, $n\times n$) or U = np.copy(A) (copy of $A$) Beware! U = A works differently.
    • L = np.eye(n) (identity matrix $n\times n$)

Check that the function also works well with the $Ax=b$ system with matrices $A$ and $b$ generated as follows

n = 5
np.random.seed(4)           
A = np.random.random((n,n)) 
b = np.random.random(n)  
`
In [20]:
%run Exercise5.py
------------- System 1 -------------

--- Data ---
A
[[2. 1. 1.]
 [1. 2. 1.]
 [1. 1. 2.]]
b
[2. 4. 6.]

--- Solution ---
U
[[2.   1.   1.  ]
 [0.   1.5  0.5 ]
 [0.   0.   1.33]]
L
[[1.   0.   0.  ]
 [0.5  1.   0.  ]
 [0.5  0.33 1.  ]]
y
[2. 3. 4.]
x
[-1.  1.  3.]

------------- System 2 -------------

--- Data ---
A
[[0.97 0.55 0.97 0.71 0.7 ]
 [0.22 0.98 0.01 0.25 0.43]
 [0.78 0.2  0.86 0.98 0.16]
 [0.6  0.01 0.39 0.04 0.96]
 [0.44 0.95 0.79 0.87 0.17]]
b
[0.07 0.6  0.17 0.73 0.41]

--- Solution ---
U
[[ 0.97  0.55  0.97  0.71  0.7 ]
 [ 0.    0.85 -0.21  0.09  0.28]
 [ 0.    0.    0.02  0.43 -0.32]
 [ 0.    0.    0.    6.43 -4.36]
 [ 0.    0.    0.    0.    0.63]]
L
[[  1.     0.     0.     0.     0.  ]
 [  0.22   1.     0.     0.     0.  ]
 [  0.81  -0.28   1.     0.     0.  ]
 [  0.62  -0.39 -15.65   1.     0.  ]
 [  0.45   0.82  27.59  -1.79   1.  ]]
y
[0.07 0.58 0.27 5.2  1.64]
x
[-2.7  -0.61 -0.66  2.57  2.6 ]