GCC Code Coverage Report


Directory: ./
File: tasks/morozov_n_siedels_method/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 112 115 97.4%
Functions: 8 9 88.9%
Branches: 74 120 61.7%

Line Branch Exec Source
1 #include "morozov_n_siedels_method/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cmath>
7 #include <cstddef>
8 #include <vector>
9
10 #include "morozov_n_siedels_method/common/include/common.hpp"
11
12 namespace morozov_n_siedels_method {
13
14
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MorozovNSiedelsMethodMPI::MorozovNSiedelsMethodMPI(const InType &in) {
15 SetTypeOfTask(GetStaticTypeOfTask());
16 GetInput() = in;
17 GetOutput();
18 6 }
19
20 6 bool MorozovNSiedelsMethodMPI::ValidationImpl() {
21 6 int rank = 0;
22 6 int mpi_size = 0;
23 6 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
24 6 MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
25
26 6 bool matrix_correct = false;
27
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank == 0) {
28 3 std::size_t n = std::get<0>(GetInput());
29 3 std::vector<double> a = std::get<1>(GetInput());
30
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 std::vector<double> b = std::get<2>(GetInput());
31
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if ((a.size() == (n * n)) && (b.size() == n)) {
32
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 int rank_a = CalcMatrixRank(n, n, a);
33 // вычисление расширенной матрицы
34 3 std::vector<double> ext_a;
35
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 3 times.
27 for (std::size_t i = 0; i < n; i++) {
36
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 24 times.
312 for (std::size_t j = 0; j < n; j++) {
37
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 19 times.
288 ext_a.push_back(a[(i * n) + j]);
38 }
39 ext_a.push_back(b[i]);
40 }
41
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 int rank_ext_a = CalcMatrixRank(n, n + 1, ext_a);
42
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rank_a >= rank_ext_a) {
43 3 matrix_correct = true;
44 }
45 }
46 }
47 6 MPI_Bcast(&matrix_correct, 1, MPI_BYTE, 0, MPI_COMM_WORLD);
48 6 return matrix_correct;
49 }
50
51 6 bool MorozovNSiedelsMethodMPI::PreProcessingImpl() {
52 6 return true;
53 }
54
55 6 bool MorozovNSiedelsMethodMPI::RunImpl() {
56 6 double eps = std::get<3>(GetInput());
57
58 6 int rank = 0;
59 6 int mpi_size = 0;
60 6 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
61 6 MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
62
63 double *a = nullptr;
64 double *b = nullptr;
65
66 6 std::size_t n = 0;
67
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank == 0) {
68 3 n = std::get<0>(GetInput());
69 a = std::get<1>(GetInput()).data();
70 b = std::get<2>(GetInput()).data();
71
72 // debug
73 // {
74 // std::cout << n << "\n";
75 // std::cout << "a: " << "\n";
76 // for (int i = 0; i < n; i++) {
77 // for (int j = 0; j < n; j++) {
78 // std::cout << a[i * n + j] << " ";
79 // }
80 // std::cout << "\n";
81 // }
82 // std::cout << "b: " << "\n";
83 // for (int i = 0; i < n; i++) {
84 // std::cout << b[i] << " ";
85 // }
86 // std::cout << "\n--------------\n";
87 // }
88 }
89 6 MPI_Bcast(&n, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);
90
91 6 int step = static_cast<int>(n) / mpi_size;
92 6 int remainder = static_cast<int>(n) % mpi_size;
93
94 6 std::vector<int> send_counts(mpi_size, step);
95
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 std::vector<int> displacements(mpi_size, 0);
96 std::size_t displacement = 0;
97
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 for (int i = 0; i < remainder; ++i) {
98 send_counts[i]++;
99 }
100
101 6 displacements[0] = 0;
102 int disp_sum = 0;
103
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for (int i = 1; i < mpi_size; ++i) {
104 6 disp_sum += send_counts[i - 1];
105 6 displacements[i] = disp_sum;
106 }
107
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 displacement = static_cast<std::size_t>(displacements[rank]);
108
109 // debug
110 // {
111 // if (rank == 0) {
112 // std::cout << "send_size: " << "\n";
113 // for (int i = 0; i < mpi_size; i++) {
114 // std::cout << send_counts[i] << " ";
115 // }
116 // std::cout << "disp: " << "\n";
117 // for (int i = 0; i < mpi_size; i++) {
118 // std::cout << displacements[i] << " ";
119 // }
120 // std::cout << "\n--------------\n";
121 // }
122 // std::cout << "rank " << rank << " l_b size: " << send_counts[rank] << "\n";
123 // }
124
125
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 std::vector<double> local_b(send_counts[rank]);
126
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Scatterv(b, send_counts.data(), displacements.data(), MPI_DOUBLE, local_b.data(),
127 static_cast<int>(local_b.size()), MPI_DOUBLE, 0, MPI_COMM_WORLD);
128
129 // //debug
130 // {
131 // std::cout << "rank: " << rank << "\n";
132 // for(int i = 0; i < send_counts[rank]; i++) {
133 // std::cout << local_b[i] << " ";
134 // }
135 // std::cout <<"\n--------------\n";
136 // }
137
138
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (int i = 0; i < mpi_size; i++) {
139 12 send_counts[i] *= static_cast<int>(n);
140 12 displacements[i] *= static_cast<int>(n);
141 }
142
143 // debug
144 // if(rank == 1) {
145 // std::cout << "send_size: " << "\n";
146 // for(int i = 0; i < mpi_size; i++) {
147 // std::cout << send_counts[i] << " ";
148 // }
149 // std::cout <<"\n";
150 // std::cout << "disp: " << "\n";
151 // for(int i = 0; i < mpi_size; i++) {
152 // std::cout << displacements[i] << " ";
153 // }
154 // std::cout <<"\n--------------\n";
155 // }
156
157
2/6
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6 std::vector<double> local_a(send_counts[rank]);
158
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Scatterv(a, send_counts.data(), displacements.data(), MPI_DOUBLE, local_a.data(),
159 static_cast<int>(local_a.size()), MPI_DOUBLE, 0, MPI_COMM_WORLD);
160
161
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (int i = 0; i < mpi_size; i++) {
162 12 send_counts[i] /= static_cast<int>(n);
163 12 displacements[i] /= static_cast<int>(n);
164 }
165
166 // debug
167 // if (rank == 0) {
168 // std::cout << "send_size: " << "\n";
169 // for (int i = 0; i < mpi_size; i++) {
170 // std::cout << send_counts[i] << " ";
171 // }
172 // std::cout << "\ndisp: " << "\n";
173 // for (int i = 0; i < mpi_size; i++) {
174 // std::cout << displacements[i] << " ";
175 // }
176 // std::cout << "\n--------------\n";
177 // }
178
179
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 std::vector<double> x(n, 0); // вектор ответа
180
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 std::vector<double> x_new(local_b.size(), 0); // вектор для рассылки
181
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 std::vector<double> iter_eps(n, -1); // вектор погрешности
182
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 std::vector<double> iter_eps_new(local_b.size(), -1); // вектор для рассылки
183 bool complete = false;
184
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 6 times.
86 while (!complete) {
185
2/2
✓ Branch 0 taken 364 times.
✓ Branch 1 taken 80 times.
444 for (std::size_t i = 0; i < local_b.size(); i++) {
186 364 std::size_t g_row = displacement + i; // позиция строки в общей матрице
187 364 double iter_x = local_b[i]; // результат на итерации
188 // циклы с суммой без элмента диагонали
189
2/2
✓ Branch 0 taken 2178 times.
✓ Branch 1 taken 364 times.
2542 for (std::size_t j = 0; j < g_row; j++) {
190 2178 iter_x = iter_x - (local_a[(i * n) + j] * x[j]);
191 }
192
2/2
✓ Branch 0 taken 2178 times.
✓ Branch 1 taken 364 times.
2542 for (std::size_t j = g_row + 1; j < n; j++) {
193 2178 iter_x = iter_x - (local_a[(i * n) + j] * x[j]);
194 }
195
196 364 iter_x = iter_x / local_a[(i * n) + g_row]; // вычисление корня стоящего на диагонали
197 // обновление погрешности
198 364 iter_eps[g_row] = std::fabs(iter_x - x[g_row]);
199 364 iter_eps_new[i] = iter_eps[g_row];
200 // обновление полученного корня
201 364 x[g_row] = iter_x;
202 364 x_new[i] = iter_x;
203 }
204
205 // debug
206 // if (rank == 1) {
207 // std::cout << "local iteration rank: " << rank << "\n";
208 // for (size_t i = 0; i < local_b.size(); i++) {
209 // std::cout << x_new[i] << " ";
210 // }
211 // std::cout << "\n";
212 // }
213
214
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 MPI_Allgatherv(x_new.data(), static_cast<int>(x_new.size()), MPI_DOUBLE, x.data(), send_counts.data(),
215 displacements.data(), MPI_DOUBLE, MPI_COMM_WORLD);
216
217
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 MPI_Allgatherv(iter_eps_new.data(), static_cast<int>(iter_eps_new.size()), MPI_DOUBLE, iter_eps.data(),
218 send_counts.data(), displacements.data(), MPI_DOUBLE, MPI_COMM_WORLD);
219
220 80 complete = !EpsOutOfBound(iter_eps, eps);
221 // debug
222 // if (rank == 0) {
223 // std::cout << "rank: " << rank << " iteration: " << iter_count <<" X:\n";
224 // for(int i = 0; i < n; i++) {
225 // std::cout << x[i] << " ";
226 // }
227 // std::cout << "rank: " << rank << " iteration: " << iter_count <<" EPS:\n";
228 // for(int i = 0; i < n; i++) {
229 // std::cout << iter_eps[i] << " ";
230 // }
231 // std::cout <<"\n--------\n";
232 // }
233 // debug
234 // if (rank == 0) {
235 // std::cout << "answer X:\n";
236 // for (int i = 0; i < n; i++) {
237 // std::cout << x[i] << " ";
238 // }
239 // std::cout << "\n";
240 // }
241 }
242
243 // debug
244 // if (rank == 0) {
245 // std::string result = "answer X:\n";
246 // for (int i = 0; i < n; i++) {
247 // result += std::to_string(x[i]) + " ";
248 // }
249 // result += '\n';
250 // std::cout << result;
251 // }
252
253
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 GetOutput() = x;
254 // std::cout << "rank:" << rank << " end of calc\n";
255
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank != 0) {
256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 delete[] a;
257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 delete[] b;
258 }
259 6 return true;
260 }
261
262 6 bool MorozovNSiedelsMethodMPI::PostProcessingImpl() {
263 6 return true;
264 }
265
266 bool MorozovNSiedelsMethodMPI::EpsOutOfBound(std::vector<double> &iter_eps, double correct_eps) {
267 80 double max_in_iter = *std::ranges::max_element(iter_eps);
268 // debug
269 // std::cout << max_in_iter << "\n";
270 80 return max_in_iter > correct_eps;
271 }
272
273 6 int MorozovNSiedelsMethodMPI::CalcMatrixRank(std::size_t n, std::size_t m, std::vector<double> &a) {
274 const double e = 1e-9;
275
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 std::vector<std::vector<double>> mat(n, std::vector<double>(m));
276
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 6 times.
54 for (std::size_t i = 0; i < n; i++) {
277
2/2
✓ Branch 0 taken 600 times.
✓ Branch 1 taken 48 times.
648 for (std::size_t j = 0; j < m; j++) {
278 600 mat[i][j] = a[(i * n) + j];
279 }
280 }
281
282 int rank = 0;
283
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::vector<bool> row_selected(n, false);
284
285
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 6 times.
54 for (std::size_t col = 0; col < n; col++) {
286 48 std::size_t pivot_row = 0;
287
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
48 if (!GetPivotRow(&pivot_row, row_selected, col, mat, e)) {
288 continue;
289 }
290 48 rank++;
291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 row_selected[pivot_row] = true;
292 // Нормализация строки и вычитание строки из других строк
293 //-> приведение к степнчатому виду
294 48 SubRow(pivot_row, col, mat, e);
295 }
296 6 return rank;
297 6 }
298
299 48 bool MorozovNSiedelsMethodMPI::GetPivotRow(std::size_t *pivot_row, std::vector<bool> &row_selected, std::size_t col,
300 std::vector<std::vector<double>> &mat, double e) {
301
1/2
✓ Branch 0 taken 312 times.
✗ Branch 1 not taken.
312 for (std::size_t row = 0; row < mat.size(); row++) {
302
3/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 264 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
312 if (!row_selected[row] && std::fabs(mat[row][col]) > e) {
303 48 *pivot_row = row;
304 48 return true;
305 }
306 }
307 return false;
308 }
309
310 48 void MorozovNSiedelsMethodMPI::SubRow(std::size_t pivot_row, std::size_t col, std::vector<std::vector<double>> &mat,
311 double e) {
312 std::size_t n = mat.size();
313 std::size_t m = mat[0].size();
314 // Нормализация строки
315 48 double pivot = mat[pivot_row][col];
316
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 48 times.
360 for (std::size_t j = col; j < n; j++) {
317 312 mat[pivot_row][j] /= pivot;
318 }
319 // Вычитание текущей строки из других строк
320
2/2
✓ Branch 0 taken 576 times.
✓ Branch 1 taken 48 times.
624 for (std::size_t row = 0; row < n; row++) {
321
3/4
✓ Branch 0 taken 528 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 528 times.
✗ Branch 3 not taken.
576 if (row != pivot_row && std::fabs(mat[row][col]) > e) {
322 double factor = mat[row][col];
323
2/2
✓ Branch 0 taken 4464 times.
✓ Branch 1 taken 528 times.
4992 for (std::size_t j = col; j < m; j++) {
324 4464 mat[row][j] -= factor * mat[pivot_row][j];
325 }
326 }
327 }
328 48 }
329
330 } // namespace morozov_n_siedels_method
331