-
Notifications
You must be signed in to change notification settings - Fork 80
Кутергин Антон. Технология SEQ-MPI. Нахождение наиболее близких соседних элементов вектора. Вариант 7 #101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
aobolensk
merged 19 commits into
learning-process:master
from
petikantra2014:kutergin_closest_pair
Dec 14, 2025
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
31c4626
rebranch
petikantra2014 a883737
clang format
petikantra2014 f5dd08c
clang-tidy
petikantra2014 fa442e1
clang t and f
petikantra2014 ee6e0e4
clang-tidy format
petikantra2014 45ddbad
clang format
petikantra2014 9b75157
clang format and tidy 2
petikantra2014 118b73e
clang format and tidy 3
petikantra2014 bac83f0
111
petikantra2014 f63c16b
112
petikantra2014 a70144d
113
petikantra2014 2824087
114
petikantra2014 dedc7d9
115
petikantra2014 233a266
116
petikantra2014 5872238
117
petikantra2014 1cc8999
118
petikantra2014 8591be5
for review
petikantra2014 210ee62
report changes
petikantra2014 71fa6b5
Conclusions
petikantra2014 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| #pragma once | ||
|
|
||
| #include <string> | ||
| #include <tuple> | ||
| #include <vector> | ||
|
|
||
| #include "task/include/task.hpp" | ||
|
|
||
| namespace kutergin_a_closest_pair { | ||
|
|
||
| using InType = std::vector<int>; | ||
| ; | ||
| using OutType = int; | ||
| using TestType = std::tuple<std::tuple<InType, int>, std::string>; | ||
| using BaseTask = ppc::task::Task<InType, OutType>; | ||
|
|
||
| } // namespace kutergin_a_closest_pair |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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ФИ1", | ||
| "task_number": "7" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| #pragma once | ||
|
|
||
| #include "kutergin_a_closest_pair/common/include/common.hpp" | ||
| #include "task/include/task.hpp" | ||
|
|
||
| namespace kutergin_a_closest_pair { | ||
|
|
||
| class KuterginAClosestPairMPI : public BaseTask { | ||
| public: | ||
| static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { | ||
| return ppc::task::TypeOfTask::kMPI; | ||
| } | ||
| explicit KuterginAClosestPairMPI(const InType &in); | ||
|
|
||
| private: | ||
| bool ValidationImpl() override; | ||
| bool PreProcessingImpl() override; | ||
| bool RunImpl() override; | ||
| bool PostProcessingImpl() override; | ||
| }; | ||
|
|
||
| } // namespace kutergin_a_closest_pair |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| #include "kutergin_a_closest_pair/mpi/include/ops_mpi.hpp" | ||
|
|
||
| #include <mpi.h> | ||
|
|
||
| #include <algorithm> | ||
| #include <cmath> | ||
| #include <limits> | ||
| #include <vector> | ||
|
|
||
| #include "kutergin_a_closest_pair/common/include/common.hpp" | ||
|
|
||
| namespace kutergin_a_closest_pair { | ||
|
|
||
| KuterginAClosestPairMPI::KuterginAClosestPairMPI(const InType &in) { | ||
| SetTypeOfTask(GetStaticTypeOfTask()); | ||
| GetInput() = in; | ||
| GetOutput() = -1; | ||
| } | ||
|
|
||
| bool KuterginAClosestPairMPI::ValidationImpl() { | ||
| return true; | ||
| } | ||
|
|
||
| bool KuterginAClosestPairMPI::PreProcessingImpl() { | ||
| return true; | ||
| } | ||
|
|
||
| namespace { | ||
|
|
||
| std::vector<int> DistributeData(int rank, int size, int n, const std::vector<int> &v) { | ||
| int local_size = n / size; | ||
| int remainder = n % size; | ||
|
|
||
| int start = (rank * local_size) + std::min(rank, remainder); | ||
| int end = start + local_size + (rank < remainder ? 1 : 0); | ||
|
|
||
| if (rank == size - 1) { | ||
| end = n; | ||
| } | ||
|
|
||
| std::vector<int> local_data(end - start); | ||
| if (rank == 0) { | ||
| std::copy(v.begin() + start, v.begin() + end, local_data.begin()); | ||
|
|
||
| for (int i = 1; i < size; ++i) { | ||
| int other_start = (i * local_size) + std::min(i, remainder); | ||
| int other_end = other_start + local_size + (i < remainder ? 1 : 0); | ||
| if (i == size - 1) { | ||
| other_end = n; | ||
| } | ||
|
|
||
| MPI_Send(v.data() + other_start, other_end - other_start, MPI_INT, i, 0, MPI_COMM_WORLD); | ||
| } | ||
| } else { | ||
| MPI_Recv(local_data.data(), static_cast<int>(local_data.size()), MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | ||
| } | ||
|
|
||
| return local_data; | ||
| } | ||
|
|
||
| int FindLocalMin(const std::vector<int> &local_data, int start_idx, int &found_idx) { | ||
| int local_min = std::numeric_limits<int>::max(); | ||
| found_idx = -1; | ||
|
|
||
| for (int i = 0; i < static_cast<int>(local_data.size()) - 1; ++i) { | ||
| int diff = std::abs(local_data[i + 1] - local_data[i]); | ||
| if (diff < local_min) { | ||
| local_min = diff; | ||
| found_idx = start_idx + i; | ||
| } | ||
| } | ||
|
|
||
| return local_min; | ||
| } | ||
|
|
||
| int CalculateStartIndex(int rank, int size, int n) { | ||
| int local_size = n / size; | ||
| int remainder = n % size; | ||
| return (rank * local_size) + std::min(rank, remainder); | ||
| } | ||
|
|
||
| int CalculateEndIndex(int rank, int size, int n) { | ||
| int local_size = n / size; | ||
| int remainder = n % size; | ||
| int end = CalculateStartIndex(rank, size, n) + local_size + (rank < remainder ? 1 : 0); | ||
| if (rank == size - 1) { | ||
| end = n; | ||
| } | ||
| return end; | ||
| } | ||
|
|
||
| int CheckBoundary(int rank, int size, int end, int n, const std::vector<int> &v, const std::vector<int> &local_data, | ||
| int current_min, int ¤t_idx) { | ||
| if (rank < size - 1 && end < n) { | ||
| int boundary_diff = std::abs(v[end] - local_data.back()); | ||
| if (boundary_diff < current_min) { | ||
| current_min = boundary_diff; | ||
| current_idx = end - 1; | ||
| } | ||
| } | ||
| return current_min; | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| bool KuterginAClosestPairMPI::RunImpl() { | ||
| int rank = 0; | ||
| int size = 0; | ||
| MPI_Comm_rank(MPI_COMM_WORLD, &rank); | ||
| MPI_Comm_size(MPI_COMM_WORLD, &size); | ||
|
|
||
| const auto &v = GetInput(); | ||
| int n = static_cast<int>(v.size()); | ||
|
|
||
| MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); | ||
|
|
||
| if (n < 2) { | ||
| GetOutput() = -1; | ||
| return true; | ||
| } | ||
|
|
||
| auto local_data = DistributeData(rank, size, n, v); | ||
| if (local_data.empty()) { | ||
| GetOutput() = -1; | ||
| return true; | ||
| } | ||
|
|
||
| int start_idx = CalculateStartIndex(rank, size, n); | ||
| int local_idx = -1; | ||
| int local_min = FindLocalMin(local_data, start_idx, local_idx); | ||
|
|
||
| int end = CalculateEndIndex(rank, size, n); | ||
| local_min = CheckBoundary(rank, size, end, n, v, local_data, local_min, local_idx); | ||
|
|
||
| struct MinIndex { | ||
| int val = 0; | ||
| int idx = -1; | ||
| }; | ||
|
|
||
| MinIndex local_result; | ||
| local_result.val = local_min; | ||
| local_result.idx = local_idx; | ||
|
|
||
| MinIndex global_result; | ||
|
|
||
| MPI_Allreduce(&local_result, &global_result, 1, MPI_2INT, MPI_MINLOC, MPI_COMM_WORLD); | ||
|
|
||
| GetOutput() = global_result.idx; | ||
| return true; | ||
| } | ||
|
|
||
| bool KuterginAClosestPairMPI::PostProcessingImpl() { | ||
| return true; | ||
| } | ||
|
|
||
| } // namespace kutergin_a_closest_pair | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # Нахождение наиболее близких соседних элементов вектора | ||
|
|
||
| - Student: Кутергин Антон Андреевич, group 3823Б1ФИ1 | ||
| - Technology: SEQ | MPI | ||
| - Variant: 7 | ||
|
|
||
| ## 1 Введение | ||
|
|
||
| Нужно было реализовать параллельный и последовательный алгоритм для поиска наиболее близких соседних элементов вектора | ||
|
|
||
| ## 2 Постановка задачи | ||
|
|
||
| На вход подается вектор v, нужно найти такой индекс i, что велечина |v[i] - v[i+1]| минимальна среди всех пар элемента | ||
|
|
||
| ## 3. Baseline Algorithm (Sequential) | ||
|
|
||
| Последовательно просматривает пары v[i], v[i+1], сравнивает разности и возвращает индекс максимума | ||
|
|
||
| ## 4. Parallelization Scheme | ||
|
|
||
| Вектор разбивается на MPI процессы, корректно обрабатывая границы между процессами, чтобы последнему числу этого процесса и первому следующего процесса также образуют пару. Каждый ищет свой локальный минимум среди всех своих соседних пар. Возвращаем глобальный индекс пары с помощью MPI_Reduce | ||
|
|
||
| ## 6. Experimental Setup | ||
|
|
||
| -HARDWARE/OS: CPU - Intel Core i5-8300H, cores/threads - 4/8, RAM - 12gb, OS - Windows 10 | ||
| TOOLCHAIN: g++ 13.3.0, build type - Release | ||
|
|
||
|
|
||
| ## 7. Results and Discussion | ||
|
|
||
| ### 7.1 Correctness | ||
|
|
||
| Функциональные тесты: вектор может принимать как положительные, так и отрицательные значения или содержать и положительные и отрицательные значения, так же обрабатывается случай, когда вектор пуст или у него одно значение и пару ему не найти. | ||
| MPI версия запускалась на 4 ядрах - эталонное ускорение в 4 раза. | ||
| Тест на производительность: генерация n чисел и запуск алгоритмов, чтобы узнать время выполнения. | ||
|
|
||
| ### 7.2 Performance | ||
|
|
||
| | Размер данных |Кол-во процессов| MPI версия (сек) | SEQ версия (сек) | | ||
| |---------------|----------------|------------------------|-------------------------| | ||
| | 100,000,000 | 2 | 0.1726183200 | 0.2780640800 | | ||
| | 100,000,000 | 4 | 0.1601058600 | 0.3270964400 | | ||
| | 100,000,000 | 8 | 0.1926481400 | 0.3761903000 | | ||
|
|
||
|
|
||
| ## 8. Conclusions | ||
|
|
||
| В ходе работы были разработаны последовательная(SEQ) и параллельная (MPI) версии алгоритма поиска пары соседних элементов с минимальной разностью. Оба варианта корректно проходят функциональные тесты, включая случаи с отрицательными значениями, смешанными диапазонами чисел и граничными условиями (пустой или одноэлементный вектор). MPI-распараллеливание показало ожидаемый выигрыш на 2 и 4 процессах относительно последовательной версии, что подтверждает эффективность алгоритма. При увелечении числа процессов до 8 наблюдается просадка из-за роста накладных расходов и нехваткой физических ядер, что привело к увелечению время выполнения. В целом работа выполнена успешно: достигнута корректность, показано преимущество MPI версии над SEQ. | ||
|
|
||
| ## 9. References | ||
| 1.Лекции по параллельному программированию | ||
| 2.Практические занятия по параллельному программированию |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| #pragma once | ||
|
|
||
| #include <vector> | ||
|
|
||
| #include "kutergin_a_closest_pair/common/include/common.hpp" | ||
| #include "task/include/task.hpp" | ||
|
|
||
| namespace kutergin_a_closest_pair { | ||
|
|
||
| class KuterginAClosestPairSEQ : public BaseTask { | ||
| public: | ||
| static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { | ||
| return ppc::task::TypeOfTask::kSEQ; | ||
| } | ||
| explicit KuterginAClosestPairSEQ(const InType &in); | ||
|
|
||
| private: | ||
| std::vector<int> data_; | ||
| bool ValidationImpl() override; | ||
| bool PreProcessingImpl() override; | ||
| bool RunImpl() override; | ||
| bool PostProcessingImpl() override; | ||
| }; | ||
|
|
||
| } // namespace kutergin_a_closest_pair |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| #include "kutergin_a_closest_pair/seq/include/ops_seq.hpp" | ||
|
|
||
| #include <algorithm> | ||
| #include <cstdlib> | ||
| #include <ranges> | ||
| #include <vector> | ||
|
|
||
| #include "kutergin_a_closest_pair/common/include/common.hpp" | ||
|
|
||
| namespace kutergin_a_closest_pair { | ||
|
|
||
| KuterginAClosestPairSEQ::KuterginAClosestPairSEQ(const InType &in) { | ||
| SetTypeOfTask(GetStaticTypeOfTask()); | ||
| GetInput() = in; | ||
| GetOutput() = -1; | ||
| } | ||
|
|
||
| bool KuterginAClosestPairSEQ::ValidationImpl() { | ||
| return true; | ||
| } | ||
|
|
||
| bool KuterginAClosestPairSEQ::PreProcessingImpl() { | ||
| return true; | ||
| } | ||
|
|
||
| bool KuterginAClosestPairSEQ::RunImpl() { | ||
| const auto &v = GetInput(); | ||
|
|
||
| if (v.size() < 2) { | ||
| GetOutput() = -1; | ||
| return true; | ||
| } | ||
|
|
||
| auto idx_range = std::views::iota(size_t{0}, v.size() - 1); | ||
|
|
||
| auto comparator = [&](size_t i, size_t j) { | ||
| int diff_i = std::abs(v[i] - v[i + 1]); | ||
| int diff_j = std::abs(v[j] - v[j + 1]); | ||
| return (diff_i < diff_j) || (diff_i == diff_j && i < j); | ||
| }; | ||
|
|
||
| auto min_it = std::ranges::min_element(idx_range, comparator); | ||
| int min_idx = static_cast<int>(*min_it); | ||
|
|
||
| GetOutput() = min_idx; | ||
| return true; | ||
| } | ||
|
|
||
| bool KuterginAClosestPairSEQ::PostProcessingImpl() { | ||
| return true; | ||
| } | ||
|
|
||
| } // namespace kutergin_a_closest_pair |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "tasks_type": "processes", | ||
| "tasks": { | ||
| "mpi": "enabled", | ||
| "seq": "enabled" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this copy will ruin your performance even though it is not really needed