Für Vorlesungen, bitte die Webseite verwenden. https://flavigny.de/lecture
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
5.4KB

  1. #include <iostream> // notwendig zur Ausgabe
  2. #include <vector>
  3. #include "hdnum.hh" // hdnum header
  4. namespace hdnum {
  5. template<typename REAL>
  6. class SparseMatrix {
  7. struct MatrixEntry {
  8. int i;
  9. int j;
  10. REAL value;
  11. };
  12. public:
  13. void AddEntry (int i, int j, REAL value) {
  14. assert(i >= 0);
  15. assert(j >= 0);
  16. if (value != .0)
  17. entries.push_back(MatrixEntry{.i=i, .j=j, .value=value});
  18. }
  19. template<typename V>
  20. void mv (Vector<V>& y, const Vector<V>& x) {
  21. zero(y);
  22. for (MatrixEntry& matrix_entry : entries) {
  23. assert(y.size() > matrix_entry.i);
  24. assert(x.size() > matrix_entry.j);
  25. y[matrix_entry.i] += matrix_entry.value * x[matrix_entry.j];
  26. }
  27. }
  28. //private:
  29. std::vector<MatrixEntry> entries;
  30. };
  31. }
  32. // generic iterative updater function
  33. typedef void iterativeUpdater(hdnum::DenseMatrix<double>& A,
  34. hdnum::SparseMatrix<double>& A_s,
  35. int N,
  36. hdnum::Vector<double>& x_tmp,
  37. hdnum::Vector<double>& b,
  38. hdnum::Vector<double>& d,
  39. hdnum::Vector<double>& x);
  40. // solve iterative based on given method
  41. void solveIterative(hdnum::DenseMatrix<double>& A,
  42. hdnum::SparseMatrix<double>& A_s,
  43. hdnum::Vector <double>& x,
  44. hdnum::Vector<double>& b,
  45. iterativeUpdater update) {
  46. int N = A.rowsize();
  47. // defekt vektor
  48. hdnum::Vector<double> d(N);
  49. // temporary variable
  50. hdnum::Vector<double> x_tmp(N);
  51. A_s.mv(x_tmp, x);
  52. d = b - x_tmp;
  53. double initialDefekt = d.two_norm();
  54. while (d.two_norm() > initialDefekt * 10e-4) {
  55. // run one iteration
  56. update(A, A_s, N, x_tmp, b, d, x);
  57. }
  58. }
  59. // richardson: W = 1/omega I => W^-1 = omega I
  60. inline void richardson(hdnum::DenseMatrix<double>& A,
  61. hdnum::SparseMatrix<double>& A_s,
  62. int N,
  63. hdnum::Vector<double>& x_tmp,
  64. hdnum::Vector<double>& b,
  65. hdnum::Vector<double>& d,
  66. hdnum::Vector<double>& x) {
  67. A_s.mv(x_tmp, x);
  68. d = b - x_tmp;
  69. // x(k+1) = x(k) + omega * d(k)
  70. // hier omega = -0.01
  71. for (int i=0; i<N; i++) {
  72. x_tmp[i] = -0.5*d[i];
  73. }
  74. x += x_tmp;
  75. }
  76. // jacobi: W = D
  77. inline void jacobi(hdnum::DenseMatrix<double>& A,
  78. hdnum::SparseMatrix<double>& A_s,
  79. int N,
  80. hdnum::Vector<double>& x_tmp,
  81. hdnum::Vector<double>& b,
  82. hdnum::Vector<double>& d,
  83. hdnum::Vector<double>& x) {
  84. A_s.mv(x_tmp, x);
  85. d = b - x_tmp;
  86. // jacobi iteration, teile durch Diagonal Elemente
  87. // x(k+1) = x(k) + D^-1 d(k)
  88. for (int i=0; i<N; i++) {
  89. x_tmp[i] = d[i]/A[i][i];
  90. }
  91. x += x_tmp;
  92. }
  93. // gauss seidel: W = L + D
  94. inline void gaussSeidel(hdnum::DenseMatrix<double>& A,
  95. hdnum::SparseMatrix<double>& A_s,
  96. int N,
  97. hdnum::Vector<double>& x_tmp,
  98. hdnum::Vector<double>& b,
  99. hdnum::Vector<double>& d,
  100. hdnum::Vector <double>& x) {
  101. A_s.mv(x_tmp, x);
  102. d = b - x_tmp;
  103. x_tmp = d;
  104. // x(k+1) = x(k) + v(k)
  105. // W*v(k) = d(k)
  106. // W untere Dreicksmatrix, loese W*v(k) = d(k) durch Vorwaertseinsetzen
  107. for (int i = 0; i<N; i++) {
  108. x_tmp[i] = d[i];
  109. for (int j=i-1; 0<=j && j<i; j++) { // Elemente abseits der Hauptdiagonale von A sind 0
  110. x_tmp[i] -= x_tmp[j] * A[i][j];
  111. }
  112. x_tmp[i] /= A[i][i];
  113. }
  114. x += x_tmp;
  115. }
  116. void testApproximation(hdnum::DenseMatrix<double>& A,
  117. hdnum::SparseMatrix<double>& A_s,
  118. hdnum::Vector<double>& x,
  119. hdnum::Vector<double>& b,
  120. iterativeUpdater updater) {
  121. int N = A.rowsize();
  122. hdnum::Vector<double> y(N);
  123. // teste iteration mit gegebenem verfahren
  124. solveIterative(A,A_s,x,b,updater);
  125. // vergleiche mit LU Zerleger
  126. hdnum::linsolve(A,y,b);
  127. std::cout << "Relativer Fehler: " << (y - x).two_norm() / y.two_norm() << std::endl;
  128. }
  129. int main () {
  130. for(int n=4; n<=9; n++) {
  131. int N = pow(2,n);
  132. // Testmatrix aufsetzen
  133. hdnum::DenseMatrix<double> A(N,N,.0);
  134. hdnum::SparseMatrix<double> A_s;
  135. for (typename hdnum::DenseMatrix<double>::size_type i=0; i<A.rowsize(); ++i) {
  136. if (i > 0) {
  137. A[i][i-1] = 1.0;
  138. A_s.AddEntry(i, i-1, 1.0);
  139. }
  140. if (i + 1 < A.colsize()) {
  141. A[i][i+1] = 1.0;
  142. A_s.AddEntry(i, i+1, 1.0);
  143. }
  144. A[i][i] -= 2.0;
  145. A_s.AddEntry(i, i, -2.0);
  146. }
  147. // Rechte Seite und Lösungsvektor
  148. hdnum::Vector<double> x(N, 0.0);
  149. hdnum::Vector<double> b(N, 1.0);
  150. // Lösen Sie nun A*x=b iterativ
  151. // Pretty-printing fuer Vektoren
  152. x.scientific(false);
  153. x.width(15);
  154. // testApproximation(A,A_s,x,b,richardson);
  155. hdnum::Timer myTimer;
  156. solveIterative(A,A_s,x,b,gaussSeidel);
  157. //hdnum::linsolve(A,x,b);
  158. std::cout << N << " " << myTimer.elapsed() << std::endl;
  159. }
  160. }