GCC Code Coverage Report


Directory: ./
File: tasks/papulina_y_simple_iteration/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 140 142 98.6%
Functions: 11 11 100.0%
Branches: 112 154 72.7%

Line Branch Exec Source
1 #include "papulina_y_simple_iteration/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cctype>
7 #include <cmath>
8 #include <cstddef>
9 #include <cstdlib>
10 #include <iostream>
11 #include <utility>
12 #include <vector>
13
14 #include "papulina_y_simple_iteration/common/include/common.hpp"
15
16 namespace papulina_y_simple_iteration {
17
18
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 PapulinaYSimpleIterationMPI::PapulinaYSimpleIterationMPI(const InType &in) {
19 SetTypeOfTask(GetStaticTypeOfTask());
20 GetInput() = in;
21 GetOutput() = std::vector<double>(0);
22
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 MPI_Comm_size(MPI_COMM_WORLD, &procNum_);
23 36 }
24 17 bool PapulinaYSimpleIterationMPI::DiagonalDominance(const std::vector<double> &a, const size_t &n) {
25 bool flag = true;
26
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 16 times.
85 for (size_t i = 0; i < n; i++) {
27 double sum = 0.0;
28
2/2
✓ Branch 0 taken 357 times.
✓ Branch 1 taken 69 times.
426 for (size_t j = 0; j < n; j++) {
29
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 69 times.
357 if (j != i) {
30 288 sum += abs(a[(i * n) + j]);
31 }
32 }
33
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 1 times.
69 if (sum > abs(a[(i * n) + i])) {
34 flag = false;
35 break;
36 }
37 }
38 17 return flag;
39 }
40 18 bool PapulinaYSimpleIterationMPI::DetermChecking(const std::vector<double> &a, const size_t &n) {
41 18 std::vector<double> tmp = a;
42
43
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 17 times.
89 for (size_t i = 0; i < n; i++) {
44
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 70 times.
72 if (std::fabs(tmp[(i * n) + i]) < 1e-10) {
45
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if (!FindAndSwapRow(tmp, i, n)) {
46 return false;
47 }
48 }
49 71 double pivot = tmp[(i * n) + i];
50
2/2
✓ Branch 0 taken 218 times.
✓ Branch 1 taken 71 times.
289 for (size_t j = i; j < n; j++) {
51 218 tmp[(i * n) + j] /= pivot;
52 }
53
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 71 times.
218 for (size_t j = i + 1; j < n; j++) {
54 147 double factor = tmp[(j * n) + i];
55
2/2
✓ Branch 0 taken 746 times.
✓ Branch 1 taken 147 times.
893 for (size_t k = i; k < n; k++) {
56 746 tmp[(j * n) + k] -= tmp[(i * n) + k] * factor;
57 }
58 }
59 }
60
61 return true;
62 }
63 2 bool PapulinaYSimpleIterationMPI::FindAndSwapRow(std::vector<double> &tmp, size_t i, size_t n) {
64
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 for (size_t j = i + 1; j < n; j++) {
65
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (std::fabs(tmp[(j * n) + i]) > 1e-10) {
66
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 for (size_t k = i; k < n; k++) {
67 3 std::swap(tmp[(i * n) + k], tmp[(j * n) + k]);
68 }
69 return true;
70 }
71 }
72 return false;
73 }
74 36 bool PapulinaYSimpleIterationMPI::ValidationImpl() {
75 36 int flag = 1;
76 36 int proc_rank = 0;
77 36 MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank);
78
79
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 if (proc_rank == 0) {
80
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 size_t n = std::get<0>(GetInput());
81 const auto &a_matrix = std::get<1>(GetInput());
82
83
5/6
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 16 times.
18 if ((n < 1) || (!DetermChecking(a_matrix, n) || (!DiagonalDominance(a_matrix, n)))) {
84 2 flag = 0; // валидация не прошла
85 } else {
86 16 double norm_b = CalculateNormB(a_matrix, n);
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (norm_b >= 1.0) {
88 std::cout << "WARNING: sufficient condition for convergence may not hold (norm_b = " << norm_b << " >= 1)\n";
89 }
90 }
91 }
92
93 36 MPI_Bcast(&flag, 1, MPI_INT, 0, MPI_COMM_WORLD);
94
95 36 return (flag == 1);
96 }
97 16 double PapulinaYSimpleIterationMPI::CalculateNormB(const std::vector<double> &a, size_t n) {
98 16 double max_row_sum = 0.0;
99
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 16 times.
83 for (size_t i = 0; i < n; i++) {
100 67 double diag = a[(i * n) + i];
101 67 double row_sum = 0.0;
102
103
2/2
✓ Branch 0 taken 351 times.
✓ Branch 1 taken 67 times.
418 for (size_t j = 0; j < n; j++) {
104
2/2
✓ Branch 0 taken 284 times.
✓ Branch 1 taken 67 times.
351 if (j != i) {
105 284 row_sum += std::abs(a[(i * n) + j] / diag);
106 }
107 }
108 67 max_row_sum = std::max(row_sum, max_row_sum);
109 }
110
111 16 return max_row_sum;
112 }
113 32 bool PapulinaYSimpleIterationMPI::PreProcessingImpl() {
114 32 int proc_rank = 0;
115 32 MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank);
116
117
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 if (proc_rank == 0) {
118 16 n_ = static_cast<size_t>(std::get<0>(GetInput()));
119 16 A_.assign(n_ * n_, 0.0);
120
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 1 times.
16 b_.assign(n_, 0.0);
121
122
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
16 std::copy(std::get<1>(GetInput()).data(), std::get<1>(GetInput()).data() + (n_ * n_), A_.data());
123
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
16 std::copy(std::get<2>(GetInput()).data(), std::get<2>(GetInput()).data() + n_, b_.data());
124 }
125
126 32 MPI_Bcast(&n_, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);
127 32 int rows_for_proc = static_cast<int>(n_) / procNum_;
128 32 int remainder = static_cast<int>(n_) % procNum_;
129
130
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 7 times.
32 int start_row = (proc_rank * rows_for_proc) + std::min(proc_rank, remainder);
131
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 7 times.
32 int last_row = start_row + rows_for_proc + (proc_rank < remainder ? 1 : 0);
132 32 int local_rows_count = last_row - start_row;
133
134 32 local_a_.resize(local_rows_count * n_);
135 32 local_b_.resize(local_rows_count);
136
137 32 std::vector<int> proc_count_elements_a(procNum_, 0);
138
1/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
32 std::vector<int> proc_count_elements_b(procNum_, 0);
139
1/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
32 std::vector<int> a_displs(procNum_, 0);
140
1/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
32 std::vector<int> b_displs(procNum_, 0);
141
142
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 32 times.
96 for (int i = 0; i < procNum_; i++) {
143
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 14 times.
64 int start = (i * rows_for_proc) + std::min(i, remainder);
144
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 14 times.
64 int end = start + rows_for_proc + (i < remainder ? 1 : 0);
145 64 int count = end - start;
146
147
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 32 times.
64 proc_count_elements_a[i] = count * static_cast<int>(n_);
148 64 proc_count_elements_b[i] = count;
149
150
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 32 times.
64 if (i > 0) {
151 32 a_displs[i] = a_displs[i - 1] + proc_count_elements_a[i - 1];
152 32 b_displs[i] = b_displs[i - 1] + proc_count_elements_b[i - 1];
153 }
154 }
155
156
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 MPI_Scatterv((proc_rank == 0) ? A_.data() : nullptr, proc_count_elements_a.data(), a_displs.data(), MPI_DOUBLE,
157
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 local_a_.data(), local_rows_count * static_cast<int>(n_), MPI_DOUBLE, 0, MPI_COMM_WORLD);
158
159
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
48 MPI_Scatterv((proc_rank == 0) ? b_.data() : nullptr, proc_count_elements_b.data(), b_displs.data(), MPI_DOUBLE,
160 local_b_.data(), local_rows_count, MPI_DOUBLE, 0, MPI_COMM_WORLD);
161
162 32 return true;
163 }
164
165 32 bool PapulinaYSimpleIterationMPI::RunImpl() {
166 32 int proc_rank = 0;
167 32 MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank);
168 32 int rows_for_proc = static_cast<int>(n_) / procNum_;
169 32 int remainder = static_cast<int>(n_) % procNum_;
170
171
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 7 times.
32 int start_row = (proc_rank * rows_for_proc) + std::min(proc_rank, remainder);
172
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 7 times.
32 int last_row = start_row + rows_for_proc + (proc_rank < remainder ? 1 : 0);
173 32 int local_rows_count = last_row - start_row;
174 32 std::vector<double> local_b_matrix(local_rows_count * n_, 0);
175
1/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
32 std::vector<double> local_d(local_rows_count, 0);
176
177 32 PrepareLocalMatrices(local_b_matrix, local_d, start_row, local_rows_count, static_cast<int>(n_));
178
179
1/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
32 std::vector<double> x(n_, 0.0);
180
1/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
32 std::vector<double> x_new(n_, 0.0);
181
182 32 double diff = 0.0;
183
184
1/2
✓ Branch 0 taken 526 times.
✗ Branch 1 not taken.
526 for (unsigned int step = 0; step < steps_count_; step++) {
185
1/4
✓ Branch 1 taken 526 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
526 std::vector<double> local_x_new(local_rows_count, 0.0);
186 526 for (size_t i = 0; std::cmp_less(i, local_rows_count); i++) {
187
2/2
✓ Branch 0 taken 8845 times.
✓ Branch 1 taken 1379 times.
10224 for (size_t j = 0; j < n_; j++) {
188 8845 local_x_new[i] += local_b_matrix[(i * n_) + j] * x[j];
189 }
190 1379 local_x_new[i] += local_d[i];
191 }
192
193
1/4
✓ Branch 1 taken 526 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
526 std::vector<int> proc_count_elemts_x(procNum_, 0);
194
1/4
✓ Branch 1 taken 526 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
526 std::vector<int> x_displs(procNum_, 0);
195 526 CalculateGatherParameters(proc_count_elemts_x, x_displs, rows_for_proc, remainder);
196 // MPI_Gatherv(local_x_new.data(), local_rows_count, MPI_DOUBLE, x_new.data(), proc_count_elemts_x.data(),
197 // x_displs.data(), MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(x_new.data(), static_cast<int>(n_), MPI_DOUBLE, 0,
198 // MPI_COMM_WORLD);
199
1/2
✓ Branch 1 taken 526 times.
✗ Branch 2 not taken.
526 MPI_Allgatherv(local_x_new.data(), local_rows_count, MPI_DOUBLE, x_new.data(), proc_count_elemts_x.data(),
200 x_displs.data(), MPI_DOUBLE, MPI_COMM_WORLD);
201 526 double local_sum_for_norm = 0.0;
202
2/2
✓ Branch 0 taken 1379 times.
✓ Branch 1 taken 526 times.
1905 for (int i = 0; i < local_rows_count; i++) {
203 1379 int global_i = start_row + i;
204 1379 double diff_i = x_new[global_i] - x[global_i];
205 1379 local_sum_for_norm += diff_i * diff_i;
206 }
207
208
1/2
✓ Branch 1 taken 526 times.
✗ Branch 2 not taken.
526 MPI_Allreduce(&local_sum_for_norm, &diff, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
209 526 diff = std::sqrt(diff);
210
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 494 times.
526 if (diff < eps_) {
211
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 x = x_new;
212 break;
213 }
214
1/2
✓ Branch 1 taken 494 times.
✗ Branch 2 not taken.
494 x = x_new;
215 }
216
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 GetOutput() = x;
217 32 return true;
218 }
219 32 bool PapulinaYSimpleIterationMPI::PostProcessingImpl() {
220 32 return true;
221 }
222 526 void PapulinaYSimpleIterationMPI::CalculateGatherParameters(std::vector<int> &proc_count_elemts_x,
223 std::vector<int> &x_displs, int rows_for_proc,
224 int remainder) const {
225 // if (proc_rank != 0) {
226 // return;
227 // }
228
2/2
✓ Branch 0 taken 1052 times.
✓ Branch 1 taken 526 times.
1578 for (int i = 0; i < procNum_; i++) {
229
2/2
✓ Branch 0 taken 842 times.
✓ Branch 1 taken 210 times.
1052 unsigned int start = (i * rows_for_proc) + std::min(i, remainder);
230
2/2
✓ Branch 0 taken 842 times.
✓ Branch 1 taken 210 times.
1052 unsigned int end = start + rows_for_proc + (i < remainder ? 1 : 0);
231 1052 unsigned int count = end - start;
232
2/2
✓ Branch 0 taken 526 times.
✓ Branch 1 taken 526 times.
1052 proc_count_elemts_x[i] = static_cast<int>(count);
233
234
2/2
✓ Branch 0 taken 526 times.
✓ Branch 1 taken 526 times.
1052 if (i > 0) {
235 526 x_displs[i] = x_displs[i - 1] + proc_count_elemts_x[i - 1];
236 }
237 }
238 526 }
239 32 void PapulinaYSimpleIterationMPI::PrepareLocalMatrices(std::vector<double> &local_b_matrix,
240 std::vector<double> &local_d, int start_row,
241 int local_rows_count, int n) {
242
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 32 times.
99 for (int i = 0; i < local_rows_count; i++) {
243 67 int global_i = start_row + i;
244 67 double diag = local_a_[(i * n) + global_i];
245 67 double inv_diag = 1.0 / diag;
246
2/2
✓ Branch 0 taken 351 times.
✓ Branch 1 taken 67 times.
418 for (int j = 0; j < n; j++) {
247
2/2
✓ Branch 0 taken 284 times.
✓ Branch 1 taken 67 times.
351 if (j != global_i) {
248 284 local_b_matrix[(i * n) + j] = -local_a_[(i * n) + j] * inv_diag;
249 }
250 }
251 67 local_d[i] = local_b_[i] * inv_diag;
252 }
253 32 }
254 } // namespace papulina_y_simple_iteration
255