| 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 |