GCC Code Coverage Report


Directory: ./
File: tasks/shkryleva_s_seidel_method/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 107 107 100.0%
Functions: 10 10 100.0%
Branches: 57 92 62.0%

Line Branch Exec Source
1 #include "shkryleva_s_seidel_method/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cmath>
7 #include <cstddef>
8 #include <random>
9 #include <vector>
10
11 #include "shkryleva_s_seidel_method/common/include/common.hpp"
12
13 namespace shkryleva_s_seidel_method {
14
15 20 ShkrylevaSSeidelMethodMPI::ShkrylevaSSeidelMethodMPI(const InType &in) {
16 SetTypeOfTask(GetStaticTypeOfTask());
17 20 GetInput() = in;
18 GetOutput() = 0;
19 20 }
20
21 20 bool ShkrylevaSSeidelMethodMPI::ValidationImpl() {
22 20 int rank = 0;
23 20 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
24
25 20 int is_valid = 0;
26
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
27
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 is_valid = ((GetInput() > 0) && (GetOutput() == 0)) ? 1 : 0;
28 }
29 20 MPI_Bcast(&is_valid, 1, MPI_INT, 0, MPI_COMM_WORLD);
30
31 20 return is_valid != 0;
32 }
33
34 20 bool ShkrylevaSSeidelMethodMPI::PreProcessingImpl() {
35 20 int rank = 0;
36 20 int size = 0;
37 20 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
38 20 MPI_Comm_size(MPI_COMM_WORLD, &size);
39
40 20 GetOutput() = 0;
41
42 20 MPI_Barrier(MPI_COMM_WORLD);
43 20 return true;
44 }
45
46 20 bool ShkrylevaSSeidelMethodMPI::RunImpl() {
47 20 int n = GetInput();
48
49 20 int rank = 0;
50 20 int size = 1;
51 20 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
52 20 MPI_Comm_size(MPI_COMM_WORLD, &size);
53
54 20 std::vector<int> row_counts(size);
55
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<int> row_displs(size);
56
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<int> matrix_counts(size);
57
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<int> matrix_displs(size);
58 20 ComputeRowDistribution(n, size, row_counts, row_displs, matrix_counts, matrix_displs);
59
60
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 int local_rows = row_counts[rank];
61 20 int start_row = row_displs[rank];
62
63 20 std::vector<double> flat_matrix;
64 20 std::vector<double> b;
65
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
66
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 InitializeMatrixAndVector(flat_matrix, b, n);
67 }
68
69
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<double> local_matrix(static_cast<size_t>(local_rows) * n, 0.0);
70
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MPI_Scatterv(flat_matrix.data(), matrix_counts.data(), matrix_displs.data(), MPI_DOUBLE, local_matrix.data(),
71 local_rows * n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
72
73
2/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20 std::vector<double> local_b(local_rows, 0.0);
74
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MPI_Scatterv(b.data(), row_counts.data(), row_displs.data(), MPI_DOUBLE, local_b.data(), local_rows, MPI_DOUBLE, 0,
75 MPI_COMM_WORLD);
76
77
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<double> x(n, 0.0);
78 const double epsilon = 1e-6;
79 const int max_iterations = 10000;
80
81
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 bool converged = SolveIteratively(local_rows, start_row, n, local_matrix, local_b, x, row_counts, row_displs, epsilon,
82 max_iterations);
83
84
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (!converged) {
85 return false;
86 }
87
88
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
89 double sum = 0.0;
90
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 10 times.
156 for (int i = 0; i < n; i++) {
91 146 sum += x[i];
92 }
93 10 GetOutput() = static_cast<int>(std::round(sum));
94 }
95
96
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MPI_Bcast(&GetOutput(), 1, MPI_INT, 0, MPI_COMM_WORLD);
97 return true;
98 }
99
100 20 bool ShkrylevaSSeidelMethodMPI::PostProcessingImpl() {
101 20 return true;
102 }
103
104 20 void ShkrylevaSSeidelMethodMPI::ComputeRowDistribution(int n, int size, std::vector<int> &row_counts,
105 std::vector<int> &row_displs, std::vector<int> &matrix_counts,
106 std::vector<int> &matrix_displs) {
107 int row_offset = 0;
108 int matrix_offset = 0;
109
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (int proc = 0; proc < size; proc++) {
110 40 int base_rows = n / size;
111
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 12 times.
40 int extra = (proc < (n % size)) ? 1 : 0;
112 40 int proc_rows = base_rows + extra;
113
114 40 row_counts[proc] = proc_rows;
115 40 row_displs[proc] = row_offset;
116 40 matrix_counts[proc] = proc_rows * n;
117 40 matrix_displs[proc] = matrix_offset;
118
119 40 row_offset += proc_rows;
120 40 matrix_offset += proc_rows * n;
121 }
122 20 }
123
124 10 void ShkrylevaSSeidelMethodMPI::InitializeMatrixAndVector(std::vector<double> &flat_matrix, std::vector<double> &b,
125 int n) {
126 10 std::random_device rd;
127 10 std::mt19937 gen(rd());
128 std::uniform_int_distribution<> dist(1, 10);
129 std::uniform_int_distribution<> dist_diag(1, 5);
130
131
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 flat_matrix.resize(static_cast<size_t>(n) * n, 0.0);
132
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 b.resize(n, 0.0);
133
134
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 10 times.
156 for (int i = 0; i < n; i++) {
135 double row_sum = 0.0;
136
137
2/2
✓ Branch 0 taken 3514 times.
✓ Branch 1 taken 146 times.
3660 for (int j = 0; j < n; j++) {
138
2/2
✓ Branch 0 taken 3368 times.
✓ Branch 1 taken 146 times.
3514 if (i != j) {
139 3368 auto val = static_cast<double>(dist(gen));
140 3368 flat_matrix[(static_cast<size_t>(i) * n) + j] = val;
141 3368 row_sum += std::abs(val);
142 }
143 }
144
145 146 flat_matrix[(static_cast<size_t>(i) * n) + i] = row_sum + static_cast<double>(dist_diag(gen));
146 }
147
148
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 std::vector<double> x_exact(n, 1.0);
149
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 10 times.
156 for (int i = 0; i < n; i++) {
150 double sum = 0.0;
151
2/2
✓ Branch 0 taken 3514 times.
✓ Branch 1 taken 146 times.
3660 for (int j = 0; j < n; j++) {
152 3514 sum += flat_matrix[(static_cast<size_t>(i) * n) + j] * x_exact[j];
153 }
154 146 b[i] = sum;
155 }
156 10 }
157
158 544 double ShkrylevaSSeidelMethodMPI::PerformLocalIteration(int local_rows, int start_row, int n,
159 const std::vector<double> &local_matrix,
160 const std::vector<double> &local_b, std::vector<double> &x) {
161 544 double local_max_diff = 0.0;
162
2/2
✓ Branch 0 taken 3671 times.
✓ Branch 1 taken 544 times.
4215 for (int i = 0; i < local_rows; i++) {
163 3671 int global_i = start_row + i;
164 double sum_off_diag = 0.0;
165
166
2/2
✓ Branch 0 taken 86397 times.
✓ Branch 1 taken 3671 times.
90068 for (int j = 0; j < n; j++) {
167
2/2
✓ Branch 0 taken 82726 times.
✓ Branch 1 taken 3671 times.
86397 if (j != global_i) {
168 82726 sum_off_diag += local_matrix[(static_cast<size_t>(i) * n) + j] * x[j];
169 }
170 }
171
172 3671 const double new_xi = (local_b[i] - sum_off_diag) / local_matrix[(static_cast<size_t>(i) * n) + global_i];
173 3671 const double diff = std::abs(new_xi - x[global_i]);
174 3671 local_max_diff = std::max(diff, local_max_diff);
175 3671 x[global_i] = new_xi;
176 }
177 544 return local_max_diff;
178 }
179
180 544 void ShkrylevaSSeidelMethodMPI::GatherX(int local_rows, int start_row, std::vector<double> &x,
181 const std::vector<int> &row_counts, const std::vector<int> &row_displs) {
182 544 std::vector<double> local_x_updated(local_rows);
183
2/2
✓ Branch 0 taken 3671 times.
✓ Branch 1 taken 544 times.
4215 for (int i = 0; i < local_rows; ++i) {
184 3671 local_x_updated[i] = x[start_row + i];
185 }
186
187
1/2
✓ Branch 1 taken 544 times.
✗ Branch 2 not taken.
544 MPI_Allgatherv(local_x_updated.data(), local_rows, MPI_DOUBLE, x.data(), row_counts.data(), row_displs.data(),
188 MPI_DOUBLE, MPI_COMM_WORLD);
189 544 }
190
191 20 bool ShkrylevaSSeidelMethodMPI::SolveIteratively(int local_rows, int start_row, int n,
192 const std::vector<double> &local_matrix,
193 const std::vector<double> &local_b, std::vector<double> &x,
194 const std::vector<int> &row_counts, const std::vector<int> &row_displs,
195 double epsilon, int max_iterations) {
196 int iteration = 0;
197
198
1/2
✓ Branch 0 taken 544 times.
✗ Branch 1 not taken.
544 while (iteration < max_iterations) {
199 544 std::vector<double> x_old = x;
200
201 544 double local_max_diff = PerformLocalIteration(local_rows, start_row, n, local_matrix, local_b, x);
202
203
1/2
✓ Branch 1 taken 544 times.
✗ Branch 2 not taken.
544 GatherX(local_rows, start_row, x, row_counts, row_displs);
204
205 544 double global_max_diff = 0.0;
206
1/2
✓ Branch 1 taken 544 times.
✗ Branch 2 not taken.
544 MPI_Allreduce(&local_max_diff, &global_max_diff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
207
208
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 524 times.
544 if (global_max_diff < epsilon) {
209 return true;
210 }
211
212
1/2
✓ Branch 0 taken 524 times.
✗ Branch 1 not taken.
524 ++iteration;
213 }
214
215 return false;
216 }
217
218 } // namespace shkryleva_s_seidel_method
219