Skip to content

Commit e22d435

Browse files
committed
Update direct methods
1 parent 4f8b3df commit e22d435

File tree

1 file changed

+93
-74
lines changed

1 file changed

+93
-74
lines changed

src/06_Direct_methods.jl

Lines changed: 93 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ A_manual = Float64[ 2 1 0;
551551
4 -3 4]
552552

553553
# ╔═╡ 039b93ac-0a0e-45c3-acf9-70ec49b077c3
554-
md"""With this slider you can stop `factorise_lu` after 1, 2 or 3 steps, checking that agrees with the steps we computed manually:
554+
md"""With this slider you can stop `factorise_lu` after 1, 2 or 3 steps, checking that agrees with the steps we computed manually. The matrices displayed below show the situation after `k = nstep_lu_A` in **Algorithm 4** has finished.
555555
556556
- `nstep_lu_A = ` $(@bind nstep_lu_A Slider(0:3; default=0, show_value=true))
557557
"""
@@ -685,25 +685,20 @@ We stay with the problem we identified at the end of the previous section. That
685685

686686
# ╔═╡ fbbff089-03ff-45ca-9ee7-2644d9fa8489
687687
md"""
688-
Applying **Algorithm 4** the first step ($k=1$) will zero out the first column in the second and third row by subtracting the 2 times (7 times) the first row from the second (third) row. This results in the matrices:
688+
Applying **Algorithm 4** the first step ($k=1$) will zero out the first column in the second and third row by subtracting the 2 times (7 times) the first row from the second (third) row. When entering the loop for $k=2$ this results in:
689689
```math
690-
\textbf A^{(2)} = \begin{pmatrix} 1 & 2 & 3\\0 & \textcolor{red}{0} & -1\\ 0 &-6 &-12\end{pmatrix}, \qquad
691-
\textbf L^{(1)} = \begin{pmatrix} 1 & & \\ 2 &\phantom{1} & \\ 7 & &\phantom{1} \end{pmatrix}.
690+
\text{at beginning of $k=2$:}\qquad
691+
\textbf U = \begin{pmatrix} 1 & 2 & 3\\0 & \textcolor{red}{0} & -1\\ 0 &-6 &-12\end{pmatrix}, \qquad
692+
\textbf L = \begin{pmatrix} 1 & & \\ 2 &\phantom{1} & \\ 7 & &\phantom{1} \end{pmatrix}.
692693
```
693-
As a result the element `Aᵏ[k, k]` (for $k = 2$) is zero as marked $\textcolor{red}{\text{in red}}$. Continuing **Algorithm 4** for `k = 2` we would thus divide by zero
694-
in the statement $L_{ik} = \frac{A_{ik}^{(k)}}{A^{(k)}_{kk}}$
695-
--- which in the introduction of a `-Inf`
696-
in the matrix `L` that is returned by the algorithm.
697-
698-
Due their central role in the Gaussian elimination algorithm
699-
the elements $\left(A^{(k)}\right)_{kk}$
700-
--- respectively `Aᵏ[k, k]` in the implementation ---
701-
are usually referred to as **pivots**.
694+
The first step of the $k=2$ iteration in **Algorithm 4** will be to compute $L_{ik} = \frac{U_{ik}}{U_{kk}}$. However, the element $U_{kk}$ is zero as marked $\textcolor{red}{\text{in red}}$. We thus divide by zero, which is exactly what leads to the introduction of a `-Inf`
695+
in the matrix `L`
702696
"""
703697

704698
# ╔═╡ 8c4bc8a8-06bf-48ce-9d76-bf0c03f5a79d
705699
md"""
706-
We run the algorithm step by step by advancing the slider:
700+
To see this we use the slider to advance the algorithm step by step,
701+
the matrices below show the situtation after the `k = nstep_lu_D` iteration has finished.
707702
708703
- `nstep_lu_D = ` $(@bind nstep_lu_D Slider(0:3; default=0, show_value=true))
709704
"""
@@ -713,7 +708,11 @@ factorise_lu_steps(D; nstep=nstep_lu_D)
713708

714709
# ╔═╡ 9d5aab1f-3156-4c73-9e2f-b91f3ebe3984
715710
md"""
716-
We observe that from step $k \geq 2$ and onwards our computations are numerical garbage because we have used a $0$ pivot.
711+
Due their central role in the Gaussian elimination algorithm
712+
the denominators $U_{kk}$ in the computation of the $L_{ik}$
713+
are usually referred to as **pivots**.
714+
715+
In summary we observe that from step $k \geq 2$ and onwards our computations are numerical garbage because we have used a $0$ pivot.
717716
"""
718717

719718
# ╔═╡ 58c13b75-006d-48e4-8ddf-290df272488b
@@ -729,6 +728,16 @@ which is the matrix $\textbf D$ in which the last two rows are swapped,
729728
the algorithm goes through as expected:
730729
"""
731730

731+
# ╔═╡ dca2b3b4-2b15-4428-91d0-2b949442b6bf
732+
md"""
733+
- `nstep_lu_PD = ` $(@bind nstep_lu_PD Slider(0:3; default=0, show_value=true))
734+
"""
735+
736+
# ╔═╡ d194baba-556c-4669-a345-255c03081965
737+
md"""
738+
Let us also check that the LU factorisation indeed yields P * U:
739+
"""
740+
732741
# ╔═╡ 49f66db0-3757-431d-85d7-4fe75096f9cc
733742
md"We remark that the permutation matrix $\mathbf P$ is given by ..."
734743

@@ -740,13 +749,14 @@ P = [1 0 0;
740749
# ╔═╡ a85a3ad2-a89d-4e7c-8275-a2f3cd2921b0
741750
P * D
742751

752+
# ╔═╡ f6cc916b-78d0-47d4-8b89-f4ab18926c1b
753+
factorise_lu_steps(P * D; nstep=nstep_lu_PD)
754+
743755
# ╔═╡ 0ea63086-f090-4b5b-a7d5-d6a1b21b1fd8
744756
let
745-
L, U = factorise_lu(P*D)
746-
@show L
747-
@show L * U
748-
@show L * U - P * D # show that L * U = P * D
749-
end;
757+
L, U = factorise_lu(P * D)
758+
L * U - P * D # show that L * U = P * D
759+
end
750760

751761
# ╔═╡ 2d461a32-c40f-4670-9252-09baa5f3a6d5
752762
md"... and exactly achieves the task of swapping the last two rows, but leaving the rest of $\mathbf D$ intact as we saw above."
@@ -776,7 +786,7 @@ Finding a suitable $\mathbf P$ can be achieved by a small
776786
modification of **Algorithm 4**.
777787
Essentially this modification boils down to **selecting a permutation
778788
of rows** of the factorised matrix on the fly,
779-
**such that the pivots** of the permuted matrix $\left(\mathbf{P} \mathbf{A}^{(k)}\right)_{kk}$ **are always nonzero**.
789+
**such that the pivots** of the permuted matrix $\mathbf{P} \mathbf{A}$ **are always nonzero**.
780790
The precise way how this is achieved is called **pivoting strategy**
781791
and the details are beyond the scope of this course.
782792
The interested reader can find some discussion in the optional
@@ -921,7 +931,7 @@ In this approach we allow ourselves
921931
some flexibility in **Algorithm 4** by
922932
allowing ourselves to change the order in the last few rows
923933
and thus *choose* the pivot amongst the entries
924-
$A^{(k)}_{ik}$ with $i \geq k$.
934+
$U_{ik}$ with $i \geq k$ in each step $k$.
925935
The resulting change of row order will then define the permutation
926936
matrix $\mathbf{P}$ we employed in our above discussion.
927937
"""
@@ -935,40 +945,39 @@ problem of factorising
935945
```
936946
where we saw previously non-pivoted LU factorisation to fail.
937947
Without any pivoting / row swapping after the first LU factorisation step
938-
(i.e after $k=1$ is completed) the situation was
948+
(i.e when $k=2$ will start) the situation is
939949
940950
```math
941-
\textbf A^{(2)} = \begin{pmatrix} 1 & 2 & 3\\0 & \textcolor{red}{0} & -1\\ 0 &-6 &-12\end{pmatrix}, \qquad
942-
\textbf L^{(1)} = \begin{pmatrix} 1 & & \\ 2 &\phantom{1} & \\ 7 & &\phantom{1} \end{pmatrix}.
951+
\text{at beginning of $k=2$:}\qquad
952+
\textbf U = \begin{pmatrix} 1 & 2 & 3\\0 & \textcolor{red}{0} & -1\\ \textcolor{orange}{0} &\textcolor{orange}{-6} &\textcolor{orange}{-12}\end{pmatrix}, \qquad
953+
\textbf L = \begin{pmatrix} 1 & & \\ \textcolor{blue}{2} &\phantom{1} & \\ \textcolor{orange}{7} & &\phantom{1} \end{pmatrix}.
943954
```
944955
945-
Looking at $\textbf A^{(2)}$ it seems very reasonable to just swap the second and the
946-
third column in $\textbf A^{(2)}$ and thus move the $-6$ to become the new pivot.
947-
For consistency we not only need to swap $\textbf A^{(2)}$, but also $\textbf L^{(2)}$.
956+
Looking at this $\textbf U$ it seems very reasonable to just swap the second and the
957+
third column in and thus move the $-6$ to become the new pivot.
958+
For consistency we not only need to swap $\textbf U$, but also $\textbf L$.
948959
This gives us
949960
```math
950-
\widetilde{\textbf{A}}^{(2)} = \begin{pmatrix} 1 & 2 & 3\\0 & \textcolor{red}{-6} &-12 \\
961+
\text{after row swap:}\qquad
962+
\textbf{U} = \begin{pmatrix} 1 & 2 & 3\\\textcolor{orange}{0} & \textcolor{red}{-6} &\textcolor{orange}{-12} \\
951963
0 & 0 & -1\end{pmatrix}, \qquad
952-
\widetilde{\textbf{L}}^{(1)} = \begin{pmatrix} 1 & & \\ 7 &\phantom{1} & \\ 2 & &\phantom{1} \end{pmatrix}.
964+
\textbf{L} = \begin{pmatrix} 1 & & \\ \textcolor{orange}{7} &\phantom{1} & \\ \textcolor{blue}{2} & &\phantom{1} \end{pmatrix}.
953965
```
954966
If we continue the algorithm now, the $-6$ sits in the position of the pivot
955967
$\left(A^{(k)}\right)_{kk}$ and the division by zero is avoided.
956968
"""
957969

958970
# ╔═╡ f4a02392-ca42-44ac-bd1c-13cb3d6fafa2
959971
md"""
960-
In fact in this particular case there is nothing left to do and the matrix
961-
$\widetilde{\textbf{A}}^{(2)}$ already is in upper triangular form.
962-
We obtain from our algorithm
972+
In fact in this particular case the matrix $\mathbf U$ is already in upper triangular form after step $k=2$, such that in the step $k=3$ nothing will change, in fact we will just get $L_{32} = 0$. After $k=3$ we thus obtain from our algorithm:
963973
```math
964-
\textbf U = \textbf A^{(3)} = \widetilde{\textbf{A}}^{(2)} = \begin{pmatrix} 1 & 2 & 3\\\textcolor{grey}{0} & -6 &-12 \\
974+
\textbf U = \begin{pmatrix} 1 & 2 & 3\\\textcolor{grey}{0} & -6 &-12 \\
965975
\textcolor{grey}{0} & \textcolor{grey}{0} & -1\end{pmatrix}
966976
\qquad
967-
\textbf L = \textbf L^{(3)} = \begin{pmatrix}1& \textcolor{grey}{0} &\textcolor{grey}{0} \\ 7 & 1 & \textcolor{grey}{0} \\ 2 & 0& 1 \end{pmatrix}.
977+
\textbf L = \begin{pmatrix}1& \textcolor{grey}{0} &\textcolor{grey}{0} \\ 7 & 1 & \textcolor{grey}{0} \\ 2 & 0& 1 \end{pmatrix}.
968978
```
969-
Since the additional row permutation we performed
970-
not taken into account in the $\textbf L$ and $\textbf U$ factors,
971-
multiplying them out will not yield $\textbf A$,
979+
Due to the additional row permutation we performed
980+
multiplying out $\textbf L \textbf U$ will not yield $\textbf A$,
972981
but a matrix where the second and third rows of $\textbf A$
973982
are swapped:
974983
```math
@@ -986,45 +995,52 @@ are swapped:
986995

987996
# ╔═╡ 2708ff44-5f30-43b3-b89a-19b9d8954100
988997
md"""
989-
To resolve this, we introduce the **permutation matrix**
990-
```math
991-
\textbf P = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 1 & 0\end{pmatrix},
992-
```
993-
which is obtained by performing exactly the same row permutations
994-
we did during the algorithm to the identity matrix
995-
--- i.e. we swap the second and third row.
996-
With this matrix we can easily check that
997-
```math
998-
\textbf L \textbf U = \textbf P \textbf A.
999-
```
1000-
1001-
If we thus extend our `factorise_lu` function to additionally
1002-
perform such pivoting permutations,
1003-
the Gaussian elimination algorithm would terminate successfully.
1004-
"""
998+
This is not surprising as with pivoting we expect to get
999+
$\textbf L \textbf U = \textbf P \textbf A$, so our missing piece is to
1000+
find the permutation matrix $\mathbf P$.
1001+
1002+
Here the correct matrix is
1003+
```math
1004+
\textbf P = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 1 & 0\end{pmatrix},
1005+
```
1006+
as we saw before. We can now understand how this matrix has been constructed:
1007+
Namely if we take the identity matrix and perform exactly the same row permutations as during the pivoted LU factorisation.
1008+
That is we swap the second and third row.
1009+
With this matrix we can easily check that
1010+
```math
1011+
\textbf L \textbf U = \textbf P \textbf A.
1012+
```
1013+
1014+
If we thus extend our `factorise_lu` function to additionally
1015+
perform such pivoting permutations,
1016+
the Gaussian elimination algorithm would always terminate successfully.
1017+
"""
10051018

10061019
# ╔═╡ 59083552-006d-4376-9c8a-2f5b85c6bb44
10071020
md"""
1008-
But pivoting brings additional opportunities.
1009-
As it turns out numerical stability of LU factorisation
1010-
improves if one permutes not only if a pivot $\left(A^{(k)}\right)_{kk}$ is zero,
1011-
but in general if one *always* swaps the order of the rows
1012-
such that the pivot is taken as large as possible.
1013-
In other words in the $k$-th step of LU factorisation
1014-
we always exchange row $k$ with the row $l$ where $l$ satisfies
1015-
```math
1016-
\left|\left(A^{(k)}\right)_{lk}\right| \leq \left|\left(A^{(k)}\right)_{ik}\right|
1017-
\qquad
1018-
\text{for all $i = k, \ldots n$}.
1019-
```
1020-
The appropriate swaps are tracked and returned as well.
1021-
Note that instead of returning a permutation matrix
1022-
$\textbf P$ (which requries to store $n^2$ elements)
1023-
it is usually more convenient to store a permutation vector $\textbf p$,
1024-
which has only $n$ elements.
1025-
This vector tracks the indices of the rows of $\mathbf A$
1026-
in the order they are used as pivots. In other words if
1027-
"""
1021+
But pivoting brings additional opportunities.
1022+
As it turns out numerical stability of LU factorisation
1023+
can improve if one permuts the rows of $\textbf U$
1024+
not only if a pivot $U_{kk}$ is zero,
1025+
but in fact during each iteration $k$, ensuring that the
1026+
**pivot** is **as large as possible**.
1027+
1028+
In other words in the $k$-th step of LU factorisation
1029+
we always exchange row $k$ with the row $l$ where $l$ satisfies
1030+
```math
1031+
\left|\,U_{lk}\,\right| \leq \left|\,U_{ik}\,\right|
1032+
\qquad
1033+
\text{for all $i = k, \ldots n$}.
1034+
```
1035+
The appropriate swaps are tracked and returned as well.
1036+
1037+
In practical algorithms instead of returning a permutation matrix
1038+
$\textbf P$ (which requries to store $n^2$ elements)
1039+
it is usually more convenient to store a permutation vector $\textbf p$,
1040+
which has only $n$ elements.
1041+
This vector tracks the indices of the rows of $\mathbf A$
1042+
in the order they are used as pivots. In other words if
1043+
"""
10281044

10291045
# ╔═╡ 6754911a-81dd-41ce-8b59-2a0743b324c0
10301046
idmx = diagm(ones(4))
@@ -2366,6 +2382,9 @@ version = "17.4.0+2"
23662382
# ╟─9d5aab1f-3156-4c73-9e2f-b91f3ebe3984
23672383
# ╟─58c13b75-006d-48e4-8ddf-290df272488b
23682384
# ╠═a85a3ad2-a89d-4e7c-8275-a2f3cd2921b0
2385+
# ╟─dca2b3b4-2b15-4428-91d0-2b949442b6bf
2386+
# ╟─f6cc916b-78d0-47d4-8b89-f4ab18926c1b
2387+
# ╟─d194baba-556c-4669-a345-255c03081965
23692388
# ╠═0ea63086-f090-4b5b-a7d5-d6a1b21b1fd8
23702389
# ╟─49f66db0-3757-431d-85d7-4fe75096f9cc
23712390
# ╠═6f59c78d-7966-45ab-8b79-8443b82ba1df

0 commit comments

Comments
 (0)