153 lines
4.2 KiB
C++
153 lines
4.2 KiB
C++
#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;
|
|
}
|
|
}
|