GCC Code Coverage Report


Directory: ./
File: tasks/pylaeva_s_simple_iteration_method/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 87 87 100.0%
Functions: 9 9 100.0%
Branches: 72 128 56.2%

Line Branch Exec Source
1 #include "pylaeva_s_simple_iteration_method/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cctype>
6 #include <cmath>
7 #include <cstddef>
8 #include <utility>
9 #include <vector>
10
11 #include "pylaeva_s_simple_iteration_method/common/include/common.hpp"
12
13 namespace pylaeva_s_simple_iteration_method {
14 namespace {
15
16 constexpr double kEps = 1e-6;
17 constexpr int kMaxIterations = 10000;
18
19 22 bool DiagonalDominance(const std::vector<double> &a, size_t n) {
20
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 22 times.
86 for (size_t i = 0; i < n; i++) {
21 64 double diag = std::fabs(a[(i * n) + i]); // Модуль диагонального элемента
22 double row_sum = 0.0; // Сумма модулей недиагональных элементов строки
23
24
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 64 times.
296 for (size_t j = 0; j < n; j++) {
25
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 64 times.
232 if (j != i) {
26 168 row_sum += std::fabs(a[(i * n) + j]);
27 }
28 }
29 // Проверка строгого диагонального преобладания:
30 // Диагональный элемент должен быть БОЛЬШЕ суммы остальных элементов строки
31
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 if (diag <= row_sum) {
32 return false;
33 }
34 }
35 return true;
36 }
37
38 172 void CalculateLocalXNew(int start, int count, size_t n, const std::vector<double> &local_a,
39 const std::vector<double> &local_b, const std::vector<double> &x,
40 std::vector<double> &local_x_new) {
41
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 172 times.
461 for (int i = 0; i < count; ++i) {
42 289 int global_i = start + i;
43 double sum = 0.0;
44
2/2
✓ Branch 0 taken 1123 times.
✓ Branch 1 taken 289 times.
1412 for (size_t j = 0; j < n; ++j) {
45 if (std::cmp_not_equal(j, global_i)) {
46 834 sum += local_a[(i * n) + j] * x[j];
47 }
48 }
49 289 local_x_new[i] = (local_b[i] - sum) / local_a[(i * n) + global_i];
50 }
51 172 }
52
53 double CalculateLocalNorm(int start, int count, const std::vector<double> &x_new, const std::vector<double> &x) {
54 double local_norm = 0.0;
55
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 172 times.
461 for (int i = 0; i < count; ++i) {
56 289 int gi = start + i;
57 289 double diff = x_new[gi] - x[gi];
58 289 local_norm += diff * diff;
59 }
60 return local_norm;
61 }
62
63
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 void CalculateChunkSizesAndDispls(int proc_num, int n, std::vector<int> &chunk_sizes, std::vector<int> &displs) {
64
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 if (displs.empty()) {
65 return;
66 }
67 44 int base = n / proc_num;
68 44 int rem = n % proc_num;
69
70 44 displs[0] = 0;
71
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 44 times.
132 for (int i = 0; i < proc_num; ++i) {
72
4/4
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 44 times.
144 chunk_sizes[i] = base + (i < rem ? 1 : 0);
73
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 44 times.
88 if (i > 0) {
74 44 displs[i] = displs[i - 1] + chunk_sizes[i - 1];
75 }
76 }
77 }
78
79
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 void CalculateMatrixChunkSizesAndDispls(int proc_num, int n, std::vector<int> &matrix_chunk_sizes,
80 std::vector<int> &matrix_displs) {
81
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (matrix_displs.empty()) {
82 return;
83 }
84 22 int base = n / proc_num;
85 22 int rem = n % proc_num;
86
87 22 matrix_displs[0] = 0;
88
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 22 times.
66 for (int i = 0; i < proc_num; ++i) {
89
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 16 times.
44 int rows = base + (i < rem ? 1 : 0);
90
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 matrix_chunk_sizes[i] = rows * n;
91
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 if (i > 0) {
92 22 matrix_displs[i] = matrix_displs[i - 1] + matrix_chunk_sizes[i - 1];
93 }
94 }
95 }
96
97 } // namespace
98
99
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 PylaevaSSimpleIterationMethodMPI::PylaevaSSimpleIterationMethodMPI(const InType &in) {
100 SetTypeOfTask(GetStaticTypeOfTask());
101 GetInput() = in;
102 22 }
103
104
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 bool PylaevaSSimpleIterationMethodMPI::ValidationImpl() {
105 const auto &n = std::get<0>(GetInput());
106 const auto &a = std::get<1>(GetInput());
107 const auto &b = std::get<2>(GetInput());
108
3/6
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
22 return ((n > 0) && (a.size() == n * n) && (b.size() == n) && (DiagonalDominance(a, n)));
109 }
110
111 22 bool PylaevaSSimpleIterationMethodMPI::PreProcessingImpl() {
112 22 return true;
113 }
114
115 22 bool PylaevaSSimpleIterationMethodMPI::RunImpl() {
116 22 int proc_num = 0;
117 22 int proc_rank = 0;
118 22 MPI_Comm_size(MPI_COMM_WORLD, &proc_num);
119 22 MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank);
120
121 22 size_t n = 0;
122 22 std::vector<double> a;
123 22 std::vector<double> b;
124
125
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
22 if (proc_rank == 0) {
126 const auto &input = GetInput();
127
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 n = std::get<0>(input);
128
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 a = std::get<1>(input);
129
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 b = std::get<2>(input);
130 }
131
132
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 MPI_Bcast(&n, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);
133
134
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 std::vector<int> chunk_sizes(proc_num);
135
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 std::vector<int> displs(proc_num);
136 22 CalculateChunkSizesAndDispls(proc_num, static_cast<int>(n), chunk_sizes, displs);
137
138
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 std::vector<int> matrix_chunk_sizes(proc_num);
139
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 std::vector<int> matrix_displs(proc_num);
140 22 CalculateMatrixChunkSizesAndDispls(proc_num, static_cast<int>(n), matrix_chunk_sizes, matrix_displs);
141
142
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 int local_rows = chunk_sizes[proc_rank];
143 22 int local_matrix_size = matrix_chunk_sizes[proc_rank];
144
145
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 std::vector<double> local_a(local_matrix_size);
146
3/6
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
22 std::vector<double> local_b(local_rows);
147
148
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
33 MPI_Scatterv(proc_rank == 0 ? a.data() : nullptr, matrix_chunk_sizes.data(), matrix_displs.data(), MPI_DOUBLE,
149 local_a.data(), local_matrix_size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
150
151
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
33 MPI_Scatterv(proc_rank == 0 ? b.data() : nullptr, chunk_sizes.data(), displs.data(), MPI_DOUBLE, local_b.data(),
152 local_rows, MPI_DOUBLE, 0, MPI_COMM_WORLD);
153
154
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 int start = displs[proc_rank];
155 int count = local_rows;
156
157
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 std::vector<double> x(n, 0.0);
158
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 std::vector<double> x_new(n, 0.0);
159
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 std::vector<double> local_x_new(count, 0.0);
160
161
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 std::vector<int> recv_counts(proc_num);
162
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 std::vector<int> allgather_displs(proc_num);
163 22 CalculateChunkSizesAndDispls(proc_num, static_cast<int>(n), recv_counts, allgather_displs);
164
165
1/2
✓ Branch 0 taken 172 times.
✗ Branch 1 not taken.
172 for (int iter = 0; iter < kMaxIterations; ++iter) {
166 172 CalculateLocalXNew(start, count, n, local_a, local_b, x, local_x_new);
167
168
1/2
✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
172 MPI_Allgatherv(local_x_new.data(), count, MPI_DOUBLE, x_new.data(), recv_counts.data(), allgather_displs.data(),
169 MPI_DOUBLE, MPI_COMM_WORLD);
170
171 172 double local_norm = CalculateLocalNorm(start, count, x_new, x);
172 172 double global_norm = 0.0;
173
1/2
✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
172 MPI_Allreduce(&local_norm, &global_norm, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
174
175
1/2
✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
172 x = x_new;
176
177
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 22 times.
172 if (std::sqrt(global_norm) < kEps) {
178 break;
179 }
180 }
181
182
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 GetOutput() = x;
183
184 22 return true;
185 }
186
187 22 bool PylaevaSSimpleIterationMethodMPI::PostProcessingImpl() {
188 22 return true;
189 }
190
191 } // namespace pylaeva_s_simple_iteration_method
192