diff --git a/lab11/game_of_life/game_of_life.cpp b/lab11/game_of_life/game_of_life.cpp index c14c1ff..f3ccb9a 100644 --- a/lab11/game_of_life/game_of_life.cpp +++ b/lab11/game_of_life/game_of_life.cpp @@ -1,11 +1,10 @@ - #include "game_of_life.h" -GameOfLife::GameOfLife(const Matrix& grid, MPIGridSize mpiProcs) +GameOfLife::GameOfLife(const SuperGrid &grid, MPIGridSize mpiProcs) : grid_(grid), mpiProcs_(mpiProcs) {} void GameOfLife::step() { - Matrix next = Matrix::zeros(grid_.rows(), grid_.cols()); + SuperGrid next = SuperGrid::zeros(grid_.rows(), grid_.cols()); const int rows = grid_.rows(); const int cols = grid_.cols(); for (int i = 0; i < rows; ++i) { @@ -25,9 +24,9 @@ int GameOfLife::countLiveNeighbors(int row, int col) const { for (int i = -1; i <= 1; ++i) { for (int j = -1; j <= 1; ++j) { if (i == 0 && j == 0) - continue; // Skip the cell itself - int nextRow = (row + i + rows) % rows; // Wrap around - int nextCol = (col + j + cols) % cols; // Wrap around + continue; // Skip the cell itself + int nextRow = (row + i + rows) % rows; // Wrap around + int nextCol = (col + j + cols) % cols; // Wrap around if (grid_(nextRow, nextCol) == 1) { count++; } @@ -47,10 +46,6 @@ int GameOfLife::updateCell(int currentState, int numLiveNeighbors) const { } } -Matrix GameOfLife::getGrid() const { - return grid_; -} +Matrix GameOfLife::getGrid() const { return grid_.get_matrix(); } -MPIGridSize GameOfLife::mpiProcs() const { - return mpiProcs_; -} +MPIGridSize GameOfLife::mpiProcs() const { return mpiProcs_; } diff --git a/lab11/game_of_life/game_of_life.h b/lab11/game_of_life/game_of_life.h index 24971dc..9e9b1d4 100644 --- a/lab11/game_of_life/game_of_life.h +++ b/lab11/game_of_life/game_of_life.h @@ -1,19 +1,20 @@ #ifndef GAME_OF_LIFE_H #define GAME_OF_LIFE_H -#include -#include -#include -#include #include +#include +#include +#include #include +#include #include "common.h" #include "matrix.h" +#include "super_grid.h" class GameOfLife { - public: - GameOfLife(const Matrix& grid, MPIGridSize mpiProcs); +public: + GameOfLife(const SuperGrid &grid, MPIGridSize mpiProcs); void step(); @@ -21,12 +22,12 @@ class GameOfLife { MPIGridSize mpiProcs() const; - private: +private: int countLiveNeighbors(int row, int col) const; int updateCell(int currentState, int numLiveNeighbors) const; - Matrix grid_; + SuperGrid grid_; MPIGridSize mpiProcs_; int myRank_ = 0; @@ -35,4 +36,4 @@ class GameOfLife { friend class GameOfLifeTest; }; -#endif // GAME_OF_LIFE_H \ No newline at end of file +#endif // GAME_OF_LIFE_H diff --git a/lab11/game_of_life/main.cpp b/lab11/game_of_life/main.cpp index 8d96296..4ce3971 100644 --- a/lab11/game_of_life/main.cpp +++ b/lab11/game_of_life/main.cpp @@ -1,15 +1,16 @@ -#include +#include #include +#include #include #include #include -#include -#include "game_of_life.h" -#include "patterns.h" -#include "matrix_io.h" -#include "utils.h" #include "common.h" +#include "game_of_life.h" +#include "matrix_io.h" +#include "patterns.h" +#include "super_grid.h" +#include "utils.h" /** * Main function to run the simulation of the game of life @@ -19,12 +20,12 @@ void gameOfLife(MPIGridSize mpiProcs) { MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Create a grid that results in some interesting patterns - const Matrix grid = Pattern(20, 40, mpiProcs) - .glider(10, 17) - .beeHive(7, 10) - .octagon(6, 27) - .octagon(12, 0) - .getGrid(); + const SuperGrid grid = Pattern(20, 40, mpiProcs) + .glider(10, 17) + .beeHive(7, 10) + .octagon(6, 27) + .octagon(12, 0) + .getGrid(); GameOfLife game(grid, mpiProcs); @@ -40,7 +41,7 @@ void gameOfLife(MPIGridSize mpiProcs) { std::cout << "Final state" << std::endl; print(game); - storeAnimation("output", grid, 150, mpiProcs); + storeAnimation("output", grid.get_matrix(), 150, mpiProcs); } /** @@ -48,7 +49,7 @@ void gameOfLife(MPIGridSize mpiProcs) { * Initializes MPI, checks command line arguments, and starts the game of life * simulation. */ -int main(int argc, char* argv[]) { +int main(int argc, char *argv[]) { MPI_Init(&argc, &argv); if (argc != 3) { std::cout << "Specify number of processes in x and y as arguments\n"; @@ -70,11 +71,11 @@ int main(int argc, char* argv[]) { try { gameOfLife({np0, np1}); - } catch (const std::exception& e) { + } catch (const std::exception &e) { std::cerr << "Error: " << e.what() << std::endl; MPI_Abort(MPI_COMM_WORLD, 1); return 1; } MPI_Finalize(); -} \ No newline at end of file +} diff --git a/lab11/game_of_life/makefile b/lab11/game_of_life/makefile index eac5f48..7eed0f4 100644 --- a/lab11/game_of_life/makefile +++ b/lab11/game_of_life/makefile @@ -23,6 +23,10 @@ test: mpicxx $(SOURCE_FILES) test.cpp -g -o game_of_life_test ${COMPILER_FLAGS} mpirun -np 16 --oversubscribe ./game_of_life_test +tests: + mpicxx $(SOURCE_FILES) test.cpp -g -o game_of_life_test ${COMPILER_FLAGS} + mpirun -np 1 --oversubscribe ./game_of_life_test + runserial: mpirun -np 1 ./$(PROGRAM_NAME) 1 1 @@ -30,4 +34,4 @@ run: release mpirun -np 16 --oversubscribe ./$(PROGRAM_NAME) 4 4 ani: animate.py - python3 animate.py \ No newline at end of file + python3 animate.py diff --git a/lab11/game_of_life/patterns.cpp b/lab11/game_of_life/patterns.cpp index 9de9c59..a0eafa4 100644 --- a/lab11/game_of_life/patterns.cpp +++ b/lab11/game_of_life/patterns.cpp @@ -1,7 +1,7 @@ #include "patterns.h" Pattern::Pattern(int rows, int cols, MPIGridSize mpiProcs) - : mpiProcs_(mpiProcs), grid_(Matrix::zeros(rows / np0(), cols / np1())) { + : mpiProcs_(mpiProcs), grid_(SuperGrid::zeros(rows / np0(), cols / np1())) { if (rows <= 0 || cols <= 0) { throw std::invalid_argument("Rows and columns must be positive"); } @@ -87,7 +87,7 @@ Pattern Pattern::octagon(int row, int col) { return *this; } -Matrix Pattern::getGrid() const { return grid_; } +SuperGrid Pattern::getGrid() const { return grid_; } Pattern Pattern::setCell(int globalRow, int globalCol) { if (globalRow < 0 || globalCol < 0 || globalRow >= numRowsTotal() || diff --git a/lab11/game_of_life/patterns.h b/lab11/game_of_life/patterns.h index 53ac75e..66e30ec 100644 --- a/lab11/game_of_life/patterns.h +++ b/lab11/game_of_life/patterns.h @@ -1,11 +1,12 @@ #ifndef PATTERNS_H #define PATTERNS_H -#include -#include -#include -#include "matrix.h" #include "common.h" +#include "matrix.h" +#include "super_grid.h" +#include +#include +#include /** * Class to create some patterns for the Game of Life. @@ -20,10 +21,10 @@ * Pattern pattern(20, 40, comm).glider(10, 17).getGrid(); */ class Pattern { - public: +public: Pattern(int rows, int cols, MPIGridSize mpiProcs); - Matrix getGrid() const; + SuperGrid getGrid() const; Pattern setCell(int globalRow, int globalCol); @@ -33,7 +34,7 @@ class Pattern { Pattern octagon(int row, int col); - private: +private: int numRowsLocal() const; int numRowsTotal() const; int numColsLocal() const; @@ -43,9 +44,9 @@ class Pattern { int np1() const; MPIGridSize mpiProcs_; - Matrix grid_; + SuperGrid grid_; - MPI_Comm comm_; + MPI_Comm comm_; }; -#endif // PATTERNS_H \ No newline at end of file +#endif // PATTERNS_H diff --git a/lab11/game_of_life/super_grid.h b/lab11/game_of_life/super_grid.h index 80ef7ba..5bb3e28 100644 --- a/lab11/game_of_life/super_grid.h +++ b/lab11/game_of_life/super_grid.h @@ -7,23 +7,48 @@ class SuperGrid { public: static SuperGrid zeros(int rows, int cols); + SuperGrid(const Matrix &other); + + double &operator()(int i, int j); + const double &operator()(int i, int j) const; + + const Matrix get_matrix() const; + int rows() const; int cols() const; - double &operator()(int i, int j); private: Matrix grid_; }; -inline SuperGrid SuperGrid::zeros(int rows, int cols) - : grid_(Matrix::zeros(rows + 2, cols + 2)), {} +inline SuperGrid::SuperGrid(const Matrix &other) : grid_(other) {} + +inline SuperGrid SuperGrid::zeros(int rows, int cols) { + return SuperGrid(Matrix::zeros(rows + 2, cols + 2)); +} inline double &SuperGrid::operator()(int i, int j) { return this->grid_(i + 1, j + 1); } +inline const double &SuperGrid::operator()(int i, int j) const { + return this->grid_(i + 1, j + 1); +} + inline int SuperGrid::rows() const { return this->grid_.rows() - 2; } inline int SuperGrid::cols() const { return this->grid_.cols() - 2; } +inline const Matrix SuperGrid::get_matrix() const { + Matrix mat = Matrix::zeros(this->rows(), this->cols()); + + for (int i = 0; i < this->rows(); i++) { + for (int j = 0; j < this->rows(); j++) { + mat(i, j) = this->grid_(i + 1, j + 1); + } + } + + return mat; +} + #endif // SUPER_GRID_H diff --git a/lab11/game_of_life/test.cpp b/lab11/game_of_life/test.cpp index 59907e6..0cebaea 100644 --- a/lab11/game_of_life/test.cpp +++ b/lab11/game_of_life/test.cpp @@ -2,6 +2,7 @@ #include "common.h" #include "game_of_life.h" #include "matrix.h" +#include "utils.h" Matrix init_step(Matrix start) { GameOfLife gol = GameOfLife(start, MPIGridSize()); @@ -21,7 +22,10 @@ TEST(test_survive_2) { start(0, 0) = 1; start(0, 1) = 1; start(1, 0) = 1; + + print(start); Matrix end = init_step(start); + print(end); check(end(0, 0), 1); } diff --git a/lab11/game_of_life/utils.cpp b/lab11/game_of_life/utils.cpp index 758d8f3..c6f711b 100644 --- a/lab11/game_of_life/utils.cpp +++ b/lab11/game_of_life/utils.cpp @@ -1,6 +1,7 @@ #include "utils.h" +#include "matrix.h" -void clearOrCreateFolder(const std::string& foldername) { +void clearOrCreateFolder(const std::string &foldername) { namespace fs = std::filesystem; fs::path folder(foldername); if (fs::exists(folder)) { @@ -21,7 +22,7 @@ void clearOrCreateFolder(const std::string& foldername) { std::cout << "Clearing folder '" << foldername << "'...\n"; // Clear the folder - for (const auto& entry : fs::directory_iterator(folder)) { + for (const auto &entry : fs::directory_iterator(folder)) { if (fs::is_directory(entry)) { fs::remove_all(entry); } else if (fs::is_regular_file(entry)) { @@ -35,10 +36,8 @@ void clearOrCreateFolder(const std::string& foldername) { } } -void storeAnimation(const std::string& foldername, - const Matrix& initstate, - int numSteps, - MPIGridSize mpiProcs) { +void storeAnimation(const std::string &foldername, const Matrix &initstate, + int numSteps, MPIGridSize mpiProcs) { GameOfLife game(initstate, mpiProcs); MatrixIO io(mpiProcs); @@ -67,7 +66,7 @@ void storeAnimation(const std::string& foldername, } } -void print(const GameOfLife& game) { +void print(const GameOfLife &game) { MatrixIO io(game.mpiProcs()); Matrix grid = io.gatherMatrixOnRoot(game.getGrid()); @@ -81,4 +80,13 @@ void print(const GameOfLife& game) { std::cout << std::endl; } } -} \ No newline at end of file +} + +void print(Matrix &grid) { + for (int i = 0; i < grid.rows(); ++i) { + for (int j = 0; j < grid.cols(); ++j) { + std::cout << ((grid(i, j) == 1) ? "X " : ". "); + } + std::cout << std::endl; + } +} diff --git a/lab11/game_of_life/utils.h b/lab11/game_of_life/utils.h index 0a45e7b..776c0c8 100644 --- a/lab11/game_of_life/utils.h +++ b/lab11/game_of_life/utils.h @@ -1,15 +1,15 @@ #ifndef UTILS_H #define UTILS_H +#include +#include #include #include -#include -#include -#include "game_of_life.h" -#include "matrix_io.h" -#include "matrix.h" #include "common.h" +#include "game_of_life.h" +#include "matrix.h" +#include "matrix_io.h" /** * Clears the contents of a folder or create it if it does not exist. @@ -17,7 +17,7 @@ * all folder contents are removed. * If the folder does not exist, it is created. */ -void clearOrCreateFolder(const std::string& foldername); +void clearOrCreateFolder(const std::string &foldername); /** * Stores the animation of the Game of Life in a bunch of text files. @@ -25,12 +25,12 @@ void clearOrCreateFolder(const std::string& foldername); * where is the step number. * The files are stored in the specified folder. */ -void storeAnimation(const std::string& foldername, - const Matrix& initstate, - int numSteps, - MPIGridSize mpiProcs); +void storeAnimation(const std::string &foldername, const Matrix &initstate, + int numSteps, MPIGridSize mpiProcs); /** Print the current grid of the game on the console */ -void print(const GameOfLife& game); +void print(const GameOfLife &game); -#endif // UTILS_H \ No newline at end of file +void print(Matrix &matrix); + +#endif // UTILS_H