|
- #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) {
- if (i < 0 || j < 0)
- HDNUM_ERROR("Zeilen und Spalten dürfen nicht negativ sein!");
- // create new matrix entry
- MatrixEntry entry;
- entry.i = i;
- entry.j = j;
- entry.value = value;
- // add entry to entries vector
- entries.insert(entries.begin(), entry);
- }
-
- template<typename V>
- void mv (Vector<V>& y, const Vector<V>& x) {
- // iterate through all entries
- for(typename std::vector<MatrixEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
- if ((*it).i > y.size() || (*it).j > x.size())
- HDNUM_ERROR("Vektor(en) hat/haben falsche Dimension!");
- // modify corresponding vector entry
- y[(*it).i] += x[(*it).j] * (*it).value;
- }
- }
-
- private:
- // vector storing non-zero elements
- std::vector<MatrixEntry> entries;
- };
- }
-
- // zum Test, fluss matrizen aus rohrleitungsnetzwerk
- hdnum::SparseMatrix<double> flussMatrixSparse(int N) {
- hdnum::SparseMatrix<double> A;
-
- // berechnung der kantenlaenge
- int n = floor(sqrt(N+1));
-
- for(int i = 0; i < N; i++) {
- int edges = 0;
- if ((i+1)%n != 0) { // nicht linker rand
- edges++;
- if (i-1 >= 0) A.AddEntry(i, i-1, -1);
- }
- if ((i+2)%n != 0) { // nicht rechter rand
- edges++;
- A.AddEntry(i, i+1, -1);
- }
- if (i+n < N) { // nicht unterer rand
- edges++;
- A.AddEntry(i, i+n, -1);
- }
- if (i-n >= -1) { // nicht oberer rand
- edges++;
- if (i-n >= 0) A.AddEntry(i, i-n, -1);
- }
- A.AddEntry(i, i, edges);
- }
- return A;
- }
-
- // Funktion zum Aufstellen der Matrix (aus rohrleitungsnetzwerk)
- hdnum::DenseMatrix<double> flussMatrix(int N) {
- hdnum::DenseMatrix<double> A(N,N);
-
- // berechnung der kantenlaenge
- int n = floor(sqrt(N+1));
-
- for(int i = 0; i < N; i++) {
- int edges = 0;
- if ((i+1)%n != 0) { // nicht linker rand
- edges++;
- if (i-1 >= 0) A(i, i-1) = -1; // falls nicht der referenzknoten
- }
- if ((i+2)%n != 0) { // nicht rechter rand
- edges++;
- A(i, i+1) = -1;
- }
- if (i+n < N) { // nicht unterer rand
- edges++;
- A(i, i+n) = -1;
- }
- if (i-n >= -1) { // nicht oberer rand
- edges++;
- if (i-n >= 0) A(i, i-n) = -1; // falls nicht der referenzknoten
- }
- A(i, i) = edges;
- }
- return A;
- }
-
- // funktion zum testen
- void testMatrixVectorProduct(int N) {
- hdnum::SparseMatrix<double> A = flussMatrixSparse(N);
- hdnum::DenseMatrix<double> B = flussMatrix(N);
-
- // test vektor
- hdnum::Vector<double> x(N);
- for(int i=0; i<N; i++) {
- x[i] = i+1;
- }
- hdnum::Vector<double> y1(N);
- hdnum::Vector<double> y2(N);
-
- // Pretty-printing fuer Vektoren
- x.scientific(false);
- x.width(15);
-
- // test ob Ax = Bx
- A.mv(y1, x);
- B.mv(y2, x);
- std::cout << "Mit Sparse Matrix: " << y1 << std::endl;
- std::cout << "Mit Dense Matrix: " << y2;
- }
-
- int main () {
- // testMatrixVectorProduct(15);
-
- // messe zeiten fuer n=4,...,14 und N = 2^n
- for(int n=4; n<=14; n++) {
- int N = pow(2, n);
-
- // test vektor
- hdnum::Vector<double> x(N);
- for(int i=0; i<N; i++) {
- x[i] = i+1;
- }
- hdnum::Vector<double> y(N);
-
- hdnum::SparseMatrix<double> A = flussMatrixSparse(N);
- hdnum::DenseMatrix<double> B = flussMatrix(N);
-
- // timer hier fuer die SparseMatrix implementierung
- hdnum::Timer myTimer;
- A.mv(y, x);
- std::cout << N << " " << myTimer.elapsed() << std::endl;
- }
- }
|