From 06b8e6cc7deb30f11338321cb02d18643d53e421 Mon Sep 17 00:00:00 2001 From: WickedJack99 Date: Tue, 6 May 2025 12:42:05 +0200 Subject: [PATCH] hi --- lab07/aaron/HPC-Lab-07.pdf | Bin 0 -> 106377 bytes lab07/aaron/e1/jacobiWaveSplitWork.cpp | 191 ++++++++++ .../e1/jacobiWaveThreadsNumEqualsRowsNum.cpp | 198 ++++++++++ lab07/aaron/e1/matrix.h | 343 ++++++++++++++++++ .../aaron/e2/__MACOSX/upload/._create_data.py | Bin 0 -> 194 bytes lab07/aaron/e2/__MACOSX/upload/._dbscan.cpp | Bin 0 -> 194 bytes lab07/aaron/e2/__MACOSX/upload/._dbscan.h | Bin 0 -> 194 bytes lab07/aaron/e2/__MACOSX/upload/._makefile | Bin 0 -> 194 bytes lab07/aaron/e2/__MACOSX/upload/._plot.py | Bin 0 -> 194 bytes lab07/aaron/e2/__MACOSX/upload/._run.cpp | Bin 0 -> 194 bytes lab07/aaron/e2/upload/benchmark.cpp | 23 ++ lab07/aaron/e2/upload/create_data.py | 12 + lab07/aaron/e2/upload/dbscan_parallel.cpp | 65 ++++ lab07/aaron/e2/upload/dbscan_parallel.h | 37 ++ lab07/aaron/e2/upload/dbscan_serial.cpp | 60 +++ lab07/aaron/e2/upload/dbscan_serial.h | 36 ++ lab07/aaron/e2/upload/makefile | 43 +++ lab07/aaron/e2/upload/plot.py | 14 + lab07/aaron/e2/upload/point.cpp | 55 +++ lab07/aaron/e2/upload/point.h | 53 +++ lab07/aaron/e2/upload/run.cpp | 19 + 21 files changed, 1149 insertions(+) create mode 100644 lab07/aaron/HPC-Lab-07.pdf create mode 100644 lab07/aaron/e1/jacobiWaveSplitWork.cpp create mode 100644 lab07/aaron/e1/jacobiWaveThreadsNumEqualsRowsNum.cpp create mode 100644 lab07/aaron/e1/matrix.h create mode 100644 lab07/aaron/e2/__MACOSX/upload/._create_data.py create mode 100644 lab07/aaron/e2/__MACOSX/upload/._dbscan.cpp create mode 100644 lab07/aaron/e2/__MACOSX/upload/._dbscan.h create mode 100644 lab07/aaron/e2/__MACOSX/upload/._makefile create mode 100644 lab07/aaron/e2/__MACOSX/upload/._plot.py create mode 100644 lab07/aaron/e2/__MACOSX/upload/._run.cpp create mode 100644 lab07/aaron/e2/upload/benchmark.cpp create mode 100644 lab07/aaron/e2/upload/create_data.py create mode 100644 lab07/aaron/e2/upload/dbscan_parallel.cpp create mode 100644 lab07/aaron/e2/upload/dbscan_parallel.h create mode 100644 lab07/aaron/e2/upload/dbscan_serial.cpp create mode 100644 lab07/aaron/e2/upload/dbscan_serial.h create mode 100644 lab07/aaron/e2/upload/makefile create mode 100644 lab07/aaron/e2/upload/plot.py create mode 100644 lab07/aaron/e2/upload/point.cpp create mode 100644 lab07/aaron/e2/upload/point.h create mode 100644 lab07/aaron/e2/upload/run.cpp diff --git a/lab07/aaron/HPC-Lab-07.pdf b/lab07/aaron/HPC-Lab-07.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b3db1ded0e42c411a52d94ac25315b208ada6b98 GIT binary patch literal 106377 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%0ACKRT962(`|?+b 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 +#include +#include + +void gauss_seidel(Matrix &phi, int maxNumIter) +{ + const int m = phi.dim1(); + const int n = phi.dim2(); + const double osth = 1. / 4; + for (int iIter = 0; iIter < maxNumIter; ++iIter) + { + // Shared data per iteration + std::vector> column(m); + for (int i = 0; i < m; ++i) + { + column[i].store(1); + } + std::atomic threadsCount(0); + +#pragma omp parallel for schedule(static) + for (int rowToCalculate = 1; rowToCalculate < (n - 1); rowToCalculate++) + { + int row = rowToCalculate; + while (column[row] < n - 1) + { + // All threads beneath T_row1 have to check specific circumstances, where + // T_row1 has no condition to wait for + if (row != 1) + { + // T_rowx has to wait at least until T_row(x-1) has calculated values from + // its last row + // T_rowx will calculate value x at row,column if T_row(x-1) has calculated + // its value at row-1, column-1 + while (column[row] == column[row - 1]) + { + // Wait for wave (thread) above + } + } + + // Central jacobi calculation + phi(row, column[row]) = osth * (phi(row + 1, column[row]) + phi(row - 1, column[row]) + phi(row, column[row] + 1) + + phi(row, column[row] - 1)); + + // Increment column index + column[row]++; + } + } + } +} + +void gauss_seidel_lin(Matrix &phi, int maxNumIter) +{ + const int m = phi.dim1(); + const int n = phi.dim2(); + + const double osth = 1. / 4; + + for (int iter = 0; iter < maxNumIter; ++iter) + { + for (int i = 1; i < m - 1; ++i) + { + for (int j = 1; j < n - 1; ++j) + { + phi(i, j) = osth * (phi(i + 1, j) + phi(i - 1, j) + phi(i, j + 1) + + phi(i, j - 1)); + } + } + } +} + +void fill_matrix(Matrix &matrix, const int filler) +{ + const int m = matrix.dim1(); + const int n = matrix.dim2(); + + for (int i = 0; i < m; ++i) + { + for (int j = 0; j < n; ++j) + { + if (i == 0 || i == m - 1 || j == 0 || j == n - 1) + { + matrix(i, j) = filler; + } + else + matrix(i, j) = 0; + } + } +} + +void check(const Matrix &a, const Matrix &b) +{ + const int m = a.dim1(); + const int n = a.dim2(); + + for (int i = 0; i < m; ++i) + { + for (int j = 0; j < n; ++j) + { + if (a(i, j) != b(i, j)) + { + std::cout << "Not equal at (" << i << ", " << j << "), a: " << a(i, j) + << " != " << b(i, j) << " :b" << std::endl; + } + } + } +} + +void print_matrix(const Matrix &matrix) +{ + const int m = matrix.dim1(); + const int n = matrix.dim2(); + + for (int i = 0; i < m; ++i) + { + for (int j = 0; j < n; ++j) + { + std::cout << matrix(i, j) << " "; + } + std::cout << std::endl; + } +} + +int main() +{ + Matrix first = Matrix(8, 8); + Matrix sec = Matrix(8, 8); + + fill_matrix(first, 10); + fill_matrix(sec, 10); + + print_matrix(first); + print_matrix(sec); + + gauss_seidel_lin(first, 1000); + gauss_seidel(sec, 1000); + + check(first, sec); + + print_matrix(first); + print_matrix(sec); + + return 0; +} \ No newline at end of file diff --git a/lab07/aaron/e1/jacobiWaveThreadsNumEqualsRowsNum.cpp b/lab07/aaron/e1/jacobiWaveThreadsNumEqualsRowsNum.cpp new file mode 100644 index 0000000..3f434eb --- /dev/null +++ b/lab07/aaron/e1/jacobiWaveThreadsNumEqualsRowsNum.cpp @@ -0,0 +1,198 @@ +// WORKS! + +/** + * Spalte 0 1 2 3 4 5 6 + * Schritt + * 0 + * + * 1 + * + * 2 + * + * 3 + * + * Über Schritte iterieren statt ? + * + * Beispiel A: jeder Thread bearbeitet eine Zeile, es gibt genau m Threads. + * D.h. m / t = 1 + * + * Beispiel B: es gibt eine konstante Anzahl Threads t es gibt m Zeilen. + * Thread tx nimmt sich irgendeine Zeile und + * + * Schritt 1 + * ------------- + * |T0|--|--|--| + * ------------- + * |--|--|--|--| + * ------------- + * |--|--|--|--| + * ------------- + * |--|--|--|--| + * ------------- + * + * Schritt 2 + * ------------- + * |xx|T0|--|--| + * ------------- + * |T1|--|--|--| + * ------------- + * |--|--|--|--| + * ------------- + * |--|--|--|--| + * ------------- + * + * Schritt 3 + * ------------- + * |xx|xx|T0|--| + * ------------- + * |xx|T1|--|--| + * ------------- + * |T2|--|--|--| + * ------------- + * |--|--|--|--| + * ------------- + * + * Schritt 4 + * ------------- + * |xx|xx|xx|T0| + * ------------- + * |xx|xx|T1|--| + * ------------- + * |xx|T2|--|--| + * ------------- + * |T3|--|--|--| + * ------------- + */ + +#include "matrix.h" +#include +#include +#include + +void gauss_seidel(Matrix &phi, int maxNumIter) +{ + const int m = phi.dim1(); + const int n = phi.dim2(); + const double osth = 1. / 4; + for (int iIter = 0; iIter < maxNumIter; ++iIter) + { + int threadNum = m - 2; + std::vector> columnsCalculated(threadNum); + for (int i = 0; i < threadNum; ++i) + { + columnsCalculated[i].store(1); + } +#pragma omp parallel num_threads(threadNum) + { + int threadId = omp_get_thread_num(); + int row = threadId + 1; + while (columnsCalculated[threadId] < n - 1) + { + int currentCol = columnsCalculated[threadId]; + if (threadId != 0) + { + while (currentCol == columnsCalculated[threadId - 1]) + { + } + } + phi(row, currentCol) = osth * (phi(row + 1, currentCol) + phi(row - 1, currentCol) + phi(row, currentCol + 1) + + phi(row, currentCol - 1)); + columnsCalculated[threadId]++; + } + } + } +} + +void gauss_seidel_lin(Matrix &phi, int maxNumIter) +{ + const int m = phi.dim1(); + const int n = phi.dim2(); + + const double osth = 1. / 4; + + for (int iter = 0; iter < maxNumIter; ++iter) + { + for (int i = 1; i < m - 1; ++i) + { + for (int j = 1; j < n - 1; ++j) + { + phi(i, j) = osth * (phi(i + 1, j) + phi(i - 1, j) + phi(i, j + 1) + + phi(i, j - 1)); + } + } + } +} + +void fill_matrix(Matrix &matrix, const int filler) +{ + const int m = matrix.dim1(); + const int n = matrix.dim2(); + + for (int i = 0; i < m; ++i) + { + for (int j = 0; j < n; ++j) + { + if (i == 0 || i == m - 1 || j == 0 || j == n - 1) + { + matrix(i, j) = filler; + } + else + matrix(i, j) = 0; + } + } +} + +void check(const Matrix &a, const Matrix &b) +{ + const int m = a.dim1(); + const int n = a.dim2(); + + for (int i = 0; i < m; ++i) + { + for (int j = 0; j < n; ++j) + { + if (a(i, j) != b(i, j)) + { + std::cout << "Not equal at (" << i << ", " << j << "), a: " << a(i, j) + << " != " << b(i, j) << " :b" << std::endl; + } + } + } +} + +void print_matrix(const Matrix &matrix) +{ + const int m = matrix.dim1(); + const int n = matrix.dim2(); + + for (int i = 0; i < m; ++i) + { + for (int j = 0; j < n; ++j) + { + std::cout << matrix(i, j) << " "; + } + std::cout << std::endl; + } +} + +int main() +{ + Matrix first = Matrix(8, 8); + Matrix sec = Matrix(8, 8); + + fill_matrix(first, 10); + fill_matrix(sec, 10); + + print_matrix(first); + print_matrix(sec); + + gauss_seidel_lin(first, 1); + gauss_seidel(sec, 1); + + check(first, sec); + + print_matrix(first); + print_matrix(sec); + + return 0; +} \ No newline at end of file diff --git a/lab07/aaron/e1/matrix.h b/lab07/aaron/e1/matrix.h new file mode 100644 index 0000000..8b2ae24 --- /dev/null +++ b/lab07/aaron/e1/matrix.h @@ -0,0 +1,343 @@ +/** + * matrix.h a very simplistic class for m times n matrices. + */ + +#ifndef MATRIX_H +#define MATRIX_H + +#include +#include +#include +#include + +// A very simplistic vector class for vectors of size n +class Vector { + public: + // constructors + Vector(int n) : n_(n), data_(n_, 0) {} + Vector(const Vector& other) = default; + Vector(Vector&& other) = default; + ~Vector() = default; + + // assignment operators + Vector& operator=(const Vector& other) = default; + Vector& operator=(Vector&& other) = default; + + // element access + double& operator()(int i) { return data_[i]; } + const double& operator()(int i) const { return data_[i]; } + + // getter functions for the dimensions + int dim() const { return n_; } + + // comparison operators + bool operator==(const Vector& b) { return (data_ == b.data_); } + bool operator!=(const Vector& b) { return (data_ != b.data_); } + + // addition + Vector& operator+=(const Vector& b) { + for (int i = 0; i < n_; ++i) { + operator()(i) += b(i); + } + return *this; + } + + // subtraction + Vector& operator-=(const Vector& b) { + for (int i = 0; i < n_; ++i) { + operator()(i) -= b(i); + } + return *this; + } + + // scalar multiplication + Vector& operator*=(double x) { + for (int i = 0; i < n_; ++i) { + operator()(i) *= x; + } + return *this; + } + + // dot product between two vectors + double dot(const Vector& other) const { + double sum = 0; + for (int i = 0; i < n_; ++i) { + sum += operator()(i) * other(i); + } + return sum; + } + + private: + int n_; // vector dimension + std::vector data_; // the vectors entries +}; + +inline double dot(const Vector& v1, const Vector& v2) { + return v1.dot(v2); +} + +// Print the vector as a table +inline std::ostream& operator<<(std::ostream& os, const Vector& a) { + const int width = 10; + const int precision = 4; + + const auto originalPrecision = os.precision(); + os << std::setprecision(precision); + + for (int i = 0; i < a.dim(); ++i) { + os << std::setw(width) << a(i) << " "; + } + + os << "\n"; + + os << std::setprecision(originalPrecision); + return os; +} + +// A very simple class for m times n matrices +class Matrix { + public: + // constructors + Matrix() : Matrix(0, 0) {} + Matrix(int m, int n) : m_(m), n_(n), data_(m_ * n_, 0) {} + Matrix(std::pair dim) : Matrix(dim.first, dim.second) {} + Matrix(int n) : Matrix(n, n) {} + Matrix(const Matrix& other) = default; + Matrix(Matrix&& other) = default; + ~Matrix() = default; + + // assignment operators + Matrix& operator=(const Matrix& other) = default; + Matrix& operator=(Matrix&& other) = default; + + // element access + double& operator()(int i, int j) { return data_[i * n_ + j]; } + const double& operator()(int i, int j) const { return data_[i * n_ + j]; } + + // getter functions for the dimensions + std::pair dim() const { return std::pair(m_, n_); } + int dim1() const { return m_; } + int dim2() const { return n_; } + int numEntries() const { return data_.size(); } + + // comparison operators + bool operator==(const Matrix& b) { return (data_ == b.data_); } + bool operator!=(const Matrix& b) { return (data_ != b.data_); } + + // addition + Matrix& operator+=(const Matrix& b) { + for (int i = 0; i < m_; ++i) { + for (int j = 0; j < n_; ++j) { + operator()(i, j) += b(i, j); + } + } + return *this; + } + + // subtraction + Matrix& operator-=(const Matrix& b) { + for (int i = 0; i < m_; ++i) { + for (int j = 0; j < n_; ++j) { + operator()(i, j) -= b(i, j); + } + } + return *this; + } + + // scalar multiplication + Matrix& operator*=(double x) { + for (int i = 0; i < m_; ++i) { + for (int j = 0; j < n_; ++j) { + operator()(i, j) *= x; + } + } + return *this; + } + + // scalar division + Matrix& operator/=(double x) { + for (int i = 0; i < m_; ++i) { + for (int j = 0; j < n_; ++j) { + operator()(i, j) /= x; + } + } + return *this; + } + + // matrix product (only for square matrices of equal dimension) + Matrix& operator*=(const Matrix& b) { + if (dim1() != dim2()) { + std::cout << "Error in matrix multiplication: no square matrix\n"; + } else if (dim1() != b.dim1() || dim2() != b.dim2()) { + std::cout << "Error in matrix multiplication: dimensions do not match\n"; + } else { + Matrix a = *this; + Matrix& c = *this; + const int m = dim1(); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < m; ++j) { + for (int k = 0; k < m; ++k) { + c(i, j) += a(i, k) * b(k, j); + } + } + } + } + + return *this; + } + + public: + int m_; // first dimension + int n_; // second dimension + std::vector data_; // the matrix' entries +}; + +// Print the matrix as a table +inline std::ostream& operator<<(std::ostream& os, const Matrix& a) { + const int width = 10; + const int precision = 4; + + const auto originalPrecision = os.precision(); + os << std::setprecision(precision); + + for (int i = 0; i < a.dim1(); ++i) { + for (int j = 0; j < a.dim2(); ++j) { + os << std::setw(width) << a(i, j) << " "; + } + if (i != a.dim1() - 1) + os << "\n"; + } + + os << std::setprecision(originalPrecision); + return os; +} + +// matrix product +inline Matrix operator*(const Matrix& a, const Matrix& b) { + if (a.dim2() == b.dim1()) { + int m = a.dim1(); + int n = a.dim2(); + int p = b.dim2(); + Matrix c(m, p); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < p; ++j) { + for (int k = 0; k < n; ++k) { + c(i, j) += a(i, k) * b(k, j); + } + } + } + return c; + } else { + return Matrix(0, 0); + } +} + +inline bool equalWithinRange(const Matrix& a, + const Matrix& b, + double eps = 1e-12) { + if (a.dim1() != b.dim1() || a.dim2() != b.dim2()) + return false; + + int m = a.dim1(); + int n = a.dim2(); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (fabs(a(i, j) - b(i, j)) > eps) { + return false; + } + } + } + + return true; +} + +// A very simple class for "3D-Matrices" (tensors) with dimension l x m x n +class Matrix3D { + public: + // constructors + Matrix3D(int l, int m, int n) : l_(l), m_(m), n_(n), data_(l) { + for (int i = 0; i < l_; ++i) { + data_[i] = std::vector>(m_); + for (int j = 0; j < m_; ++j) { + data_[i][j] = std::vector(n_, 0); + } + } + } + Matrix3D(int n) : Matrix3D(n, n, n) {} + Matrix3D(const Matrix3D& other) = default; + Matrix3D(Matrix3D&& other) = default; + ~Matrix3D() = default; + + // assignment operators + Matrix3D& operator=(const Matrix3D& other) = default; + Matrix3D& operator=(Matrix3D&& other) = default; + + // element access + double& operator()(int i, int j, int k) { return data_[i][j][k]; } + const double& operator()(int i, int j, int k) const { return data_[i][j][k]; } + + // getter functions for the dimensions + int dim1() const { return l_; } + int dim2() const { return m_; } + int dim3() const { return n_; } + + // comparison operators + bool operator==(const Matrix3D& b) { return (data_ == b.data_); } + bool operator!=(const Matrix3D& b) { return (data_ != b.data_); } + + // addition + Matrix3D& operator+=(const Matrix3D& b) { + for (int i = 0; i < l_; ++i) { + for (int j = 0; j < m_; ++j) { + for (int k = 0; k < n_; ++k) { + operator()(i, j, k) += b(i, j, k); + } + } + } + return *this; + } + + // substraction + Matrix3D& operator-=(const Matrix3D& b) { + for (int i = 0; i < l_; ++i) { + for (int j = 0; j < m_; ++j) { + for (int k = 0; k < n_; ++k) { + operator()(i, j, k) -= b(i, j, k); + } + } + } + return *this; + } + + // scalar multiplication + Matrix3D& operator*=(double x) { + for (int i = 0; i < l_; ++i) { + for (int j = 0; j < m_; ++j) { + for (int k = 0; k < n_; ++k) { + operator()(i, j, k) *= x; + } + } + } + return *this; + } + + // scalar division + Matrix3D& operator/=(double x) { + for (int i = 0; i < l_; ++i) { + for (int j = 0; j < m_; ++j) { + for (int k = 0; k < n_; ++k) { + operator()(i, j, k) /= x; + } + } + } + return *this; + } + + private: + int l_; // first dimension + int m_; // second dimension + int n_; // third dimension + std::vector>> data_; // the tensors' entries +}; + +#endif // MATRIX_H \ No newline at end of file diff --git a/lab07/aaron/e2/__MACOSX/upload/._create_data.py b/lab07/aaron/e2/__MACOSX/upload/._create_data.py new file mode 100644 index 0000000000000000000000000000000000000000..5c3c52cf9a8d5394add9ae1515e17dddf3a34aa0 GIT binary patch literal 194 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@dO|S@ectp5x_AdBnYYuq+->g?hRuS?L<;D7nKJx%nxn KN>*kjCba-l!W*9e literal 0 HcmV?d00001 diff --git a/lab07/aaron/e2/__MACOSX/upload/._dbscan.cpp b/lab07/aaron/e2/__MACOSX/upload/._dbscan.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c3c52cf9a8d5394add9ae1515e17dddf3a34aa0 GIT binary patch literal 194 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@dO|S@ectp5x_AdBnYYuq+->g?hRuS?L<;D7nKJx%nxn KN>*kjCba-l!W*9e literal 0 HcmV?d00001 diff --git a/lab07/aaron/e2/__MACOSX/upload/._dbscan.h b/lab07/aaron/e2/__MACOSX/upload/._dbscan.h new file mode 100644 index 0000000000000000000000000000000000000000..5c3c52cf9a8d5394add9ae1515e17dddf3a34aa0 GIT binary patch literal 194 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@dO|S@ectp5x_AdBnYYuq+->g?hRuS?L<;D7nKJx%nxn KN>*kjCba-l!W*9e literal 0 HcmV?d00001 diff --git a/lab07/aaron/e2/__MACOSX/upload/._makefile b/lab07/aaron/e2/__MACOSX/upload/._makefile new file mode 100644 index 0000000000000000000000000000000000000000..5c3c52cf9a8d5394add9ae1515e17dddf3a34aa0 GIT binary patch literal 194 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@dO|S@ectp5x_AdBnYYuq+->g?hRuS?L<;D7nKJx%nxn KN>*kjCba-l!W*9e literal 0 HcmV?d00001 diff --git a/lab07/aaron/e2/__MACOSX/upload/._plot.py b/lab07/aaron/e2/__MACOSX/upload/._plot.py new file mode 100644 index 0000000000000000000000000000000000000000..5c3c52cf9a8d5394add9ae1515e17dddf3a34aa0 GIT binary patch literal 194 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@dO|S@ectp5x_AdBnYYuq+->g?hRuS?L<;D7nKJx%nxn KN>*kjCba-l!W*9e literal 0 HcmV?d00001 diff --git a/lab07/aaron/e2/__MACOSX/upload/._run.cpp b/lab07/aaron/e2/__MACOSX/upload/._run.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c3c52cf9a8d5394add9ae1515e17dddf3a34aa0 GIT binary patch literal 194 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@dO|S@ectp5x_AdBnYYuq+->g?hRuS?L<;D7nKJx%nxn KN>*kjCba-l!W*9e literal 0 HcmV?d00001 diff --git a/lab07/aaron/e2/upload/benchmark.cpp b/lab07/aaron/e2/upload/benchmark.cpp new file mode 100644 index 0000000..41aa205 --- /dev/null +++ b/lab07/aaron/e2/upload/benchmark.cpp @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include "dbscan.h" + +using namespace HPC; + +static void BM_DBSCAN(benchmark::State& state) { + // Load points from file + std::vector points = readPointsFromFile("data"); + + // Create DBSCAN object with parameters from the benchmark state + DBSCAN ds(5, 0.01); + + // Measure the time taken to run DBSCAN + for (auto _ : state) { + ds.run(points); + } +} + +BENCHMARK(BM_DBSCAN)->Unit(benchmark::kMillisecond)->Iterations(10); +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/lab07/aaron/e2/upload/create_data.py b/lab07/aaron/e2/upload/create_data.py new file mode 100644 index 0000000..145515a --- /dev/null +++ b/lab07/aaron/e2/upload/create_data.py @@ -0,0 +1,12 @@ +from sklearn.datasets import make_blobs +from sklearn.preprocessing import StandardScaler +import numpy as np + +centers = [[1, 1], [-1, -1], [1, -1], [-1.5, -1.5], [-2, 2], [1, 3]] +X, labels_true = make_blobs( + n_samples=27*1024, centers=centers, cluster_std=0.25, random_state=0 +) + +X = StandardScaler().fit_transform(X) + +np.savetxt("data", X) diff --git a/lab07/aaron/e2/upload/dbscan_parallel.cpp b/lab07/aaron/e2/upload/dbscan_parallel.cpp new file mode 100644 index 0000000..16a3ae6 --- /dev/null +++ b/lab07/aaron/e2/upload/dbscan_parallel.cpp @@ -0,0 +1,65 @@ +#include "dbscan_parallel.h" +#include +#include + +namespace HPC { + +DBSCAN::DBSCAN(int minPts, double eps) : minPoints_(minPts), epsilon_(eps) {} + +void DBSCAN::run(const std::vector& points) { + initializeNeighbors(); + + dataset_ = points; + const int n = dataset_.size(); + + int clusterIndex = 0; + for (int i = 0; i < n; ++i) { + Point& point = dataset_[i]; + if (point.clusterID < 0) { + std::set neighbours = point.neighbors; + if (neighbours.size() < minPoints_) { + point.clusterID = noiseID; + } else { + clusterIndex++; + expandCluster(point, neighbours, clusterIndex); + } + } + } +} + +bool DBSCAN::expandCluster(Point& p, std::set& neighbours, int clusterID) { + p.clusterID = clusterID; + + std::set updatedNeighbours = neighbours; + + // Use of do-while instead of clearing neighbors + do { + neighbours = updatedNeighbours; + + for (int i : neighbours) { + Point& pPrime = dataset_[i]; + if (pPrime.clusterID < 0) { + pPrime.clusterID = clusterID; // serves as marking the point as visited + std::set newNeighbours = pPrime.neighbors; + if (newNeighbours.size() >= minPoints_) { + updatedNeighbours.merge(newNeighbours); + } + } + } + } while (updatedNeighbours.size() != neighbours.size()); + return true; +} + +std::set DBSCAN::initializeNeighbors() { + #pragma omp parallel for + for (int i = 0; i < dataset_.size(); ++i) { + Point& pointToCheckNeighborsFor = dataset_[i]; + for (int j = 0; j < dataset_.size(); ++j) { + if (pointToCheckNeighborsFor.distance(dataset_[j]) <= epsilon_) { + pointToCheckNeighborsFor.neighbors.insert(j); + } + } + } +} + +} // namespace HPC \ No newline at end of file diff --git a/lab07/aaron/e2/upload/dbscan_parallel.h b/lab07/aaron/e2/upload/dbscan_parallel.h new file mode 100644 index 0000000..8584c6a --- /dev/null +++ b/lab07/aaron/e2/upload/dbscan_parallel.h @@ -0,0 +1,37 @@ +#ifndef DBSCAN_H +#define DBSCAN_H + +#include +#include + +#include "point.h" + +namespace HPC { + +class DBSCAN { + public: + DBSCAN(int minPts, double eps); + + void run(const std::vector& points); + + const std::vector& getPoints() const { return dataset_; } + + private: + std::set regionQuery(const Point& point) const; + std::set DBSCAN::initializeNeighbors(); + bool expandCluster(Point& point, std::set& neighbours, int clusterID); + + // void merge(std::vector& n, const std::vector& nPrime) const; + + const int unclassifiedID = -1; + const int noiseID = -2; + + const int minPoints_; + const double epsilon_; + + std::vector dataset_; +}; + +} // namespace HPC + +#endif // DBSCAN_H diff --git a/lab07/aaron/e2/upload/dbscan_serial.cpp b/lab07/aaron/e2/upload/dbscan_serial.cpp new file mode 100644 index 0000000..b940748 --- /dev/null +++ b/lab07/aaron/e2/upload/dbscan_serial.cpp @@ -0,0 +1,60 @@ +#include "dbscan.h" +#include +#include + +namespace HPC { + +DBSCAN::DBSCAN(int minPts, double eps) : minPoints_(minPts), epsilon_(eps) {} + +void DBSCAN::run(const std::vector& points) { + dataset_ = points; + const int n = dataset_.size(); + + int clusterIndex = 0; + for (int i = 0; i < n; ++i) { + Point& point = dataset_[i]; + if (point.clusterID < 0) { + std::set neighbours = regionQuery(point); + if (neighbours.size() < minPoints_) { + point.clusterID = noiseID; + } else { + clusterIndex++; + expandCluster(point, neighbours, clusterIndex); + } + } + } +} + +bool DBSCAN::expandCluster(Point& p, std::set& neighbours, int clusterID) { + p.clusterID = clusterID; + + std::set updatedNeighbours = neighbours; + neighbours.clear(); + while (updatedNeighbours.size() != neighbours.size()) { + neighbours = updatedNeighbours; + + for (int i : neighbours) { + Point& pPrime = dataset_[i]; + if (pPrime.clusterID < 0) { + pPrime.clusterID = clusterID; // serves as marking the point as visited + std::set newNeighbours = regionQuery(pPrime); + if (newNeighbours.size() >= minPoints_) { + updatedNeighbours.merge(newNeighbours); + } + } + } + } + return true; +} + +std::set DBSCAN::regionQuery(const Point& point) const { + std::set neighbours; + for (int i = 0; i < dataset_.size(); ++i) { + if (point.distance(dataset_[i]) <= epsilon_) { + neighbours.insert(i); + } + } + return neighbours; +} + +} // namespace HPC \ No newline at end of file diff --git a/lab07/aaron/e2/upload/dbscan_serial.h b/lab07/aaron/e2/upload/dbscan_serial.h new file mode 100644 index 0000000..7f90e75 --- /dev/null +++ b/lab07/aaron/e2/upload/dbscan_serial.h @@ -0,0 +1,36 @@ +#ifndef DBSCAN_H +#define DBSCAN_H + +#include +#include + +#include "point.h" + +namespace HPC { + +class DBSCAN { + public: + DBSCAN(int minPts, double eps); + + void run(const std::vector& points); + + const std::vector& getPoints() const { return dataset_; } + + private: + std::set regionQuery(const Point& point) const; + bool expandCluster(Point& point, std::set& neighbours, int clusterID); + + // void merge(std::vector& n, const std::vector& nPrime) const; + + const int unclassifiedID = -1; + const int noiseID = -2; + + const int minPoints_; + const double epsilon_; + + std::vector dataset_; +}; + +} // namespace HPC + +#endif // DBSCAN_H diff --git a/lab07/aaron/e2/upload/makefile b/lab07/aaron/e2/upload/makefile new file mode 100644 index 0000000..e1863e0 --- /dev/null +++ b/lab07/aaron/e2/upload/makefile @@ -0,0 +1,43 @@ +# Makefile for DBSCAN program + +# ---------------------------------------------------- +# Parameters +# Change these parameters according to your needs. + +# SOURCE_FILES: The source files of the algorithm, used for each build. +# You can add more source files here if needed. +SOURCE_FILES = dbscan.cpp point.cpp + +# Main rogram, used to cluster the data and save the result. +# PROGRAM_NAME: The name of the program that will be generated after compilation. +PROGRAM_NAME = dbscan +RUN_MAIN = run.cpp + +# Benchmark program: This program is used to benchmark the performance of the algorithm. +# It is not used for the actual clustering process. +BENCHMARK_PROGRAM_NAME = dbscan_bench +BENCHMARK_MAIN = benchmark.cpp + +COMPILER_FLAGS = -fopenmp -std=c++17 -lpthread + +# ---------------------------------------------------- +# The actual makefile rules, only change these if you really need to. + +# Default target +# The default target is the one that will be executed when you run 'make' without any arguments. +default: release + +release: $(RUN_MAIN) $(SOURCE_FILES) + g++ $(RUN_MAIN) $(SOURCE_FILES) $(COMPILER_FLAGS) -o $(PROGRAM_NAME) -O3 + +debug: $(RUN_MAIN) $(SOURCE_FILES) + g++ $(RUN_MAIN) $(SOURCE_FILES) $(COMPILER_FLAGS) -o $(PROGRAM_NAME) -O0 -g + +benchmark: $(BENCHMARK_MAIN) $(SOURCE_FILES) + g++ $(BENCHMARK_MAIN) $(SOURCE_FILES) $(COMPILER_FLAGS) -o $(BENCHMARK_PROGRAM_NAME) -O3 -lbenchmark + +run_bench: benchmark + ./$(BENCHMARK_PROGRAM_NAME) + +run: release + ./$(PROGRAM_NAME) diff --git a/lab07/aaron/e2/upload/plot.py b/lab07/aaron/e2/upload/plot.py new file mode 100644 index 0000000..63e876f --- /dev/null +++ b/lab07/aaron/e2/upload/plot.py @@ -0,0 +1,14 @@ +import pylab as plt +import numpy as np + +plt.figure() +points = plt.loadtxt("clustered") +cluster_index_column = 2 +clusters = np.unique(points[:, cluster_index_column]) +print(clusters) +for c in clusters: + points_in_cluster = points[np.where( + points[:, cluster_index_column] == c)[0]] + plt.scatter(points_in_cluster[:, 0], points_in_cluster[:, 1], label=c) + +plt.show() diff --git a/lab07/aaron/e2/upload/point.cpp b/lab07/aaron/e2/upload/point.cpp new file mode 100644 index 0000000..f2fca1b --- /dev/null +++ b/lab07/aaron/e2/upload/point.cpp @@ -0,0 +1,55 @@ +#include +#include + +#include "point.h" + +Point::Point(const std::vector& coordinatesIn) + : coordinates(coordinatesIn) {} + +double& Point::operator()(int i) { + return coordinates[i]; +} + +const double& Point::operator()(int i) const { + return coordinates[i]; +} + +double Point::distance(const Point& other) const { + double distance = 0; + for (int i = 0; i < coordinates.size(); ++i) { + const double p = coordinates[i]; + const double q = other.coordinates[i]; + distance += (p - q) * (p - q); + } + + return distance; +} + +std::vector readPointsFromFile(const std::string& filename) { + std::vector points; + std::ifstream fin(filename); + + double x, y; + + while (fin >> x >> y) { + Point point({x, y}); + points.push_back(point); + } + return points; +} + +std::ostream& operator<<(std::ostream& os, const Point& point) { + for (auto coordinate : point.coordinates) { + os << coordinate << "\t"; + } + os << point.clusterID; + return os; +} + +void writePointsToFile(const std::vector& points, + const std::string& filename) { + std::ofstream fout(filename); + for (auto point : points) { + fout << point << "\n"; + } +} \ No newline at end of file diff --git a/lab07/aaron/e2/upload/point.h b/lab07/aaron/e2/upload/point.h new file mode 100644 index 0000000..c77bbc2 --- /dev/null +++ b/lab07/aaron/e2/upload/point.h @@ -0,0 +1,53 @@ +#ifndef POINT_H +#define POINT_H + +#include +#include +#include + +/** + * Class representing a point in the dataset. + * + * Stores the coordinates of the point, its cluster ID, and whether it is a core + * point. + */ +class Point { + public: + Point(const std::vector& coordinatesIn); + + double& operator()(int i); + const double& operator()(int i) const; + + double distance(const Point& other) const; + + std::vector coordinates; + int clusterID = -1; + bool isCorePoint = false; + std::set neighbors; +}; + +/** + * Read points from a file and return them as a vector of Point objects. + */ +std::vector readPointsFromFile(const std::string& filename); + +/** + * Print a point to an output stream. The + * coordinates are separated by tabs, and the + * cluster ID is printed at the end. + */ +std::ostream& operator<<(std::ostream& os, const Point& point); + +/** + * Write points to a file. + * + * Each point is written on a new line, with + * coordinates separated by tabs and the + * cluster ID at the end. + * + * Can be read with numpy.loadtxt, the last column give the cluster ID. + */ +void writePointsToFile(const std::vector& points, + const std::string& filename); + +#endif // POINT_H \ No newline at end of file diff --git a/lab07/aaron/e2/upload/run.cpp b/lab07/aaron/e2/upload/run.cpp new file mode 100644 index 0000000..a66ab54 --- /dev/null +++ b/lab07/aaron/e2/upload/run.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include "dbscan.h" + +using namespace HPC; + + +int main() { + + std::vector points = readPointsFromFile("data"); + + DBSCAN ds(5, 0.01); + ds.run(points); + + writePointsToFile(ds.getPoints(), "clustered"); + + return 0; +}