GCC Code Coverage Report


Directory: ./
File: tasks/klimenko_v_seidel_method/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 106 110 96.4%
Functions: 9 11 81.8%
Branches: 59 98 60.2%

Line Branch Exec Source
1 #include "klimenko_v_seidel_method/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <climits>
6 #include <cmath>
7 #include <cstddef>
8 #include <random>
9 #include <vector>
10
11 #include "klimenko_v_seidel_method/common/include/common.hpp"
12
13 namespace klimenko_v_seidel_method {
14
15 20 KlimenkoVSeidelMethodMPI::KlimenkoVSeidelMethodMPI(const InType &in) {
16 SetTypeOfTask(GetStaticTypeOfTask());
17 20 GetInput() = in;
18 GetOutput() = 0;
19 20 }
20
21 20 bool KlimenkoVSeidelMethodMPI::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 KlimenkoVSeidelMethodMPI::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 KlimenkoVSeidelMethodMPI::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 = 1000;
80
81
1/2
✓ Branch 0 taken 262 times.
✗ Branch 1 not taken.
262 for (int iteration = 0; iteration < max_iterations; iteration++) {
82
1/2
✓ Branch 1 taken 262 times.
✗ Branch 2 not taken.
262 std::vector<double> x_old = x;
83
84 262 PerformSeidelIteration(local_rows, start_row, n, local_matrix, local_b, x);
85
86
1/4
✓ Branch 1 taken 262 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
262 std::vector<double> local_x_updated(local_rows);
87 UpdateLocalXVector(local_rows, start_row, x, local_x_updated);
88
89
1/2
✓ Branch 1 taken 262 times.
✗ Branch 2 not taken.
262 MPI_Allgatherv(local_x_updated.data(), local_rows, MPI_DOUBLE, x.data(), row_counts.data(), row_displs.data(),
90 MPI_DOUBLE, MPI_COMM_WORLD);
91
92 262 double local_diff = ComputeLocalDifference(local_rows, start_row, x, x_old);
93 262 double global_diff = 0.0;
94
1/2
✓ Branch 1 taken 262 times.
✗ Branch 2 not taken.
262 MPI_Allreduce(&local_diff, &global_diff, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
95 262 global_diff = std::sqrt(global_diff);
96
97
2/2
✓ Branch 0 taken 242 times.
✓ Branch 1 taken 20 times.
262 if (global_diff < epsilon) {
98 break;
99 }
100 }
101
102
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (rank == 0) {
103 10 GetOutput() = ComputeFinalResult(x, n);
104 }
105
106
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MPI_Bcast(&GetOutput(), 1, MPI_INT, 0, MPI_COMM_WORLD);
107 20 return true;
108 }
109
110 20 bool KlimenkoVSeidelMethodMPI::PostProcessingImpl() {
111 20 return GetOutput() > 0;
112 }
113
114 20 void KlimenkoVSeidelMethodMPI::ComputeRowDistribution(int n, int size, std::vector<int> &row_counts,
115 std::vector<int> &row_displs, std::vector<int> &matrix_counts,
116 std::vector<int> &matrix_displs) {
117 int row_offset = 0;
118 int matrix_offset = 0;
119
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (int proc = 0; proc < size; proc++) {
120 40 int base_rows = n / size;
121
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 10 times.
40 int extra = (proc < (n % size)) ? 1 : 0;
122 40 int proc_rows = base_rows + extra;
123
124 40 row_counts[proc] = proc_rows;
125 40 row_displs[proc] = row_offset;
126 40 matrix_counts[proc] = proc_rows * n;
127 40 matrix_displs[proc] = matrix_offset;
128
129 40 row_offset += proc_rows;
130 40 matrix_offset += proc_rows * n;
131 }
132 20 }
133
134 10 int KlimenkoVSeidelMethodMPI::ComputeFinalResult(const std::vector<double> &x, int n) {
135 double sum = 0.0;
136
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 10 times.
153 for (int i = 0; i < n; i++) {
137 143 sum += x[i];
138 }
139 10 return static_cast<int>(std::round(sum));
140 }
141
142 10 void KlimenkoVSeidelMethodMPI::InitializeMatrixAndVector(std::vector<double> &flat_matrix, std::vector<double> &b,
143 int n) {
144 10 std::random_device rd;
145 10 std::mt19937 gen(rd());
146 std::uniform_real_distribution<double> dist_off_diag(0.0, 1.0);
147 std::uniform_int_distribution<int> dist_diag(10, 19);
148
149
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 flat_matrix.resize(static_cast<size_t>(n) * n, 0.0);
150
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 b.resize(n, 0.0);
151
152
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 std::vector<double> x_exact(n, 1.0);
153
154
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 10 times.
153 for (int i = 0; i < n; i++) {
155 double row_sum = 0.0;
156
157
2/2
✓ Branch 0 taken 4213 times.
✓ Branch 1 taken 143 times.
4356 for (int j = 0; j < n; j++) {
158
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 4070 times.
4213 if (i == j) {
159 143 flat_matrix[(static_cast<size_t>(i) * n) + j] = static_cast<double>(dist_diag(gen));
160 } else {
161 double val = dist_off_diag(gen);
162 4070 flat_matrix[(static_cast<size_t>(i) * n) + j] = val;
163 4070 row_sum += std::abs(val);
164 }
165 }
166
167
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 81 times.
143 if (std::abs(flat_matrix[(static_cast<size_t>(i) * n) + i]) < row_sum) {
168 62 flat_matrix[(static_cast<size_t>(i) * n) + i] = row_sum + 1.0;
169 }
170 }
171
172
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 10 times.
153 for (int i = 0; i < n; i++) {
173 double sum = 0.0;
174
2/2
✓ Branch 0 taken 4213 times.
✓ Branch 1 taken 143 times.
4356 for (int j = 0; j < n; j++) {
175 4213 sum += flat_matrix[(static_cast<size_t>(i) * n) + j] * x_exact[j];
176 }
177 143 b[i] = sum;
178 }
179 10 }
180
181 262 void KlimenkoVSeidelMethodMPI::PerformSeidelIteration(int local_rows, int start_row, int n,
182 const std::vector<double> &local_matrix,
183 const std::vector<double> &local_b, std::vector<double> &x) {
184
2/2
✓ Branch 0 taken 2920 times.
✓ Branch 1 taken 262 times.
3182 for (int i = 0; i < local_rows; i++) {
185 2920 int global_i = start_row + i;
186 double sum_off_diag = 0.0;
187
188
2/2
✓ Branch 0 taken 100054 times.
✓ Branch 1 taken 2920 times.
102974 for (int j = 0; j < n; j++) {
189
2/2
✓ Branch 0 taken 97134 times.
✓ Branch 1 taken 2920 times.
100054 if (j != global_i) {
190 97134 sum_off_diag += local_matrix[(static_cast<size_t>(i) * n) + j] * x[j];
191 }
192 }
193
194 2920 x[global_i] = (local_b[i] - sum_off_diag) / local_matrix[(static_cast<size_t>(i) * n) + global_i];
195 }
196 262 }
197
198 void KlimenkoVSeidelMethodMPI::UpdateLocalXVector(int local_rows, int start_row, const std::vector<double> &x,
199 std::vector<double> &local_x_updated) {
200
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2920 times.
✓ Branch 3 taken 262 times.
3182 for (int i = 0; i < local_rows; ++i) {
201 2920 local_x_updated[i] = x[start_row + i];
202 }
203 }
204
205 double KlimenkoVSeidelMethodMPI::ComputeLocalDifference(int local_rows, int start_row, const std::vector<double> &x,
206 const std::vector<double> &x_old) {
207 double local_diff = 0.0;
208
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2920 times.
✓ Branch 3 taken 262 times.
3182 for (int i = 0; i < local_rows; i++) {
209 2920 int gi = start_row + i;
210 2920 double d = x[gi] - x_old[gi];
211 2920 local_diff += d * d;
212 }
213 return local_diff;
214 }
215
216 } // namespace klimenko_v_seidel_method
217