Skip to content
Closed
Show file tree
Hide file tree
Changes from 16 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"
}
}
28 changes: 28 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,28 @@
#pragma once

#include <vector>

#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;
static void BuildSendCountsAndDispls(int m, int n, int world_size, std::vector<int> &sendcounts,
std::vector<int> &displs);
static void BuildRecvCountsColsAndDispls(int m, int world_size, std::vector<int> &recv_counts_cols,
std::vector<int> &recv_displs_cols);
};

} // namespace litvyakov_d_min_val_by_col
184 changes: 184 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,184 @@
#include "litvyakov_d_min_val_by_col/mpi/include/min_val_by_col.hpp"

#include <mpi.h>

#include <algorithm>
#include <cstddef>
#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(static_cast<size_t>(m), std::numeric_limits<Type>::max());
return std::cmp_equal(res.size(), m);
}

void LitvyakovDMinValByColMPI::BuildSendCountsAndDispls(int m, int n, int world_size, std::vector<int> &sendcounts,
std::vector<int> &displs) {
int base_cols = 0;
int rem_cols = 0;
if (world_size > 0) {
base_cols = m / world_size;
rem_cols = m % world_size;
}

sendcounts.assign(static_cast<size_t>(world_size), 0);
displs.assign(static_cast<size_t>(world_size), 0);

for (int idx = 0; idx < world_size; ++idx) {
int cols = base_cols;
if (idx < rem_cols) {
cols = cols + 1;
}
sendcounts[static_cast<size_t>(idx)] = cols * n;

if (idx == 0) {
displs[static_cast<size_t>(idx)] = 0;
} else {
displs[static_cast<size_t>(idx)] =
displs[static_cast<size_t>(idx - 1)] + sendcounts[static_cast<size_t>(idx - 1)];
}
}
}

void LitvyakovDMinValByColMPI::BuildRecvCountsColsAndDispls(int m, int world_size, std::vector<int> &recv_counts_cols,
std::vector<int> &recv_displs_cols) {
int base_cols = 0;
int rem_cols = 0;
if (world_size > 0) {
base_cols = m / world_size;
rem_cols = m % world_size;
}

recv_counts_cols.assign(static_cast<size_t>(world_size), 0);
recv_displs_cols.assign(static_cast<size_t>(world_size), 0);

for (int idx = 0; idx < world_size; ++idx) {
int cols = base_cols;
if (idx < rem_cols) {
cols = cols + 1;
}
recv_counts_cols[static_cast<size_t>(idx)] = cols;
if (idx == 0) {
recv_displs_cols[static_cast<size_t>(idx)] = 0;
} else {
recv_displs_cols[static_cast<size_t>(idx)] =
recv_displs_cols[static_cast<size_t>(idx - 1)] + recv_counts_cols[static_cast<size_t>(idx - 1)];
}
}
}

bool LitvyakovDMinValByColMPI::RunImpl() {
int world_size = 0;
int world_rank = 0;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

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

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

std::vector<int> sendcounts;
std::vector<int> displs;
BuildSendCountsAndDispls(m, n, world_size, sendcounts, displs);

int local_cols = 0;
if (sendcounts.size() > static_cast<size_t>(world_rank)) {
local_cols = sendcounts[static_cast<size_t>(world_rank)] / n;
} else {
local_cols = 0;
}

int local_elems = local_cols * n;
std::vector<Type> local_block(static_cast<size_t>(local_elems));

Type *recvbuf_scatter = nullptr;
if (local_elems > 0) {
recvbuf_scatter = local_block.data();
}

Type *sendbuf_scatter = nullptr;
if (world_rank == 0) {
sendbuf_scatter = mat.data();
} else {
sendbuf_scatter = nullptr;
}

int err = MPI_Scatterv(sendbuf_scatter, sendcounts.data(), displs.data(), datatype, recvbuf_scatter, local_elems,
datatype, 0, MPI_COMM_WORLD);
if (err != MPI_SUCCESS) {
return false;
}

std::vector<Type> local_res(static_cast<size_t>(local_cols), std::numeric_limits<Type>::max());
for (int col_idx = 0; col_idx < local_cols; ++col_idx) {
Type min_val = std::numeric_limits<Type>::max();
std::size_t base_index = static_cast<std::size_t>(col_idx) * static_cast<std::size_t>(n);
for (int row = 0; row < n; ++row) {
min_val = std::min(local_block[base_index + static_cast<std::size_t>(row)], min_val);
}
local_res[static_cast<size_t>(col_idx)] = min_val;
}

std::vector<int> recv_counts_cols;
std::vector<int> recv_displs_cols;
BuildRecvCountsColsAndDispls(m, world_size, recv_counts_cols, recv_displs_cols);

OutType &res = GetOutput();
res.resize(static_cast<size_t>(m));

const Type *sendbuf_gath = nullptr;
if (!local_res.empty()) {
sendbuf_gath = local_res.data();
} else {
sendbuf_gath = nullptr;
}

err = MPI_Gatherv(sendbuf_gath, static_cast<int>(local_res.size()), datatype, res.data(), recv_counts_cols.data(),
recv_displs_cols.data(), datatype, 0, MPI_COMM_WORLD);
if (err != MPI_SUCCESS) {
return false;
}

MPI_Bcast(res.data(), m, datatype, 0, MPI_COMM_WORLD);

return true;
}

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

} // 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. Схема распараллеливания
В параллельной версии каждому процессу столбцы делятся почти поровну между процессами(за исключением остатка от деления между процессами). После вычисления локальных минимумов промежуточные результаты объединяются в финальный с помощью MPI_Gatherv.

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

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

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

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

### 7.2 Производительность
Для теста производительности была использована сгенерированная матрица размерами 2000 на 2000 с элементами от -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
Loading
Loading