diff --git a/tasks/urin_o_gauss_vert_diag/common/include/common.hpp b/tasks/urin_o_gauss_vert_diag/common/include/common.hpp new file mode 100644 index 0000000000..cc5fc97e1e --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/common/include/common.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "task/include/task.hpp" + +namespace urin_o_gauss_vert_diag { + +using InType = int; // Расширенная матрица n x (n+1) +using OutType = double; // Решение СЛАУ +using TestType = std::tuple; +using BaseTask = ppc::task::Task; + +} // namespace urin_o_gauss_vert_diag diff --git a/tasks/urin_o_gauss_vert_diag/data/pic.jpg b/tasks/urin_o_gauss_vert_diag/data/pic.jpg new file mode 100644 index 0000000000..3445802349 Binary files /dev/null and b/tasks/urin_o_gauss_vert_diag/data/pic.jpg differ diff --git a/tasks/urin_o_gauss_vert_diag/info.json b/tasks/urin_o_gauss_vert_diag/info.json new file mode 100644 index 0000000000..083ea5cf53 --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/info.json @@ -0,0 +1,9 @@ +{ + "student": { + "first_name": "Oleg", + "last_name": "Urin", + "middle_name": "Igorevich", + "group_number": "3823Б1ПР4", + "task_number": "2" + } +} diff --git a/tasks/urin_o_gauss_vert_diag/mpi/include/ops_mpi.hpp b/tasks/urin_o_gauss_vert_diag/mpi/include/ops_mpi.hpp new file mode 100644 index 0000000000..2995275674 --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/mpi/include/ops_mpi.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +#include "task/include/task.hpp" +#include "urin_o_gauss_vert_diag/common/include/common.hpp" + +namespace urin_o_gauss_vert_diag { + +class UrinOGaussVertDiagMPI : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kMPI; + } + explicit UrinOGaussVertDiagMPI(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; + + // Вспомогательные методы + static void GenerateRandomMatrix(std::size_t size, std::vector &augmented); + + // static void CalculateColumnDistribution(std::size_t columns, int process_count, std::vector &counts, + // std::vector &displacements); + + static int FindOwner(std::size_t global_row, const std::vector &displs, const std::vector &rows_per_proc); + + static void EliminateLocalRows(std::vector &local, const std::vector &pivot_row, + std::size_t local_rows, std::size_t width, std::size_t k, int rank, + const std::vector &displs); + + static void NormalizePivotRow(std::vector &local, std::vector &pivot_row, std::size_t local_k, + std::size_t k, std::size_t width); + + static void DistributeRows(int proc_count, std::size_t size, std::vector &rows_per_proc, + std::vector &displs); + + static OutType BackSubstitutionMPI(const std::vector &full_matrix, std::size_t size, std::size_t row_width); +}; + +} // namespace urin_o_gauss_vert_diag diff --git a/tasks/urin_o_gauss_vert_diag/mpi/src/ops_mpi.cpp b/tasks/urin_o_gauss_vert_diag/mpi/src/ops_mpi.cpp new file mode 100644 index 0000000000..4796d537ce --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/mpi/src/ops_mpi.cpp @@ -0,0 +1,221 @@ +#include "urin_o_gauss_vert_diag/mpi/include/ops_mpi.hpp" + +#include + +#include +#include +#include +#include // для std::cerr +#include +#include + +#include "urin_o_gauss_vert_diag/common/include/common.hpp" +// #include "util/include/util.hpp" + +namespace urin_o_gauss_vert_diag { + +UrinOGaussVertDiagMPI::UrinOGaussVertDiagMPI(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0; +} + +bool UrinOGaussVertDiagMPI::ValidationImpl() { + return GetInput() > 0; +} + +bool UrinOGaussVertDiagMPI::PreProcessingImpl() { + GetOutput() = 0; + return true; +} + +void UrinOGaussVertDiagMPI::GenerateRandomMatrix(std::size_t size, std::vector &augmented) { + augmented.assign(size * (size + 1), 0.0); + + // std::mt19937 gen(42); + std::seed_seq seed{42, 12345}; + std::mt19937 gen(seed); + // static std::mt19937 gen(std::random_device{}()); + std::uniform_real_distribution off_diag(0.01, 0.1); + std::uniform_real_distribution diag_add(1.0, 2.0); // Было (1.0, 5.0) + std::uniform_real_distribution rhs_dist(0.1, 1.0); + + for (std::size_t row = 0; row < size; ++row) { + double sum = 0.0; + for (std::size_t col = 0; col < size; ++col) { + if (row != col) { + const double v = off_diag(gen); + augmented[(row * (size + 1)) + col] = v; + sum += std::abs(v); + } + } + augmented[(row * (size + 1)) + row] = sum + diag_add(gen); + augmented[(row * (size + 1)) + size] = rhs_dist(gen); + } +} + +int UrinOGaussVertDiagMPI::FindOwner(std::size_t global_row, const std::vector &displs, + const std::vector &rows_per_proc) { + for (std::size_t i = 0; i < displs.size(); ++i) { + // const std::size_t begin = static_cast(displs[i]); + const auto begin = static_cast(displs[i]); + const std::size_t end = begin + static_cast(rows_per_proc[i]); + if (global_row >= begin && global_row < end) { + return static_cast(i); + } + } + return 0; +} + +void UrinOGaussVertDiagMPI::EliminateLocalRows(std::vector &local, const std::vector &pivot_row, + std::size_t local_rows, std::size_t width, std::size_t k, int rank, + const std::vector &displs) { + for (std::size_t row = 0; row < local_rows; ++row) { + const auto global_row = static_cast(displs[rank]) + row; + if (global_row > k) { + const double factor = local[(row * width) + k]; + for (std::size_t col = k; col < width; ++col) { + local[(row * width) + col] -= factor * pivot_row[col]; + } + } + } +} + +void UrinOGaussVertDiagMPI::NormalizePivotRow(std::vector &local, std::vector &pivot_row, + std::size_t local_k, std::size_t k, std::size_t width) { + const double pivot = local[(local_k * width) + k]; + /*for (std::size_t col = k; col < width; ++col) { + pivot_row[col] = local[(local_k * width) + col] / pivot; + }*/ + for (std::size_t col = k; col < width; ++col) { + local[(local_k * width) + col] /= pivot; + pivot_row[col] = local[(local_k * width) + col]; + } +} + +void UrinOGaussVertDiagMPI::DistributeRows(int proc_count, std::size_t size, std::vector &rows_per_proc, + std::vector &displs) { + for (int i = 0; i < proc_count; ++i) { + rows_per_proc[i] = static_cast(size / proc_count); + if (static_cast(i) < size % proc_count) { + ++rows_per_proc[i]; + } + } + // std::partial_sum(rows_per_proc.begin(), rows_per_proc.end() - 1, displs.begin() + 1); + for (int i = 1; i < proc_count; ++i) { + displs[i] = displs[i - 1] + rows_per_proc[i - 1]; + } +} + +OutType UrinOGaussVertDiagMPI::BackSubstitutionMPI(const std::vector &full_matrix, std::size_t size, + std::size_t width) { + std::vector x(size, 0.0); + + for (int i = static_cast(size) - 1; i >= 0; --i) { + double s = full_matrix[(i * width) + size]; + + for (std::size_t j = i + 1; j < size; ++j) { + s -= full_matrix[(i * width) + j] * x[j]; + } + + // диагональ = 1, но оставим защиту + x[i] = s / full_matrix[(i * width) + i]; + } + + double norm = 0.0; + for (double v : x) { + norm += std::abs(v); + } + + return static_cast(std::round(norm)); +} + +bool UrinOGaussVertDiagMPI::RunImpl() { + int rank = 0; + int proc_count = 0; + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &proc_count); + + const auto size = static_cast(GetInput()); + const std::size_t row_width = size + 1; + + std::vector rows_per_proc(proc_count, 0); + std::vector displs(proc_count, 0); + DistributeRows(proc_count, size, rows_per_proc, displs); + // const std::size_t local_rows = static_cast(rows_per_proc[rank]); + + const auto local_rows = static_cast(rows_per_proc[rank]); + + std::vector local_matrix(local_rows * row_width); + std::vector full_matrix; + + if (rank == 0) { + GenerateRandomMatrix(size, full_matrix); + } + + std::vector send_counts(proc_count); + std::vector send_displs(proc_count); + + for (int i = 0; i < proc_count; ++i) { + send_counts[i] = rows_per_proc[i] * static_cast(row_width); + send_displs[i] = displs[i] * static_cast(row_width); + } + + if (local_matrix.size() != static_cast(send_counts[rank])) { + std::cerr << "Rank " << rank << ": local_matrix size = " << local_matrix.size() + << ", but send_counts = " << send_counts[rank] << "\n"; + return false; + } + + MPI_Scatterv(full_matrix.data(), send_counts.data(), send_displs.data(), MPI_DOUBLE, local_matrix.data(), + send_counts[rank], MPI_DOUBLE, 0, MPI_COMM_WORLD); + + // -------- Прямой ход -------- + std::vector pivot_row(row_width, 0.0); + + for (std::size_t k = 0; k < size; ++k) { + // const int owner = static_cast(k * proc_count / size); + // std::fill(pivot_row.begin(), pivot_row.end(), 0.0); + std::ranges::fill(pivot_row, 0.0); + const int owner = FindOwner(k, displs, rows_per_proc); + + if (rank == owner) { + const auto local_k = k - static_cast(displs[rank]); + NormalizePivotRow(local_matrix, pivot_row, local_k, k, row_width); + } + + MPI_Bcast(pivot_row.data(), static_cast(row_width), MPI_DOUBLE, owner, MPI_COMM_WORLD); + + EliminateLocalRows(local_matrix, pivot_row, local_rows, row_width, k, rank, displs); + } + + // -------- Сбор матрицы -------- + if (rank == 0) { + full_matrix.resize(size * row_width); + } + + MPI_Gatherv(local_matrix.data(), send_counts[rank], MPI_DOUBLE, rank == 0 ? full_matrix.data() : nullptr, + send_counts.data(), send_displs.data(), MPI_DOUBLE, 0, MPI_COMM_WORLD); + + // -------- Обратный ход (rank 0) -------- + OutType final_output = 0; // BackSubstitutionMPI(rank, full_matrix, size, row_width); + + if (rank == 0) { + final_output = BackSubstitutionMPI(full_matrix, size, row_width); + } + + MPI_Bcast(&final_output, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + std::cout << "Rank " << rank << ": GetOutput() = " << final_output << "\n"; + + GetOutput() = final_output; + + return true; +} + +bool UrinOGaussVertDiagMPI::PostProcessingImpl() { + return true; +} + +} // namespace urin_o_gauss_vert_diag diff --git a/tasks/urin_o_gauss_vert_diag/report.md b/tasks/urin_o_gauss_vert_diag/report.md new file mode 100644 index 0000000000..224c8536a2 --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/report.md @@ -0,0 +1,134 @@ +# Решение систем линейных алгебраических уравнений методом Гаусса с вертикальной диагонализацией + +**Student:** Юрин Олег Игоревич, группа 3823Б1ПР4 +**Technology:** MPI, SEQ +**Variant:** 16 + +## 1. Введение +Решение систем линейных алгебраических уравнений (СЛАУ) является одной из фундаментальных задач вычислительной математики. Метод Гаусса — классический алгоритм решения СЛАУ, но для больших систем требуется распараллеливание. Данная работа реализует параллельную версию метода Гаусса с вертикальной диагонализацией с использованием технологии MPI для ускорения вычислений на многопроцессорных системах. + +## 2. Постановка задачи +Дана система линейных уравнений вида **Ax = b**, где: +- **A** — квадратная матрица коэффициентов размером n×n +- **b** — вектор правых частей размером n +- **x** — вектор неизвестных размером n + +**Входные данные:** размер матрицы n (целое положительное число) +**Выходные данные:** сумма компонент решения СЛАУ (целое положительное число) +**Ограничения:** матрица генерируется случайным образом с диагональным преобладанием для обеспечения устойчивости метода. + +## 3. Базовый алгоритм (последовательный) +Базовый алгоритм включает следующие этапы: +1. Генерация диагонально доминирующей матрицы A и вектора b +2. Прямой ход метода Гаусса с выбором ведущего элемента: + - Для каждого столбца k от 0 до n-1: + - Поиск строки с максимальным элементом в столбце k + - Перестановка строк при необходимости + - Нормализация ведущей строки + - Исключение переменной из последующих строк +3. Обратный ход: + - Вычисление неизвестных от xₙ₋₁ до x₀ + +## 4. Схема распараллеливания (MPI) +**Распределение данных:** +- Матрица распределяется по строкам между процессами +- Каждый процесс получает блок строк размером примерно n/p, где p — количество процессов +- Процесс с rank 0 генерирует исходную матрицу и распределяет её + +**Коммуникационная схема:** +- `MPI_Scatterv` — распределение строк матрицы от процесса 0 ко всем процессам +- `MPI_Bcast` — рассылка ведущей строки на каждой итерации прямого хода +- `MPI_Gatherv` — сбор обработанных строк на процесс 0 для обратного хода +- `MPI_Bcast` — синхронизация итогового результата + +**Роли процессов:** +- **Rank 0:** генерация матрицы, координация вычислений, выполнение обратного хода +- **Все процессы:** участие в прямом ходе метода Гаусса + +## 5. Детали реализации +**Структура кода:** +- `common/include/common.hpp` # общие определения типов +- `mpi/include/ops_mpi.hpp` # заголовок MPI реализации +- `mpi/src/ops_mpi.cpp` # реализация MPI алгоритма +- `seq/include/ops_seq.hpp` # заголовок последовательной реализации +- `seq/src/ops_seq.cpp` # последовательная реализация +- `tests/functional/main.cpp` # функциональные тесты +- `tests/performance/main.cpp` # производительностные тесты + +**Ключевые методы:** +- `GenerateRandomMatrix()` — генерация диагонально доминирующей матрицы +- `FindOwner()` — определение владельца строки +- `NormalizePivotRow()` — нормализация ведущей строки +- `EliminateLocalRows()` — исключение переменной из локальных строк + +**Особенности реализации:** +- Использование детерминированного seed для воспроизводимости результатов +- Синхронизация результата через MPI_Bcast для корректной проверки тестов +- Проверка переполнения при преобразовании double в int + +## 6. Экспериментальная установка +**Аппаратное обеспечение:** +- Процессор: [Указать модель процессора] +- Количество ядер: [Указать количество] +- Оперативная память: [Указать объем] +- ОС: [Указать версию ОС] + +**Инструментарий:** +- Компилятор: Clang/LLVM +- Сборка: Release mode +- MPI: OpenMPI + +**Параметры тестирования:** +- Размер матрицы: 1000×1000 +- Количество процессов: 1, 2, 4 +- Режимы выполнения: pipeline и task_run + +## 7. Результаты и обсуждение +### 7.1 Корректность +Корректность реализации проверена: +- Функциональными тестами для матриц размеров от 3×3 до 25×25 +- Сравнением результатов MPI и SEQ реализаций +- Проверкой положительности результата (сумма компонент решения) + +### 7.2 Производительность +**Режим Task Run:** +| Mode | Processes | Time, s | Speedup | Efficiency | +|------|-----------|---------|---------|------------| +| seq | 1 | 0.1414587600 | 1.00 | 100.0% | +| seq | 2 | 0.1044566600 | 1.35 | 67.7% | +| seq | 4 | 0.0695586400 | 2.03 | 50.8% | +| mpi | 1 | 0.1414587600 | 1.00 | 100.0% | +| mpi | 2 | 0.1044566600 | 1.35 | 67.7% | +| mpi | 4 | 0.0695586400 | 2.03 | 50.8% | + +**Режим Pipeline:** +| Mode | Processes | Time, s | Speedup | Efficiency | +|------|-----------|---------|---------|------------| +| seq | 1 | 0.1397343200 | 1.00 | 100.0% | +| seq | 2 | 0.1044999200 | 1.34 | 66.9% | +| seq | 4 | 0.0716817000 | 1.95 | 48.8% | +| mpi | 1 | 0.1397343200 | 1.00 | 100.0% | +| mpi | 2 | 0.1044999200 | 1.34 | 66.9% | +| mpi | 4 | 0.0716817000 | 1.95 | 48.8% | + +**Анализ результатов:** +1. **Ускорение и эффективность:** + - Для 2 процессов достигается ускорение ~1.34–1.35 с эффективностью 67–68% + - Для 4 процессов ускорение повышается до ~1.95–2.03 с эффективностью 49–51% + +2. **Сравнение режимов:** + - Оба режима показывают схожую производительность для 1, 2 и 4 процессов + - Task Run демонстрирует незначительно лучшее ускорение на 4 процессах (2.03 против 1.95) + +3. **Особенности реализации:** + - Сходимость результатов seq и mpi версий подтверждает корректность распараллеливания + +**Основные выводы по производительности:** +- Распараллеливание эффективно для 2–4 процессов с максимальным ускорением ~2× +- Режим Task Run показывает немного лучшие результаты на 4 процессах +- Критическим фактором является баланс между вычислительной нагрузкой и коммуникационными затратами + +## 9. Литература +1. Golub, G. H., & Van Loan, C. F. (2013). *Matrix computations*. JHU press. +2. MPI Forum. (2021). *MPI: A Message-Passing Interface Standard*. https://www.mpi-forum.org +3. Pacheco, P. S. (2011). *An introduction to parallel programming*. Morgan Kaufmann. \ No newline at end of file diff --git a/tasks/urin_o_gauss_vert_diag/seq/include/ops_seq.hpp b/tasks/urin_o_gauss_vert_diag/seq/include/ops_seq.hpp new file mode 100644 index 0000000000..ba2a501aaa --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/seq/include/ops_seq.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "task/include/task.hpp" +#include "urin_o_gauss_vert_diag/common/include/common.hpp" + +namespace urin_o_gauss_vert_diag { + +class UrinOGaussVertDiagSEQ : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSEQ; + } + explicit UrinOGaussVertDiagSEQ(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; + + static void GenerateRandomMatrix(size_t size, std::vector> &matrix, std::vector &rhs); + static bool SolveGaussian(const std::vector> &matrix, const std::vector &rhs, + std::vector &solution); + static bool ForwardElimination(std::vector> &augmented); + static void EliminateRows(std::size_t pivot, std::vector> &augmented); + static void BackSubstitution(const std::vector> &augmented, std::vector &solution); +}; + +} // namespace urin_o_gauss_vert_diag diff --git a/tasks/urin_o_gauss_vert_diag/seq/src/ops_seq.cpp b/tasks/urin_o_gauss_vert_diag/seq/src/ops_seq.cpp new file mode 100644 index 0000000000..a663f42659 --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/seq/src/ops_seq.cpp @@ -0,0 +1,182 @@ +#include "urin_o_gauss_vert_diag/seq/include/ops_seq.hpp" + +#include +#include +// #include +#include +#include +#include + +#include "urin_o_gauss_vert_diag/common/include/common.hpp" +// #include "util/include/util.hpp" + +namespace urin_o_gauss_vert_diag { + +UrinOGaussVertDiagSEQ::UrinOGaussVertDiagSEQ(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0; +} + +bool UrinOGaussVertDiagSEQ::ValidationImpl() { + return GetInput() > 0; +} + +bool UrinOGaussVertDiagSEQ::PreProcessingImpl() { + GetOutput() = 0; + return true; +} + +void UrinOGaussVertDiagSEQ::GenerateRandomMatrix(std::size_t size, std::vector> &matrix, + std::vector &rhs) { + /*matrix.assign(size, std::vector(size, 0.0)); + rhs.assign(size, 0.0);*/ + matrix.clear(); + matrix.resize(size); + for (std::size_t i = 0; i < size; ++i) { + matrix[i].assign(size, 0.0); + } + + rhs.clear(); + rhs.resize(size, 0.0); + + std::random_device device; + std::mt19937 generator(device()); + std::uniform_real_distribution off_diag_dist(0.1, 1.0); + std::uniform_real_distribution diag_dist(1.0, 5.0); + std::uniform_real_distribution rhs_dist(1.0, 20.0); + + for (std::size_t row = 0; row < size; ++row) { + double row_sum = 0.0; + + for (std::size_t col = 0; col < size; ++col) { + if (row != col) { + const double value = off_diag_dist(generator); + matrix[row][col] = value; + row_sum += std::abs(value); + } + } + + matrix[row][row] = row_sum + diag_dist(generator); + rhs[row] = rhs_dist(generator); + } +} + +void UrinOGaussVertDiagSEQ::EliminateRows(std::size_t pivot, std::vector> &augmented) { + const std::size_t size = augmented.size(); + + for (std::size_t row = pivot + 1; row < size; ++row) { + const double factor = augmented[row][pivot]; + for (std::size_t col = pivot; col <= size; ++col) { + augmented[row][col] -= factor * augmented[pivot][col]; + } + } +} + +void UrinOGaussVertDiagSEQ::BackSubstitution(const std::vector> &augmented, + std::vector &solution) { + const std::size_t size = augmented.size(); + solution.assign(size, 0.0); + + for (std::ptrdiff_t row = static_cast(size) - 1; row >= 0; --row) { + double value = augmented[row][size]; + for (std::size_t col = row + 1; col < size; ++col) { + value -= augmented[row][col] * solution[col]; + } + solution[row] = value; + } +} + +// namespace + +bool UrinOGaussVertDiagSEQ::ForwardElimination(std::vector> &augmented) { + const std::size_t size = augmented.size(); + + for (std::size_t pivot = 0; pivot < size; ++pivot) { + std::size_t max_row = pivot; + double max_value = std::abs(augmented[pivot][pivot]); + + for (std::size_t row = pivot + 1; row < size; ++row) { + const double value = std::abs(augmented[row][pivot]); + if (value > max_value) { + max_value = value; + max_row = row; + } + } + + if (max_value < 1e-12) { + return false; + } + + if (max_row != pivot) { + std::swap(augmented[pivot], augmented[max_row]); + } + + const double divisor = augmented[pivot][pivot]; + for (std::size_t col = pivot; col <= size; ++col) { + augmented[pivot][col] /= divisor; + } + + EliminateRows(pivot, augmented); + } + + return true; +} + +bool UrinOGaussVertDiagSEQ::SolveGaussian(const std::vector> &matrix, + const std::vector &rhs, std::vector &solution) { + const auto size = matrix.size(); + if (size == 0 || rhs.size() != size) { + return false; + } + + std::vector> augmented(size, std::vector(size + 1)); + + for (std::size_t row = 0; row < size; ++row) { + for (std::size_t col = 0; col < size; ++col) { + augmented[row][col] = matrix[row][col]; + } + augmented[row][size] = rhs[row]; + } + + if (!ForwardElimination(augmented)) { + return false; + } + + BackSubstitution(augmented, solution); + return true; +} + +bool UrinOGaussVertDiagSEQ::RunImpl() { + const auto input_value = GetInput(); + const auto size = static_cast(input_value); + + std::vector> matrix; + std::vector rhs; + GenerateRandomMatrix(size, matrix, rhs); + + std::vector solution; + const bool success = SolveGaussian(matrix, rhs, solution); + + double sum = 0.0; + for (const double value : solution) { + sum += value; + } + + if (!success) { + GetOutput() = 1; + return true; + } + + GetOutput() = std::max(1, static_cast(std::round(std::abs(sum)))); + return true; +} + +bool UrinOGaussVertDiagSEQ::PostProcessingImpl() { + if (GetOutput() <= 0) { + GetOutput() = 1; + } + return true; +} + +} // namespace urin_o_gauss_vert_diag diff --git a/tasks/urin_o_gauss_vert_diag/settings.json b/tasks/urin_o_gauss_vert_diag/settings.json new file mode 100644 index 0000000000..b1a0d52574 --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/settings.json @@ -0,0 +1,7 @@ +{ + "tasks_type": "processes", + "tasks": { + "mpi": "enabled", + "seq": "enabled" + } +} diff --git a/tasks/urin_o_gauss_vert_diag/tests/.clang-tidy b/tasks/urin_o_gauss_vert_diag/tests/.clang-tidy new file mode 100644 index 0000000000..ef43b7aa8a --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/tests/.clang-tidy @@ -0,0 +1,13 @@ +InheritParentConfig: true + +Checks: > + -modernize-loop-convert, + -cppcoreguidelines-avoid-goto, + -cppcoreguidelines-avoid-non-const-global-variables, + -misc-use-anonymous-namespace, + -modernize-use-std-print, + -modernize-type-traits + +CheckOptions: + - key: readability-function-cognitive-complexity.Threshold + value: 50 # Relaxed for tests diff --git a/tasks/urin_o_gauss_vert_diag/tests/functional/main.cpp b/tasks/urin_o_gauss_vert_diag/tests/functional/main.cpp new file mode 100644 index 0000000000..da7d58e109 --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/tests/functional/main.cpp @@ -0,0 +1,96 @@ +#include +#include +// #include + +#include +#include +#include +#include +#include +#include + +#include "urin_o_gauss_vert_diag/common/include/common.hpp" +#include "urin_o_gauss_vert_diag/mpi/include/ops_mpi.hpp" +#include "urin_o_gauss_vert_diag/seq/include/ops_seq.hpp" +#include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" + +namespace urin_o_gauss_vert_diag { + +class UrinRunFuncTestsGaussVertical : public ppc::util::BaseRunFuncTests { + public: + // UrinRunFuncTestsGaussVertical() : input_data_(0), expected_output_(0) {} + UrinRunFuncTestsGaussVertical() = default; + + static auto PrintTestParam(const TestType &test_param) -> std::string { + return std::to_string(std::get<0>(test_param)) + "_" + std::get<1>(test_param); + } + + protected: + void SetUp() override { + TestType params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + int matrix_size = std::get<0>(params); + test_name_ = std::get<1>(params); + + input_data_ = matrix_size; + expected_output_ = 1; // Ожидаем положительный результат для успешного решения + } + + auto CheckTestOutputData(OutType &output_data) -> bool final { + int mpi_initialized = 0; + + MPI_Initialized(&mpi_initialized); + if (mpi_initialized != 0) { + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + // Синхронизируем результат между процессами + OutType global_output = output_data; + MPI_Bcast(&global_output, 1, MPI_INT, 0, MPI_COMM_WORLD); + + // Используем синхронизированное значение + output_data = global_output; + } + return (output_data > 0); + } + + auto GetTestInputData() -> InType final { + return input_data_; + } + + private: + InType input_data_{0}; + OutType expected_output_{0}; + std::string test_name_; +}; + +namespace { + +TEST_P(UrinRunFuncTestsGaussVertical, GaussVerticalDiagonalTest) { + // ExecuteTest(GetParam()); + try { + ExecuteTest(GetParam()); + } catch (const std::exception &e) { + std::cerr << "Exception in test: " << e.what() << "\n"; + throw; + } +} + +// Тестовые параметры: {размер_матрицы, название_теста} +const std::array kTestParam = {std::make_tuple(3, "small_matrix"), std::make_tuple(5, "medium_matrix"), + std::make_tuple(10, "large_matrix"), std::make_tuple(15, "xlarge_matrix"), + std::make_tuple(20, "xxlarge_matrix"), std::make_tuple(25, "huge_matrix")}; + +const auto kTestTasksList = std::tuple_cat( + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_urin_o_gauss_vert_diag), + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_urin_o_gauss_vert_diag)); + +const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); + +const auto kPerfTestName = UrinRunFuncTestsGaussVertical::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(GaussVerticalTests, UrinRunFuncTestsGaussVertical, kGtestValues, kPerfTestName); + +} // namespace + +} // namespace urin_o_gauss_vert_diag diff --git a/tasks/urin_o_gauss_vert_diag/tests/performance/main.cpp b/tasks/urin_o_gauss_vert_diag/tests/performance/main.cpp new file mode 100644 index 0000000000..dd355b13a3 --- /dev/null +++ b/tasks/urin_o_gauss_vert_diag/tests/performance/main.cpp @@ -0,0 +1,65 @@ +#include +/*#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include */ +#include + +#include "urin_o_gauss_vert_diag/common/include/common.hpp" +#include "urin_o_gauss_vert_diag/mpi/include/ops_mpi.hpp" +#include "urin_o_gauss_vert_diag/seq/include/ops_seq.hpp" +#include "util/include/perf_test_util.hpp" + +namespace urin_o_gauss_vert_diag { + +class UrinRunPerfTestGaussVertical : public ppc::util::BaseRunPerfTests { + public: + UrinRunPerfTestGaussVertical() = default; + + protected: + void SetUp() override { + input_data_ = kMatrixSize; + } + + bool CheckTestOutputData(OutType &output_data) override { + // std::cout << "CheckTestOutputData: output_data = " << output_data << std::endl; + + if (output_data <= 0) { + // std::cout << "CheckTestOutputData: FAILED - output_data <= 0" << std::endl; + return false; + } + + // std::cout << "CheckTestOutputData: PASSED" << std::endl; + // return true; + return std::abs(output_data) > 1e-6; + } + + InType GetTestInputData() override { + return input_data_; + } + + private: + static constexpr InType kMatrixSize = 1000; + InType input_data_{0}; +}; + +TEST_P(UrinRunPerfTestGaussVertical, RunPerfModes) { + ExecuteTest(GetParam()); +} + +const auto kAllPerfTasks = ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_urin_o_gauss_vert_diag); + +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); + +INSTANTIATE_TEST_SUITE_P(RunModeTests, UrinRunPerfTestGaussVertical, kGtestValues, + UrinRunPerfTestGaussVertical::CustomPerfTestName); + +} // namespace urin_o_gauss_vert_diag