GCC Code Coverage Report


Directory: ./
File: tasks/sannikov_i_horizontal_band_gauss/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 128 131 97.7%
Functions: 9 9 100.0%
Branches: 78 124 62.9%

Line Branch Exec Source
1 #include "sannikov_i_horizontal_band_gauss/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cmath>
7 #include <cstddef>
8 #include <tuple>
9 #include <vector>
10
11 #include "sannikov_i_horizontal_band_gauss/common/include/common.hpp"
12
13 namespace sannikov_i_horizontal_band_gauss {
14
15
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 SannikovIHorizontalBandGaussMPI::SannikovIHorizontalBandGaussMPI(const InType &in) {
16 SetTypeOfTask(GetStaticTypeOfTask());
17 auto &input_buffer = GetInput();
18 InType tmp(in);
19 input_buffer.swap(tmp);
20 GetOutput().clear();
21 24 }
22
23
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 bool SannikovIHorizontalBandGaussMPI::ValidationImpl() {
24 (void)this;
25
26 const auto &a = std::get<0>(GetInput());
27 const auto &rhs = std::get<1>(GetInput());
28
29
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
24 if (a.empty() || rhs.empty()) {
30 return false;
31 }
32
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (a.size() != rhs.size()) {
33 return false;
34 }
35 24 return GetOutput().empty();
36 }
37
38
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 bool SannikovIHorizontalBandGaussMPI::PreProcessingImpl() {
39 (void)this;
40
41 GetOutput().clear();
42 24 return GetOutput().empty();
43 }
44 namespace {
45 24 void BuildRowPartition(int size, int n, std::vector<int> *counts, std::vector<int> *displs) {
46 24 counts->assign(size, 0);
47 24 displs->assign(size, 0);
48
49 24 const int base = n / size;
50 24 const int rem = n % size;
51
52 int disp = 0;
53
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
72 for (int res = 0; res < size; ++res) {
54
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 14 times.
82 (*counts)[res] = base + ((res < rem) ? 1 : 0);
55 48 (*displs)[res] = disp;
56 48 disp += (*counts)[res];
57 }
58 24 }
59 void FillPivotSegmentIfOwner(int k, int j_end, int band_eff, int w, int rank, int owner, int row_begin,
60 const std::vector<double> &a_loc, const std::vector<double> &b_loc,
61 std::vector<double> *pivot_seg, double *pivot_b) {
62 94 if (rank != owner) {
63 return;
64 }
65
66 47 const int loc_k = k - row_begin;
67 47 const double *rowk = &a_loc[static_cast<std::size_t>(loc_k) * static_cast<std::size_t>(w)];
68
69
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 47 times.
132 for (int j = k; j <= j_end; ++j) {
70 85 const int band_off = j - (k - band_eff);
71 85 (*pivot_seg)[static_cast<std::size_t>(j - k)] = rowk[static_cast<std::size_t>(band_off)];
72 }
73
74 47 *pivot_b = b_loc[static_cast<std::size_t>(loc_k)];
75 }
76
77 94 void EliminateLocalRows(int k, int j_end, int band_eff, int w, int row_begin, int loc_rows, std::vector<double> &a_loc,
78 std::vector<double> &b_loc, const std::vector<double> &pivot_seg, double pivot_b,
79 double pivot) {
80 94 const int i_start = std::max(row_begin, k + 1);
81 94 const int i_end = std::min(row_begin + loc_rows - 1, k + band_eff);
82
83
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 94 times.
132 for (int i = i_start; i <= i_end; ++i) {
84 38 const int loc_i = i - row_begin;
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 double *rowi = &a_loc[static_cast<std::size_t>(loc_i) * static_cast<std::size_t>(w)];
86
87 38 const int off_ik = k - (i - band_eff);
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (off_ik < 0 || off_ik >= w) {
89 continue;
90 }
91
92 38 const double mn = rowi[static_cast<std::size_t>(off_ik)] / pivot;
93 38 rowi[static_cast<std::size_t>(off_ik)] = 0.0;
94
95
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 38 times.
96 for (int j = k + 1; j <= j_end; ++j) {
96 58 const int off_ij = j - (i - band_eff);
97
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 if (off_ij >= 0 && off_ij < w) {
98 58 rowi[static_cast<std::size_t>(off_ij)] -= mn * pivot_seg[static_cast<std::size_t>(j - k)];
99 }
100 }
101
102 38 b_loc[static_cast<std::size_t>(loc_i)] -= mn * pivot_b;
103 }
104 94 }
105
106 24 bool ForwardElimination(int n, int band_eff, int w, int rank, int row_begin, int loc_rows,
107 const std::vector<int> &owner_of_row, std::vector<double> &a_loc, std::vector<double> &b_loc) {
108 24 std::vector<double> pivot_seg;
109
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 pivot_seg.reserve(static_cast<std::size_t>(band_eff) + 1U);
110
111
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 24 times.
118 for (int k = 0; k < n; ++k) {
112
1/2
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
94 const int owner = owner_of_row[static_cast<std::size_t>(k)];
113
1/2
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
94 const int j_end = std::min(n - 1, k + band_eff);
114 94 const int len = (j_end - k) + 1;
115
116
1/4
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
94 pivot_seg.assign(static_cast<std::size_t>(len), 0.0);
117
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 47 times.
94 double pivot_b = 0.0;
118
119 FillPivotSegmentIfOwner(k, j_end, band_eff, w, rank, owner, row_begin, a_loc, b_loc, &pivot_seg, &pivot_b);
120
121
1/2
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
94 MPI_Bcast(pivot_seg.data(), len, MPI_DOUBLE, owner, MPI_COMM_WORLD);
122
1/2
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
94 MPI_Bcast(&pivot_b, 1, MPI_DOUBLE, owner, MPI_COMM_WORLD);
123
124 94 const double pivot = pivot_seg[0];
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
94 if (pivot == 0.0) {
126 return false;
127 }
128
129 94 EliminateLocalRows(k, j_end, band_eff, w, row_begin, loc_rows, a_loc, b_loc, pivot_seg, pivot_b, pivot);
130 }
131
132 return true;
133 }
134 24 bool BackSubstitution(int n, int band_eff, int w, int rank, int row_begin, const std::vector<int> &owner_of_row,
135 const std::vector<double> &a_loc, const std::vector<double> &b_loc, std::vector<double> *x_out) {
136 24 std::vector<double> x(static_cast<std::size_t>(n), 0.0);
137
138
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 24 times.
118 for (int k = n - 1; k >= 0; --k) {
139
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 47 times.
94 const int ow = owner_of_row[static_cast<std::size_t>(k)];
140
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 47 times.
94 const int j_end = std::min(n - 1, k + band_eff);
141
142 94 double xk = 0.0;
143
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 47 times.
94 if (rank == ow) {
144 47 const int loc_i = k - row_begin;
145 47 const double *rowk = &a_loc[static_cast<std::size_t>(loc_i) * static_cast<std::size_t>(w)];
146
147 double s = 0.0;
148
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 47 times.
85 for (int j = k + 1; j <= j_end; ++j) {
149 38 const int band_off = j - (k - band_eff);
150
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 if (band_off >= 0 && band_off < w) {
151 38 s += rowk[static_cast<std::size_t>(band_off)] * x[static_cast<std::size_t>(j)];
152 }
153 }
154
155 const int off_kk = k - (k - band_eff);
156 47 const double diag = rowk[static_cast<std::size_t>(off_kk)];
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
47 if (diag == 0.0) {
158 return false;
159 }
160
161 47 xk = (b_loc[static_cast<std::size_t>(loc_i)] - s) / diag;
162 }
163
164
1/2
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
94 MPI_Bcast(&xk, 1, MPI_DOUBLE, ow, MPI_COMM_WORLD);
165 94 x[static_cast<std::size_t>(k)] = xk;
166 }
167
168 x_out->swap(x);
169 24 return true;
170 }
171 } // namespace
172
173 24 bool SannikovIHorizontalBandGaussMPI::RunImpl() {
174 const auto &input = GetInput();
175 const auto &a_in = std::get<0>(input);
176 const auto &b_in = std::get<1>(input);
177 24 const std::size_t band_in = std::get<2>(input);
178
179 24 int rank = 0;
180 24 int size = 1;
181 24 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
182 24 MPI_Comm_size(MPI_COMM_WORLD, &size);
183
184 24 int n = 0;
185 24 int band_eff = 0;
186
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
187 12 n = static_cast<int>(a_in.size());
188 12 band_eff = static_cast<int>(band_in);
189 }
190
191 24 MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
192 24 MPI_Bcast(&band_eff, 1, MPI_INT, 0, MPI_COMM_WORLD);
193 int w = 0;
194 24 w = (2 * band_eff) + 1;
195
196 24 std::vector<int> row_cnts;
197 24 std::vector<int> row_disp;
198
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 BuildRowPartition(size, n, &row_cnts, &row_disp);
199 int loc_rows = 0;
200 int row_begin = 0;
201
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 loc_rows = row_cnts[rank];
202 24 row_begin = row_disp[rank];
203
204
1/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
24 std::vector<int> owner_of_row(static_cast<std::size_t>(n), 0);
205
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
72 for (int res = 0; res < size; ++res) {
206 int begin = 0;
207 int end = 0;
208 48 begin = row_disp[res];
209 48 end = begin + row_cnts[res];
210
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 48 times.
142 for (int i = begin; i < end; ++i) {
211 94 owner_of_row[static_cast<std::size_t>(i)] = res;
212 }
213 }
214
215 24 std::vector<double> send_a;
216 24 std::vector<double> send_b;
217
218
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
219
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 send_a.assign(static_cast<std::size_t>(n) * static_cast<std::size_t>(w), 0.0);
220
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 send_b.resize(static_cast<std::size_t>(n));
221 int j_start = 0;
222 int j_end = 0;
223 int off = 0;
224
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 12 times.
59 for (int i = 0; i < n; ++i) {
225 47 j_start = std::max(0, i - band_eff);
226 47 j_end = std::min(n - 1, i + band_eff);
227
228
2/2
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 47 times.
170 for (int j = j_start; j <= j_end; ++j) {
229 123 off = j - (i - band_eff);
230 123 send_a[(static_cast<std::size_t>(i) * static_cast<std::size_t>(w)) + static_cast<std::size_t>(off)] =
231 123 a_in[static_cast<std::size_t>(i)][static_cast<std::size_t>(j)];
232 }
233
234 47 send_b[static_cast<std::size_t>(i)] = b_in[static_cast<std::size_t>(i)];
235 }
236 }
237
1/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
24 std::vector<int> counts_a(size);
238
1/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
24 std::vector<int> displs_a(size);
239
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
72 for (int res = 0; res < size; ++res) {
240 48 counts_a[res] = row_cnts[res] * w;
241 48 displs_a[res] = row_disp[res] * w;
242 }
243
244
1/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
24 std::vector<double> a_loc(static_cast<std::size_t>(loc_rows * static_cast<std::size_t>(w)), 0.0);
245
1/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
24 std::vector<double> b_loc(static_cast<std::size_t>(loc_rows), 0.0);
246
247
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
36 MPI_Scatterv(rank == 0 ? send_a.data() : nullptr, counts_a.data(), displs_a.data(), MPI_DOUBLE, a_loc.data(),
248
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 counts_a[rank], MPI_DOUBLE, 0, MPI_COMM_WORLD);
249
250
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
36 MPI_Scatterv(rank == 0 ? send_b.data() : nullptr, row_cnts.data(), row_disp.data(), MPI_DOUBLE, b_loc.data(),
251 loc_rows, MPI_DOUBLE, 0, MPI_COMM_WORLD);
252
253
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
24 if (!ForwardElimination(n, band_eff, w, rank, row_begin, loc_rows, owner_of_row, a_loc, b_loc)) {
254 return false;
255 }
256
257 24 std::vector<double> x;
258
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
24 if (!BackSubstitution(n, band_eff, w, rank, row_begin, owner_of_row, a_loc, b_loc, &x)) {
259 return false;
260 }
261
262 GetOutput().swap(x);
263 24 return !GetOutput().empty();
264 }
265 24 bool SannikovIHorizontalBandGaussMPI::PostProcessingImpl() {
266 (void)this;
267
268 24 return !GetOutput().empty();
269 }
270
271 } // namespace sannikov_i_horizontal_band_gauss
272