From b8f56b402f424b9e31e1904f4fe187c38bbd05e5 Mon Sep 17 00:00:00 2001 From: Quaha Date: Tue, 18 Nov 2025 00:09:19 +0300 Subject: [PATCH 01/17] Seq solution --- .../common/include/common.hpp | 23 +++++ .../data/pic.jpg | Bin 0 -> 15356 bytes .../info.json | 9 ++ .../mpi/include/ops_mpi.hpp | 22 +++++ .../mpi/src/ops_mpi.cpp | 54 ++++++++++++ .../report.md | 82 +++++++++++++++++ .../seq/include/ops_seq.hpp | 23 +++++ .../seq/src/ops_seq.cpp | 54 ++++++++++++ .../settings.json | 7 ++ .../tests/.clang-tidy | 13 +++ .../tests/functional/main.cpp | 83 ++++++++++++++++++ .../tests/performance/main.cpp | 45 ++++++++++ 12 files changed, 415 insertions(+) create mode 100644 tasks/romanov_a_integration_rect_method/common/include/common.hpp create mode 100644 tasks/romanov_a_integration_rect_method/data/pic.jpg create mode 100644 tasks/romanov_a_integration_rect_method/info.json create mode 100644 tasks/romanov_a_integration_rect_method/mpi/include/ops_mpi.hpp create mode 100644 tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp create mode 100644 tasks/romanov_a_integration_rect_method/report.md create mode 100644 tasks/romanov_a_integration_rect_method/seq/include/ops_seq.hpp create mode 100644 tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp create mode 100644 tasks/romanov_a_integration_rect_method/settings.json create mode 100644 tasks/romanov_a_integration_rect_method/tests/.clang-tidy create mode 100644 tasks/romanov_a_integration_rect_method/tests/functional/main.cpp create mode 100644 tasks/romanov_a_integration_rect_method/tests/performance/main.cpp diff --git a/tasks/romanov_a_integration_rect_method/common/include/common.hpp b/tasks/romanov_a_integration_rect_method/common/include/common.hpp new file mode 100644 index 0000000000..ceb34245fa --- /dev/null +++ b/tasks/romanov_a_integration_rect_method/common/include/common.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include + +#include "task/include/task.hpp" + +namespace romanov_a_integration_rect_method { + +using InType = std::tuple, double, double, int>; +using OutType = double; +using TestType = std::tuple, double, double, int, double>;; +using BaseTask = ppc::task::Task; + +constexpr double EPS = 1e-10; + +inline bool IsEqual(double a, double b) { + return std::abs(a - b) <= EPS; +} + +} // namespace romanov_a_integration_rect_method diff --git a/tasks/romanov_a_integration_rect_method/data/pic.jpg b/tasks/romanov_a_integration_rect_method/data/pic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..34458023494a39d66880a98aa5dcad18eb14b249 GIT binary patch literal 15356 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 + +#include +#include + +#include "romanov_a_integration_rect_method/common/include/common.hpp" +#include "util/include/util.hpp" + +namespace romanov_a_integration_rect_method { + +RomanovAIntegrationRectMethodMPI::RomanovAIntegrationRectMethodMPI(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0.0; +} + +bool RomanovAIntegrationRectMethodMPI::ValidationImpl() { + return (std::get<3>(GetInput()) > 0) && (IsEqual(GetOutput(), 0.0)); +} + +bool RomanovAIntegrationRectMethodMPI::PreProcessingImpl() { + return true; +} + +bool RomanovAIntegrationRectMethodMPI::RunImpl() { + auto [f, a, b, n] = GetInput(); + + double sgn = 1.0; + if (a > b) { + std::swap(a, b); + sgn = -1.0; + } + + double delta_x = (b - a) / static_cast(n); + + double mid = a + delta_x / 2.0; + + for (int i = 0; i < n; ++i) { + GetOutput() += f(mid) * delta_x; + mid += delta_x; + } + + GetOutput() *= sgn; + + return true; +} + +bool RomanovAIntegrationRectMethodMPI::PostProcessingImpl() { + return true; +} + +} // namespace romanov_a_integration_rect_method diff --git a/tasks/romanov_a_integration_rect_method/report.md b/tasks/romanov_a_integration_rect_method/report.md new file mode 100644 index 0000000000..46c8d2e4de --- /dev/null +++ b/tasks/romanov_a_integration_rect_method/report.md @@ -0,0 +1,82 @@ +# Интегрирование – метод прямоугольников + +- Студент: Романов Артем Сергеевич, группа 3823Б1ФИ3 +- Технологии: SEQ, MPI +- Вариант: 19 + +## 1. Введение +Интегрирование функций является составной частью многих научных и технических задач. Поскольку аналитическое интегрирование не всегда возможно, часто используются различные методы численного интегрирования. Метод прямоугольников является одним из наиболее простых для понимания и реализации методов, идея которого заключается в приближении значения интеграла некоторой интегральной суммой. + +В рамках данной работы реализуется последовательная и параллельная версия алгоритма численного вычисления значения интеграла методом прямоугольников, а также исследуется эффективность их работы. + +## 2. Постановка задачи +Пусть задана функция + +$$ +f(x): \mathbb{R} \to \mathbb{R}, +$$ + +которая интегрируема на заданном отрезке $[a,b]$. Требуется приближённо вычислить значение определённого интеграла + +$$ +I = \int\limits_a^b f(x)dx +$$ +с помощью метода прямоугольников. + +Входными данными являются функция $f(x): \mathbb{R} \to \mathbb{R}$, вещественные границы отрезка интегрирования $a, b$ $(a < b)$, на котором функция определена и число слагаемых $n$ в интегральной сумме. + + +## 3. Базовый алгоритм (последовательный) +Метода прямоугольников заключается приближении значения определённого интеграла с помощью интегральной суммы: +$$ +\int_{a}^{b} f(x) \, dx \approx \sum_{i=1}^{n} f\left(x_{i}^{*}\right) \times \Delta x_{i}, x_{i}^{*} \in\left[x_{i-1}, x_{i}\right], \Delta x_i = x_i - x_{i-1} +$$ +Все $\Delta x_i$ полагаются равными $\frac{b-a}{n}$, где $n$ - число элементарных отрезков, а $x_i^*$ выбирается по-разному в зависимости от варианта метода прямоугольников. Основных вариаций три: +1. **Метод левых прямоугольников** - используется значение функции в левой границе каждого элементарного отрезка - $x_i^* = x_{i-1}$; +2. **Метод правых прямоугольников** - используется значение функции в правой границе каждого элементарного отрезка - $x_i^* = x_{i}$; +3. **Метод средних прямоугольников** - используется значение функции в середине каждого элементарного отрезка - $x_i^* = \frac{x_{i-1} + x_{i}}{2}$. + +В данной работе реализуется метод средних прямоугольников. +## 4. Схема паралеллизации +- For MPI: data distribution, communication pattern/topology, rank roles. +- For threads: decomposition, scheduling, synchronization. +Diagrams or short pseudocode are welcome. + +## 5. Детали реализации +- Code structure (files, key classes/functions) +- Important assumptions and corner cases +- Memory usage considerations + +## 6. Условия проведения экспериментов +- Hardware/OS: CPU model, cores/threads, RAM, OS version +- Toolchain: compiler, version, build type (Release/RelWithDebInfo) +- Environment: PPC_NUM_THREADS / PPC_NUM_PROC, other relevant vars +- Data: how test data is generated or sourced (relative paths) + +## 7. Результаты + +### 7.1 Корректность +Briefly explain how correctness was verified (reference results, invariants, unit tests). + +### 7.2 Эффективность +Present time, speedup and efficiency. Example table: + +| Mode | Count | Time, s | Speedup | Efficiency | +|-------------|-------|---------|---------|------------| +| seq | 1 | 1.234 | 1.00 | N/A | +| omp | 2 | 0.700 | 1.76 | 88.0% | +| omp | 4 | 0.390 | 3.16 | 79.0% | + +Optionally add plots (use relative paths), and discuss bottlenecks and scalability limits. + +## 8. Заключение +Summarize findings and limitations. + +## 9. Список литературы +1. Павлова Т. Ю. Численное интегрирование [Электронный ресурс]. – Кемерово: Кемеровский государственный университет, Институт фундаментальных наук. – Режим доступа: [https://ifn.kemsu.ru/page_teachers/pavlova/Numerical_integration.Brief_theory.pdf](https://ifn.kemsu.ru/page_teachers/pavlova/Numerical_integration.Brief_theory.pdf) – (дата обращения: 12.11.2025). + + +## Приложение +```cpp +// Short, readable code excerpts if needed +``` \ No newline at end of file diff --git a/tasks/romanov_a_integration_rect_method/seq/include/ops_seq.hpp b/tasks/romanov_a_integration_rect_method/seq/include/ops_seq.hpp new file mode 100644 index 0000000000..2a94becc81 --- /dev/null +++ b/tasks/romanov_a_integration_rect_method/seq/include/ops_seq.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "romanov_a_integration_rect_method/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace romanov_a_integration_rect_method { + +class RomanovAIntegrationRectMethodSEQ : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSEQ; + } + explicit RomanovAIntegrationRectMethodSEQ(const InType &in); + + private: + + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} // namespace romanov_a_integration_rect_method diff --git a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp new file mode 100644 index 0000000000..8fba378791 --- /dev/null +++ b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp @@ -0,0 +1,54 @@ +#include "romanov_a_integration_rect_method/seq/include/ops_seq.hpp" + +#include +#include + +#include + +#include "romanov_a_integration_rect_method/common/include/common.hpp" +#include "util/include/util.hpp" + +namespace romanov_a_integration_rect_method { + +RomanovAIntegrationRectMethodSEQ::RomanovAIntegrationRectMethodSEQ(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0.0; +} + +bool RomanovAIntegrationRectMethodSEQ::ValidationImpl() { + return (std::get<3>(GetInput()) > 0) && (IsEqual(GetOutput(), 0.0)); +} + +bool RomanovAIntegrationRectMethodSEQ::PreProcessingImpl() { + return true; +} + +bool RomanovAIntegrationRectMethodSEQ::RunImpl() { + auto [f, a, b, n] = GetInput(); + + double sgn = 1.0; + if (a > b) { + std::swap(a, b); + sgn = -1.0; + } + + double delta_x = (b - a) / static_cast(n); + + double mid = a + delta_x / 2.0; + + for (int i = 0; i < n; ++i) { + GetOutput() += f(mid) * delta_x; + mid += delta_x; + } + + GetOutput() *= sgn; + + return true; +} + +bool RomanovAIntegrationRectMethodSEQ::PostProcessingImpl() { + return true; +} + +} // namespace romanov_a_integration_rect_method diff --git a/tasks/romanov_a_integration_rect_method/settings.json b/tasks/romanov_a_integration_rect_method/settings.json new file mode 100644 index 0000000000..b1a0d52574 --- /dev/null +++ b/tasks/romanov_a_integration_rect_method/settings.json @@ -0,0 +1,7 @@ +{ + "tasks_type": "processes", + "tasks": { + "mpi": "enabled", + "seq": "enabled" + } +} diff --git a/tasks/romanov_a_integration_rect_method/tests/.clang-tidy b/tasks/romanov_a_integration_rect_method/tests/.clang-tidy new file mode 100644 index 0000000000..ef43b7aa8a --- /dev/null +++ b/tasks/romanov_a_integration_rect_method/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/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp new file mode 100644 index 0000000000..7acd2fb8e4 --- /dev/null +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -0,0 +1,83 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "romanov_a_integration_rect_method/common/include/common.hpp" +#include "romanov_a_integration_rect_method/mpi/include/ops_mpi.hpp" +#include "romanov_a_integration_rect_method/seq/include/ops_seq.hpp" +#include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" + +namespace romanov_a_integration_rect_method { + +class RomanovAIntegrationRectMethodFuncTests : public ppc::util::BaseRunFuncTests { + public: + static std::string PrintTestParam(const TestType &test_param) { + auto [f, a, b, n, result] = test_param; + + // Минус (-) от отрицательных чисел в имени gtest нельзя, функцию в имя gtest не поместить, точку (.) тоже... Как жить то? + return "_id" + std::to_string((int)(std::abs((result - a + 2.0 * b + 4.0) * 334))) + "_n" + std::to_string(n); + } + + protected: + void SetUp() override { + TestType params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + + auto [f, a, b, n, result] = params; + + input_data_ = std::make_tuple(std::function(f), a, b, n); + + expected_ = result; + } + + bool CheckTestOutputData(OutType &output_data) final { + return IsEqual(static_cast(output_data), expected_); + } + + InType GetTestInputData() final { + return input_data_; + } + + private: + InType input_data_; + double expected_; +}; + +namespace { + +TEST_P(RomanovAIntegrationRectMethodFuncTests, MatmulFromPic) { + ExecuteTest(GetParam()); +} + +const std::array kTestParam = { + std::make_tuple([](double x) { return x; }, 0.0, 1.0, 1000000, 0.5), + std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 1000000 + 1, 1.0 / 3.0), + std::make_tuple([](double x) { return std::sin(x) * x - std::sqrt(x); }, 0.0, 3.1415, 1000000 + 2, -0.570462), + std::make_tuple([](double x) { return std::exp(x) - x; }, 3.0, -1.0, 1000000 + 3, 42.0 + 1.0 / std::exp(1.0) - std::exp(3.0)), + std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, 3.1415, 1000000 + 4, -0.894667) +}; + +const auto kTestTasksList = + std::tuple_cat(ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_romanov_a_integration_rect_method), + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_romanov_a_integration_rect_method)); + +const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); + +const auto kPerfTestName = RomanovAIntegrationRectMethodFuncTests::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(PicMatrixTests, RomanovAIntegrationRectMethodFuncTests, kGtestValues, kPerfTestName); + +} // namespace + +} // namespace romanov_a_integration_rect_method diff --git a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp new file mode 100644 index 0000000000..39772e6866 --- /dev/null +++ b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp @@ -0,0 +1,45 @@ +#include + +#include "romanov_a_integration_rect_method/common/include/common.hpp" +#include "romanov_a_integration_rect_method/mpi/include/ops_mpi.hpp" +#include "romanov_a_integration_rect_method/seq/include/ops_seq.hpp" +#include "util/include/perf_test_util.hpp" + +namespace romanov_a_integration_rect_method { + +class RomanovAIntegrationRectMethodPerfTests : public ppc::util::BaseRunPerfTests { + const int kCount_ = 10'000'000; + InType input_data_{}; + + void SetUp() override { + auto f = std::function([](double x) { return x * x; }); + double a = 0.0; + double b = 1.0; + int n = kCount_; + + input_data_ = std::make_tuple(f, a, b, n); + } + + bool CheckTestOutputData(OutType &output_data) final { + return IsEqual(static_cast(output_data), 1.0/3.0); + } + + InType GetTestInputData() final { + return input_data_; + } +}; + +TEST_P(RomanovAIntegrationRectMethodPerfTests, RunPerfModes) { + ExecuteTest(GetParam()); +} + +const auto kAllPerfTasks = + ppc::util::MakeAllPerfTasks(PPC_SETTINGS_romanov_a_integration_rect_method); + +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); + +const auto kPerfTestName = RomanovAIntegrationRectMethodPerfTests::CustomPerfTestName; + +INSTANTIATE_TEST_SUITE_P(RunModeTests, RomanovAIntegrationRectMethodPerfTests, kGtestValues, kPerfTestName); + +} // namespace romanov_a_integration_rect_method From 2cce983e32af002efbbb65526cb6e3ce0da308e2 Mon Sep 17 00:00:00 2001 From: Quaha Date: Tue, 18 Nov 2025 23:11:31 +0300 Subject: [PATCH 02/17] Mpi and seq versions --- .../common/include/common.hpp | 2 +- .../mpi/src/ops_mpi.cpp | 51 +++++++++++++++---- .../seq/src/ops_seq.cpp | 26 ++++++---- .../tests/functional/main.cpp | 2 +- .../tests/performance/main.cpp | 2 +- 5 files changed, 58 insertions(+), 25 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/common/include/common.hpp b/tasks/romanov_a_integration_rect_method/common/include/common.hpp index ceb34245fa..cf54081f7b 100644 --- a/tasks/romanov_a_integration_rect_method/common/include/common.hpp +++ b/tasks/romanov_a_integration_rect_method/common/include/common.hpp @@ -14,7 +14,7 @@ using OutType = double; using TestType = std::tuple, double, double, int, double>;; using BaseTask = ppc::task::Task; -constexpr double EPS = 1e-10; +constexpr double EPS = 1e-4; inline bool IsEqual(double a, double b) { return std::abs(a - b) <= EPS; diff --git a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp index 78d065c282..3cdc0bdad9 100644 --- a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp +++ b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp @@ -17,7 +17,16 @@ RomanovAIntegrationRectMethodMPI::RomanovAIntegrationRectMethodMPI(const InType } bool RomanovAIntegrationRectMethodMPI::ValidationImpl() { - return (std::get<3>(GetInput()) > 0) && (IsEqual(GetOutput(), 0.0)); + if (!IsEqual(GetOutput(), 0.0)) { + return false; + } + else if (std::get<3>(GetInput()) <= 0) { + return false; + } + else if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { + return false; + } + return true; } bool RomanovAIntegrationRectMethodMPI::PreProcessingImpl() { @@ -25,24 +34,44 @@ bool RomanovAIntegrationRectMethodMPI::PreProcessingImpl() { } bool RomanovAIntegrationRectMethodMPI::RunImpl() { - auto [f, a, b, n] = GetInput(); - - double sgn = 1.0; - if (a > b) { - std::swap(a, b); - sgn = -1.0; + + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + int num_processes = 0; + MPI_Comm_size(MPI_COMM_WORLD, &num_processes); + + double a, b; + int n; + + double result = 0.0; + + if (rank == 0) { + a = std::get<1>(GetInput()); + b = std::get<2>(GetInput()); + n = std::get<3>(GetInput()); } + MPI_Bcast(&a, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&b, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); + + auto f = std::get<0>(GetInput()); + + int left_border = rank * (n / num_processes); + int right_border = std::min(n, (rank + 1) * (n / num_processes)); double delta_x = (b - a) / static_cast(n); + double mid = a + delta_x * static_cast(left_border) + delta_x / 2.0; - double mid = a + delta_x / 2.0; + double current_result = 0.0; - for (int i = 0; i < n; ++i) { - GetOutput() += f(mid) * delta_x; + for (int i = left_border; i < right_border; ++i) { + current_result += f(mid) * delta_x; mid += delta_x; } - GetOutput() *= sgn; + MPI_Allreduce(¤t_result, &result, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + GetOutput() = result; return true; } diff --git a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp index 8fba378791..1bed64900a 100644 --- a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp +++ b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp @@ -17,7 +17,16 @@ RomanovAIntegrationRectMethodSEQ::RomanovAIntegrationRectMethodSEQ(const InType } bool RomanovAIntegrationRectMethodSEQ::ValidationImpl() { - return (std::get<3>(GetInput()) > 0) && (IsEqual(GetOutput(), 0.0)); + if (!IsEqual(GetOutput(), 0.0)) { + return false; + } + else if (std::get<3>(GetInput()) <= 0) { + return false; + } + else if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { + return false; + } + return true; } bool RomanovAIntegrationRectMethodSEQ::PreProcessingImpl() { @@ -25,24 +34,19 @@ bool RomanovAIntegrationRectMethodSEQ::PreProcessingImpl() { } bool RomanovAIntegrationRectMethodSEQ::RunImpl() { - auto [f, a, b, n] = GetInput(); - - double sgn = 1.0; - if (a > b) { - std::swap(a, b); - sgn = -1.0; - } + const auto& [f, a, b, n] = GetInput(); double delta_x = (b - a) / static_cast(n); - double mid = a + delta_x / 2.0; + double result = 0.0; + for (int i = 0; i < n; ++i) { - GetOutput() += f(mid) * delta_x; + result += f(mid) * delta_x; mid += delta_x; } - GetOutput() *= sgn; + GetOutput() = result; return true; } diff --git a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp index 7acd2fb8e4..a5d0e6dcda 100644 --- a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -64,7 +64,7 @@ const std::array kTestParam = { std::make_tuple([](double x) { return x; }, 0.0, 1.0, 1000000, 0.5), std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 1000000 + 1, 1.0 / 3.0), std::make_tuple([](double x) { return std::sin(x) * x - std::sqrt(x); }, 0.0, 3.1415, 1000000 + 2, -0.570462), - std::make_tuple([](double x) { return std::exp(x) - x; }, 3.0, -1.0, 1000000 + 3, 42.0 + 1.0 / std::exp(1.0) - std::exp(3.0)), + std::make_tuple([](double x) { return std::exp(x) - x; }, -1.0, 3.0, 1000000 + 3, -4.0 - 1.0 / std::exp(1.0) + std::exp(3.0)), std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, 3.1415, 1000000 + 4, -0.894667) }; diff --git a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp index 39772e6866..c4485882f3 100644 --- a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp @@ -8,7 +8,7 @@ namespace romanov_a_integration_rect_method { class RomanovAIntegrationRectMethodPerfTests : public ppc::util::BaseRunPerfTests { - const int kCount_ = 10'000'000; + const int kCount_ = 500'000'000; InType input_data_{}; void SetUp() override { From b5daaba91f1709ac78987db1d73571f5b4319d1c Mon Sep 17 00:00:00 2001 From: Quaha Date: Tue, 18 Nov 2025 23:23:05 +0300 Subject: [PATCH 03/17] Report formulas update --- .../report.md | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/report.md b/tasks/romanov_a_integration_rect_method/report.md index 46c8d2e4de..c971577bfb 100644 --- a/tasks/romanov_a_integration_rect_method/report.md +++ b/tasks/romanov_a_integration_rect_method/report.md @@ -10,17 +10,10 @@ В рамках данной работы реализуется последовательная и параллельная версия алгоритма численного вычисления значения интеграла методом прямоугольников, а также исследуется эффективность их работы. ## 2. Постановка задачи -Пусть задана функция +Пусть задана функция $f(x): \mathbb{R} \to \mathbb{R},$ которая интегрируема на заданном отрезке $[a,b]$. Требуется приближённо вычислить значение определённого интеграла -$$ -f(x): \mathbb{R} \to \mathbb{R}, -$$ +$I = \int\limits_a^b f(x)dx$ -которая интегрируема на заданном отрезке $[a,b]$. Требуется приближённо вычислить значение определённого интеграла - -$$ -I = \int\limits_a^b f(x)dx -$$ с помощью метода прямоугольников. Входными данными являются функция $f(x): \mathbb{R} \to \mathbb{R}$, вещественные границы отрезка интегрирования $a, b$ $(a < b)$, на котором функция определена и число слагаемых $n$ в интегральной сумме. @@ -28,13 +21,13 @@ $$ ## 3. Базовый алгоритм (последовательный) Метода прямоугольников заключается приближении значения определённого интеграла с помощью интегральной суммы: -$$ -\int_{a}^{b} f(x) \, dx \approx \sum_{i=1}^{n} f\left(x_{i}^{*}\right) \times \Delta x_{i}, x_{i}^{*} \in\left[x_{i-1}, x_{i}\right], \Delta x_i = x_i - x_{i-1} -$$ + +$\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$,где $x_{i}^{\*} \in [x_{i-1}, x_{i}]$ и $\Delta x_i = x_i - x_{i-1}$ + Все $\Delta x_i$ полагаются равными $\frac{b-a}{n}$, где $n$ - число элементарных отрезков, а $x_i^*$ выбирается по-разному в зависимости от варианта метода прямоугольников. Основных вариаций три: -1. **Метод левых прямоугольников** - используется значение функции в левой границе каждого элементарного отрезка - $x_i^* = x_{i-1}$; -2. **Метод правых прямоугольников** - используется значение функции в правой границе каждого элементарного отрезка - $x_i^* = x_{i}$; -3. **Метод средних прямоугольников** - используется значение функции в середине каждого элементарного отрезка - $x_i^* = \frac{x_{i-1} + x_{i}}{2}$. +1. **Метод левых прямоугольников** - используется значение функции в левой границе каждого элементарного отрезка: $x_i^* = x_{i-1}$; +2. **Метод правых прямоугольников** - используется значение функции в правой границе каждого элементарного отрезка: $x_i^* = x_{i}$; +3. **Метод средних прямоугольников** - используется значение функции в середине каждого элементарного отрезка: $x_i^* = \frac{x_{i-1} + x_{i}}{2}$. В данной работе реализуется метод средних прямоугольников. ## 4. Схема паралеллизации From 839ba97dec072eb8e9cec2d843104c1d331ff9b5 Mon Sep 17 00:00:00 2001 From: Quaha Date: Tue, 18 Nov 2025 23:59:51 +0300 Subject: [PATCH 04/17] CI restart No1 --- tasks/romanov_a_integration_rect_method/report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/romanov_a_integration_rect_method/report.md b/tasks/romanov_a_integration_rect_method/report.md index c971577bfb..9783c88824 100644 --- a/tasks/romanov_a_integration_rect_method/report.md +++ b/tasks/romanov_a_integration_rect_method/report.md @@ -31,7 +31,7 @@ $\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$, В данной работе реализуется метод средних прямоугольников. ## 4. Схема паралеллизации -- For MPI: data distribution, communication pattern/topology, rank roles. +- For MPI: data distribution, communication pattern/topology, rank roles.. - For threads: decomposition, scheduling, synchronization. Diagrams or short pseudocode are welcome. From 5af80f428282e650f8c62a431dc97ab92c0125f6 Mon Sep 17 00:00:00 2001 From: Quaha Date: Wed, 19 Nov 2025 14:01:18 +0300 Subject: [PATCH 05/17] Clang Format --- .../common/include/common.hpp | 6 ++--- .../mpi/src/ops_mpi.cpp | 9 +++----- .../seq/include/ops_seq.hpp | 1 - .../seq/src/ops_seq.cpp | 11 ++++----- .../tests/functional/main.cpp | 23 +++++++++++-------- .../tests/performance/main.cpp | 5 ++-- 6 files changed, 26 insertions(+), 29 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/common/include/common.hpp b/tasks/romanov_a_integration_rect_method/common/include/common.hpp index cf54081f7b..eefedbb760 100644 --- a/tasks/romanov_a_integration_rect_method/common/include/common.hpp +++ b/tasks/romanov_a_integration_rect_method/common/include/common.hpp @@ -1,17 +1,17 @@ #pragma once +#include #include #include -#include - #include "task/include/task.hpp" namespace romanov_a_integration_rect_method { using InType = std::tuple, double, double, int>; using OutType = double; -using TestType = std::tuple, double, double, int, double>;; +using TestType = std::tuple, double, double, int, double>; +; using BaseTask = ppc::task::Task; constexpr double EPS = 1e-4; diff --git a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp index 3cdc0bdad9..1857db3cbb 100644 --- a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp +++ b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp @@ -19,11 +19,9 @@ RomanovAIntegrationRectMethodMPI::RomanovAIntegrationRectMethodMPI(const InType bool RomanovAIntegrationRectMethodMPI::ValidationImpl() { if (!IsEqual(GetOutput(), 0.0)) { return false; - } - else if (std::get<3>(GetInput()) <= 0) { + } else if (std::get<3>(GetInput()) <= 0) { return false; - } - else if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { + } else if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { return false; } return true; @@ -34,10 +32,9 @@ bool RomanovAIntegrationRectMethodMPI::PreProcessingImpl() { } bool RomanovAIntegrationRectMethodMPI::RunImpl() { - int rank = 0; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - + int num_processes = 0; MPI_Comm_size(MPI_COMM_WORLD, &num_processes); diff --git a/tasks/romanov_a_integration_rect_method/seq/include/ops_seq.hpp b/tasks/romanov_a_integration_rect_method/seq/include/ops_seq.hpp index 2a94becc81..4dd738629b 100644 --- a/tasks/romanov_a_integration_rect_method/seq/include/ops_seq.hpp +++ b/tasks/romanov_a_integration_rect_method/seq/include/ops_seq.hpp @@ -13,7 +13,6 @@ class RomanovAIntegrationRectMethodSEQ : public BaseTask { explicit RomanovAIntegrationRectMethodSEQ(const InType &in); private: - bool ValidationImpl() override; bool PreProcessingImpl() override; bool RunImpl() override; diff --git a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp index 1bed64900a..97f0faf8ee 100644 --- a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp +++ b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp @@ -1,10 +1,9 @@ #include "romanov_a_integration_rect_method/seq/include/ops_seq.hpp" +#include #include #include -#include - #include "romanov_a_integration_rect_method/common/include/common.hpp" #include "util/include/util.hpp" @@ -19,11 +18,9 @@ RomanovAIntegrationRectMethodSEQ::RomanovAIntegrationRectMethodSEQ(const InType bool RomanovAIntegrationRectMethodSEQ::ValidationImpl() { if (!IsEqual(GetOutput(), 0.0)) { return false; - } - else if (std::get<3>(GetInput()) <= 0) { + } else if (std::get<3>(GetInput()) <= 0) { return false; - } - else if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { + } else if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { return false; } return true; @@ -34,7 +31,7 @@ bool RomanovAIntegrationRectMethodSEQ::PreProcessingImpl() { } bool RomanovAIntegrationRectMethodSEQ::RunImpl() { - const auto& [f, a, b, n] = GetInput(); + const auto &[f, a, b, n] = GetInput(); double delta_x = (b - a) / static_cast(n); double mid = a + delta_x / 2.0; diff --git a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp index a5d0e6dcda..0c50341509 100644 --- a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -6,12 +6,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include "romanov_a_integration_rect_method/common/include/common.hpp" #include "romanov_a_integration_rect_method/mpi/include/ops_mpi.hpp" @@ -26,8 +26,9 @@ class RomanovAIntegrationRectMethodFuncTests : public ppc::util::BaseRunFuncTest static std::string PrintTestParam(const TestType &test_param) { auto [f, a, b, n, result] = test_param; - // Минус (-) от отрицательных чисел в имени gtest нельзя, функцию в имя gtest не поместить, точку (.) тоже... Как жить то? - return "_id" + std::to_string((int)(std::abs((result - a + 2.0 * b + 4.0) * 334))) + "_n" + std::to_string(n); + // Минус (-) от отрицательных чисел в имени gtest нельзя, функцию в имя gtest не поместить, точку (.) тоже... Как + // жить то? + return "_id" + std::to_string((int)(std::abs((result - a + 2.0 * b + 4.0) * 334))) + "_n" + std::to_string(n); } protected: @@ -64,17 +65,19 @@ const std::array kTestParam = { std::make_tuple([](double x) { return x; }, 0.0, 1.0, 1000000, 0.5), std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 1000000 + 1, 1.0 / 3.0), std::make_tuple([](double x) { return std::sin(x) * x - std::sqrt(x); }, 0.0, 3.1415, 1000000 + 2, -0.570462), - std::make_tuple([](double x) { return std::exp(x) - x; }, -1.0, 3.0, 1000000 + 3, -4.0 - 1.0 / std::exp(1.0) + std::exp(3.0)), - std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, 3.1415, 1000000 + 4, -0.894667) -}; + std::make_tuple([](double x) { return std::exp(x) - x; }, -1.0, 3.0, 1000000 + 3, + -4.0 - 1.0 / std::exp(1.0) + std::exp(3.0)), + std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, 3.1415, 1000000 + 4, -0.894667)}; -const auto kTestTasksList = - std::tuple_cat(ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_romanov_a_integration_rect_method), - ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_romanov_a_integration_rect_method)); +const auto kTestTasksList = std::tuple_cat(ppc::util::AddFuncTask( + kTestParam, PPC_SETTINGS_romanov_a_integration_rect_method), + ppc::util::AddFuncTask( + kTestParam, PPC_SETTINGS_romanov_a_integration_rect_method)); const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); -const auto kPerfTestName = RomanovAIntegrationRectMethodFuncTests::PrintFuncTestName; +const auto kPerfTestName = + RomanovAIntegrationRectMethodFuncTests::PrintFuncTestName; INSTANTIATE_TEST_SUITE_P(PicMatrixTests, RomanovAIntegrationRectMethodFuncTests, kGtestValues, kPerfTestName); diff --git a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp index c4485882f3..cbc42620f1 100644 --- a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp @@ -21,7 +21,7 @@ class RomanovAIntegrationRectMethodPerfTests : public ppc::util::BaseRunPerfTest } bool CheckTestOutputData(OutType &output_data) final { - return IsEqual(static_cast(output_data), 1.0/3.0); + return IsEqual(static_cast(output_data), 1.0 / 3.0); } InType GetTestInputData() final { @@ -34,7 +34,8 @@ TEST_P(RomanovAIntegrationRectMethodPerfTests, RunPerfModes) { } const auto kAllPerfTasks = - ppc::util::MakeAllPerfTasks(PPC_SETTINGS_romanov_a_integration_rect_method); + ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_romanov_a_integration_rect_method); const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); From 5f7de185baaa83852afb8ea2c732dddcf152499f Mon Sep 17 00:00:00 2001 From: Quaha Date: Wed, 19 Nov 2025 15:52:27 +0300 Subject: [PATCH 06/17] Func tests fixes --- .../tests/functional/main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp index 0c50341509..bcaded6e19 100644 --- a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -62,12 +62,12 @@ TEST_P(RomanovAIntegrationRectMethodFuncTests, MatmulFromPic) { } const std::array kTestParam = { - std::make_tuple([](double x) { return x; }, 0.0, 1.0, 1000000, 0.5), - std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 1000000 + 1, 1.0 / 3.0), - std::make_tuple([](double x) { return std::sin(x) * x - std::sqrt(x); }, 0.0, 3.1415, 1000000 + 2, -0.570462), - std::make_tuple([](double x) { return std::exp(x) - x; }, -1.0, 3.0, 1000000 + 3, + std::make_tuple([](double x) { return x; }, 0.0, 1.0, 10000000, 0.5), + std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 10000000 + 1, 1.0 / 3.0), + std::make_tuple([](double x) { return std::sin(x) * x - std::sqrt(x); }, 0.0, 3.1415, 10000000 + 2, -0.570462), + std::make_tuple([](double x) { return std::exp(x) - x; }, -1.0, 3.0, 10000000 + 3, -4.0 - 1.0 / std::exp(1.0) + std::exp(3.0)), - std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, 3.1415, 1000000 + 4, -0.894667)}; + std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, 3.1415, 10000000 + 4, -0.894667)}; const auto kTestTasksList = std::tuple_cat(ppc::util::AddFuncTask( kTestParam, PPC_SETTINGS_romanov_a_integration_rect_method), From 800fbd3bda44e5819c4f2f83cf7029108129089c Mon Sep 17 00:00:00 2001 From: Quaha Date: Wed, 19 Nov 2025 17:01:52 +0300 Subject: [PATCH 07/17] Yet Another ClangF fix --- .../common/include/common.hpp | 5 ++--- .../mpi/src/ops_mpi.cpp | 18 +++++++++--------- .../seq/src/ops_seq.cpp | 11 +++++------ .../tests/functional/main.cpp | 16 ++++++---------- .../tests/performance/main.cpp | 5 ++++- 5 files changed, 26 insertions(+), 29 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/common/include/common.hpp b/tasks/romanov_a_integration_rect_method/common/include/common.hpp index eefedbb760..19e25fcab7 100644 --- a/tasks/romanov_a_integration_rect_method/common/include/common.hpp +++ b/tasks/romanov_a_integration_rect_method/common/include/common.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include "task/include/task.hpp" @@ -14,10 +13,10 @@ using TestType = std::tuple, double, double, int, ; using BaseTask = ppc::task::Task; -constexpr double EPS = 1e-4; +constexpr double kEps = 1e-4; inline bool IsEqual(double a, double b) { - return std::abs(a - b) <= EPS; + return std::abs(a - b) <= kEps; } } // namespace romanov_a_integration_rect_method diff --git a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp index 1857db3cbb..a03a33d284 100644 --- a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp +++ b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp @@ -1,12 +1,9 @@ #include "romanov_a_integration_rect_method/mpi/include/ops_mpi.hpp" #include - -#include -#include +#include #include "romanov_a_integration_rect_method/common/include/common.hpp" -#include "util/include/util.hpp" namespace romanov_a_integration_rect_method { @@ -19,9 +16,11 @@ RomanovAIntegrationRectMethodMPI::RomanovAIntegrationRectMethodMPI(const InType bool RomanovAIntegrationRectMethodMPI::ValidationImpl() { if (!IsEqual(GetOutput(), 0.0)) { return false; - } else if (std::get<3>(GetInput()) <= 0) { + } + if (std::get<3>(GetInput()) <= 0) { return false; - } else if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { + } + if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { return false; } return true; @@ -38,8 +37,9 @@ bool RomanovAIntegrationRectMethodMPI::RunImpl() { int num_processes = 0; MPI_Comm_size(MPI_COMM_WORLD, &num_processes); - double a, b; - int n; + double a = 0.0; + double b = 0.0; + int n = 0; double result = 0.0; @@ -58,7 +58,7 @@ bool RomanovAIntegrationRectMethodMPI::RunImpl() { int right_border = std::min(n, (rank + 1) * (n / num_processes)); double delta_x = (b - a) / static_cast(n); - double mid = a + delta_x * static_cast(left_border) + delta_x / 2.0; + double mid = a + (delta_x * static_cast(left_border)) + (delta_x / 2.0); double current_result = 0.0; diff --git a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp index 97f0faf8ee..93ad65339f 100644 --- a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp +++ b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp @@ -1,11 +1,8 @@ #include "romanov_a_integration_rect_method/seq/include/ops_seq.hpp" #include -#include -#include #include "romanov_a_integration_rect_method/common/include/common.hpp" -#include "util/include/util.hpp" namespace romanov_a_integration_rect_method { @@ -18,9 +15,11 @@ RomanovAIntegrationRectMethodSEQ::RomanovAIntegrationRectMethodSEQ(const InType bool RomanovAIntegrationRectMethodSEQ::ValidationImpl() { if (!IsEqual(GetOutput(), 0.0)) { return false; - } else if (std::get<3>(GetInput()) <= 0) { + } + if (std::get<3>(GetInput()) <= 0) { return false; - } else if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { + } + if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { return false; } return true; @@ -34,7 +33,7 @@ bool RomanovAIntegrationRectMethodSEQ::RunImpl() { const auto &[f, a, b, n] = GetInput(); double delta_x = (b - a) / static_cast(n); - double mid = a + delta_x / 2.0; + double mid = a + (delta_x / 2.0); double result = 0.0; diff --git a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp index bcaded6e19..1ef979bd38 100644 --- a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -1,17 +1,13 @@ #include #include -#include #include #include #include -#include -#include -#include -#include #include -#include -#include +#include +#include +#include #include "romanov_a_integration_rect_method/common/include/common.hpp" #include "romanov_a_integration_rect_method/mpi/include/ops_mpi.hpp" @@ -28,7 +24,7 @@ class RomanovAIntegrationRectMethodFuncTests : public ppc::util::BaseRunFuncTest // Минус (-) от отрицательных чисел в имени gtest нельзя, функцию в имя gtest не поместить, точку (.) тоже... Как // жить то? - return "_id" + std::to_string((int)(std::abs((result - a + 2.0 * b + 4.0) * 334))) + "_n" + std::to_string(n); + return "_id" + std::to_string(static_cast(std::abs((result - a + (2.0 * b) + 4.0) * 334))) + "_n" + std::to_string(n); } protected: @@ -64,9 +60,9 @@ TEST_P(RomanovAIntegrationRectMethodFuncTests, MatmulFromPic) { const std::array kTestParam = { std::make_tuple([](double x) { return x; }, 0.0, 1.0, 10000000, 0.5), std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 10000000 + 1, 1.0 / 3.0), - std::make_tuple([](double x) { return std::sin(x) * x - std::sqrt(x); }, 0.0, 3.1415, 10000000 + 2, -0.570462), + std::make_tuple([](double x) { return (std::sin(x) * x) - std::sqrt(x); }, 0.0, 3.1415, 10000000 + 2, -0.570462), std::make_tuple([](double x) { return std::exp(x) - x; }, -1.0, 3.0, 10000000 + 3, - -4.0 - 1.0 / std::exp(1.0) + std::exp(3.0)), + -4.0 - (1.0 / std::numbers::e) + std::exp(3.0)), std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, 3.1415, 10000000 + 4, -0.894667)}; const auto kTestTasksList = std::tuple_cat(ppc::util::AddFuncTask( diff --git a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp index cbc42620f1..5ab4aebf4d 100644 --- a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp @@ -1,5 +1,8 @@ #include +#include +#include + #include "romanov_a_integration_rect_method/common/include/common.hpp" #include "romanov_a_integration_rect_method/mpi/include/ops_mpi.hpp" #include "romanov_a_integration_rect_method/seq/include/ops_seq.hpp" @@ -9,7 +12,7 @@ namespace romanov_a_integration_rect_method { class RomanovAIntegrationRectMethodPerfTests : public ppc::util::BaseRunPerfTests { const int kCount_ = 500'000'000; - InType input_data_{}; + InType input_data_; void SetUp() override { auto f = std::function([](double x) { return x * x; }); From cbe4c2c0c5eb96b3c0d539f0e012ce9d54be6dbc Mon Sep 17 00:00:00 2001 From: Quaha Date: Wed, 19 Nov 2025 17:20:19 +0300 Subject: [PATCH 08/17] Something with precommit --- .../mpi/src/ops_mpi.cpp | 1 + .../tests/functional/main.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp index a03a33d284..258ec7a55c 100644 --- a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp +++ b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp @@ -1,6 +1,7 @@ #include "romanov_a_integration_rect_method/mpi/include/ops_mpi.hpp" #include + #include #include "romanov_a_integration_rect_method/common/include/common.hpp" diff --git a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp index 1ef979bd38..969020f726 100644 --- a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -2,12 +2,12 @@ #include #include +#include #include #include -#include -#include -#include #include +#include +#include #include "romanov_a_integration_rect_method/common/include/common.hpp" #include "romanov_a_integration_rect_method/mpi/include/ops_mpi.hpp" @@ -24,7 +24,8 @@ class RomanovAIntegrationRectMethodFuncTests : public ppc::util::BaseRunFuncTest // Минус (-) от отрицательных чисел в имени gtest нельзя, функцию в имя gtest не поместить, точку (.) тоже... Как // жить то? - return "_id" + std::to_string(static_cast(std::abs((result - a + (2.0 * b) + 4.0) * 334))) + "_n" + std::to_string(n); + return "_id" + std::to_string(static_cast(std::abs((result - a + (2.0 * b) + 4.0) * 334))) + "_n" + + std::to_string(n); } protected: From 7ad598d873a06bbe072d8daf22383a8d021211ae Mon Sep 17 00:00:00 2001 From: Quaha Date: Wed, 19 Nov 2025 18:06:24 +0300 Subject: [PATCH 09/17] Yet Yet another CLang fix --- .../common/include/common.hpp | 1 + .../mpi/src/ops_mpi.cpp | 19 +++---------------- .../tests/functional/main.cpp | 8 ++++---- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/common/include/common.hpp b/tasks/romanov_a_integration_rect_method/common/include/common.hpp index 19e25fcab7..3144fe9c08 100644 --- a/tasks/romanov_a_integration_rect_method/common/include/common.hpp +++ b/tasks/romanov_a_integration_rect_method/common/include/common.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp index 258ec7a55c..e45f49494d 100644 --- a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp +++ b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include "romanov_a_integration_rect_method/common/include/common.hpp" @@ -32,29 +32,16 @@ bool RomanovAIntegrationRectMethodMPI::PreProcessingImpl() { } bool RomanovAIntegrationRectMethodMPI::RunImpl() { + const auto &[f, a, b, n] = GetInput(); + int rank = 0; MPI_Comm_rank(MPI_COMM_WORLD, &rank); int num_processes = 0; MPI_Comm_size(MPI_COMM_WORLD, &num_processes); - double a = 0.0; - double b = 0.0; - int n = 0; - double result = 0.0; - if (rank == 0) { - a = std::get<1>(GetInput()); - b = std::get<2>(GetInput()); - n = std::get<3>(GetInput()); - } - MPI_Bcast(&a, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&b, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); - - auto f = std::get<0>(GetInput()); - int left_border = rank * (n / num_processes); int right_border = std::min(n, (rank + 1) * (n / num_processes)); diff --git a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp index 969020f726..12e9dd317f 100644 --- a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -4,9 +4,9 @@ #include #include #include -#include #include #include +#include #include #include "romanov_a_integration_rect_method/common/include/common.hpp" @@ -49,7 +49,7 @@ class RomanovAIntegrationRectMethodFuncTests : public ppc::util::BaseRunFuncTest private: InType input_data_; - double expected_; + double expected_ = 0.0; }; namespace { @@ -61,10 +61,10 @@ TEST_P(RomanovAIntegrationRectMethodFuncTests, MatmulFromPic) { const std::array kTestParam = { std::make_tuple([](double x) { return x; }, 0.0, 1.0, 10000000, 0.5), std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 10000000 + 1, 1.0 / 3.0), - std::make_tuple([](double x) { return (std::sin(x) * x) - std::sqrt(x); }, 0.0, 3.1415, 10000000 + 2, -0.570462), + std::make_tuple([](double x) { return (std::sin(x) * x) - std::sqrt(x); }, 0.0, std::numbers::pi, 10000000 + 2, -0.570626), std::make_tuple([](double x) { return std::exp(x) - x; }, -1.0, 3.0, 10000000 + 3, -4.0 - (1.0 / std::numbers::e) + std::exp(3.0)), - std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, 3.1415, 10000000 + 4, -0.894667)}; + std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, std::numbers::pi, 10000000 + 4, -0.894831)}; const auto kTestTasksList = std::tuple_cat(ppc::util::AddFuncTask( kTestParam, PPC_SETTINGS_romanov_a_integration_rect_method), From 8eff99a587bc60eeb1fd0c14a71fc9497b948d18 Mon Sep 17 00:00:00 2001 From: Quaha Date: Wed, 19 Nov 2025 18:22:25 +0300 Subject: [PATCH 10/17] Yet Yet Yet Another CLang fix --- tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp | 3 +-- .../tests/functional/main.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp index e45f49494d..5ab184de41 100644 --- a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp +++ b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp @@ -40,8 +40,6 @@ bool RomanovAIntegrationRectMethodMPI::RunImpl() { int num_processes = 0; MPI_Comm_size(MPI_COMM_WORLD, &num_processes); - double result = 0.0; - int left_border = rank * (n / num_processes); int right_border = std::min(n, (rank + 1) * (n / num_processes)); @@ -55,6 +53,7 @@ bool RomanovAIntegrationRectMethodMPI::RunImpl() { mid += delta_x; } + double result = 0.0; MPI_Allreduce(¤t_result, &result, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); GetOutput() = result; diff --git a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp index 12e9dd317f..661633ee37 100644 --- a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -61,10 +61,12 @@ TEST_P(RomanovAIntegrationRectMethodFuncTests, MatmulFromPic) { const std::array kTestParam = { std::make_tuple([](double x) { return x; }, 0.0, 1.0, 10000000, 0.5), std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 10000000 + 1, 1.0 / 3.0), - std::make_tuple([](double x) { return (std::sin(x) * x) - std::sqrt(x); }, 0.0, std::numbers::pi, 10000000 + 2, -0.570626), + std::make_tuple([](double x) { return (std::sin(x) * x) - std::sqrt(x); }, 0.0, std::numbers::pi, 10000000 + 2, + -0.570626), std::make_tuple([](double x) { return std::exp(x) - x; }, -1.0, 3.0, 10000000 + 3, -4.0 - (1.0 / std::numbers::e) + std::exp(3.0)), - std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, std::numbers::pi, 10000000 + 4, -0.894831)}; + std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, std::numbers::pi, 10000000 + 4, + -0.894831)}; const auto kTestTasksList = std::tuple_cat(ppc::util::AddFuncTask( kTestParam, PPC_SETTINGS_romanov_a_integration_rect_method), From fc7581c01fde826873c3d3d3f3baf377f819a617 Mon Sep 17 00:00:00 2001 From: Quaha Date: Wed, 19 Nov 2025 20:34:31 +0300 Subject: [PATCH 11/17] CI build --- tasks/romanov_a_integration_rect_method/report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/romanov_a_integration_rect_method/report.md b/tasks/romanov_a_integration_rect_method/report.md index 9783c88824..c971577bfb 100644 --- a/tasks/romanov_a_integration_rect_method/report.md +++ b/tasks/romanov_a_integration_rect_method/report.md @@ -31,7 +31,7 @@ $\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$, В данной работе реализуется метод средних прямоугольников. ## 4. Схема паралеллизации -- For MPI: data distribution, communication pattern/topology, rank roles.. +- For MPI: data distribution, communication pattern/topology, rank roles. - For threads: decomposition, scheduling, synchronization. Diagrams or short pseudocode are welcome. From 0d357d59f87c919d4ec9e409a38af12b3bbebd9f Mon Sep 17 00:00:00 2001 From: Quaha Date: Wed, 19 Nov 2025 21:26:49 +0300 Subject: [PATCH 12/17] Smaller tests --- .../tests/functional/main.cpp | 10 +++++----- .../tests/performance/main.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp index 661633ee37..1623ed93b1 100644 --- a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -59,13 +59,13 @@ TEST_P(RomanovAIntegrationRectMethodFuncTests, MatmulFromPic) { } const std::array kTestParam = { - std::make_tuple([](double x) { return x; }, 0.0, 1.0, 10000000, 0.5), - std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 10000000 + 1, 1.0 / 3.0), - std::make_tuple([](double x) { return (std::sin(x) * x) - std::sqrt(x); }, 0.0, std::numbers::pi, 10000000 + 2, + std::make_tuple([](double x) { return x; }, 0.0, 1.0, 1000000, 0.5), + std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 1000000 + 1, 1.0 / 3.0), + std::make_tuple([](double x) { return (std::sin(x) * x) - std::sqrt(x); }, 0.0, std::numbers::pi, 1000000 + 2, -0.570626), - std::make_tuple([](double x) { return std::exp(x) - x; }, -1.0, 3.0, 10000000 + 3, + std::make_tuple([](double x) { return std::exp(x) - x; }, -1.0, 3.0, 1000000 + 3, -4.0 - (1.0 / std::numbers::e) + std::exp(3.0)), - std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, std::numbers::pi, 10000000 + 4, + std::make_tuple([](double x) { return std::cos(x) * std::sqrt(x); }, 0.0, std::numbers::pi, 1000000 + 4, -0.894831)}; const auto kTestTasksList = std::tuple_cat(ppc::util::AddFuncTask( diff --git a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp index 5ab4aebf4d..c5189de032 100644 --- a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp @@ -11,7 +11,7 @@ namespace romanov_a_integration_rect_method { class RomanovAIntegrationRectMethodPerfTests : public ppc::util::BaseRunPerfTests { - const int kCount_ = 500'000'000; + const int kCount_ = 50'000'000; InType input_data_; void SetUp() override { From 7527b07d6c04a78558d5e55c7ac4f5315ba834ed Mon Sep 17 00:00:00 2001 From: Quaha Date: Wed, 19 Nov 2025 22:39:03 +0300 Subject: [PATCH 13/17] Mpi bug fix --- tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp index 5ab184de41..836f45a4b2 100644 --- a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp +++ b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp @@ -40,8 +40,10 @@ bool RomanovAIntegrationRectMethodMPI::RunImpl() { int num_processes = 0; MPI_Comm_size(MPI_COMM_WORLD, &num_processes); - int left_border = rank * (n / num_processes); - int right_border = std::min(n, (rank + 1) * (n / num_processes)); + int block_size = (n + num_processes - 1) / num_processes; + + int left_border = rank * block_size; + int right_border = std::min(n, (rank + 1) * block_size); double delta_x = (b - a) / static_cast(n); double mid = a + (delta_x * static_cast(left_border)) + (delta_x / 2.0); From 79f3150539ab34d8d179414a10baaf95fcf430c8 Mon Sep 17 00:00:00 2001 From: Quaha Date: Thu, 20 Nov 2025 10:43:38 +0300 Subject: [PATCH 14/17] Cov fix --- .../mpi/src/ops_mpi.cpp | 12 +-- .../report.md | 90 ++++++++++++++----- .../seq/src/ops_seq.cpp | 12 +-- .../tests/performance/main.cpp | 2 +- 4 files changed, 73 insertions(+), 43 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp index 836f45a4b2..1b4f9ab491 100644 --- a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp +++ b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp @@ -15,16 +15,8 @@ RomanovAIntegrationRectMethodMPI::RomanovAIntegrationRectMethodMPI(const InType } bool RomanovAIntegrationRectMethodMPI::ValidationImpl() { - if (!IsEqual(GetOutput(), 0.0)) { - return false; - } - if (std::get<3>(GetInput()) <= 0) { - return false; - } - if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { - return false; - } - return true; + return (IsEqual(GetOutput(), 0.0) && (std::get<3>(GetInput()) > 0) && + (std::get<1>(GetInput()) < std::get<2>(GetInput()))); } bool RomanovAIntegrationRectMethodMPI::PreProcessingImpl() { diff --git a/tasks/romanov_a_integration_rect_method/report.md b/tasks/romanov_a_integration_rect_method/report.md index c971577bfb..0f868fd901 100644 --- a/tasks/romanov_a_integration_rect_method/report.md +++ b/tasks/romanov_a_integration_rect_method/report.md @@ -1,13 +1,13 @@ # Интегрирование – метод прямоугольников - Студент: Романов Артем Сергеевич, группа 3823Б1ФИ3 -- Технологии: SEQ, MPI +- Технологии: SEQ | MPI - Вариант: 19 ## 1. Введение Интегрирование функций является составной частью многих научных и технических задач. Поскольку аналитическое интегрирование не всегда возможно, часто используются различные методы численного интегрирования. Метод прямоугольников является одним из наиболее простых для понимания и реализации методов, идея которого заключается в приближении значения интеграла некоторой интегральной суммой. -В рамках данной работы реализуется последовательная и параллельная версия алгоритма численного вычисления значения интеграла методом прямоугольников, а также исследуется эффективность их работы. +Целью данной работы является реализация последовательной и параллельной версии алгоритма численного вычисления значения интеграла методом прямоугольников, а также исследования эффективности их работы. ## 2. Постановка задачи Пусть задана функция $f(x): \mathbb{R} \to \mathbb{R},$ которая интегрируема на заданном отрезке $[a,b]$. Требуется приближённо вычислить значение определённого интеграла @@ -16,11 +16,11 @@ $I = \int\limits_a^b f(x)dx$ с помощью метода прямоугольников. -Входными данными являются функция $f(x): \mathbb{R} \to \mathbb{R}$, вещественные границы отрезка интегрирования $a, b$ $(a < b)$, на котором функция определена и число слагаемых $n$ в интегральной сумме. +Входными данными являются функция $f(x): \mathbb{R} \to \mathbb{R}$, вещественные границы отрезка интегрирования $a, b$ $(a < b)$, на котором функция определена, и натуральное число слагаемых $n$ в интегральной сумме. ## 3. Базовый алгоритм (последовательный) -Метода прямоугольников заключается приближении значения определённого интеграла с помощью интегральной суммы: +Метод прямоугольников заключается приближении значения определённого интеграла с помощью интегральной суммы: $\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$,где $x_{i}^{\*} \in [x_{i-1}, x_{i}]$ и $\Delta x_i = x_i - x_{i-1}$ @@ -30,10 +30,53 @@ $\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$, 3. **Метод средних прямоугольников** - используется значение функции в середине каждого элементарного отрезка: $x_i^* = \frac{x_{i-1} + x_{i}}{2}$. В данной работе реализуется метод средних прямоугольников. -## 4. Схема паралеллизации -- For MPI: data distribution, communication pattern/topology, rank roles. -- For threads: decomposition, scheduling, synchronization. -Diagrams or short pseudocode are welcome. + +Последовательный алгоритм реализует описанный выше способ вычисления и может быть представлен следующим псевдокодом: + +```python +  delta_x = (b - a) / n; +  mid = a + (delta_x / 2); +  result = 0.0; +  for (i = 0; i < n; i += 1) { +    result += f(mid) * delta_x; +    mid += delta_x; +  } +``` +## 4. Схема параллелизации +Вычисления в параллельном алгоритме организованы схожим образом: каждый процесс вычисляет значение интеграла на некотором подотрезке номеров слагаемых интегральной суммы. + +Изначально каждый процесс получает свой ранг и общее число процессов: +```cpp +  int rank = 0; +  MPI_Comm_rank(MPI_COMM_WORLD, &rank); +  +  int num_processes = 0; +  MPI_Comm_size(MPI_COMM_WORLD, &num_processes); +``` + +На основе этих данных вычисляются левые и правые границы номеров слагаемых: +```cpp +  int block_size = (n + num_processes - 1) / num_processes; +  int left_border = rank * block_size; +  int right_border = std::min(n, (rank + 1) * block_size); +``` + +После этого схожий с последовательной версией цикл считает значение интеграла на подотрезке: +```cpp +  double current_result = 0.0; +  for (int i = left_border; i < right_border; ++i) { +    current_result += f(mid) * delta_x; +    mid += delta_x; +  } +``` + +Затем итоговые значения суммируются и рассылаются по всем процессам: +```cpp +  double result = 0.0; +  MPI_Allreduce(¤t_result, &result, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +  GetOutput() = result; +``` + ## 5. Детали реализации - Code structure (files, key classes/functions) @@ -41,8 +84,8 @@ Diagrams or short pseudocode are welcome. - Memory usage considerations ## 6. Условия проведения экспериментов -- Hardware/OS: CPU model, cores/threads, RAM, OS version -- Toolchain: compiler, version, build type (Release/RelWithDebInfo) +- Hardware/OS: Intel Core i5-10400f, 6 ядер и 12 потоков, 32GB RAM, Ubuntu 24.04.2 - Docker (запущенный на Windows 10); +- Toolchain: GCC 13.3.0, C++ with Release build type - Environment: PPC_NUM_THREADS / PPC_NUM_PROC, other relevant vars - Data: how test data is generated or sourced (relative paths) @@ -54,11 +97,18 @@ Briefly explain how correctness was verified (reference results, invariants, uni ### 7.2 Эффективность Present time, speedup and efficiency. Example table: -| Mode | Count | Time, s | Speedup | Efficiency | -|-------------|-------|---------|---------|------------| -| seq | 1 | 1.234 | 1.00 | N/A | -| omp | 2 | 0.700 | 1.76 | 88.0% | -| omp | 4 | 0.390 | 3.16 | 79.0% | +| Mode | Count | Time, s | Speedup | Efficiency | +| ---- | ----- | ------- | ------- | ---------- | +| SEQ | 1 | 1.321 | 1.00 | N/A | +| OMP | 2 | 0.687 | 1.92 | 96.0% | +| OMP | 4 | 0.398 | 3.31 | 82.8% | +| OMP | 6 | 0.261 | 5.06 | 84.3% | +| OMP | 8 | 0.212 | 6.23 | 77.9% | +| OMP | 10 | 0.161 | 8.20 | 82.0% | +| OMP | 12 | 0.181 | 7.29 | 60.8% | +| OMP | 15 | 0.313 | 4.22 | 28.1% | +| OMP | 18 | 0.257 | 5.14 | 28.6% | +| OMP | 24 | 0.227 | 5.81 | 24.2% | Optionally add plots (use relative paths), and discuss bottlenecks and scalability limits. @@ -66,10 +116,6 @@ Optionally add plots (use relative paths), and discuss bottlenecks and scalabili Summarize findings and limitations. ## 9. Список литературы -1. Павлова Т. Ю. Численное интегрирование [Электронный ресурс]. – Кемерово: Кемеровский государственный университет, Институт фундаментальных наук. – Режим доступа: [https://ifn.kemsu.ru/page_teachers/pavlova/Numerical_integration.Brief_theory.pdf](https://ifn.kemsu.ru/page_teachers/pavlova/Numerical_integration.Brief_theory.pdf) – (дата обращения: 12.11.2025). - - -## Приложение -```cpp -// Short, readable code excerpts if needed -``` \ No newline at end of file +1. Павлова Т. Ю. Численное интегрирование [Электронный ресурс]. – Кемерово: Кемеровский государственный университет, Институт фундаментальных наук. – Режим доступа: https://ifn.kemsu.ru/page_teachers/pavlova/Numerical_integration.Brief_theory.pdf (дата обращения: 12.11.2025); +2. Оболенский А., Нестеров А. Parallel Programming course. MPI (detailed API overview) [Электронный ресурс]. – Нижегородский государственный университет. – Режим доступа: https://learning-process.github.io/parallel_programming_slides/slides/03-mpi-api.pdf (дата обращения: 18.11.2025); +3. Оболенский А., Нестеров А. Parallel Programming course. Introduction [Электронный ресурс]. – Нижегородский государственный университет. – Режим доступа: https://learning-process.github.io/parallel_programming_slides/slides/01-intro.pdf (дата обращения: 18.11.2025). \ No newline at end of file diff --git a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp index 93ad65339f..22c5eec23c 100644 --- a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp +++ b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp @@ -13,16 +13,8 @@ RomanovAIntegrationRectMethodSEQ::RomanovAIntegrationRectMethodSEQ(const InType } bool RomanovAIntegrationRectMethodSEQ::ValidationImpl() { - if (!IsEqual(GetOutput(), 0.0)) { - return false; - } - if (std::get<3>(GetInput()) <= 0) { - return false; - } - if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { - return false; - } - return true; + return (IsEqual(GetOutput(), 0.0) && (std::get<3>(GetInput()) > 0) && + (std::get<1>(GetInput()) < std::get<2>(GetInput()))); } bool RomanovAIntegrationRectMethodSEQ::PreProcessingImpl() { diff --git a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp index c5189de032..5ab4aebf4d 100644 --- a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp @@ -11,7 +11,7 @@ namespace romanov_a_integration_rect_method { class RomanovAIntegrationRectMethodPerfTests : public ppc::util::BaseRunPerfTests { - const int kCount_ = 50'000'000; + const int kCount_ = 500'000'000; InType input_data_; void SetUp() override { From 3db6f8c7e6a47032b70e356de8a91ea8a90f28f5 Mon Sep 17 00:00:00 2001 From: Quaha Date: Thu, 20 Nov 2025 13:07:02 +0300 Subject: [PATCH 15/17] Report --- .../report.md | 111 ++++++++++++------ .../tests/functional/main.cpp | 2 +- 2 files changed, 75 insertions(+), 38 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/report.md b/tasks/romanov_a_integration_rect_method/report.md index 0f868fd901..0d64cd2669 100644 --- a/tasks/romanov_a_integration_rect_method/report.md +++ b/tasks/romanov_a_integration_rect_method/report.md @@ -7,7 +7,7 @@ ## 1. Введение Интегрирование функций является составной частью многих научных и технических задач. Поскольку аналитическое интегрирование не всегда возможно, часто используются различные методы численного интегрирования. Метод прямоугольников является одним из наиболее простых для понимания и реализации методов, идея которого заключается в приближении значения интеграла некоторой интегральной суммой. -Целью данной работы является реализация последовательной и параллельной версии алгоритма численного вычисления значения интеграла методом прямоугольников, а также исследования эффективности их работы. +Целью данной работы является реализация последовательной и параллельной версий алгоритма численного нахождения значения интеграла методом прямоугольников, а также исследования эффективности их работы. ## 2. Постановка задачи Пусть задана функция $f(x): \mathbb{R} \to \mathbb{R},$ которая интегрируема на заданном отрезке $[a,b]$. Требуется приближённо вычислить значение определённого интеграла @@ -16,13 +16,22 @@ $I = \int\limits_a^b f(x)dx$ с помощью метода прямоугольников. -Входными данными являются функция $f(x): \mathbb{R} \to \mathbb{R}$, вещественные границы отрезка интегрирования $a, b$ $(a < b)$, на котором функция определена, и натуральное число слагаемых $n$ в интегральной сумме. +**Входные данные:** +- функция $f(x): \mathbb{R} \to \mathbb{R}$; +- вещественные границы отрезка интегрирования $a, b$ $(a < b)$, на котором функция определена; +- натуральное число слагаемых $n$ в интегральной сумме. + +**Выходные данные:** +- $I$ - приближённое значение интеграла. ## 3. Базовый алгоритм (последовательный) Метод прямоугольников заключается приближении значения определённого интеграла с помощью интегральной суммы: -$\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$,где $x_{i}^{\*} \in [x_{i-1}, x_{i}]$ и $\Delta x_i = x_i - x_{i-1}$ +$\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$,где +- $a = x_0 < x_1 < ... < x_n = b$; +- $x_{i}^{\*} \in [x_{i-1}, x_{i}]$; +- $\Delta x_i = x_i - x_{i-1}$. Все $\Delta x_i$ полагаются равными $\frac{b-a}{n}$, где $n$ - число элементарных отрезков, а $x_i^*$ выбирается по-разному в зависимости от варианта метода прямоугольников. Основных вариаций три: 1. **Метод левых прямоугольников** - используется значение функции в левой границе каждого элементарного отрезка: $x_i^* = x_{i-1}$; @@ -31,7 +40,7 @@ $\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$, В данной работе реализуется метод средних прямоугольников. -Последовательный алгоритм реализует описанный выше способ вычисления и может быть представлен следующим псевдокодом: +Последовательный алгоритм использует представленный выше способ вычисления и может быть описан следующим псевдокодом: ```python   delta_x = (b - a) / n; @@ -42,10 +51,10 @@ $\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$,     mid += delta_x;   } ``` -## 4. Схема параллелизации +## 4. Параллелизация Вычисления в параллельном алгоритме организованы схожим образом: каждый процесс вычисляет значение интеграла на некотором подотрезке номеров слагаемых интегральной суммы. -Изначально каждый процесс получает свой ранг и общее число процессов: +Каждый процесс обладает своей копией входных данных и в начале получает свой ранг и общее число процессов: ```cpp   int rank = 0;   MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -61,7 +70,7 @@ $\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$,   int right_border = std::min(n, (rank + 1) * block_size); ``` -После этого схожий с последовательной версией цикл считает значение интеграла на подотрезке: +После этого схожий с последовательной версией цикл считает значение интеграла на своём подотрезке: ```cpp   double current_result = 0.0;   for (int i = left_border; i < right_border; ++i) { @@ -79,43 +88,71 @@ $\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$, ## 5. Детали реализации -- Code structure (files, key classes/functions) -- Important assumptions and corner cases -- Memory usage considerations +Структура проекта глобально соответствует шаблону, предложенному в примерах, однако в реализации присутствует ряд особенностей: +1) Для проверки корректности результата выполнения кода в тестах используется следующая функция проверки равенства вещественных чисел: +```cpp +constexpr double kEps = 1e-4; + +inline bool IsEqual(double a, double b) { +  return std::abs(a - b) <= kEps; +} +``` +2) Интегрируемая функция передаётся в виде объекта `std::function 0`); + - левая и правая границы интегрирования должны удовлетворять неравенству `a < b`. ## 6. Условия проведения экспериментов -- Hardware/OS: Intel Core i5-10400f, 6 ядер и 12 потоков, 32GB RAM, Ubuntu 24.04.2 - Docker (запущенный на Windows 10); -- Toolchain: GCC 13.3.0, C++ with Release build type -- Environment: PPC_NUM_THREADS / PPC_NUM_PROC, other relevant vars -- Data: how test data is generated or sourced (relative paths) +- **Аппаратное обеспечение/ОС:** Intel Core i5-10400f, 6 ядер/12 логических процессоров, 32GB RAM DDR4 2667 Mhz, Ubuntu 24.04.2/Docker (под Windows 10 Home 22H2); +- **Инструменты сборки:** GCC 13.3.0, Release, Cmake 3.28.3; +- **Переменные окружения:** Не использовались (запуск тестов происходил с флагом `-np `); +- **Данные:** Тестовые данные генерировались вручную. ## 7. Результаты ### 7.1 Корректность -Briefly explain how correctness was verified (reference results, invariants, unit tests). - -### 7.2 Эффективность -Present time, speedup and efficiency. Example table: - -| Mode | Count | Time, s | Speedup | Efficiency | -| ---- | ----- | ------- | ------- | ---------- | -| SEQ | 1 | 1.321 | 1.00 | N/A | -| OMP | 2 | 0.687 | 1.92 | 96.0% | -| OMP | 4 | 0.398 | 3.31 | 82.8% | -| OMP | 6 | 0.261 | 5.06 | 84.3% | -| OMP | 8 | 0.212 | 6.23 | 77.9% | -| OMP | 10 | 0.161 | 8.20 | 82.0% | -| OMP | 12 | 0.181 | 7.29 | 60.8% | -| OMP | 15 | 0.313 | 4.22 | 28.1% | -| OMP | 18 | 0.257 | 5.14 | 28.6% | -| OMP | 24 | 0.227 | 5.81 | 24.2% | - -Optionally add plots (use relative paths), and discuss bottlenecks and scalability limits. +Код последовательной и параллельной версии алгоритма проверялся на некоторой группе тестов, включающей в себя различные интегрируемые функции, границы отрезков интегрирования и число слагаемых в интегральной сумме. + +В каждом тесте проверялось, что приближённое вычисленное значение интеграла отличалось от реального не более чем на $\epsilon = 10^{-4}$. + +### 7.2 Производительность + +Время, ускорение и эффективность измерялись на следующем тесте: +- $f(x) = x^2$ +- $a = 0$ +- $b = 1$ +- $n = 500'000'000$ + +В результате запуска последовательной версии алгоритма и параллельной на различном числе процессов были получены следующие данные: + +| Режим | Число процессов | Время, с | Ускорение | Эффективность | +| ----- | --------------- | -------- | --------- | ------------- | +| SEQ | 1 | 1.321 | 1.00 | N/A | +| OMP | 2 | 0.687 | 1.92 | 96.0% | +| OMP | 4 | 0.398 | 3.31 | 82.8% | +| OMP | 6 | 0.261 | 5.06 | 84.3% | +| OMP | 8 | 0.212 | 6.23 | 77.9% | +| OMP | 10 | 0.161 | 8.20 | 82.0% | +| OMP | 11 | 0.154 | 8.56 | 77.8% | +| OMP | 12 | 0.138 | 9.57 | 79.8% | +| OMP | 13 | 0.235 | 5.62 | 43.2% | +| OMP | 14 | 0.237 | 5.57 | 39.8% | +| OMP | 15 | 0.313 | 4.22 | 28.1% | +| OMP | 18 | 0.257 | 5.14 | 28.6% | +| OMP | 24 | 0.227 | 5.81 | 24.2% | + +По данной таблице видно, что достаточно эффективное ускорение присутствует при использовании от 2 до 12 процессов, что соответствует числу логических процессоров. При использовании большего числа процессов эффективность и ускорение сильно падают. + +В случае с двумя процессами код был достаточно хорошо оптимизирован компилятором, из-за чего его эффективность очень высока (при сравннении с иным числом процессов). + +Эффективность параллелизации при числе процессов до 6 обеспечивается наличием 6 физических ядер, при большем числе процессов, вероятно, влияет технология Hyper-Threading, благодаря которой каждое физическое ядро процессора представляется внутри ОС как 2 независимых. Такое возможное влияние на MPI программы упоминается в некоторых статьях в сети Интернет, например в [4]. +Потеря производительности при большем числе процессов чем 12 скорее всего происходит из-за частных смен контекста процессов и простоев. ## 8. Заключение -Summarize findings and limitations. +В рамках данной работы были разработаны последовательная и параллельная версии алгоритма численного вычисления определённого интеграла методом прямоугольников, а также проанализировано ускорение, которое может быть получено благодаря параллелизации кода, и его причины. ## 9. Список литературы -1. Павлова Т. Ю. Численное интегрирование [Электронный ресурс]. – Кемерово: Кемеровский государственный университет, Институт фундаментальных наук. – Режим доступа: https://ifn.kemsu.ru/page_teachers/pavlova/Numerical_integration.Brief_theory.pdf (дата обращения: 12.11.2025); -2. Оболенский А., Нестеров А. Parallel Programming course. MPI (detailed API overview) [Электронный ресурс]. – Нижегородский государственный университет. – Режим доступа: https://learning-process.github.io/parallel_programming_slides/slides/03-mpi-api.pdf (дата обращения: 18.11.2025); -3. Оболенский А., Нестеров А. Parallel Programming course. Introduction [Электронный ресурс]. – Нижегородский государственный университет. – Режим доступа: https://learning-process.github.io/parallel_programming_slides/slides/01-intro.pdf (дата обращения: 18.11.2025). \ No newline at end of file +1. Павлова Т. Ю. Численное интегрирование [Электронный ресурс]. – Кемеровский государственный университет, Институт фундаментальных наук. – URL: https://ifn.kemsu.ru/page_teachers/pavlova/Numerical_integration.Brief_theory.pdf (дата обращения: 12.11.2025); +2. Оболенский А., Нестеров А. Parallel Programming course. MPI (detailed API overview) [Электронный ресурс]. – Нижегородский государственный университет. – URL: https://learning-process.github.io/parallel_programming_slides/slides/03-mpi-api.pdf (дата обращения: 18.11.2025); +3. Оболенский А., Нестеров А. Parallel Programming course. Introduction [Электронный ресурс]. – Нижегородский государственный университет. – URL: https://learning-process.github.io/parallel_programming_slides/slides/01-intro.pdf (дата обращения: 18.11.2025); +4. Hyper-threading [Электронный ресурс]. – Wikipedia EN. – URL: https://en.wikipedia.org/wiki/Hyper-threading (дата обращения: 20.11.2025). \ No newline at end of file diff --git a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp index 1623ed93b1..9108ff0fd1 100644 --- a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -59,7 +59,7 @@ TEST_P(RomanovAIntegrationRectMethodFuncTests, MatmulFromPic) { } const std::array kTestParam = { - std::make_tuple([](double x) { return x; }, 0.0, 1.0, 1000000, 0.5), + std::make_tuple([](double x) { return x; }, 0.0, 1.0, 2, 0.5), std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 1000000 + 1, 1.0 / 3.0), std::make_tuple([](double x) { return (std::sin(x) * x) - std::sqrt(x); }, 0.0, std::numbers::pi, 1000000 + 2, -0.570626), From 6767cdec1bd7795e9cec8143c5d1af2887248428 Mon Sep 17 00:00:00 2001 From: Quaha Date: Fri, 21 Nov 2025 23:25:32 +0300 Subject: [PATCH 16/17] Sending fix, Report update --- .../mpi/src/ops_mpi.cpp | 28 ++++++++-- .../report.md | 51 +++++++++++-------- .../seq/src/ops_seq.cpp | 12 ++++- .../tests/functional/main.cpp | 3 +- .../tests/performance/main.cpp | 11 ++-- 5 files changed, 74 insertions(+), 31 deletions(-) diff --git a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp index 1b4f9ab491..05d84d9a17 100644 --- a/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp +++ b/tasks/romanov_a_integration_rect_method/mpi/src/ops_mpi.cpp @@ -15,8 +15,16 @@ RomanovAIntegrationRectMethodMPI::RomanovAIntegrationRectMethodMPI(const InType } bool RomanovAIntegrationRectMethodMPI::ValidationImpl() { - return (IsEqual(GetOutput(), 0.0) && (std::get<3>(GetInput()) > 0) && - (std::get<1>(GetInput()) < std::get<2>(GetInput()))); + if (!IsEqual(GetOutput(), 0.0)) { + return false; + } + if (std::get<3>(GetInput()) <= 0) { + return false; + } + if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { + return false; + } + return true; } bool RomanovAIntegrationRectMethodMPI::PreProcessingImpl() { @@ -24,7 +32,7 @@ bool RomanovAIntegrationRectMethodMPI::PreProcessingImpl() { } bool RomanovAIntegrationRectMethodMPI::RunImpl() { - const auto &[f, a, b, n] = GetInput(); + const auto f = std::get<0>(GetInput()); int rank = 0; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -32,6 +40,20 @@ bool RomanovAIntegrationRectMethodMPI::RunImpl() { int num_processes = 0; MPI_Comm_size(MPI_COMM_WORLD, &num_processes); + double a = 0.0; + double b = 0.0; + int n = 0; + + if (rank == 0) { + a = std::get<1>(GetInput()); + b = std::get<2>(GetInput()); + n = std::get<3>(GetInput()); + } + + MPI_Bcast(&a, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&b, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); + int block_size = (n + num_processes - 1) / num_processes; int left_border = rank * block_size; diff --git a/tasks/romanov_a_integration_rect_method/report.md b/tasks/romanov_a_integration_rect_method/report.md index 0d64cd2669..a4cd37276d 100644 --- a/tasks/romanov_a_integration_rect_method/report.md +++ b/tasks/romanov_a_integration_rect_method/report.md @@ -63,6 +63,14 @@ $\int_{a}^{b} f(x) dx \approx \sum_{i=1}^{n} f(x_{i}^{\*}) \cdot \Delta x_{i}$,   MPI_Comm_size(MPI_COMM_WORLD, &num_processes); ``` +Затем 0-ой процесс получает входные данные и рассылает их всем остальным процессам: + +```cpp +  MPI_Bcast(&a, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); +  MPI_Bcast(&b, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); +  MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); +``` + На основе этих данных вычисляются левые и правые границы номеров слагаемых: ```cpp   int block_size = (n + num_processes - 1) / num_processes; @@ -118,36 +126,38 @@ inline bool IsEqual(double a, double b) { ### 7.2 Производительность Время, ускорение и эффективность измерялись на следующем тесте: -- $f(x) = x^2$ -- $a = 0$ -- $b = 1$ -- $n = 500'000'000$ +- $f(x) = x^3$ +- $a = -10$ +- $b = 10$ +- $n = 100'000'000$ В результате запуска последовательной версии алгоритма и параллельной на различном числе процессов были получены следующие данные: | Режим | Число процессов | Время, с | Ускорение | Эффективность | | ----- | --------------- | -------- | --------- | ------------- | -| SEQ | 1 | 1.321 | 1.00 | N/A | -| OMP | 2 | 0.687 | 1.92 | 96.0% | -| OMP | 4 | 0.398 | 3.31 | 82.8% | -| OMP | 6 | 0.261 | 5.06 | 84.3% | -| OMP | 8 | 0.212 | 6.23 | 77.9% | -| OMP | 10 | 0.161 | 8.20 | 82.0% | -| OMP | 11 | 0.154 | 8.56 | 77.8% | -| OMP | 12 | 0.138 | 9.57 | 79.8% | -| OMP | 13 | 0.235 | 5.62 | 43.2% | -| OMP | 14 | 0.237 | 5.57 | 39.8% | -| OMP | 15 | 0.313 | 4.22 | 28.1% | -| OMP | 18 | 0.257 | 5.14 | 28.6% | -| OMP | 24 | 0.227 | 5.81 | 24.2% | +| SEQ | 1 | 1.89 | 1.00 | N/A | +| OMP | 2 | 1.05 | 1.80 | 90.0% | +| OMP | 4 | 0.64 | 2.95 | 73.8% | +| OMP | 6 | 0.44 | 4.30 | 71.7% | +| OMP | 8 | 0.35 | 5.40 | 67.5% | +| OMP | 10 | 0.31 | 6.1 | 61.0% | +| OMP | 11 | 0.28 | 6.75 | 61.4% | +| OMP | 12 | 0.27 | 7.00 | 58.3% | +| OMP | 13 | 0.44 | 4.30 | 33.1% | +| OMP | 14 | 0.46 | 4.11 | 29.4% | +| OMP | 16 | 0.46 | 4.11 | 25.7% | +| OMP | 18 | 0.45 | 4.20 | 23.3% | +| OMP | 24 | 0.41 | 4.61 | 19.2% | По данной таблице видно, что достаточно эффективное ускорение присутствует при использовании от 2 до 12 процессов, что соответствует числу логических процессоров. При использовании большего числа процессов эффективность и ускорение сильно падают. -В случае с двумя процессами код был достаточно хорошо оптимизирован компилятором, из-за чего его эффективность очень высока (при сравннении с иным числом процессов). +В случае с двумя процессами код был достаточно хорошо оптимизирован компилятором, из-за чего его эффективность очень высока (при сравнении с иным числом процессов). Эффективность параллелизации при числе процессов до 6 обеспечивается наличием 6 физических ядер, при большем числе процессов, вероятно, влияет технология Hyper-Threading, благодаря которой каждое физическое ядро процессора представляется внутри ОС как 2 независимых. Такое возможное влияние на MPI программы упоминается в некоторых статьях в сети Интернет, например в [4]. -Потеря производительности при большем числе процессов чем 12 скорее всего происходит из-за частных смен контекста процессов и простоев. +В данном случае этот эффект может достигаться из-за того, что программа не имеет как таковой работы с памятью: каждому процессу для работы требуется некоторое число целочисленных и вещественных переменных, а также адрес интегрируемой функции - все эти данные могут уместиться в наборе регистров, которые присутствуют у каждого логического процессора. + +Потеря производительности при большем числе процессов чем 12 может происходить из-за частых смен контекста процессов. ## 8. Заключение В рамках данной работы были разработаны последовательная и параллельная версии алгоритма численного вычисления определённого интеграла методом прямоугольников, а также проанализировано ускорение, которое может быть получено благодаря параллелизации кода, и его причины. @@ -155,4 +165,5 @@ inline bool IsEqual(double a, double b) { 1. Павлова Т. Ю. Численное интегрирование [Электронный ресурс]. – Кемеровский государственный университет, Институт фундаментальных наук. – URL: https://ifn.kemsu.ru/page_teachers/pavlova/Numerical_integration.Brief_theory.pdf (дата обращения: 12.11.2025); 2. Оболенский А., Нестеров А. Parallel Programming course. MPI (detailed API overview) [Электронный ресурс]. – Нижегородский государственный университет. – URL: https://learning-process.github.io/parallel_programming_slides/slides/03-mpi-api.pdf (дата обращения: 18.11.2025); 3. Оболенский А., Нестеров А. Parallel Programming course. Introduction [Электронный ресурс]. – Нижегородский государственный университет. – URL: https://learning-process.github.io/parallel_programming_slides/slides/01-intro.pdf (дата обращения: 18.11.2025); -4. Hyper-threading [Электронный ресурс]. – Wikipedia EN. – URL: https://en.wikipedia.org/wiki/Hyper-threading (дата обращения: 20.11.2025). \ No newline at end of file +4. Hyper-threading [Электронный ресурс]. – Wikipedia EN. – URL: https://en.wikipedia.org/wiki/Hyper-threading (дата обращения: 20.11.2025); +5. Гиперпоточность [Электронный ресурс]. – RuWiki – URL: https://ru.ruwiki.ru/wiki/Гиперпоточность (дата обращения: 21.11.2025). \ No newline at end of file diff --git a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp index 22c5eec23c..93ad65339f 100644 --- a/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp +++ b/tasks/romanov_a_integration_rect_method/seq/src/ops_seq.cpp @@ -13,8 +13,16 @@ RomanovAIntegrationRectMethodSEQ::RomanovAIntegrationRectMethodSEQ(const InType } bool RomanovAIntegrationRectMethodSEQ::ValidationImpl() { - return (IsEqual(GetOutput(), 0.0) && (std::get<3>(GetInput()) > 0) && - (std::get<1>(GetInput()) < std::get<2>(GetInput()))); + if (!IsEqual(GetOutput(), 0.0)) { + return false; + } + if (std::get<3>(GetInput()) <= 0) { + return false; + } + if (std::get<1>(GetInput()) >= std::get<2>(GetInput())) { + return false; + } + return true; } bool RomanovAIntegrationRectMethodSEQ::PreProcessingImpl() { diff --git a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp index 9108ff0fd1..005954ba6f 100644 --- a/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/functional/main.cpp @@ -58,7 +58,8 @@ TEST_P(RomanovAIntegrationRectMethodFuncTests, MatmulFromPic) { ExecuteTest(GetParam()); } -const std::array kTestParam = { +const std::array kTestParam = { + std::make_tuple([](double x) { return x; }, -1.0, 1.0, 1, 0), std::make_tuple([](double x) { return x; }, 0.0, 1.0, 2, 0.5), std::make_tuple([](double x) { return x * x; }, 0.0, 1.0, 1000000 + 1, 1.0 / 3.0), std::make_tuple([](double x) { return (std::sin(x) * x) - std::sqrt(x); }, 0.0, std::numbers::pi, 1000000 + 2, diff --git a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp index 5ab4aebf4d..1cedce5a13 100644 --- a/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp +++ b/tasks/romanov_a_integration_rect_method/tests/performance/main.cpp @@ -1,5 +1,6 @@ #include +#include #include #include @@ -11,20 +12,20 @@ namespace romanov_a_integration_rect_method { class RomanovAIntegrationRectMethodPerfTests : public ppc::util::BaseRunPerfTests { - const int kCount_ = 500'000'000; + const int kCount_ = 100'000'000; InType input_data_; void SetUp() override { - auto f = std::function([](double x) { return x * x; }); - double a = 0.0; - double b = 1.0; + auto f = std::function([](double x) { return std::pow(x, 3); }); + double a = -10.0; + double b = 10.0; int n = kCount_; input_data_ = std::make_tuple(f, a, b, n); } bool CheckTestOutputData(OutType &output_data) final { - return IsEqual(static_cast(output_data), 1.0 / 3.0); + return IsEqual(static_cast(output_data), 0.0); } InType GetTestInputData() final { From 3c2d15c9271913ecc6fd83ad07a881e1ac927295 Mon Sep 17 00:00:00 2001 From: Artem Romanov Date: Sun, 30 Nov 2025 21:47:02 +0300 Subject: [PATCH 17/17] Report fix, Useless file was deleted --- .../data/pic.jpg | Bin 15356 -> 0 bytes .../report.md | 24 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 tasks/romanov_a_integration_rect_method/data/pic.jpg diff --git a/tasks/romanov_a_integration_rect_method/data/pic.jpg b/tasks/romanov_a_integration_rect_method/data/pic.jpg deleted file mode 100644 index 34458023494a39d66880a98aa5dcad18eb14b249..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15356 zcmb7r1ymeM+h(J|Lh#^jgS!(nxH}|3!r<;sAOsKYPH>0dE6e&6od zf6v*P!%WfLQ`J@7_0Ic9Kg~R?0BAB2(h>j^6aYX$Ucl2D)Qq&4n7)#VqJ*^E>wk89 z2OtHO1put99qm;lMM<@^bx5DB{PT@p``&{cY=3?J4+YZh<mpyF;3wpd(jL+|a@S=2LIFre$`zZZ5<)UDE+G2tEq@V>V}Xyt;v7Y z4gRYRwzdCtd?@4?0V_+VUw!>5zs?xN$XZ<$@`(WXBLo}(6+jXY{WX5b|Bzyn1pqu3 z000yDpKS(708r--0JwAi*+%&V0ABb3K<&tXw*6;LY~S0z|J@uc}B7ywT50pPhd z0AT(A0Him+_d(wNhjSx^>>`Ammks1)0$2h@04X31SOZ{y2~uMNSO8Xl>uDYk17M(k zm0#~LkOB)2`>PgAVo71sMPU1NFQ79WC$- z0Uiz!76ux!R|O4nIS^rBkx>xfV4>h3hd=?)FmUkC&@nJ!u~@NjUXmf;vT=)OeDcew z8Y8Em`noY_Uo!DAF1^Q*^SP5kQd-wxrQ0dNSA z4iO=HHP8Vl7-(2nXlTUe$S5$7gP@>c(BUuuSa`B$n5-h?%2?P4IBZ-h_Kp=*FL5b2 zMBm$e^!*e)Hcrhc_F7dfDyFidlaiL5TODi^o0UDfMrE*``7{UoY6==11|1Lr5SWE7 z$Aqi}Jt})ogXX0k>MxE4Ncus+5yA){#z7(OyeXs56>}TSH!UPkRd@`O)C&{{JxaZU z3dWq3W;mr(;ooeu)rI48wv;6---WI|e`ktH3MX~p!O-Jqs1~P7Du-|)?vnnfWirkq zuT!)eXP&2P%7V6bNT>UAR7v9-9GfNUT6naiu^sHoj5{-uI^vdD@Xc!%{{T>6;JR;T z^j;`v*-$g){&*Ef-QYewdTJ(m*~XkMUlwtsK|2hxS~#IuPyl4LqqfP=%$ygw_UiQc zKS7h}-j(sJdB&`MoTB8y`*}^$BTQvCa9?wAF>@$7VkekE2za z;EYQl*-~;cz?RzQ6w3M%sJ9|g1_RQ#y@IW5*{M#5NQqP_2EFW|$h;O7+Eh;8tls6j zRBK4ZOON4)9&M8K;zV<`(fUFFBp@5_T8aBalZI^xpNIM)8q9LZlNaXHYB3PXAF0^`<4(kgxJ*8aN~9k5zUxXXSPA zY6b(w)}kNKg3=#Y+ZT$F~iWgw2P|?BJ(Xx*NT=ZdxE^l>#b&d5egtiwlOi- zS2CLJ(zcNVsL1cTd}KaGItNjkFbi`r9%BriEl<%f3-wppmBvUFITgvmeKeAWrXLJY zmT;snllkZR1Q-1u*GI~<6kBQ932wY_KvW|ZJG$}WuJOm8g4^Xqu;9Grc|e^SxM6}A?Yk` zIX0_Gh(E*u%jttk$rNHyV|hw5qKyx`DzhZ^d7b)fg)-!;TC&EY9$9=pHqw4F*omK99fTb zK0=SyYR6mM7XsEy=hZ}&#;il1dD^SuC8SHW7I3DJ5kY`|4p+-E-|^yDn}xUsUh3q%LRVW;`k6fxz@O2+FXIuJ#m@ zT9}$EYR*MrpT$0K{N>#PbJJL~^b^238v0m*Sad94t9ja@yiqic+_3&qTychxy~ab~ zc4D4BlGK!1VDATVmTf3nx&SrWXNC!)0`8Qd+H%L}T&zd{*4h~W;J5Lqvz5nqi71lC z=R7$2;`PMj$u{b17`w_aqTJ(iLFRrr(v&{WL_*%?%4aVS|i6|A1IPccJ`s zbPYl!Y`-umdXJ_4D`)ojT5qnSx+1UJ8-dCkj)%dIxC1Dz(#HA*X$qD4C6PtgIOdnt zXR4CCc|)Kq+kGBk7$t-?9jm`r7i6fqv%5hhEq)BAAL7D3kDwEi+!-_+Qhd;qOiS4G zW6%eRuI|7TG0O9}8GVlBdVci2>}vUX^Rub5(&lD&rd8quec#e)>W|nT-1s7d0^R9z zwGZ{5kNHW4sP0q-m=kj^3X{xAxH;p(Wp?NiqooHq&OEYV<#8dmPJydzK5rEG)refOr( zW6+CaofzxqxT5cRhu=_lSC|lN*-!Pc$r9YoEh`+GWJO_}QgV_lj)}>0keUUeR-g!M zv<;8maPp&#qCh9TqPP0!@_C>nX&(Ph?gV$Dnmfms{jjJgZ>ffD#iGEX5kLh!kT@tNi4N}25OvU3x(lq^q&@q87} zle8LkPsu5Pa@~zH)YG!M`@}q^&n=y1N!3n?VNI*4`_8nxAU_SR*}Is^FdO(jr^0bL zcfmz47>~jS{6gEj_VW|K;nnvjVw$?X?t)snK!?k9lHF%9sk?S%*pRQNkmVRGcQlG? z_X!gNmoFSw0;U8OF?qO+TWd;>-K(%g*RXVjD~2kW?P$~wOuM>8@BeCyU>hV%Gc0a1 z{vl=6afmuIX*k(|fl<*{l7Z^AeNw#++*l$Txj5c#@I&Uz_Ln%p%)RaKx8Lnu;T4-S zN^D8*Wby})s;nj0I@JttTPpN=?>g^Z%f2d>c^P|?zxP!pV^C} zF`0M5ov1_xxWb(6NZSA2NOaSM=W`tmdr)@O{v@3QxW}J#tjnfSc}>R>RZcTak__gg zC?hdlX3^B)zt5XJYhKT+nVx^)@&q^*Jk!}MV<4{_NUiF7)7a3#D(AW?R8sFZ41Pmx zr8YEkfO8Q?xl^QIgcT?XLPeW`4|+!`iZvHen#Q2M0QZ$rj;5RRd6zSdSx@j(BhSyv z^pK1f_Mau}ES?v9VLa;xsl+nqvp~5kuT`VHlfytoUpsg^a*%PcwQ5^@ZKS;&^DzD% zQP4F3FMMV^(>VP5>De@cp?f-9jP-?iHt&l$^;cTzDfW=eMS^tFG$WsdT&MbVxyr&8cMO8(9`#HyS)ZX^63;m!7Gx z09!P3V$(2Ra(wMsk-Xr+uRVoQuH_q7zfX4bZWAp6TD~1ti`T9#&<5+Or&xAr#IbEg zgzUWI$hCVE^AdryO>2*t>Iu*g(!{rzvw?pCVh12`vG{Uk7Hjz0rRUArhfF+G*d3R2 zn&KP1>eFPQ!_9lKvwX~1qGL_wQ$H_)`ZJDN1rJXnNuE87mpMkMt{-Shc$um@_=>!; zuDUb_?cyA1T8m8j@ovRenbfou{9i}reSRc4^==7#0xC_e%g>&Gl~tyn_qJO0y2}3i z2O+24Y4_yK2=s4TGtS+EN6u)Ra3lN$x2td7L09#>c(XIH%Pd+;VAN{D<~@pqR~0Wf znZ`8dp13^ppG=O9!8a~UXy2rBVc?y(_!Z5d+nViqD2eK=YV3&Uw%)4!kx>*#)PUFg znw@<)Zw7hfAvWcXV`1Rj6md@>&~44VEpA^CBsoD`>sd8W3p+SsD-f7YgMKY^A(YFl zdcNdz1b?_WixF33l34x;o#^&3f?d{dyRJvgAv}}JT|&DzaLv6ldS8y-Jb#Ya^R;I$ z@&n>=QPOF^hbSJ|ND+ygx~x$zJMZv$aP{EGGO^ZNs{ESG#P+CnpWFT2|2{@~3LRnm4_iGoa88nO5jpz;Ki$f0yIkAXVL zJT0SGe}b#8A_NTaxf(AdDm6;aJ#u?fHGxkq#(Zfm zBF!aE*o#NzUZggr_)2UtfEjeVzxPqyI)CRrh2Z(T*BO#do|R%pQ23%tcdUp+?hbr+ z%bIq&$8FaJ?;-QU6YwB(_kR3h@CoR60*;@6>ovn!?2RXY|5`kmS)BN4RiLetl7Dq+ z6Eci*qvNjisAZmXn!fE-aSJt(4# z@{^4wGfmA9b#P*7bETD}Kq^vjbg*c`q{Fz40^kSqF^tR45+Y31EeBV!4}M+VtO{A( zE8H&8?!Dba`EBW}HEdxe^-12@g@eoFG>JdC^aXi~iT8#MPci37*bQenLh_<#-+g5$ zBz>(QMw`utE@2v8!6Au`v9|mC>v@~x>sdx(Q;{ctSOHOY*}=DTP8|1@Y0bscX1@B;}ivRTs=vn1FQS%pgad& zV{8>s7;DPSZvs=Jmr8FLXR?sg>6-n~Ns}<=AR#x(d`#9TfOz?DuAwUi&m1YQbEw$3&zG^Gwn|js+AUNu=3E0+V2yk#m@p z8E$GvKQA9KW*qHA0T5#+z9Z^tz#}=Ke)}hw!4rQ!c5m>GrPx{QY+0|S_eWLeVtDM8N z_m(1u>JV$-U);mkLehWi^#p_~SfSmCjS9KBYZNwQniQ#;yeTEa9HX%lTpu`Dj|tG3 z^V`n#QX)BzupHLmD{|t>D(1 zwnz+Z+qE7}1n!VtjAcYx^-AH@nbq^Z%<$ltk(c0)L|B27Hw~O44!-MmnYI6JoM-Mu z;ohR(2DyiR+;`#*JppiiQhgda!(?ui#jt~Al41mJJ$ev$f(u>El*YAFYcs?sIEoo) z2jVBIg6RC?V~EiT7o?(=Sn6y;EB$Lc=%|hIzAj_e4oo^?D@qE)8|J4h;*vt(pFCvs zX~0j`VRq@e&A&2x%~aDkTI^h6RjH@kH`$Eef**&L9^nG|;djz*8(32C{O>GD%nagg z?YJ$Rxa8&^#z4jEGR)*Yk4rMP;^wppcSoS)q>M?o+jf!kNoD0(57hdZ&>_p!eYTY% zX<>3^ec_b9TplgY#;&;VoyG4*uTN|PchT$>vbKwc6z0+Q`ID&ah#zT^@;~rp=~53( zs1mGdXh}&VWtzn?V99ETgZaCxrt=5}0{m@Tv*SwRcH|XXk}a!5e^2ALx1h=53v(mU zr6IlV={iB%JhQnxsLzdq5G(*fS+=8eCU2t`nMW^?^j(Vu&K^~NWg79{>(9)FjH+nH z5VwMs49{V0XsTVlF{L|y(#awnjrWO zv0wQ7RtSY<Tgaz$cC_g*vDyqCtjhFYR%<+_Y2giI<3R!w6DHOU>(kLB7w7GML~lOPnslo8oj#s(#AFrn#z6fD5%c5p zfn<-erIC!EdHOa8SF{#wG>Zf`$1fwW{O|N056LdQXuj6qX7_<6&c3 zLh&mGP*gjgcHk$Knq!s9m8$il>C@XeM;254_)_ZY`$Z4jEl8RE1k5umuniU6_77Ik z%dYj$3c_MxP^62Y3LNd63IF(*m&(`clZY>1DTqFX?i^w=Q`c6-KH@Er+5*rin%$5D zwC$1<2Y62t6?vy@J^>;lb8C*Ew4cYJbz2XjY@SqSG#r@D{nA|rb=LBd??z`eB0mUhjVh7%KWCL=Kk)&5zNbAo~L2rf5nKgLUZWaa_ z{HYl>yL9~SDcA)Y!DB}J^DdAzgWZ_W`Cu(TcKi)zQ}s z&~Z!Azi36@89Q;GNWf$rIHN&+0t{VROWOKI&%;+Bw7!bX!MFqS=odP$lvN-kzA^PN&&3nP zTWL<^CFQ9v<7o8J=a)qhp5mGXTu~Fk`#tCQF+m6?Sa0|N`U&{*p_XQ9y~sP&=n0S? znKe*hj7eX{Qy%8?^PlrPaDW6e&t*+r8_kf#8%Quy(4Fl>kmGUtJ~LBRQL3-X`>rmt z=p*B)12rZXnf(3pcceT%*!6ClA?~p~)49Tm>jYg_9lQM&&Ad}673yRrbo=!BOj4v; z+W{-VT!~AtS7ARN=@_b#|IK#QZ$E@T&?F6$E}~=3dA6T@3&iD#kXd_{>0VKX-nXSY zh=}RUL_S%(l9YHjjp*`6I$&5e{kv=$nO4(P%PYe*DyB0fGCX-^jnny~5LRF@F69Rw zv=^Ghp*31txF{iTg~9CBI=g?D5h}W5TP2rkNuQYvz;=zEgN0V%D^OTByT|R0R0tzx zeGJ+~^bj{ai8z;(lAWVxHoG|vh}ab>_9-vpm-Xfz{P4-UrYAJ|_(d;VAk`$U>Z>`) z!`^adtw&`pT<2WRxymW(q`W$P9F6|C@iA7yQ%asrj~L)N0=`*h0T0rZmRD9p_$#CL z>IZgLlZiKck5MH&i@(<+HHa+s5NTEH4dpzoW_-Q}$8K&Yw=heWZ0xDte1{UN?5{|d zX(1w!ESm+Bn*<67&kjW+5+(a+r(`i}jB7!jQ?wiWk(dhiSn&Rbx(XJ!V2S%rdy-a&lS`FrD2^xW ztt)*yd{pLjpagnCWqdG!#C_lfET>EDW(VO=oobd^5bqXFd%)rg?^t>VwIzZpOz`+y zZ5gcV3U{tz1BV!>7w}p9zD1)+(1)>RjnP2!NuBmIJscGuT53zy?36 zcrDzV*m@-MS5y}FCZ)_ts*g7Pwd*Kw#ncRt1^;HV@-HXNL{HPAH$w~}`ss7SmJW@5 zG7A-cgpobWNy{PNzV9p%Lx8V`lI7P}u0!|Q2H)h`$eU1hzUIYXOj}uOMm_bAcA?`END>8x?kVwHKD zM&_F$teS)1t-R>dAV{hzPb5hQjo&T?UFz;HF_5<%jUmt<`^xFvR7&>;Dh*u*)r>a- z&@xJ$7Nk;`h^C3ru;PJJ;r+o2Wj<7jKPM0$Oly4u(QdhDXBe%g`5b0(6#BUd>KqY^RLg~CgMavK zt)n>E#!y}8C^hFBHW(ykpN8y$U7EDN(3-1OQ%HF`N2@}^mFNDLXJCp;ai`(I~HYG_7_XH9d~+ z?H&FAR`LIkmte`Tz$`vdrcup3lx|7pfpfqm$!~F!DAeU!;Io}MuJYa1d9|6kgn=yq zo&CX9GSj9klM<^jm(i_&4_=m#fm|)_OhzkQH73sVNUh+;2S*yRt6ZIj?OiBdv&k|n zCxY?XRvHG+MDvZXE`PyNr@C1a2rTU#VD0z?OQ}QUc_6SfK1|_9;q+vsd}Rxwxl2`8 zylJN+6d`ObJF~(T*{Ng>I^BtD8AbPMT7))wU1ZnPMVcX-TagOJc42g}jzHAFMkY8? zY)U3t_;qpfa$T@$8}=@@4(EFut6EtIrjGcenXQrqMnBr*LrdpDMZ1W70_w7FbdTFk z`noGwAyPy`p1)E-m1a$T<8Lj3u@JGdWEG+iQUr@P{s}Ec&X*313F_rMu^HsTH$Ths zc8eyBvL5)U_rJp1riFIK?tH8nZb`)x)p;C67AK_5;dio zZ?U-`D%xv9Gs85z??Xq*sdk;15geSr`W9Viyewsp6we9_2NWrWXc_G6N_q>a#GR!H zimq}ICq(C`2gRzSX7c2X)#O$eM)ya5Or&8!dr$rrS<6-%>4bW*iC@?2>y`JF6k~d# z?g(xp`G;?CefvbOH`?}k_f|gr@60Zma-k}!hewlXv5Yr@c zZ*zTzuB4NK4xS~Q_Pkts)p+|w{Y~Mm5Oq(d^Rj10d|`^}&n${M-JjSj+jR{PTDFDE zGKkc?=gUPERJ!h0V`C5W4S|y)SG#XdK;eUWe@5O}xn-RV)Au+sRe^3#+@RxWOStU6 z$=GNkNq57Gptlf~xT|_$;35dQF);su3}yQ!s=3P(+ik@4w7ndg=i6TBkeIYP_SmdV z(qP1SDGZnWNJCrhe6KP;rxY_?5H%_rJk#`_%!QF4^Zrfbwg0vouk$|$3Vy5bL%x^O z=ObVF3gVq!Z9%5fCDvS8o&CKinE~77(VLgG0XNgjgnofE3Fg#~YLe`oj(tH~7JqVg zjJLiBDivxMRjd1qAJN$tGRU?e3_B_Z^TcE9Ci@ugbp6}L0df_;uD9i%*adH`LKu8c z3w*8D&#H)n1dlu1yaS|MI$QdeQ!aM;P5#XV{Xi;NJ!a|_4_$OK`|k+kuEHzomOGyS z@e}SOQE=en=gaOvhw`geku}IS&Ne3O3rkGlg=rNz*s&tEcaBeh9b^eT*3;e2wykAc z3O!WR&eg8DLUcltAyC{&HL{Dw$il%nf0oSL~cz zrApa+`uVSFHN>&WWJJhCf~DapVTdSSFuc3ut?G9b;p%Eb^Ng49Owo>N8$z^m!+t9GFa;_>@5uGp8(rS$oCc2L^`<(u z9y?^ZWSmhZn?L@NdUbI8*Ecr>GgYGsG-F!zsQvPxW@OMiht<^a^CU?J8n`A6I^+NZ zU-6)iFeR(S*^b0TlQjbI*~2Ujct(xBHT7#)YJLnTyF>HtIK3xQsdG`_U_!8#v`Wp&KTfyocy{gJUeYLAkE>jBf!ngphgH`*>(_ zACWTD7IjH*xH<35G+)}FG1%S1m->Ne*0xf=LT0mZX&X-a4(gifs{-$Uk|V(V9MO(|ogKK$Ymvt*a%TBSP9 zsWYxiqncaDdl5~5OUVO4 z$51{{p0{L|fmt6;+1pqi3pe&JdXKRS6@@$(`W?vxSP2nSQWP#^b8nm8afu`PyXK&O zO>aNO_1@PtaP?Pw%^uiLQ_kZbh=r!{Z4p3R-FHySwkAf&0eKLXFWz74*=VZ>9Nio(<(NoLT+uto&GVjhRzt(#5 z^yXu}y909&eO-}B&fyf-5o;3xVbNqt#r)xcuG+4-!UyG=l;0Cg1+)Y4Zz%9K`GbcJ zv9(T#-?l8@txhFRn2z7sL4;E220!CzTv&dthqyV;nj8ZMWZI1#R|U0fl`qip-I$q( zt3j(I%AQZa-Pk2Rds~5Cx%VTRtn>Y7hA;l0y_A9l=?_m`klgUuSN;**s~+2lktWf} zq>HgwEymWLB9^gOpC=OKD@^M;p<%7Yk)|zA->Bc2m#HyMs~-gKtNk|MWc|t{zL1pw zb~I5R7@Rv($4w8y;G=9bb<(yer8&M2vpca!%U$R%^JFq#4wM67NYXF?Umce~{qo~c=y5seijy3sz&Q-nP zzhdm!Si|5jm?x)sEtZiVL(%bOy*MJ-{IkTkrI12jb^pLFoRk#;rTro+20776;mmztLJZ?4rR`zofEK&D+$G* z_cv9N+dzBtkl$oKE@s(_MGW_oXn#Sm8SogtuI??ZqLXcyWF%kbh@ESsM+GvLvZE*p zwd9KE3<3WIl4%5Hgo+Sbqvg%(?HjmBx$Fw*wrJ@_YH;-p)ON^or!Mz$G(i%`Z&$ed zG?!x5X%f^8yE zQBTXAQ<~d^2LrLc=lyoXaQ?fB?m)FP6!QMGt>V&I_awLSR*elBn|kV=N&?}a(FQ46 z22zT!k4%Jk@WQdsC#-L#=l>-HAda6q(=80!k=P2J350#hU&Tv097m_`o7uY2JS^(AE&vzLVvgp;&}z#kt4ZMVh0FZLzE+mXPNnlT z!>O0bh6mYpO|B|flc4F0gAqQo)P?uqWf)%&s8vz&nZ~pg#eJTwp@+(A6!L2q2q}94 zb@90ch&~!w*%;En{L<9?srJe7xuV^)R`Trf)(yp$_L_=P=MYUUk6H%qH-*%AhF4^0ys1Mwzd)Ph%LkKq4T_KbryH5(pF048|Dyq3JRx^*2`;B8=#7p zf~AExV8h#QRx>)REEIpl<(qS2F-ob*2qPd;%ls&BR1p_dbW5B^IsI4irzGq&7_CVH z^Wbn7mo7!PNf=hCrP!KEutB73^Wu1}ZuJVH*7oFRN9D*H;T>_xqP&p^)R*@faqaaAW8mt;5QKcu(ZA|F2vd%k z0K#ECdly{Q*4X5Q+&PfcWaBhOe(Y%b$vAbHd|7=_L>W1590%G8$QFhK26)&x7nIX9uUPw<@D?PFyVafn zj+2ETNq|hltgJ1K7c0s!ioZ9&r26u-b1%Qt?7WmMP3;s%i`L57CuMakGA+c{P>-gY z=w15#w%fXITijj*jR;6zJqfwSSvGz$gq?;dZrY|f>jf5FQ&&|e! zq{p`V#26T(Pk;^c8c7<@kN+rM-2zu_h?|diWXpdH$joWeE!2mbMgo_5n}lf+hbsk2 zAb>r9-9?oRaU-<$vU1#6Gv~2%Q z9BD=uhTZ#4cZ-^IZ1U7^P&S-NqSA?Q7Ea{vFfm+wV? zc*r>aU2)xyW`Ty3+ACdhrfX{VcbIZdK*|%qJaPV%Ho?qbmgDmqd|9{_BXwx4-{uc!NPzr7D2yB;+jt>e zlxM`uh5$usLu`0SGeSV)H%FJ5Nn18vL@yejul7|*O&p6%$T2o4HhmPmm9|p0`H%A) z|Br)RHl#vp9;db|9wHY1@}FduAbQW7dN%>S~*=S3TDWpANFMQBo0^n^k6A z0()Kd!q=>JtGDQFH8FATlz{Rlk~CQ|{YXoojOvKBtFe6yr3rdx{v%MK=@E~gEk7q2 z^VY;^`!8WC^eCYveb@VI{#DNYdF*1zyk!H#5=sK!q>(R=73g4;(3gX=!9^Vd90 z4a1PDU0XyzFE=<_9x`uujyY`3yCJZSdZdWPLu!`~|8)iQmm^y9kY8CoP4d2}`7lrT z5@+pH@6GMFM(O+!TL-rH0tqi?^*^aC8;R1f+w2PWo{RU|2<5m}>TjA=R-?=^siw4o z$hW<+D2>68Ekq0qpc5IG!UI%xG5v<@-(~jfc9HgwN;S0<{m==-t=jaibz0>$SZf(pJ&DPOQ1gZ3SrUa3atBJ1YbQH;GR#EYN)UKKN_qxJb{OOm0+b7o;^ z>JXj!gUkQT8`|m;a^hSA@vLQ@MeyuBtZj=P(`-s}Og<!foQEPYD(A_GcokyEFn zT0h@#(GB>fLZH*mf+8b=35&ZA>$bKu`l4D8^D5S)^0{K9-syv?Yq{wDGG#owwla~Q z1n$kiC`QEcyq^bS@vL6;-~h-|W1guRbGhXEcJyFSXH(4B-wf8la2HSDlm9{^X%vz4 z{7KB_=N8E>dD&w7!afZLfu6B1Um2`kks`n=`K5>O%h`vO3n3mI;v@M zZcr4A)#j%i{U?nY5t>bRB;&2`BzjBLNVSyvaPD&IUCCPMN_C7$akHG~0HtiihmE7z z$b9YH_jrk|*O#%@Hu3~~3VztNR31}xuCl7SqA|jM^*nlCHP5fhqp_!lO%muKuGHo{ z2$=N9ALAWKy%73j-?W%}-$#?&R)q1hR~>(%txm3+xm0dIZgOEtgO~nG{hW$4Z$P?@ zqX8?2fmu&@<|-xe_a1+RhboWP8iNgy$1abTPRU{B9FGeq$sEzvU__@5GK_;WHy14x zcDwh%F)#&T8!n+HR*b17<9kEKj@QaV)cerrgBrU^YNWZUt8{6hh=Tbf?4|DbGS-u! z3Sxb;5_Nt{7Lb!ZPYHe=Y8XHk>h)UqkL^m`A@p`}ve`+@bxE5|Cs@<9Wo{2YJxv@D z9dCggGXgg~vVFp|gOx~_Ty1Jj5)-0RzImmr#x9y|jOhSEB7QF;#P+qj&`v*C%|s0Q z$?%luf|Mi-j(@=IKm857&fyXodmv&qtfCK#3O5t3lq+~s%fV<$ zRS-cl7ak85UYRl{gPI`aNl4*v$9b<&iIKg5qc~XNq*fo*t-~&I8?tBw+pco@U6>j% zSXEdK8e9Ui84jcO-8grAmtb-)|EFQRwl_-;yZ1NLKTpl*^Gls4O2#=4#vLj5jW2m( zv*A0D(ahmmg2`qipL@cc|7D4hjoF3__X~`o5Rt{7kGxUzd{v0u{FuF}VUVwCf0d9h z^tM38c*$I%5Awj}a|lVgz=uHUYqE|E?$0`hF<3fb7!iChutxv|hkyF*I5JB8%LF4( zwMZ_bT_4`}^-PSm?OBb)Y&`+hmqf5=B5bT7C)lxV7$ zSdd3Re)}sR94(?v$*U#FE)u?q8o}^a7Y-z}`lB@vE*61Wf>rOOqQ}p4{nh9VUqsbH zZ!eRW