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

Filter by extension

Filter by extension

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

#include <string>
#include <tuple>

#include "task/include/task.hpp"

namespace sizov_d_string_mismatch_count {

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

} // namespace sizov_d_string_mismatch_count
2 changes: 2 additions & 0 deletions tasks/sizov_d_string_mismatch_count/data/strings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1234567890
12345X7890
9 changes: 9 additions & 0 deletions tasks/sizov_d_string_mismatch_count/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"student": {
"first_name": "Дмитрий",
"last_name": "Сизов",
"middle_name": "Игоревич",
"group_number": "3823Б1ФИ2",
"task_number": "1"
}
}
29 changes: 29 additions & 0 deletions tasks/sizov_d_string_mismatch_count/mpi/include/ops_mpi.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <string>

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

namespace sizov_d_string_mismatch_count {

class SizovDStringMismatchCountMPI : public BaseTask {
public:
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kMPI;
}

explicit SizovDStringMismatchCountMPI(const InType &input);

private:
std::string str_a_;
std::string str_b_;
int global_result_ = 0;

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

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

#include <mpi.h>

#include <cstddef>
#include <string>
#include <string_view>

#include "sizov_d_string_mismatch_count/common/include/common.hpp"
#include "util/include/util.hpp"

namespace sizov_d_string_mismatch_count {
SizovDStringMismatchCountMPI::SizovDStringMismatchCountMPI(const InType &input) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = input;
GetOutput() = 0;
}

bool SizovDStringMismatchCountMPI::ValidationImpl() {
const auto &input = GetInput();
const auto &a = std::get<0>(input);
const auto &b = std::get<1>(input);
return !a.empty() && a.size() == b.size();
}

bool SizovDStringMismatchCountMPI::PreProcessingImpl() {
const auto &input = GetInput();
str_a_ = std::get<0>(input);
str_b_ = std::get<1>(input);
return true;
}

bool SizovDStringMismatchCountMPI::RunImpl() {
int rank = 0;
int size = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);

const int total_size = static_cast<int>(str_a_.size());
if (total_size == 0) {
return true;
}

const int base = total_size / size;
const int remainder = total_size % size;
const int start = (rank * base) + std::min(rank, remainder);
const int local_size = base + (rank < remainder ? 1 : 0);

std::string_view local_a(str_a_.data() + start, local_size);
std::string_view local_b(str_b_.data() + start, local_size);

int local_result = 0;
for (int i = 0; i < local_size; ++i) {
if (local_a[i] != local_b[i]) {
++local_result;
}
}

MPI_Reduce(&local_result, &global_result_, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Bcast(&global_result_, 1, MPI_INT, 0, MPI_COMM_WORLD);

GetOutput() = global_result_;
return true;
}

bool SizovDStringMismatchCountMPI::PostProcessingImpl() {
return true;
}
} // namespace sizov_d_string_mismatch_count
44 changes: 44 additions & 0 deletions tasks/sizov_d_string_mismatch_count/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
### Отчёт по задаче: "Подсчет числа несовпадающих символов двух строк"
**Вариант:** №27
**Выполнил студент группы 3823Б1ФИ2:** Сизов Дмитрий Игоревич
**Работу проверили:** преподаватель Нестеров Александр Юрьевич и преподаватель Оболенский Арсений Андреевич

## Введение
В рамках данной работы реализован алгоритм подсчета несовпадающих символов в двух строках одинаковой длины, а также выполнена его параллелизация с использованием технологии MPI. Целью является ускорение вычислений за счет распределения работы между несколькими процессами.

## Постановка задачи и формальное описание
Имеются две строки одинаковой длины. Требуется определить количество позиций, на которых символы в строках различаются.
Формально: пусть `A` и `B` — строки длины `n`. Необходимо вычислить:
`count = количество таких i, что A[i] ≠ B[i] для 0 ≤ i < n`

## Пример
Строка A: `"abcde"`
Строка B: `"abzdf"`
Несовпадения: 2 (позиции 2 и 4)

## Реализация разделена на модули
- `ops_seq.hpp` и `ops_seq.cpp` — реализация последовательного алгоритма
- `ops_mpi.hpp` и `ops_mpi.cpp` — реализация параллельного алгоритма
- `common.hpp` — общее определение входных/выходных типов

## Описание последовательной версии
Алгоритм проходит по всем символам строк и сравнивает их попарно. Каждое несовпадение увеличивает счетчик. Итог — общее количество отличий.

## Описание параллельной версии
Параллельный алгоритм с использованием MPI делит входные строки на блоки, равномерно распределяемые между процессами. Каждый процесс сравнивает символы в своем участке и подсчитывает количество несовпадений. Частичные результаты объединяются с помощью `MPI_Reduce`, а итоговая сумма сохраняется на процессе с рангом 0.
Такой подход позволяет ускорить вычисления за счёт распределённой обработки данных.

## Тестирования разделены на модули
- `functional/main.cpp` — функциональные тесты
- `performance/main.cpp` — производительные тесты

## Функциональное тестирование
Функциональные тесты предназначены для проверки корректности работы алгоритма на заранее известных входных данных.
В рамках теста используются строки, считываемые из файла `strings.txt`. Файл содержит две строки, которые сравниваются с помощью обеих реализаций.
Ожидаемый результат рассчитывается в рамках теста: для каждой позиции двух строк выполняется сравнение, и при обнаружении различий счётчик увеличивается.
Результат, возвращаемый алгоритмом, сопоставляется с ожидаемым значением. Это позволяет удостовериться в корректности как последовательной, так и MPI-реализации.

## Тестирование производительности
В тестировании на производительность формируются две строки по 1 миллиону символов.
Первая строка полностью состоит из символов `'a'`, вторая — копия первой, но с заменой первых 10% символов на `'b'`.
Это гарантирует строго определённое число несовпадений (100 000), что позволяет точно проверить корректность результата.
29 changes: 29 additions & 0 deletions tasks/sizov_d_string_mismatch_count/seq/include/ops_seq.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <string>

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

namespace sizov_d_string_mismatch_count {

class SizovDStringMismatchCountSEQ : public BaseTask {
public:
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kSEQ;
}

explicit SizovDStringMismatchCountSEQ(const InType &input);

private:
std::string str_a_;
std::string str_b_;
int result_ = 0;

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

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

#include <cstddef>
#include <string>

#include "sizov_d_string_mismatch_count/common/include/common.hpp"
#include "util/include/util.hpp"

namespace sizov_d_string_mismatch_count {

SizovDStringMismatchCountSEQ::SizovDStringMismatchCountSEQ(const InType &input) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = input;
GetOutput() = 0;
}

bool SizovDStringMismatchCountSEQ::ValidationImpl() {
const auto &input = GetInput();
const auto &a = std::get<0>(input);
const auto &b = std::get<1>(input);
return !a.empty() && a.size() == b.size();
}

bool SizovDStringMismatchCountSEQ::PreProcessingImpl() {
const auto &input = GetInput();
str_a_ = std::get<0>(input);
str_b_ = std::get<1>(input);
result_ = 0;
return true;
}

bool SizovDStringMismatchCountSEQ::RunImpl() {
result_ = 0;
for (std::size_t i = 0; i < str_a_.size(); ++i) {
if (str_a_[i] != str_b_[i]) {
++result_;
}
}
return true;
}

bool SizovDStringMismatchCountSEQ::PostProcessingImpl() {
GetOutput() = result_;
return true;
}

} // namespace sizov_d_string_mismatch_count
7 changes: 7 additions & 0 deletions tasks/sizov_d_string_mismatch_count/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tasks_type": "processes",
"tasks": {
"mpi": "enabled",
"seq": "enabled"
}
}
91 changes: 91 additions & 0 deletions tasks/sizov_d_string_mismatch_count/tests/functional/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include <gtest/gtest.h>
#include <mpi.h>

#include <array>
#include <cstddef>
#include <fstream>
#include <stdexcept>
#include <string>
#include <tuple>

#include "sizov_d_string_mismatch_count/common/include/common.hpp"
#include "sizov_d_string_mismatch_count/mpi/include/ops_mpi.hpp"
#include "sizov_d_string_mismatch_count/seq/include/ops_seq.hpp"
#include "util/include/func_test_util.hpp"
#include "util/include/util.hpp"

namespace sizov_d_string_mismatch_count {

class SizovDRunFuncTestsStringMismatchCount : public ppc::util::BaseRunFuncTests<InType, OutType, TestType> {
public:
static std::string PrintTestParam(const TestType &test_param) {
return test_param;
}

protected:
void SetUp() override {
std::string abs_path = ppc::util::GetAbsoluteTaskPath(PPC_ID_sizov_d_string_mismatch_count, "strings.txt");

std::ifstream file(abs_path);
if (!file.is_open()) {
throw std::runtime_error("Cannot open strings.txt");
}

std::string a;
std::string b;
std::getline(file, a);
std::getline(file, b);
file.close();

input_data_ = std::make_tuple(a, b);
is_valid_ = !a.empty() && a.size() == b.size();

expected_result_ = 0;
if (is_valid_) {
for (size_t i = 0; i < a.size(); ++i) {
if (a[i] != b[i]) {
++expected_result_;
}
}
}
}

InType GetTestInputData() override {
return input_data_;
}

bool CheckTestOutputData(OutType &output_data) override {
int rank = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (!is_valid_ || rank != 0) {
return true;
}
return output_data == expected_result_;
}

private:
InType input_data_;
OutType expected_result_ = 0;
bool is_valid_ = true;
};

namespace {

TEST_P(SizovDRunFuncTestsStringMismatchCount, CompareStringsFromFile) {
ExecuteTest(GetParam());
}

const std::array<TestType, 1> kTestParam = {"default"};

const auto kTaskList = std::tuple_cat(ppc::util::AddFuncTask<SizovDStringMismatchCountMPI, InType>(
kTestParam, PPC_SETTINGS_sizov_d_string_mismatch_count),
ppc::util::AddFuncTask<SizovDStringMismatchCountSEQ, InType>(
kTestParam, PPC_SETTINGS_sizov_d_string_mismatch_count));

const auto kGtestValues = ppc::util::ExpandToValues(kTaskList);
const auto kTestName = SizovDRunFuncTestsStringMismatchCount::PrintFuncTestName<SizovDRunFuncTestsStringMismatchCount>;

INSTANTIATE_TEST_SUITE_P(CompareFromFile, SizovDRunFuncTestsStringMismatchCount, kGtestValues, kTestName);

} // namespace
} // namespace sizov_d_string_mismatch_count
Loading
Loading