| @@ -0,0 +1,19 @@ | |||||
| set terminal png size 1000,1000 | |||||
| set output 'iterative_solvers_plot.png' | |||||
| set logscale xy | |||||
| set ylabel "Laufzeit in Sekunden" | |||||
| set xlabel "Matrixgröße" | |||||
| set format y "%g" | |||||
| plot 'richardson_1.dat' title "Richardson Iteration v1", \ | |||||
| 'richardson_2.dat' title "Richardson Iteration v2", \ | |||||
| 'jacobi_1.dat' title "Jacobi Iteration v1", \ | |||||
| 'jacobi_2.dat' title "Jacobi Iteration v2",\ | |||||
| 'gauss_seidel_1.dat' title "Gauss Seidel Iteration v1",\ | |||||
| 'gauss_seidel_2.dat' title "Gauss Seidel Iteration v2",\ | |||||
| 'linsolve_1.dat' title "hdnum::linsolve",\ | |||||
| 0.000000020*x**4 title "c n^4", \ | |||||
| 0.000000025*x**3 title "b n^3" | |||||
| @@ -0,0 +1,175 @@ | |||||
| \documentclass[uebung]{../../../lecture} | |||||
| \title{Einführung in die Numerik: Übungsblatt 7} | |||||
| \author{Leon Burgard, Christian Merten} | |||||
| \begin{document} | |||||
| \punkte | |||||
| \begin{aufgabe}[] | |||||
| \begin{enumerate}[a)] | |||||
| \item Mit der Block LU-Zerlegung von $A$ folgt | |||||
| \begin{align*} | |||||
| A &= \begin{pmatrix} Id & 0 \\ | |||||
| A_{21}A_{11}^{-1} & Id \end{pmatrix} | |||||
| \begin{pmatrix} A_{11} & A_{12} \\ | |||||
| 0 & S\end{pmatrix} | |||||
| = \begin{pmatrix} | |||||
| A_{11} & A_{12} \\ | |||||
| A_{21} A_{11}A_{11}^{-1} A_{22}A_{11}^{-1}A_{12} + S | |||||
| \end{pmatrix} | |||||
| = \begin{pmatrix} | |||||
| A_{11} & A_{12} \\ | |||||
| A_{21} & A_{21}A_{11}^{-1}A_{12} + S | |||||
| \end{pmatrix} | |||||
| .\end{align*} | |||||
| Damit folgt | |||||
| \[ | |||||
| A_{22} = A_{21}A_{11}^{-1}A_{12} + S \implies S = A_{22} - A_{21}A_{11}^{-1}A_{12} | |||||
| .\] | |||||
| \item Sei $A$ hermitesch und positiv definit. Dann ist | |||||
| \[ | |||||
| \overline{A}^{T} = \begin{pmatrix} \overline{A_{11}}^{T} & \overline{A_{21}}^{T} \\ | |||||
| \overline{A_{12}}^{T} & \overline{A_{22}}^{T} | |||||
| \end{pmatrix} = | |||||
| \begin{pmatrix} A_{11} & A_{12} \\ A_{21} & A_{22} \end{pmatrix} = A | |||||
| .\] | |||||
| Damit folgt $\overline{A_{11}}^{T} = A_{11}$ und $\overline{A_{12}}^{T} = A_{21}$. Dann folgt | |||||
| \[ | |||||
| \overline{S}^{T} = \overline{A_{22}}^{T} - \overline{A_{12}}^{T} \overline{A_{11}}^{-T} \overline{A_{21}}^{T} | |||||
| = A_{22} - A_{21}A_{11}^{-1}A_{12} = S | |||||
| .\] Also $S$ und $A_{11}$ hermitesch. Da $A$ hermitesch und positiv definit, sind alle | |||||
| führenden Hauptminoren positiv, d.h. auch alle führenden Hauptminoren von $A_{11}$ sind positiv, | |||||
| d.h. $A_{11}$ positiv definit. | |||||
| \end{enumerate} | |||||
| \end{aufgabe} | |||||
| \begin{aufgabe} | |||||
| Beh.: Der Algorithmus ist wie angegeben durchführbar. | |||||
| \begin{proof} | |||||
| Induktionsbehauptung: $\forall 1 \le j < n$: $u_j \neq 0$ und $|u_j| > |b_j|$. | |||||
| Endliche Induktion über $j < n$. $j = 1$: $u_1 = a_1 \neq 0$. $|u_1| > |b_1|$. | |||||
| Sei $j < n$ und Induktionsbehauptung für $j-1$ gezeigt. Dann gilt $u_{j-1} \neq 0$, also | |||||
| $l_j = \frac{c_j}{u_{j-1}}$ und $u_j = a_j - \frac{c_j}{u_{j-1}}b_{j-1}$. Damit folgt | |||||
| \begin{salign*} | |||||
| |u_j| &= \left| a_j - \frac{c_j}{u_{j-1}}b_{j-1} \right| \\ | |||||
| &\ge \left| |a_j| - \frac{|c_j|}{|u_{j-1}|}|b_{j-1}| \right| \\ | |||||
| &\ge \Big| |b_j| + \underbrace{|c_j|}_{\neq 0} \Big( 1 - \underbrace{\frac{|b_{j-1|}}{|u_{j-1}|}}_{ \text{I.V.:} < 1} \Big) \Big| \\ | |||||
| &> |b_j| > 0 | |||||
| .\end{salign*} | |||||
| Das zeigt die Induktionsbehauptung. | |||||
| Für $j = n$ folgt ganz analog | |||||
| \begin{salign*} | |||||
| |u_n| &= \left| a_n - \frac{c_n}{u_{n-1}}b_{n-1} \right| \\ | |||||
| &\ge \Big| |c_n| \Big(1 - \underbrace{\frac{|b_{n-1}|}{|u_{n-1}|}}_{< 1}\Big) \Big| \\ | |||||
| &> 0 | |||||
| .\end{salign*} | |||||
| \end{proof} | |||||
| Beh.: Der Algorithmus liefert die angegebene LU-Zerlegung. | |||||
| \begin{proof} | |||||
| Es müssen je Zeile nur die $c_j$ eliminiert werden. Das wird mit $l_j = c_j / u_{j-1}$ erreicht. | |||||
| Da $b_j \neq 0$, wird noch die Diagonale modifiziert um $-l_{j}b_{j-1}$. Die $b_j$ werden | |||||
| nicht verändert, da die Elemente in $A$ oberhalb der $b_j$ null sind. Damit folgt die angegebene | |||||
| LU-Zerlegung. | |||||
| \end{proof} | |||||
| Beh.: $\text{det}(A) \neq 0$. | |||||
| \begin{proof} | |||||
| Es ist $\text{det}(A) = \text{det}(L) \cdot \text{det}(U) = 1 \underbrace{\cdot u_1 \cdots u_n}_{\neq 0} \neq 0$ | |||||
| \end{proof} | |||||
| \end{aufgabe} | |||||
| \begin{aufgabe} | |||||
| Sei $A \in \R^{n \times n}$ gegeben durch | |||||
| \[ | |||||
| a_{ij} = \begin{cases} | |||||
| +1 & i=j \lor j=n \\ | |||||
| -1 & i > j \\ | |||||
| 0 &\text{sonst} | |||||
| \end{cases} | |||||
| .\] | |||||
| \begin{enumerate}[a)] | |||||
| \item Es gilt nach VL für $1 \le k < n$: | |||||
| \[ | |||||
| l_i^{(k)} = \begin{cases} | |||||
| 0 & 1 \le i \le k \\ | |||||
| a_{ik}/a_{kk} & k < i \le n | |||||
| \end{cases} | |||||
| .\] | |||||
| Für $1 \le i < n$ gilt: Wegen $a_{ij} = 0$ für $j > i$, werden die Pivotelemenete $a_{ii} = 1$ | |||||
| nicht modifiziert. Damit folgt | |||||
| \[ | |||||
| l_{ij} = \begin{cases} | |||||
| 0 & i < j \\ | |||||
| +1 & i = j \\ | |||||
| -1 & i> j | |||||
| \end{cases} | |||||
| ,\] also $|l_{ij}| \le 1$. Da $l_{ij} = -1$ für $i > j$, gilt für $i > k$: | |||||
| \[ | |||||
| a_{in}^{(k)} = a_{in}^{(k-1)} - (-1) \cdot a_{kn}^{(k)} | |||||
| .\] Damit folgt | |||||
| \[ | |||||
| u_{in}^{(k)} = \begin{cases} | |||||
| u_{in}^{(k-1)} & 1 \le i \le k \\ | |||||
| u_{in}^{(k-1)} + u_{kn}^{(k)} & k+1 \le i \le n | |||||
| \end{cases} | |||||
| = \begin{cases} | |||||
| u_{in}^{(k-1)} & 1 \le i \le k \\ | |||||
| 2 u_{in}^{(k-1)} & k+1 \le i \le n | |||||
| \end{cases} | |||||
| .\] Insgesamt folgt | |||||
| \[ | |||||
| u_{nn} = u_{n n}^{(n-1)} = 2 u_{nn}^{(n-2)} = \ldots = 2^{n-1} u_{nn}^{(1)} = 2^{n-1} | |||||
| .\] | |||||
| \item Verwende Spaltenvertauschungen $Q \in \R^{n \times n}$, $j$-te Spalte von $Q$ gegeben als | |||||
| \[ | |||||
| Q_j = \begin{cases} | |||||
| e_n & j = 1 \\ | |||||
| e_{j-1} & 1 < j \le n | |||||
| \end{cases} | |||||
| .\] Dann hat $AQ$ die Form | |||||
| \[ | |||||
| (AQ)_{ij} = \begin{cases} | |||||
| +1 & j = 1 \lor i+1 = j \\ | |||||
| -1 & j\neq 1 \land j < i+1 \\ | |||||
| 0 & \text{sonst} | |||||
| \end{cases} | |||||
| .\] | |||||
| Induktion über $n$. Für $n = 2$ gilt | |||||
| \[ | |||||
| A = \begin{pmatrix} 1 & 1 \\ -1 & 1 \end{pmatrix} | |||||
| \implies | |||||
| AQ = \begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix} | |||||
| = | |||||
| \underbrace{\begin{pmatrix} 1 & 0 \\ 1 & 1 \end{pmatrix}}_{=: L} | |||||
| \underbrace{\begin{pmatrix} 1 & 1 \\ 0 & -2 \end{pmatrix} }_{=: U} | |||||
| .\] Es gilt also $u_{nn} = -2$, insbes. $|u_{nn}| = 2 = \max \{|1|, |-2|\} $. | |||||
| Sei nun $n \in \N$ beliebig und Beh. gezeigt für $n-1$. Dann ist | |||||
| \[ | |||||
| AQ = \begin{bmatrix} \tilde{A} & \begin{matrix} 0 \\ \vdots \\ 1 \end{matrix} \\ | |||||
| \begin{matrix} 1 & -1 & \cdots & -1 \end{matrix} & -1 \end{bmatrix} | |||||
| .\] Wende Operationen der Gauß-Elimination von $\tilde{A} \in \R^{(n-1)\times (n-1)}$ auf $AQ$ an | |||||
| Für $1 \le i \le n-2$ gilt $a_{in}= 0$, also bleibt $n$-te Spalte unverändert. Letzte Zeile | |||||
| zu $0$ eliminiert, bis auf $a_{n(n-1} = -1$. Nach I.V. gilt | |||||
| jetzt $a'_{(n-1)(n-1)} = -2$. Mit $l = 1$ folgt | |||||
| \[ | |||||
| u_{nn} = a'_{nn} = a_{nn} - a_{(n-1)n} = -1 -1 = -2 | |||||
| .\] Es ist weiter | |||||
| \[ | |||||
| u_{ni} = a_{ni} = \begin{cases} | |||||
| 0 & 1 \le i < n -1 \\ | |||||
| 1 & i = n-1 \\ | |||||
| -2 & i = n | |||||
| \end{cases} | |||||
| .\] Damit folgt die Behauptung. | |||||
| \end{enumerate} | |||||
| \end{aufgabe} | |||||
| \begin{aufgabe} | |||||
| siehe \textit{prog\_iterative\_solvers.cc} und \textit{iterative\_solvers\_plot.png}. | |||||
| \end{aufgabe} | |||||
| \end{document} | |||||
| @@ -0,0 +1,183 @@ | |||||
| #include <iostream> // notwendig zur Ausgabe | |||||
| #include <vector> | |||||
| #include "hdnum.hh" // hdnum header | |||||
| namespace hdnum { | |||||
| template<typename REAL> | |||||
| class SparseMatrix { | |||||
| struct MatrixEntry { | |||||
| int i; | |||||
| int j; | |||||
| REAL value; | |||||
| }; | |||||
| public: | |||||
| void AddEntry (int i, int j, REAL value) { | |||||
| assert(i >= 0); | |||||
| assert(j >= 0); | |||||
| if (value != .0) | |||||
| entries.push_back(MatrixEntry{.i=i, .j=j, .value=value}); | |||||
| } | |||||
| template<typename V> | |||||
| void mv (Vector<V>& y, const Vector<V>& x) { | |||||
| zero(y); | |||||
| for (MatrixEntry& matrix_entry : entries) { | |||||
| assert(y.size() > matrix_entry.i); | |||||
| assert(x.size() > matrix_entry.j); | |||||
| y[matrix_entry.i] += matrix_entry.value * x[matrix_entry.j]; | |||||
| } | |||||
| } | |||||
| //private: | |||||
| std::vector<MatrixEntry> entries; | |||||
| }; | |||||
| } | |||||
| // generic iterative updater function | |||||
| typedef void iterativeUpdater(hdnum::DenseMatrix<double>& A, | |||||
| hdnum::SparseMatrix<double>& A_s, | |||||
| int N, | |||||
| hdnum::Vector<double>& x_tmp, | |||||
| hdnum::Vector<double>& b, | |||||
| hdnum::Vector<double>& d, | |||||
| hdnum::Vector<double>& x); | |||||
| // solve iterative based on given method | |||||
| void solveIterative(hdnum::DenseMatrix<double>& A, | |||||
| hdnum::SparseMatrix<double>& A_s, | |||||
| hdnum::Vector <double>& x, | |||||
| hdnum::Vector<double>& b, | |||||
| iterativeUpdater update) { | |||||
| int N = A.rowsize(); | |||||
| // defekt vektor | |||||
| hdnum::Vector<double> d(N); | |||||
| // temporary variable | |||||
| hdnum::Vector<double> x_tmp(N); | |||||
| A_s.mv(x_tmp, x); | |||||
| d = b - x_tmp; | |||||
| double initialDefekt = d.two_norm(); | |||||
| while (d.two_norm() > initialDefekt * 10e-4) { | |||||
| // run one iteration | |||||
| update(A, A_s, N, x_tmp, b, d, x); | |||||
| } | |||||
| } | |||||
| // richardson: W = 1/omega I => W^-1 = omega I | |||||
| inline void richardson(hdnum::DenseMatrix<double>& A, | |||||
| hdnum::SparseMatrix<double>& A_s, | |||||
| int N, | |||||
| hdnum::Vector<double>& x_tmp, | |||||
| hdnum::Vector<double>& b, | |||||
| hdnum::Vector<double>& d, | |||||
| hdnum::Vector<double>& x) { | |||||
| A_s.mv(x_tmp, x); | |||||
| d = b - x_tmp; | |||||
| // x(k+1) = x(k) + omega * d(k) | |||||
| // hier omega = -0.01 | |||||
| for (int i=0; i<N; i++) { | |||||
| x_tmp[i] = -0.5*d[i]; | |||||
| } | |||||
| x += x_tmp; | |||||
| } | |||||
| // jacobi: W = D | |||||
| inline void jacobi(hdnum::DenseMatrix<double>& A, | |||||
| hdnum::SparseMatrix<double>& A_s, | |||||
| int N, | |||||
| hdnum::Vector<double>& x_tmp, | |||||
| hdnum::Vector<double>& b, | |||||
| hdnum::Vector<double>& d, | |||||
| hdnum::Vector<double>& x) { | |||||
| A_s.mv(x_tmp, x); | |||||
| d = b - x_tmp; | |||||
| // jacobi iteration, teile durch Diagonal Elemente | |||||
| // x(k+1) = x(k) + D^-1 d(k) | |||||
| for (int i=0; i<N; i++) { | |||||
| x_tmp[i] = d[i]/A[i][i]; | |||||
| } | |||||
| x += x_tmp; | |||||
| } | |||||
| // gauss seidel: W = L + D | |||||
| inline void gaussSeidel(hdnum::DenseMatrix<double>& A, | |||||
| hdnum::SparseMatrix<double>& A_s, | |||||
| int N, | |||||
| hdnum::Vector<double>& x_tmp, | |||||
| hdnum::Vector<double>& b, | |||||
| hdnum::Vector<double>& d, | |||||
| hdnum::Vector <double>& x) { | |||||
| A_s.mv(x_tmp, x); | |||||
| d = b - x_tmp; | |||||
| x_tmp = d; | |||||
| // x(k+1) = x(k) + v(k) | |||||
| // W*v(k) = d(k) | |||||
| // W untere Dreicksmatrix, loese W*v(k) = d(k) durch Vorwaertseinsetzen | |||||
| for (int i = 0; i<N; i++) { | |||||
| x_tmp[i] = d[i]; | |||||
| for (int j=i-1; 0<=j && j<i; j++) { // Elemente abseits der Hauptdiagonale von A sind 0 | |||||
| x_tmp[i] -= x_tmp[j] * A[i][j]; | |||||
| } | |||||
| x_tmp[i] /= A[i][i]; | |||||
| } | |||||
| x += x_tmp; | |||||
| } | |||||
| void testApproximation(hdnum::DenseMatrix<double>& A, | |||||
| hdnum::SparseMatrix<double>& A_s, | |||||
| hdnum::Vector<double>& x, | |||||
| hdnum::Vector<double>& b, | |||||
| iterativeUpdater updater) { | |||||
| int N = A.rowsize(); | |||||
| hdnum::Vector<double> y(N); | |||||
| // teste iteration mit gegebenem verfahren | |||||
| solveIterative(A,A_s,x,b,updater); | |||||
| // vergleiche mit LU Zerleger | |||||
| hdnum::linsolve(A,y,b); | |||||
| std::cout << "Relativer Fehler: " << (y - x).two_norm() / y.two_norm() << std::endl; | |||||
| } | |||||
| int main () { | |||||
| for(int n=4; n<=9; n++) { | |||||
| int N = pow(2,n); | |||||
| // Testmatrix aufsetzen | |||||
| hdnum::DenseMatrix<double> A(N,N,.0); | |||||
| hdnum::SparseMatrix<double> A_s; | |||||
| for (typename hdnum::DenseMatrix<double>::size_type i=0; i<A.rowsize(); ++i) { | |||||
| if (i > 0) { | |||||
| A[i][i-1] = 1.0; | |||||
| A_s.AddEntry(i, i-1, 1.0); | |||||
| } | |||||
| if (i + 1 < A.colsize()) { | |||||
| A[i][i+1] = 1.0; | |||||
| A_s.AddEntry(i, i+1, 1.0); | |||||
| } | |||||
| A[i][i] -= 2.0; | |||||
| A_s.AddEntry(i, i, -2.0); | |||||
| } | |||||
| // Rechte Seite und Lösungsvektor | |||||
| hdnum::Vector<double> x(N, 0.0); | |||||
| hdnum::Vector<double> b(N, 1.0); | |||||
| // Lösen Sie nun A*x=b iterativ | |||||
| // Pretty-printing fuer Vektoren | |||||
| x.scientific(false); | |||||
| x.width(15); | |||||
| // testApproximation(A,A_s,x,b,richardson); | |||||
| hdnum::Timer myTimer; | |||||
| solveIterative(A,A_s,x,b,gaussSeidel); | |||||
| //hdnum::linsolve(A,x,b); | |||||
| std::cout << N << " " << myTimer.elapsed() << std::endl; | |||||
| } | |||||
| } | |||||