Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
4ead59a
add test task
lisssq Nov 16, 2025
497335d
fix tasts name
lisssq Nov 16, 2025
d5146b3
Merge upstream changes
lisssq Nov 16, 2025
80a704f
seq is built before tests
lisssq Nov 19, 2025
90486b8
seq is built with 10 tests
lisssq Nov 19, 2025
f579806
seq is build with 10 func passed tests and 2 perf passed tests
lisssq Nov 19, 2025
f4483c0
seq is build with 10 func passed tests and 2 perf passed tests
lisssq Nov 19, 2025
479b479
seq + mpi are built with 20 func and 4 perf passed tests
lisssq Nov 20, 2025
3843f28
pre_commit_1
lisssq Nov 20, 2025
b35b484
seq + mpi are built with 20 func and 4 perf passed tests + modified f…
lisssq Nov 20, 2025
8cdff8b
fix mpi failed tests
lisssq Nov 23, 2025
28adad4
clang-format fixes
lisssq Nov 23, 2025
da7a8c5
clang-format fixes_1
lisssq Nov 23, 2025
8822f89
fixes
lisssq Nov 23, 2025
f8d90e4
deleted the commented code
lisssq Nov 23, 2025
0b529a1
report add
lisssq Nov 23, 2025
2f84b71
clang-tidy fix-1
lisssq Nov 24, 2025
5e5ff27
pre-commit after clang-tidy fix-1
lisssq Nov 24, 2025
57fc4dd
clang-tidy fix-2
lisssq Nov 24, 2025
051645b
clang-tidy fix-3
lisssq Nov 24, 2025
2a7e579
clang-tidy fix-4
lisssq Nov 24, 2025
3a5fdb7
Merge remote-tracking branch 'upstream/master' into popova_e_integr_m…
lisssq Nov 25, 2025
95b47d4
delete data-pic
lisssq Nov 25, 2025
5f677ba
fix generate without seed
lisssq Nov 30, 2025
cb62a99
pre-commit fix
lisssq Nov 30, 2025
c4bf111
delete random generate
lisssq Nov 30, 2025
926695b
add MPI_Scatterv and delete #ifdef from func_main
lisssq Dec 2, 2025
903f68a
expanded functions sets
lisssq Dec 3, 2025
55731d6
delete switch-case and add class with functions
lisssq Dec 4, 2025
9f131cd
hlpmpls
lisssq Dec 4, 2025
5f7ee30
hlpmpls pre-commit
lisssq Dec 4, 2025
f68102c
cleaning up unnecessary code
lisssq Dec 4, 2025
82fea03
clang-tidy fix-5
lisssq Dec 4, 2025
9affe13
clang-tidy fix-6
lisssq Dec 5, 2025
96bcccc
changing the report
lisssq Dec 5, 2025
c605d23
initializing the structure of the second task
lisssq Dec 18, 2025
20b3571
seq + functional_tests
lisssq Dec 20, 2025
84f0a43
mpi + tests
lisssq Dec 22, 2025
a902d5a
hlpmplsrll
lisssq Dec 22, 2025
80984e1
clang-format
lisssq Dec 22, 2025
55f29a5
fix mpi
lisssq Dec 22, 2025
e0a0043
fix 2-d task
lisssq Dec 24, 2025
80919b1
delete 1-st task from this branch
lisssq Dec 24, 2025
6fbb7ea
clang-tidy fix 1
lisssq Dec 24, 2025
4d7a2bc
clang-tidy fix 2
lisssq Dec 24, 2025
ba631b2
clang-tidy fix 2
lisssq Dec 24, 2025
bb60c1f
clang-tidy fix 3
lisssq Dec 24, 2025
f2343e5
add report and other fixes
lisssq Dec 25, 2025
db43c69
add report and other fixes
lisssq Dec 25, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "task/include/task.hpp"

namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector {

using InType = std::pair<int, int>; // rows, cols
using OutType = std::vector<double>;
using TestType = std::tuple<std::pair<int, int>, std::string>;
using BaseTask = ppc::task::Task<InType, OutType>;

} // namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"student": {
"first_name": "Елизавета",
"last_name": "Попова",
"middle_name": "Сергеевна",
"group_number": "3823Б1ПР1",
"task_number": "2"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <utility>
#include <vector>

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

namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector {

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

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

static std::pair<int, int> GetLocalColumnsCounts(int cols, int rank, int size);
static void CountSeq(int rows, int cols, std::vector<double> &result);
static void CountMpi(int rows, int cols, int rank, int size, std::vector<double> &result);

int rows_ = 0;
int cols_ = 0;
};

} // namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/mpi/include/ops_mpi.hpp"

#include <mpi.h>

#include <utility>
#include <vector>

#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/common/include/common.hpp"

namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector {

std::pair<int, int> PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::GetLocalColumnsCounts(int cols,
int rank,
int size) {
int base_cols = cols / size;
int remainder = cols % size;

int local_cols = base_cols;
if (rank < remainder) {
local_cols = local_cols + 1;
}

int start_col = 0;
for (int i = 0; i < rank; ++i) {
int cols_for_i = base_cols;
if (i < remainder) {
cols_for_i = cols_for_i + 1;
}
start_col = start_col + cols_for_i;
}

return {local_cols, start_col};
}

void PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::CountSeq(int rows, int cols,
std::vector<double> &result) {
for (int i = 0; i < rows; ++i) {
double sum = 0.0;
for (int j = 0; j < cols; ++j) {
double matrix_value = (i + j) * 1.5;
double vector_value = j * 2.0;
sum += matrix_value * vector_value;
}
result[i] = sum;
}
}

void PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::CountMpi(int rows, int cols, int rank, int size,
std::vector<double> &result) {
auto [local_cols, start_col] = GetLocalColumnsCounts(cols, rank, size);

std::vector<double> local_result(rows, 0.0);

for (int i = 0; i < rows; ++i) {
double sum = 0.0;
for (int j = 0; j < local_cols; ++j) {
int global_col = start_col + j;
double matrix_value = (i + global_col) * 1.5;
double vector_value = global_col * 2.0;
sum += matrix_value * vector_value;
}
local_result[i] = sum;
}

MPI_Allreduce(local_result.data(), result.data(), rows, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
}

PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI(
const InType &in) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
GetOutput() = std::vector<double>();
}

bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::ValidationImpl() {
int rows = GetInput().first;
int cols = GetInput().second;
return (rows > 0 && cols > 0);
}

bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::PreProcessingImpl() {
rows_ = GetInput().first;
cols_ = GetInput().second;

GetOutput().resize(rows_, 0.0);
return true;
}

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

if (cols_ < size) {
if (rank == 0) {
CountSeq(rows_, cols_, GetOutput());
}
MPI_Bcast(GetOutput().data(), rows_, MPI_DOUBLE, 0, MPI_COMM_WORLD);
} else {
CountMpi(rows_, cols_, rank, size, GetOutput());
}

MPI_Barrier(MPI_COMM_WORLD);
return true;
}

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

} // namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# Ленточная вертикальная схема - умножение матрицы на вектор

- **Студент**: Попова Елизавета Сергеевна, группа 3823Б1ПР1
- **Технология**: SEQ | MPI
- **Вариант**: 12

## 1. Введение

Умножение матрицы на вектор — фундаментальная операция линейной алгебры, которая широко применима в научных вычислениях, машинном обучении, компьютерной графике и других областях. При умножении матрицы размером `m × n` на вектор размером `n` получается вектор размером `m`.

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

## 2. Постановка задачи
Задача: реализовать последовательную (SEQ) и параллельную (MPI) версию умножения матрицы на вектор с использованием вертикальной ленточной схемы.

Входные данные представлены в виде пары целых чисел (rows, cols):
```cpp
using InType = std::pair<int, int>;
```
- rows — количество строк матрицы (тип `int`, положительное число)
- cols — количество столбцов матрицы (тип `int`, положительное число)

Выходные данные (результат вычислений) представлены в виде вектора размером `rows`:
```cpp
using OutType = std::vector<double>;
```

Тестовые данные (содержание матрицы и вектора) генерируются по следующей схеме:
- Матрица А: `A[i][j] = (i + j) * 1.5`
- Вектор v: `v[j] = j * 2.0`

Результат вычисляется как `result[i] = SUMMA (A[i][j] * v[j])`



## 3. Базовый алгоритм (последовательная версия)
Последовательная версия алгоритма состоит из 4-х этапов:
1. `ValidationImpl()`: проверяем, что поступившие входные данные соответствуют органичениям (`rows > 0`, `cols > 0`).
2. `PreProcessingImpl()`: инициализация размеров задачи и выделение памяти для результата;
3. `RunImpl()`: основной этап вычислений:
- Для каждой строки матрицы выполняется суммирование произведений элементов строки на соответствующие элементы векторы;
- Результат сохраняется в выходной вектор.
```cpp
for (int i = 0; i < rows; ++i) {
double sum = 0.0;
for (int j = 0; j < cols; ++j) {
double matrix_value = (i + j) * 1.5;
double vector_value = j * 2.0;
sum += matrix_value * vector_value;
}
result[i] = sum;
}
```
4. `PostProcessingImpl()`: завершающий этап.


## 4. Схема распараллеливания
При распараллеливании используется вертикальная ленточная схема (Vertical Ribbon Scheme):
- Матрица делится на части между процессами по столбцам;
- Каждый процесс получает блок столбцов матрицы и соответствующие элементы вектора;
- Каждый процесс вычисляет частичную сумму для каждой строки на своей части столбцов;
- Частичные суммы собираются воедино с помощью MPI_Allreduce.

Особенности реализации:
- Если число столбцов меньше числа процессов, вычисления выполняются на процессе rank = 0, а результат рассылается через MPI_Bcast;
- При неравномерном делении столбцов первые процессы получают на один столбец больше;
- Для распределения столбцов используется вспомогательный метод `GetLocalColumnsCounts()`.

## 5. Детали реализации

Структура проекта
| Файл | Суть |
| ---------------------- | ------------------------------ |
| `common.hpp` | Общее определение типов данных |
| `ops_seq.hpp/.cpp` | Последовательная реализация |
| `ops_mpi.hpp/.cpp` | MPI-реализация |
| `functional/main.cpp` | Функциональные тесты |
| `performance/main.cpp` | Тесты на производительность |

### 5.1. Метод распределения столбцов
Обеспечивается равномерное распределение нагрузки между процессами при вертикальном разделении матрицы. Кратко об алгоритме:
- Вычисляем базовое количество столбцов (минимальное на процесс);
- Считаем количество "лишних" столбцов, которые нужно распределить напервые процессы;
- Вычисляем начальный столбец (индекс)
```cpp
static std::pair<int, int> GetLocalColumnsCounts(int cols, int rank, int size) {
int base_cols = cols / size;
int remainder = cols % size;

int local_cols = base_cols;
if (rank < remainder) {
local_cols = local_cols + 1;
}

int start_col = 0;
for (int i = 0; i < rank; ++i) {
int cols_for_i = base_cols;
if (i < remainder) {
cols_for_i = cols_for_i + 1;
}
start_col = start_col + cols_for_i;
}

return {local_cols, start_col};
}
```

### 5.2. Метод для параллельного вычисления
Реализуется параллельное вычисление. Кратко об алгоритме:
- Через `GetLocalColumnsCounts` получаем границы обрабатываемых столбцов;
- Каждый процесс вычисляет частичные суммы для своей части столбца;
- Суммируем частичные суммы всех процессов.
```cpp
static void CountMpi(int rows, int cols, int rank, int size,
std::vector<double> &result) {
auto [local_cols, start_col] = GetLocalColumnsCounts(cols, rank, size);

std::vector<double> local_result(rows, 0.0);

for (int i = 0; i < rows; ++i) {
double sum = 0.0;
for (int j = 0; j < local_cols; ++j) {
int global_col = start_col + j;
double matrix_value = (i + global_col) * 1.5;
double vector_value = global_col * 2.0;
sum += matrix_value * vector_value;
}
local_result[i] = sum;
}

MPI_Allreduce(local_result.data(), result.data(),
rows, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
}
```

### 5.3. Основная логика `RumImpl()`
Интеграция логики выполнения вычислений. Кратко:
- Получаем ранг и размер;
- Используем необходимый алгоритм в зависимости от соотношения процессов и столбцов.
```cpp
bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::RunImpl() {
int rank = 0, size = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);

if (cols_ < size) {
if (rank == 0) {
CountSeq(rows_, cols_, GetOutput());
}
MPI_Bcast(GetOutput().data(), rows_, MPI_DOUBLE, 0, MPI_COMM_WORLD);
} else {
CountMpi(rows_, cols_, rank, size, GetOutput());
}

MPI_Barrier(MPI_COMM_WORLD);
return true;
}
```


## 6. Экспериментальная среда
| Параметр | Значение |
| ---------- | ------------------------------------------------ |
| CPU | Intel Core i3-6006U (2 ядра / 4 потока, 2.0 ГГц) |
| RAM | 8 GB |
| ОС | Windows 10 64-bit |
| Компилятор | MSVC (Visual Studio Build Tools) |
| MPI | Microsoft MPI 10.1 (mpiexec 10.1.12498.52) |


## 7. Результаты и обсуждение


### 7.1 Корректность
Функциональные тесты проверяют корректность вычислений для различных размеров матриц:
- Квадратные матрицы: (1×1), (2×2), (3×3), (4×4), (5×5), (10×10), (16×16), (17×17);
- Прямоугольные матрицы: (3×5), (5×3), (15×3), (3×15), (84×11), (11×84).

Ожидаемый результат результат (с учетом одновременного заполнения матрицы) вычисляется по аналитической формуле:
- `expected[i] = SUMMA((i + j) * 1.5 * (j * 2.0))`,
- с точностью проверки `ε = 10^-10`.

Обе реализации (`SEQ`, `MPI`) прошли все тесты успешно.

### 7.2 Производительность
Результаты измерений на матрице размером 5000 х 5000

| Mode | Count | Time, s | Speedup | Efficiency |
| ---- | ----- | ------- | ------- | ---------- |
| SEQ | 1 | 0.0524 | 1 | N/A |
| MPI | 2 | 0.0343 | 1.53 | 76.5% |
| MPI | 4 | 0.0291 | 1.80 | 45.0% |



## 8. Заключение
В ходе работы:
- Реализована последовательная версия умножения матрицы на вектор с использованием аналитических вормул без явного хранения матрицы;
- Разработана параллельная реализация с использованием вертикальной ленточной схемы распределения данных через MPI;
- Проведено тестирование корректность для разноразмерных матриц;
- Рассчитаны характеристики ускорения и эффективности для распараллеленого алгоритма.



## 9. Источники
1. Сысоев А. В., Лекции по курсу «Параллельное программирование для кластерных систем».
2. Документация по курсу «Параллельное программирование», URL: https://learning-process.github.io/parallel_programming_course/ru/index.html
3. Репозиторий курса «Параллельное программирование», URL: https://github.com/learning-process/ppc-2025-processes-engineers
Loading
Loading