GCC Code Coverage Report


Directory: ./
File: tasks/afanasyev_a_it_seidel_method/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 106 110 96.4%
Functions: 8 8 100.0%
Branches: 74 108 68.5%

Line Branch Exec Source
1 #include "afanasyev_a_it_seidel_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 "afanasyev_a_it_seidel_method/common/include/common.hpp"
11
12 namespace afanasyev_a_it_seidel_method {
13
14 namespace {
15
16 62 double CalculateMaxDiff(const std::vector<double> &a, const std::vector<double> &b) {
17 62 double max_diff = 0.0;
18
2/2
✓ Branch 0 taken 370 times.
✓ Branch 1 taken 62 times.
432 for (std::size_t i = 0; i < a.size(); ++i) {
19 370 max_diff = std::max(max_diff, std::abs(a[i] - b[i]));
20 }
21 62 return max_diff;
22 }
23
24 void SafeVectorCopy(std::vector<double> &dest, const std::vector<double> &src) {
25
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (dest.size() == src.size()) {
26
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3 times.
21 for (std::size_t i = 0; i < src.size(); ++i) {
27 18 dest[i] = src[i];
28 }
29 }
30 }
31
32 62 bool PerformIteration(int system_size, int start_row, int end_row, const std::vector<std::vector<double>> &a,
33 const std::vector<double> &b, std::vector<double> &local_x, std::vector<double> &global_x) {
34
2/2
✓ Branch 0 taken 185 times.
✓ Branch 1 taken 62 times.
247 for (int i = start_row; i < end_row; ++i) {
35
1/2
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
185 if (i >= system_size) {
36 break;
37 }
38
39 185 double sum = b[i];
40
41
2/2
✓ Branch 0 taken 590 times.
✓ Branch 1 taken 185 times.
775 for (int j = 0; j < i; ++j) {
42 590 sum -= a[i][j] * global_x[j];
43 }
44
45
2/2
✓ Branch 0 taken 590 times.
✓ Branch 1 taken 185 times.
775 for (int j = i + 1; j < system_size; ++j) {
46 590 sum -= a[i][j] * global_x[j];
47 }
48
49 185 local_x[i] = sum / a[i][i];
50 }
51
52 62 int rank = 0;
53 62 int size = 0;
54 62 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
55 62 MPI_Comm_size(MPI_COMM_WORLD, &size);
56
57 62 int rows_per_process = system_size / size;
58 62 int remainder = system_size % size;
59
60 62 std::vector<int> sendcounts(size);
61
1/4
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
62 std::vector<int> displs(size);
62
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 62 times.
186 for (int proc = 0; proc < size; ++proc) {
63
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 42 times.
124 int cnt = rows_per_process + (proc < remainder ? 1 : 0);
64 124 sendcounts[proc] = cnt;
65 124 displs[proc] = (proc * rows_per_process) + std::min(proc, remainder);
66 }
67
68
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
62 int sendcount = end_row - start_row;
69
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
62 MPI_Allgatherv(local_x.data() + start_row, sendcount, MPI_DOUBLE, global_x.data(), sendcounts.data(), displs.data(),
70 MPI_DOUBLE, MPI_COMM_WORLD);
71
72 62 return true;
73 }
74
75 62 bool CheckConvergence(int rank, double max_diff, double epsilon, const std::vector<double> &global_x,
76 std::vector<double> &x) {
77
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 31 times.
62 if (rank == 0) {
78
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 28 times.
31 if (max_diff < epsilon) {
79 3 int converged = 1;
80 3 MPI_Bcast(&converged, 1, MPI_INT, 0, MPI_COMM_WORLD);
81 SafeVectorCopy(x, global_x);
82 return true;
83 }
84
85 28 int converged = 0;
86 28 MPI_Bcast(&converged, 1, MPI_INT, 0, MPI_COMM_WORLD);
87 } else {
88 31 int converged = 0;
89 31 MPI_Bcast(&converged, 1, MPI_INT, 0, MPI_COMM_WORLD);
90
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 28 times.
31 if (converged != 0) {
91 3 return true;
92 }
93 }
94
95 return false;
96 }
97 } // namespace
98
99
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 AfanasyevAItSeidelMethodMPI::AfanasyevAItSeidelMethodMPI(const InType &in) {
100 SetTypeOfTask(GetStaticTypeOfTask());
101
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 GetInput() = in;
102 6 GetOutput() = std::vector<double>();
103 6 }
104
105 6 bool AfanasyevAItSeidelMethodMPI::ValidationImpl() {
106 6 return GetInput().size() >= 3;
107 }
108
109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 bool AfanasyevAItSeidelMethodMPI::PreProcessingImpl() {
110 try {
111 6 int system_size = static_cast<int>(GetInput()[0]);
112 6 epsilon_ = GetInput()[1];
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 max_iterations_ = static_cast<int>(GetInput()[2]);
114
115 A_.clear();
116
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 A_.resize(system_size);
117
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 6 times.
42 for (int i = 0; i < system_size; ++i) {
118
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 A_[i].resize(system_size);
119
2/2
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 36 times.
304 for (int j = 0; j < system_size; ++j) {
120
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 232 times.
268 if (i == j) {
121 36 A_[i][j] = system_size + 1.0;
122 } else {
123 232 A_[i][j] = 1.0 / (std::abs(i - j) + 1.0);
124 }
125 }
126 }
127
128 b_.clear();
129
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 b_.resize(system_size);
130
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 6 times.
42 for (int i = 0; i < system_size; ++i) {
131 36 b_[i] = i + 1.0;
132 }
133
134 x_.clear();
135
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 x_.resize(system_size, 0.0);
136
137 6 return true;
138 } catch (...) {
139 return false;
140 }
141 }
142
143 6 bool AfanasyevAItSeidelMethodMPI::RunImpl() {
144 6 int rank = 0;
145 6 int size = 0;
146 6 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
147 6 MPI_Comm_size(MPI_COMM_WORLD, &size);
148
149 6 int system_size = static_cast<int>(A_.size());
150
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (system_size == 0) {
151 return false;
152 }
153
154 6 int rows_per_process = system_size / size;
155 6 int remainder = system_size % size;
156
157
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 int start_row = (rank * rows_per_process) + std::min(rank, remainder);
158
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 int end_row = start_row + rows_per_process + (rank < remainder ? 1 : 0);
159
160 6 std::vector<double> local_x(system_size, 0.0);
161
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 std::vector<double> global_x(system_size, 0.0);
162
163
1/2
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
62 for (int iter = 0; iter < max_iterations_; ++iter) {
164
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
62 std::vector<double> prev_x = global_x;
165
166
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
62 if (!PerformIteration(system_size, start_row, end_row, A_, b_, local_x, global_x)) {
167 return false;
168 }
169
170
3/4
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 6 times.
62 if (CheckConvergence(rank, CalculateMaxDiff(global_x, prev_x), epsilon_, global_x, x_)) {
171 break;
172 }
173 }
174
175
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Barrier(MPI_COMM_WORLD);
176
177
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank == 0) {
178
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 OutType output;
179
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 output.reserve(x_.size());
180
3/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 3 times.
21 for (const double val : x_) {
181 output.push_back(val);
182 }
183
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 GetOutput() = output;
184 } else {
185 3 GetOutput() = std::vector<double>();
186 }
187 // Synchronize output on all ranks so tests running per-process can validate output
188 {
189 6 int out_size = static_cast<int>(GetOutput().size());
190
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Bcast(&out_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
191
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 GetOutput().resize(out_size);
192
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (out_size > 0) {
193
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Bcast(GetOutput().data(), out_size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
194 }
195 }
196
197 return true;
198 }
199
200 6 bool AfanasyevAItSeidelMethodMPI::PostProcessingImpl() {
201 try {
202 6 int rank = 0;
203
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
204
205
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank != 0) {
206 return true;
207 }
208
209 3 int system_size = static_cast<int>(A_.size());
210
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (x_.size() != static_cast<std::size_t>(system_size)) {
211 return false;
212 }
213
214 double residual_norm = 0.0;
215
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3 times.
21 for (int i = 0; i < system_size; ++i) {
216 double sum = 0.0;
217
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 18 times.
152 for (int j = 0; j < system_size; ++j) {
218 134 sum += A_[i][j] * x_[j];
219 }
220 18 residual_norm += std::abs(sum - b_[i]);
221 }
222
223 3 residual_norm /= system_size;
224 3 return residual_norm < epsilon_ * 1000;
225 } catch (...) {
226 return false;
227 }
228 }
229
230 } // namespace afanasyev_a_it_seidel_method
231