GCC Code Coverage Report


Directory: ./
File: tasks/ivanova_p_simple_iteration_method/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 92 92 100.0%
Functions: 10 10 100.0%
Branches: 46 82 56.1%

Line Branch Exec Source
1 #include "ivanova_p_simple_iteration_method/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cmath>
6 #include <cstddef>
7 #include <vector>
8
9 #include "ivanova_p_simple_iteration_method/common/include/common.hpp"
10
11 namespace ivanova_p_simple_iteration_method {
12
13 namespace { // Анонимный namespace для всех вспомогательных функций
14
15 // Распределение строк матрицы по процессам
16 20 void ComputeDistribution(int n, int size, std::vector<int> &row_counts, std::vector<int> &row_displs,
17 std::vector<int> &matrix_counts, std::vector<int> &matrix_displs) {
18 int row_offset = 0;
19 int matrix_offset = 0;
20
21
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (int proc = 0; proc < size; ++proc) {
22 40 int base_rows = n / size;
23
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 10 times.
40 int extra = (proc < (n % size)) ? 1 : 0;
24 40 int proc_rows = base_rows + extra;
25
26 40 row_counts[proc] = proc_rows;
27 40 row_displs[proc] = row_offset;
28 40 matrix_counts[proc] = proc_rows * n;
29 40 matrix_displs[proc] = matrix_offset;
30
31 40 row_offset += proc_rows;
32 40 matrix_offset += proc_rows * n;
33 }
34 20 }
35
36 // Инициализация матрицы и вектора (на нулевом процессе)
37 10 void InitializeSystem(std::vector<double> &flat_matrix, std::vector<double> &b, int n) {
38 10 flat_matrix.resize(static_cast<size_t>(n) * n, 0.0);
39
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 10 times.
153 for (int i = 0; i < n; ++i) {
40 143 flat_matrix[(static_cast<size_t>(i) * n) + i] = 1.0; // Единичная матрица
41 }
42 10 b.resize(n, 1.0); // Вектор из единиц
43 10 }
44
45 // Вычисление локального произведения (часть матрично-векторного умножения)
46 438 void ComputeLocalProduct(const std::vector<double> &local_matrix, const std::vector<double> &x,
47 const std::vector<double> &local_b, std::vector<double> &local_x_new, int local_rows,
48 int start_row, int n, double tau) {
49
2/2
✓ Branch 0 taken 3239 times.
✓ Branch 1 taken 438 times.
3677 for (int i = 0; i < local_rows; ++i) {
50 double ax_i = 0.0;
51
2/2
✓ Branch 0 taken 96471 times.
✓ Branch 1 taken 3239 times.
99710 for (int j = 0; j < n; ++j) {
52 96471 ax_i += local_matrix[(static_cast<size_t>(i) * n) + j] * x[j];
53 }
54 3239 local_x_new[i] = x[start_row + i] - (tau * (ax_i - local_b[i]));
55 }
56 438 }
57
58 // Новая функция: сбор нового вектора
59 438 void AllGatherVector(const std::vector<double> &local_x, std::vector<double> &x_global,
60 const std::vector<int> &row_counts, const std::vector<int> &row_displs) {
61 438 const int local_size = static_cast<int>(local_x.size());
62 438 MPI_Allgatherv(local_x.data(), local_size, MPI_DOUBLE, x_global.data(), row_counts.data(), row_displs.data(),
63 MPI_DOUBLE, MPI_COMM_WORLD);
64 438 }
65
66 // Новая функция: проверка сходимости для всех процессов
67 438 bool CheckConvergenceAll(double local_diff, double epsilon) {
68 438 double global_diff = 0.0;
69 438 MPI_Allreduce(&local_diff, &global_diff, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
70 438 return std::sqrt(global_diff) < epsilon;
71 }
72
73 // Вычисление локальной нормы разности
74 double ComputeLocalDiff(const std::vector<double> &x_new, const std::vector<double> &x, int local_rows, int start_row) {
75 double local_diff = 0.0;
76
2/2
✓ Branch 0 taken 3239 times.
✓ Branch 1 taken 438 times.
3677 for (int i = 0; i < local_rows; ++i) {
77 3239 double d = x_new[start_row + i] - x[start_row + i];
78 3239 local_diff += d * d;
79 }
80 return local_diff;
81 }
82
83 } // namespace
84
85 20 IvanovaPSimpleIterationMethodMPI::IvanovaPSimpleIterationMethodMPI(const InType &in) {
86 SetTypeOfTask(GetStaticTypeOfTask());
87 20 GetInput() = in;
88 GetOutput() = 0;
89 20 }
90
91 20 bool IvanovaPSimpleIterationMethodMPI::ValidationImpl() {
92 20 int rank = 0;
93 20 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
94
95 20 int is_valid = 0;
96
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
97
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 is_valid = ((GetInput() > 0) && (GetOutput() == 0)) ? 1 : 0;
98 }
99
100 20 MPI_Bcast(&is_valid, 1, MPI_INT, 0, MPI_COMM_WORLD);
101 20 return is_valid != 0;
102 }
103
104 20 bool IvanovaPSimpleIterationMethodMPI::PreProcessingImpl() {
105 20 int rank = 0;
106 20 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
107
108
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
109 10 GetOutput() = 0;
110 }
111
112 20 MPI_Barrier(MPI_COMM_WORLD);
113 20 return true;
114 }
115
116 20 bool IvanovaPSimpleIterationMethodMPI::RunImpl() {
117 20 int n = GetInput();
118
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (n <= 0) {
119 return false;
120 }
121
122 20 int rank = 0;
123 20 int size = 0;
124 20 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
125 20 MPI_Comm_size(MPI_COMM_WORLD, &size);
126
127 // Вычисляем распределение данных
128 20 std::vector<int> row_counts(size);
129
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<int> row_displs(size);
130
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<int> matrix_counts(size);
131
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<int> matrix_displs(size);
132
133 20 ComputeDistribution(n, size, row_counts, row_displs, matrix_counts, matrix_displs);
134
135
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 int local_rows = row_counts[rank];
136 20 int start_row = row_displs[rank];
137
138 // Подготовка данных на нулевом процессе
139 20 std::vector<double> flat_matrix;
140 20 std::vector<double> b;
141
142
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
143
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 InitializeSystem(flat_matrix, b, n);
144 }
145
146 // Распределение матрицы по процессам (плоский формат)
147
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<double> local_matrix(static_cast<size_t>(local_rows) * n, 0.0);
148
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MPI_Scatterv(flat_matrix.data(), matrix_counts.data(), matrix_displs.data(), MPI_DOUBLE, local_matrix.data(),
149 local_rows * n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
150
151 // Распределение вектора b по процессам
152
2/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20 std::vector<double> local_b(local_rows, 0.0);
153
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MPI_Scatterv(b.data(), row_counts.data(), row_displs.data(), MPI_DOUBLE, local_b.data(), local_rows, MPI_DOUBLE, 0,
154 MPI_COMM_WORLD);
155
156 // Параметры метода
157 const double tau = 0.5;
158 const double epsilon = 1e-6;
159 const int max_iterations = 1000;
160
161 // Инициализация вектора решения
162
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<double> x(n, 0.0);
163
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<double> x_new(n, 0.0);
164
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<double> local_x_new(local_rows, 0.0);
165
166 // Метод простой итерации
167
1/2
✓ Branch 0 taken 438 times.
✗ Branch 1 not taken.
438 for (int iteration = 0; iteration < max_iterations; ++iteration) {
168 438 ComputeLocalProduct(local_matrix, x, local_b, local_x_new, local_rows, start_row, n, tau);
169
170
1/2
✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
438 AllGatherVector(local_x_new, x_new, row_counts, row_displs);
171
172 double local_diff = ComputeLocalDiff(x_new, x, local_rows, start_row);
173
174 x.swap(x_new);
175
176
3/4
✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 418 times.
✓ Branch 4 taken 20 times.
438 if (CheckConvergenceAll(local_diff, epsilon)) {
177 break;
178 }
179 }
180
181 // Вычисление суммы компонент вектора решения
182 20 double local_sum = 0.0;
183
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 20 times.
163 for (int i = 0; i < local_rows; ++i) {
184 143 local_sum += x[start_row + i];
185 }
186
187 // Сбор результата на нулевом процессе
188 20 double global_sum = 0.0;
189
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MPI_Reduce(&local_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
190
191 // Сохранение результата и рассылка всем процессам
192
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
193 10 GetOutput() = static_cast<int>(std::round(global_sum));
194 }
195
196
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MPI_Bcast(&GetOutput(), 1, MPI_INT, 0, MPI_COMM_WORLD);
197
198 return true;
199 }
200
201 20 bool IvanovaPSimpleIterationMethodMPI::PostProcessingImpl() {
202 20 return GetOutput() > 0;
203 }
204
205 } // namespace ivanova_p_simple_iteration_method
206