Skip to content
Closed
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/common/include/common.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <tuple>
#include <vector>

#include "task/include/task.hpp"

namespace litvyakov_d_min_val_by_col {

using InType = std::tuple<int, int, std::vector<double>>;
using OutType = std::vector<double>;
using TestType = std::tuple<int, int, std::vector<double>, std::vector<double>>;
using BaseTask = ppc::task::Task<InType, OutType>;

} // namespace litvyakov_d_min_val_by_col
2,002 changes: 2,002 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/data/matrix_2000x2000

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"student": {
"first_name": "Даниил",
"last_name": "Литвяков",
"middle_name": "Дмитриевич",
"group_number": "3823Б1ПМоп3",
"task_number": "1"
}
}
22 changes: 22 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/mpi/include/min_val_by_col.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "litvyakov_d_min_val_by_col/common/include/common.hpp"
#include "task/include/task.hpp"

namespace litvyakov_d_min_val_by_col {

class LitvyakovDMinValByColMPI : public BaseTask {
public:
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kMPI;
}
explicit LitvyakovDMinValByColMPI(const InType &in);

private:
bool ValidationImpl() override;
bool PreProcessingImpl() override;
bool RunImpl() override;
bool PostProcessingImpl() override;
};

} // namespace litvyakov_d_min_val_by_col
80 changes: 80 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/mpi/src/min_val_by_col.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include "litvyakov_d_min_val_by_col/mpi/include/min_val_by_col.hpp"

#include <mpi.h>

#include <algorithm>
#include <limits>
#include <type_traits>
#include <utility>
#include <vector>

#include "litvyakov_d_min_val_by_col/common/include/common.hpp"

namespace litvyakov_d_min_val_by_col {

LitvyakovDMinValByColMPI::LitvyakovDMinValByColMPI(const InType &in) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
}

bool LitvyakovDMinValByColMPI::ValidationImpl() {
int world_rank = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
if (world_rank == 0) {
const auto &n = std::get<0>(GetInput());
const auto &m = std::get<1>(GetInput());
const auto &mat = std::get<2>(GetInput());
return ((n > 0) && (m > 0) && std::cmp_equal(mat.size(), (n * m)));
}
return true;
}

bool LitvyakovDMinValByColMPI::PreProcessingImpl() {
const auto &m = std::get<1>(GetInput());
auto &mat = std::get<2>(GetInput());
using Type = std::remove_reference_t<decltype(mat[0])>;
OutType &res = GetOutput();
res.resize(m, std::numeric_limits<Type>::max());
return std::cmp_equal(res.size(), m);
}

bool LitvyakovDMinValByColMPI::RunImpl() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see data scatter from rank 0 to other ranks

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Исправлено

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const auto &n = std::get<0>(GetInput());
const auto &m = std::get<1>(GetInput());
auto &mat = std::get<2>(GetInput());

int world_size = 0;
int world_rank = 0;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

using Type = std::remove_reference_t<decltype(mat[0])>;
MPI_Datatype datatype = MPI_DOUBLE;

OutType &res = GetOutput();
OutType proc_res(m, std::numeric_limits<Type>::max());

for (int j = world_rank; j < m; j += world_size) {
Type min_val = std::numeric_limits<Type>::max();
for (int i = 0; i < n; ++i) {
min_val = std::min(mat[(j * n) + i], min_val);
}
proc_res[j] = min_val;
}

MPI_Allreduce(proc_res.data(), res.data(), m, datatype, MPI_MIN, MPI_COMM_WORLD);

return true;
}

bool LitvyakovDMinValByColMPI::PostProcessingImpl() {
int world_rank = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
if (world_rank == 0) {
const auto &m = std::get<1>(GetInput());
return std::cmp_equal(GetOutput().size(), m);
}
return true;
}

} // namespace litvyakov_d_min_val_by_col
73 changes: 73 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
## Министерство науки и высшего образования Российской Федерации
## Федеральное государственное автономное образовательное учреждение высшего образования
## **«Национальный исследовательский Нижегородский государственный университет им. Н.И. Лобачевского»**
### Институт информационных технологий, математики и механики

### **Направление подготовки:** «Прикладная математика и информатика»

---

# Отчёт
### По задаче
**Нахождение минимальных значений по столбцам матрицы**
**Вариант №18**

**Выполнил:**
Студент группы 3823Б1ПМоп3
**Литвяков Д.Д.**

---

## 1. Введение
Последовательные программы полностью используют аппаратные возможности. Параллельные версии алгоритмов могут ускорить работу программы, в том числе при работе с большими матрицами, за счёт одновременного выполнения нескольких задач на разных ядрах.

## 2. Постановка задачи
Требуется найти минимальные значения по каждому столбцу матрицы размером n*m.
Вход:
n — число строк (int)
m — число столбцов (int)
std::vector<double> длины n*m
Выход:
std::vector<double> длины m — минимумы по каждому столбцу.

## 3. Базовый Алгоритм (Последовательный)
```
for j in 0..m-1:
min_val = +inf
for i in 0..n-1:
v = mat[j*n + i]
if v < min_val:
min_val = v
res[j] = min_val
```

## 4. Схема распараллеливания
В параллельной версии каждому процессу достаются столбцы следующим образом: 1 процесс - 1 столбец, 2 процесс - 2 столбец и так далее. После подсчёта локальных минимумов в столбцах результат объединяются с помощью MPI_Allreduce(proc_res.data(), res.data(), m, datatype, MPI_MIN, MPI_COMM_WORLD).

## 5. Детали реализации
Каждый процесс хранит промежуточный результат в локальных векторах инициализированных максимальными значениями размера m.

## 6. Характеристики локальной машины
- Аппаратное обеспечение/Операционная система: AMD Ryzen 5 5600, 32 GB DDR4-3200, Windows 10.
- Компилятор: MSVC, Тип сборки: Release.
- Данные: сгенерированная матрица матрица размерами 4000 на 4000 с элементами от -1e-6 до 1e-6.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your elements are not like that in the tests

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Исправлено


## 7. Результаты

### 7.1 Корректность
Функциональные тесты: программа была проверена для типовых матриц.

### 7.2 Производительность
Для теста производительности была использована сгенерированная матрица размерами 4000 на 4000 с элементами от -1e-6 до 1e-6. Результаты были записаны в таблицу:

| Mode | Count | Time, s | Speedup | Efficiency |
|-------------|-------|---------|---------|------------|
| seq | 1 | 0.0058 | 1.00 | N/A |
| mpi | 2 | 0.0044 | 1.31 | 31.0% |
| mpi | 4 | 0.0030 | 1.93 | 31.0% |

## 8. Выводы
Реализована последовательная и параллельная версия алгоритма поиска минимума по столбцам.

## 9. Список литературы
1. https://learn.microsoft.com/ru-ru/message-passing-interface/microsoft-mpi
22 changes: 22 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/seq/include/min_val_by_col.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "litvyakov_d_min_val_by_col/common/include/common.hpp"
#include "task/include/task.hpp"

namespace litvyakov_d_min_val_by_col {

class LitvyakovDMinValByColSEQ : public BaseTask {
public:
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kSEQ;
}
explicit LitvyakovDMinValByColSEQ(const InType &in);

private:
bool ValidationImpl() override;
bool PreProcessingImpl() override;
bool RunImpl() override;
bool PostProcessingImpl() override;
};

} // namespace litvyakov_d_min_val_by_col
53 changes: 53 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/seq/src/min_val_by_col.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "litvyakov_d_min_val_by_col/seq/include/min_val_by_col.hpp"

#include <algorithm>
#include <limits>
#include <type_traits>
#include <utility>
#include <vector>

#include "litvyakov_d_min_val_by_col/common/include/common.hpp"

namespace litvyakov_d_min_val_by_col {

LitvyakovDMinValByColSEQ::LitvyakovDMinValByColSEQ(const InType &in) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
}

bool LitvyakovDMinValByColSEQ::ValidationImpl() {
const auto &n = std::get<0>(GetInput());
const auto &m = std::get<1>(GetInput());
const auto &mat = std::get<2>(GetInput());
return ((n > 0) && (m > 0) && std::cmp_equal(mat.size(), (n * m)));
}

bool LitvyakovDMinValByColSEQ::PreProcessingImpl() {
OutType &res = GetOutput();
const auto &m = std::get<1>(GetInput());
const auto &mat = std::get<2>(GetInput());
using Type = std::remove_reference_t<decltype(mat[0])>;
res.resize(m, std::numeric_limits<Type>::max());
return (std::cmp_equal(res.size(), m));
}

bool LitvyakovDMinValByColSEQ::RunImpl() {
OutType &res = GetOutput();
const auto &n = std::get<0>(GetInput());
const auto &m = std::get<1>(GetInput());
auto &mat = std::get<2>(GetInput());

for (int j = 0; j < m; ++j) {
for (int i = 0; i < n; ++i) {
res[j] = std::min(res[j], mat[(j * n) + i]);
}
}

return true;
}

bool LitvyakovDMinValByColSEQ::PostProcessingImpl() {
return true;
}

} // namespace litvyakov_d_min_val_by_col
7 changes: 7 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tasks_type": "processes",
"tasks": {
"mpi": "enabled",
"seq": "enabled"
}
}
13 changes: 13 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/tests/.clang-tidy
Original file line number Diff line number Diff line change
@@ -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
69 changes: 69 additions & 0 deletions tasks/litvyakov_d_min_val_by_col/tests/functional/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <gtest/gtest.h>

#include <array>
#include <cfloat>
#include <cstddef>
#include <string>
#include <tuple>
#include <vector>

#include "litvyakov_d_min_val_by_col/common/include/common.hpp"
#include "litvyakov_d_min_val_by_col/mpi/include/min_val_by_col.hpp"
#include "litvyakov_d_min_val_by_col/seq/include/min_val_by_col.hpp"
#include "util/include/func_test_util.hpp"
#include "util/include/util.hpp"

namespace litvyakov_d_min_val_by_col {

class LitvyakovDRunFuncFindMinValByCol : public ppc::util::BaseRunFuncTests<InType, OutType, TestType> {
public:
static std::string PrintTestParam(const TestType &test_param) {
return "matrix_" + std::to_string(std::get<0>(test_param)) + "x" + std::to_string(std::get<1>(test_param));
}

protected:
void SetUp() override {
params_ = std::get<static_cast<std::size_t>(ppc::util::GTestParamIndex::kTestParams)>(GetParam());
input_data_ = std::make_tuple(std::get<0>(params_), std::get<1>(params_), std::get<2>(params_));
output_vector_ = std::get<3>(params_);
}

bool CheckTestOutputData(OutType &output_data) final {
return output_data == output_vector_;
}

InType GetTestInputData() final {
return input_data_;
}

private:
TestType params_;
InType input_data_;
OutType output_vector_;
};

const std::array<TestType, 8> kTestParam = {
TestType(3, 3, {-1, -2, -5, -4, -3, -8, -7, -6, -9}, {-5, -8, -9}),
TestType(2, 4, {0, 1, 5, 3, 2, 0, 8, 7}, {0, 3, 0, 7}),
TestType(1, 1, {-1.}, {-1.}),
TestType(4, 2, {8, 6, 4, 2, 7, 5, 3, 1}, {2, 1}),
TestType(1, 5, {9, 8, 7, 6, 5}, {9, 8, 7, 6, 5}),
TestType(5, 1, {3, -1, 7, 0, 2}, {-1}),
TestType(4, 3, {1.1, 4.0, 0.02, 7, 9, 2.0, 5, 1, 3, 8, 6, 4}, {0.02, 1, 3}),
TestType(2, 2, {1, 50, 100, -10.0001}, {1, -10.0001}),
};

TEST_P(LitvyakovDRunFuncFindMinValByCol, FindMinInColumns) {
ExecuteTest(GetParam());
}

const auto kTestTasksList = std::tuple_cat(
ppc::util::AddFuncTask<LitvyakovDMinValByColMPI, InType>(kTestParam, PPC_SETTINGS_litvyakov_d_min_val_by_col),
ppc::util::AddFuncTask<LitvyakovDMinValByColSEQ, InType>(kTestParam, PPC_SETTINGS_litvyakov_d_min_val_by_col));

const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList);

const auto kPerfTestName = LitvyakovDRunFuncFindMinValByCol::PrintFuncTestName<LitvyakovDRunFuncFindMinValByCol>;

INSTANTIATE_TEST_SUITE_P(MinValByColumns, LitvyakovDRunFuncFindMinValByCol, kGtestValues, kPerfTestName);
} // namespace litvyakov_d_min_val_by_col
Loading
Loading