GCC Code Coverage Report


Directory: ./
File: tasks/smetanin_d_gauss_vert_sch/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 124 132 93.9%
Functions: 11 11 100.0%
Branches: 78 112 69.6%

Line Branch Exec Source
1 #include "smetanin_d_gauss_vert_sch/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cmath>
7 #include <cstddef>
8 #include <limits>
9 #include <utility>
10 #include <vector>
11
12 #include "smetanin_d_gauss_vert_sch/common/include/common.hpp"
13
14 namespace smetanin_d_gauss_vert_sch {
15
16 namespace {
17
18 constexpr auto kLocalAt = [](std::vector<double> &data, int n, int row, int lc) -> double & {
19 return data[(static_cast<std::size_t>(lc) * static_cast<std::size_t>(n)) + static_cast<std::size_t>(row)];
20 };
21
22 constexpr auto kConstLocalAt = [](const std::vector<double> &data, int n, int row, int lc) -> const double & {
23
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
146 return data[(static_cast<std::size_t>(lc) * static_cast<std::size_t>(n)) + static_cast<std::size_t>(row)];
24 };
25
26 constexpr auto kGetOwner = [](const std::vector<int> &displs, const std::vector<int> &col_counts, int col) -> int {
27
3/6
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
100 for (size_t pr = 0; pr < col_counts.size(); ++pr) {
28
9/12
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 44 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 32 times.
✓ Branch 11 taken 12 times.
100 if (displs[pr] <= col && col < displs[pr] + col_counts[pr]) {
29 70 return static_cast<int>(pr);
30 }
31 }
32 return -1;
33 };
34
35 6 void DistributeColumns(int size, int total_cols, std::vector<int> &col_counts, std::vector<int> &displs) {
36 6 const int base = total_cols / size;
37 6 const int rem = total_cols % size;
38 6 col_counts.resize(size);
39 6 displs.resize(size, 0);
40
41
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (int pr = 0; pr < size; ++pr) {
42
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
22 col_counts[pr] = base + (pr < rem ? 1 : 0);
43
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (pr > 0) {
44 6 displs[pr] = displs[pr - 1] + col_counts[pr - 1];
45 }
46 }
47 6 }
48
49 6 void ScatterMatrix(const InType &input, int n, int start_col, int local_cols, std::vector<double> &local_matrix) {
50 6 local_matrix.resize(static_cast<std::size_t>(n) * static_cast<std::size_t>(local_cols));
51
52
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 6 times.
25 for (int lc = 0; lc < local_cols; ++lc) {
53 19 const int gc = start_col + lc;
54
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 19 times.
133 for (int row = 0; row < n; ++row) {
55 114 kLocalAt(local_matrix, n, row, lc) =
56 114 input.augmented_matrix[(static_cast<std::size_t>(row) * static_cast<std::size_t>(n + 1)) +
57 114 static_cast<std::size_t>(gc)];
58 }
59 }
60 6 }
61
62 32 bool FindPivotAndSwap(int i, int n, int bw, int rank, int pivot_owner, int start_col, std::vector<double> &local_matrix,
63 double eps) {
64 32 int max_row_local = i;
65 32 double max_val_local = 0.0;
66
67
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 if (rank == pivot_owner) {
68 16 const int lc = i - start_col;
69 16 max_val_local = std::abs(kConstLocalAt(local_matrix, n, i, lc));
70 16 const int pivot_row_end = std::min(n - 1, i + bw);
71
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 16 times.
43 for (int ri = i + 1; ri <= pivot_row_end; ++ri) {
72
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
54 const double val = std::abs(kConstLocalAt(local_matrix, n, ri, lc));
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 if (val > max_val_local) {
74 max_val_local = val;
75 max_row_local = ri;
76 }
77 }
78 }
79
80 32 MPI_Bcast(&max_row_local, 1, MPI_INT, pivot_owner, MPI_COMM_WORLD);
81 32 MPI_Bcast(&max_val_local, 1, MPI_DOUBLE, pivot_owner, MPI_COMM_WORLD);
82
83
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 if (max_val_local <= eps) {
84 return false;
85 }
86
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (max_row_local != i) {
88 const int local_cols = static_cast<int>(local_matrix.size() / n);
89 for (int lc = 0; lc < local_cols; ++lc) {
90 std::swap(kLocalAt(local_matrix, n, i, lc), kLocalAt(local_matrix, n, max_row_local, lc));
91 }
92 }
93
94 return true;
95 }
96
97 32 void ComputeAndBroadcastFactors(int i, int n, int bw, int rank, int pivot_owner, int start_col,
98 std::vector<double> &local_matrix, std::vector<double> &factors) {
99 32 const int elim_end = std::min(n - 1, i + bw);
100 32 const int num_factors = elim_end - i;
101 32 factors.assign(static_cast<std::size_t>(num_factors), 0.0);
102
103
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 if (rank == pivot_owner) {
104 16 const int lc = i - start_col;
105 16 const double pivot = kConstLocalAt(local_matrix, n, i, lc);
106
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 16 times.
43 for (int k = 0; k < num_factors; ++k) {
107 27 const int ri = i + 1 + k;
108 double &entry = kLocalAt(local_matrix, n, ri, lc);
109 27 const double factor = entry / pivot;
110 27 factors[static_cast<std::size_t>(k)] = factor;
111 27 entry = 0.0;
112 }
113 }
114
115 32 MPI_Bcast(factors.data(), num_factors, MPI_DOUBLE, pivot_owner, MPI_COMM_WORLD);
116 32 }
117
118 32 void EliminateBelowPivot(int i, int n, int bw, int start_col, int local_cols, const std::vector<double> &factors,
119 std::vector<double> &local_matrix, double eps) {
120 32 const int num_factors = static_cast<int>(factors.size());
121
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 32 times.
86 for (int k = 0; k < num_factors; ++k) {
122 54 const int ri = i + 1 + k;
123
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 const double factor = factors[static_cast<std::size_t>(k)];
124
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (std::abs(factor) <= eps) {
125 continue;
126 }
127
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 54 times.
266 for (int lc = 0; lc < local_cols; ++lc) {
128 212 const int gc = start_col + lc;
129
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 129 times.
212 if (gc <= i) {
130 83 continue;
131 }
132
4/4
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 65 times.
129 if (gc < n && gc > i + bw) {
133 37 continue;
134 }
135 92 kLocalAt(local_matrix, n, ri, lc) -= factor * kConstLocalAt(local_matrix, n, i, lc);
136 }
137 }
138 32 }
139
140 6 void BackSubstitution(int n, int bw, int rank, int b_owner, int start_col, int local_cols,
141 const std::vector<double> &local_matrix, const std::vector<int> &displs,
142 const std::vector<int> &col_counts, OutType &sol, double eps) {
143 const int b_col = n;
144
145
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 6 times.
38 for (int i = n - 1; i >= 0; --i) {
146 const int diag_owner = kGetOwner(displs, col_counts, i);
147
148 32 double local_sum = 0.0;
149 32 const int col_end = std::min(n - 1, i + bw);
150
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 32 times.
146 for (int lc = 0; lc < local_cols; ++lc) {
151 114 const int gc = start_col + lc;
152
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 27 times.
114 if (gc <= i || gc > col_end) {
153 87 continue;
154 }
155 27 local_sum += kConstLocalAt(local_matrix, n, i, lc) * sol[static_cast<std::size_t>(gc)];
156 }
157
158 32 double global_sum = 0.0;
159 32 MPI_Allreduce(&local_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
160
161 32 double b_val = 0.0;
162
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 if (rank == b_owner) {
163 16 const int lc_b = b_col - start_col;
164 16 b_val = kConstLocalAt(local_matrix, n, i, lc_b);
165 }
166 32 MPI_Bcast(&b_val, 1, MPI_DOUBLE, b_owner, MPI_COMM_WORLD);
167
168 32 double diag = 0.0;
169
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 if (rank == diag_owner) {
170 16 const int lc_d = i - start_col;
171 16 diag = kConstLocalAt(local_matrix, n, i, lc_d);
172 }
173 32 MPI_Bcast(&diag, 1, MPI_DOUBLE, diag_owner, MPI_COMM_WORLD);
174
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (std::abs(diag) <= eps) {
176 sol.clear();
177 return;
178 }
179
180 32 const double sum = b_val - global_sum;
181 32 sol[static_cast<std::size_t>(i)] = sum / diag;
182 }
183 }
184
185 } // anonymous namespace
186
187
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 SmetaninDGaussVertSchMPI::SmetaninDGaussVertSchMPI(const InType &in) {
188 SetTypeOfTask(GetStaticTypeOfTask());
189 GetInput() = in;
190 GetOutput().clear();
191 6 }
192
193 6 bool SmetaninDGaussVertSchMPI::ValidationImpl() {
194 const InType &input = GetInput();
195 const OutType &output = GetOutput();
196
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 if (input.n <= 0 || input.bandwidth < 0 || input.bandwidth >= input.n) {
197 return false;
198 }
199
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 const std::size_t expected_size = static_cast<std::size_t>(input.n) * static_cast<std::size_t>(input.n + 1);
200
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (input.augmented_matrix.size() != expected_size) {
201 return false;
202 }
203 6 return output.empty();
204 }
205
206 6 bool SmetaninDGaussVertSchMPI::PreProcessingImpl() {
207 6 return true;
208 }
209
210 6 bool SmetaninDGaussVertSchMPI::RunImpl() {
211 const InType &input = GetInput();
212 6 const int n = input.n;
213 6 const int bw = input.bandwidth;
214 const double eps = std::numeric_limits<double>::epsilon() * 100.0;
215
216 6 int rank = 0;
217 6 int size = 1;
218 6 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
219 6 MPI_Comm_size(MPI_COMM_WORLD, &size);
220
221 6 const int total_cols = n + 1;
222
223 6 std::vector<int> col_counts;
224 6 std::vector<int> displs;
225
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 DistributeColumns(size, total_cols, col_counts, displs);
226
227
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 const int start_col = displs[rank];
228 6 const int local_cols = col_counts[rank];
229
230 6 std::vector<double> local_matrix;
231
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 ScatterMatrix(input, n, start_col, local_cols, local_matrix);
232
233
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 6 times.
38 for (int i = 0; i < n; ++i) {
234 const int pivot_owner = kGetOwner(displs, col_counts, i);
235
236
2/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 32 times.
32 if (!FindPivotAndSwap(i, n, bw, rank, pivot_owner, start_col, local_matrix, eps)) {
237 return false;
238 }
239
240 32 std::vector<double> factors;
241
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 ComputeAndBroadcastFactors(i, n, bw, rank, pivot_owner, start_col, local_matrix, factors);
242
243 32 EliminateBelowPivot(i, n, bw, start_col, local_cols, factors, local_matrix, eps);
244 }
245
246
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 OutType sol(static_cast<std::size_t>(n), 0.0);
247 const int b_owner = kGetOwner(displs, col_counts, n);
248
249
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 BackSubstitution(n, bw, rank, b_owner, start_col, local_cols, local_matrix, displs, col_counts, sol, eps);
250
251
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (sol.empty()) {
252 return false;
253 }
254
255 GetOutput() = std::move(sol);
256 6 return true;
257 }
258
259 6 bool SmetaninDGaussVertSchMPI::PostProcessingImpl() {
260 6 return !GetOutput().empty();
261 }
262
263 } // namespace smetanin_d_gauss_vert_sch
264