GCC Code Coverage Report


Directory: ./
File: tasks/dergachev_a_simple_iteration_method/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 104 104 100.0%
Functions: 11 11 100.0%
Branches: 55 94 58.5%

Line Branch Exec Source
1 #include "dergachev_a_simple_iteration_method/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cmath>
6 #include <cstddef>
7 #include <vector>
8
9 #include "dergachev_a_simple_iteration_method/common/include/common.hpp"
10
11 namespace dergachev_a_simple_iteration_method {
12
13 namespace {
14
15 20 void ComputeRowDistribution(int n, int size, std::vector<int> &row_counts, std::vector<int> &row_displs,
16 std::vector<int> &matrix_counts, std::vector<int> &matrix_displs) {
17 int row_offset = 0;
18 int matrix_offset = 0;
19
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (int proc = 0; proc < size; proc++) {
20 40 int base_rows = n / size;
21
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 10 times.
40 int extra = (proc < (n % size)) ? 1 : 0;
22 40 int proc_rows = base_rows + extra;
23
24 40 row_counts[proc] = proc_rows;
25 40 row_displs[proc] = row_offset;
26 40 matrix_counts[proc] = proc_rows * n;
27 40 matrix_displs[proc] = matrix_offset;
28
29 40 row_offset += proc_rows;
30 40 matrix_offset += proc_rows * n;
31 }
32 20 }
33
34 10 int ComputeFinalResult(const std::vector<double> &x, int n) {
35 double sum = 0.0;
36
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 10 times.
153 for (int i = 0; i < n; i++) {
37 143 sum += x[i];
38 }
39 10 return static_cast<int>(std::round(sum));
40 }
41
42 10 void InitializeMatrixAndVector(std::vector<double> &flat_matrix, std::vector<double> &b, int n) {
43 10 flat_matrix.resize(static_cast<std::size_t>(n) * n, 0.0);
44
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 10 times.
153 for (int i = 0; i < n; i++) {
45 143 flat_matrix[(static_cast<std::size_t>(i) * n) + i] = 1.0;
46 }
47 10 b.resize(n, 1.0);
48 10 }
49
50 438 void ComputeLocalProduct(const std::vector<double> &local_matrix, const std::vector<double> &x,
51 const std::vector<double> &local_b, std::vector<double> &local_x_new, int local_rows,
52 int start_row, int n, double tau) {
53
2/2
✓ Branch 0 taken 3239 times.
✓ Branch 1 taken 438 times.
3677 for (int i = 0; i < local_rows; i++) {
54 double ax_i = 0.0;
55
2/2
✓ Branch 0 taken 96471 times.
✓ Branch 1 taken 3239 times.
99710 for (int j = 0; j < n; j++) {
56 96471 ax_i += local_matrix[(static_cast<std::size_t>(i) * n) + j] * x[j];
57 }
58 3239 local_x_new[i] = x[start_row + i] - (tau * (ax_i - local_b[i]));
59 }
60 438 }
61
62 438 void GatherResults(const std::vector<double> &local_x_new, std::vector<double> &x_new,
63 const std::vector<int> &row_counts, const std::vector<int> &row_displs, int rank, int size,
64 int local_rows, int start_row) {
65
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 219 times.
438 if (rank == 0) {
66
2/2
✓ Branch 0 taken 1673 times.
✓ Branch 1 taken 219 times.
1892 for (int i = 0; i < local_rows; i++) {
67 1673 x_new[start_row + i] = local_x_new[i];
68 }
69
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 219 times.
438 for (int proc = 1; proc < size; proc++) {
70 219 MPI_Recv(x_new.data() + row_displs[proc], row_counts[proc], MPI_DOUBLE, proc, 0, MPI_COMM_WORLD,
71 MPI_STATUS_IGNORE);
72 }
73 } else {
74 219 MPI_Send(local_x_new.data(), local_rows, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
75 }
76 438 }
77
78 double ComputeLocalDiff(const std::vector<double> &x_new, const std::vector<double> &x, int local_rows, int start_row) {
79 double local_diff = 0.0;
80
2/2
✓ Branch 0 taken 3239 times.
✓ Branch 1 taken 438 times.
3677 for (int i = 0; i < local_rows; i++) {
81 3239 double d = x_new[start_row + i] - x[start_row + i];
82 3239 local_diff += d * d;
83 }
84 return local_diff;
85 }
86
87 438 int CheckConvergence(double local_diff, double epsilon, int rank) {
88 438 double global_diff = 0.0;
89 438 MPI_Reduce(&local_diff, &global_diff, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
90
91 438 int converged = 0;
92
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 219 times.
438 if (rank == 0) {
93 219 global_diff = std::sqrt(global_diff);
94
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 10 times.
428 converged = (global_diff < epsilon) ? 1 : 0;
95 }
96 438 MPI_Bcast(&converged, 1, MPI_INT, 0, MPI_COMM_WORLD);
97 438 return converged;
98 }
99
100 } // namespace
101
102 20 DergachevASimpleIterationMethodMPI::DergachevASimpleIterationMethodMPI(const InType &in) {
103 SetTypeOfTask(GetStaticTypeOfTask());
104 20 GetInput() = in;
105 GetOutput() = 0;
106 20 }
107
108 20 bool DergachevASimpleIterationMethodMPI::ValidationImpl() {
109 20 int rank = 0;
110 20 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
111
112 20 int is_valid = 0;
113
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
114
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;
115 }
116 20 MPI_Bcast(&is_valid, 1, MPI_INT, 0, MPI_COMM_WORLD);
117
118 20 return is_valid != 0;
119 }
120
121 20 bool DergachevASimpleIterationMethodMPI::PreProcessingImpl() {
122 20 int rank = 0;
123 20 int size = 0;
124 20 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
125 20 MPI_Comm_size(MPI_COMM_WORLD, &size);
126
127
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (size < 1) {
128 return false;
129 }
130
131 20 GetOutput() = 0;
132
133 20 MPI_Barrier(MPI_COMM_WORLD);
134 return true;
135 }
136
137 20 bool DergachevASimpleIterationMethodMPI::RunImpl() {
138 20 int n = GetInput();
139
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (n <= 0) {
140 return false;
141 }
142
143 20 int rank = 0;
144 20 int size = 1;
145 20 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
146 20 MPI_Comm_size(MPI_COMM_WORLD, &size);
147
148 20 std::vector<int> row_counts(size);
149
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);
150
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);
151
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);
152 20 ComputeRowDistribution(n, size, row_counts, row_displs, matrix_counts, matrix_displs);
153
154
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 int local_rows = row_counts[rank];
155 20 int start_row = row_displs[rank];
156
157 20 std::vector<double> flat_matrix;
158 20 std::vector<double> b;
159
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);
160
161
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
162
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 InitializeMatrixAndVector(flat_matrix, b, n);
163 }
164
165
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<std::size_t>(local_rows) * n, 0.0);
166
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(),
167 local_rows * n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
168
169
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);
170
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,
171 MPI_COMM_WORLD);
172
173 const double tau = 0.5;
174 const double epsilon = 1e-6;
175 const int max_iterations = 1000;
176
177
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<double> local_x_new(local_rows, 0.0);
178
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<double> x_new(n, 0.0);
179
180
1/2
✓ Branch 0 taken 438 times.
✗ Branch 1 not taken.
438 for (int iteration = 0; iteration < max_iterations; iteration++) {
181 438 ComputeLocalProduct(local_matrix, x, local_b, local_x_new, local_rows, start_row, n, tau);
182
1/2
✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
438 GatherResults(local_x_new, x_new, row_counts, row_displs, rank, size, local_rows, start_row);
183
1/2
✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
438 MPI_Bcast(x_new.data(), n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
184
185 double local_diff = ComputeLocalDiff(x_new, x, local_rows, start_row);
186
1/2
✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
438 int converged = CheckConvergence(local_diff, epsilon, rank);
187
188
1/2
✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
438 x = x_new;
189
190
2/2
✓ Branch 0 taken 418 times.
✓ Branch 1 taken 20 times.
438 if (converged != 0) {
191 break;
192 }
193 }
194
195
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
196 10 GetOutput() = ComputeFinalResult(x, n);
197 }
198
199
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MPI_Bcast(&GetOutput(), 1, MPI_INT, 0, MPI_COMM_WORLD);
200
201 return true;
202 }
203
204 20 bool DergachevASimpleIterationMethodMPI::PostProcessingImpl() {
205 20 return GetOutput() > 0;
206 }
207
208 } // namespace dergachev_a_simple_iteration_method
209