| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "shilin_n_gauss_band_horizontal_scheme/mpi/include/ops_mpi.hpp" | ||
| 2 | |||
| 3 | #include <mpi.h> | ||
| 4 | |||
| 5 | #include <cmath> | ||
| 6 | #include <cstddef> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "shilin_n_gauss_band_horizontal_scheme/common/include/common.hpp" | ||
| 10 | |||
| 11 | namespace shilin_n_gauss_band_horizontal_scheme { | ||
| 12 | |||
| 13 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | ShilinNGaussBandHorizontalSchemeMPI::ShilinNGaussBandHorizontalSchemeMPI(const InType &in) { |
| 14 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 15 | 12 | int rank = 0; | |
| 16 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); |
| 17 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 18 | InType &input_ref = GetInput(); | ||
| 19 | input_ref.clear(); | ||
| 20 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | input_ref.reserve(in.size()); |
| 21 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 6 times.
|
42 | for (const auto &row : in) { |
| 22 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | input_ref.push_back(row); |
| 23 | } | ||
| 24 | } | ||
| 25 | 12 | GetOutput() = std::vector<double>(); | |
| 26 | 12 | } | |
| 27 | |||
| 28 | 12 | bool ShilinNGaussBandHorizontalSchemeMPI::ValidationImpl() { | |
| 29 | 12 | int rank = 0; | |
| 30 | 12 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 31 | |||
| 32 | 12 | int validation_result = 1; | |
| 33 | |||
| 34 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 35 | const InType &input = GetInput(); | ||
| 36 | 6 | validation_result = ValidateInput(input); | |
| 37 | } | ||
| 38 | |||
| 39 | 12 | MPI_Bcast(&validation_result, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 40 | |||
| 41 | 12 | return validation_result != 0; | |
| 42 | } | ||
| 43 | |||
| 44 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | int ShilinNGaussBandHorizontalSchemeMPI::ValidateInput(const InType &input) { |
| 45 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (input.empty()) { |
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | size_t n = input.size(); | ||
| 50 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (n == 0) { |
| 51 | return 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | size_t cols = input[0].size(); | ||
| 55 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (cols < n + 1) { |
| 56 | return 0; | ||
| 57 | } | ||
| 58 | |||
| 59 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 6 times.
|
36 | for (size_t i = 1; i < n; ++i) { |
| 60 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (input[i].size() != cols) { |
| 61 | return 0; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | return 1; | ||
| 66 | } | ||
| 67 | |||
| 68 | 12 | bool ShilinNGaussBandHorizontalSchemeMPI::PreProcessingImpl() { | |
| 69 | 12 | GetOutput() = std::vector<double>(); | |
| 70 | 12 | return true; | |
| 71 | } | ||
| 72 | |||
| 73 | 12 | bool ShilinNGaussBandHorizontalSchemeMPI::RunImpl() { | |
| 74 | 12 | int rank = 0; | |
| 75 | 12 | int size = 0; | |
| 76 | 12 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 77 | 12 | MPI_Comm_size(MPI_COMM_WORLD, &size); | |
| 78 | |||
| 79 | 12 | InType augmented_matrix; | |
| 80 | size_t n = 0; | ||
| 81 | size_t cols = 0; | ||
| 82 | |||
| 83 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 84 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | augmented_matrix = GetInput(); |
| 85 | n = augmented_matrix.size(); | ||
| 86 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | cols = (n > 0) ? augmented_matrix[0].size() : 0; |
| 87 | } | ||
| 88 | |||
| 89 | 12 | int n_int = static_cast<int>(n); | |
| 90 | 12 | int cols_int = static_cast<int>(cols); | |
| 91 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | MPI_Bcast(&n_int, 1, MPI_INT, 0, MPI_COMM_WORLD); |
| 92 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | MPI_Bcast(&cols_int, 1, MPI_INT, 0, MPI_COMM_WORLD); |
| 93 | 12 | n = static_cast<size_t>(n_int); | |
| 94 | 12 | cols = static_cast<size_t>(cols_int); | |
| 95 | |||
| 96 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
12 | if (n == 0 || cols < n + 1) { |
| 97 | return false; | ||
| 98 | } | ||
| 99 | |||
| 100 | 12 | InType local_matrix; | |
| 101 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | std::vector<int> global_to_local(n, -1); |
| 102 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | DistributeRows(augmented_matrix, n, cols, rank, size, local_matrix, global_to_local); |
| 103 | |||
| 104 |
2/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
|
12 | if (!ForwardEliminationMPI(local_matrix, global_to_local, n, cols, rank, size)) { |
| 105 | return false; | ||
| 106 | } | ||
| 107 | |||
| 108 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | std::vector<double> x = BackSubstitutionMPI(local_matrix, global_to_local, n, cols, rank, size); |
| 109 | |||
| 110 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | GetOutput() = x; |
| 111 | |||
| 112 | return true; | ||
| 113 | 12 | } | |
| 114 | |||
| 115 | 12 | void ShilinNGaussBandHorizontalSchemeMPI::DistributeRows(const InType &augmented_matrix, size_t n, size_t cols, | |
| 116 | int rank, int size, InType &local_matrix, | ||
| 117 | std::vector<int> &global_to_local) { | ||
| 118 | // распределение строк по round-robin: строка i -> процесс i % size | ||
| 119 | int local_rows = 0; | ||
| 120 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 12 times.
|
84 | for (size_t i = 0; i < n; ++i) { |
| 121 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
|
72 | if (static_cast<int>(i) % size == rank) { |
| 122 | 36 | local_rows++; | |
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 |
1/2✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
12 | local_matrix = InType(local_rows, std::vector<double>(cols)); |
| 127 | // маппинг глобальных индексов строк на локальные индексы | ||
| 128 | int local_idx = 0; | ||
| 129 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 12 times.
|
84 | for (size_t i = 0; i < n; ++i) { |
| 130 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
|
72 | if (static_cast<int>(i) % size == rank) { |
| 131 | 36 | global_to_local[i] = local_idx; | |
| 132 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 17 times.
|
36 | if (rank == 0) { |
| 133 | 19 | local_matrix[local_idx] = augmented_matrix[i]; | |
| 134 | } else { | ||
| 135 | 17 | MPI_Recv(local_matrix[local_idx].data(), static_cast<int>(cols), MPI_DOUBLE, 0, static_cast<int>(i), | |
| 136 | MPI_COMM_WORLD, MPI_STATUS_IGNORE); | ||
| 137 | } | ||
| 138 | 36 | local_idx++; | |
| 139 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 17 times.
|
36 | } else if (rank == 0) { |
| 140 | 17 | MPI_Send(augmented_matrix[i].data(), static_cast<int>(cols), MPI_DOUBLE, static_cast<int>(i) % size, | |
| 141 | static_cast<int>(i), MPI_COMM_WORLD); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | 12 | } | |
| 145 | |||
| 146 | 12 | bool ShilinNGaussBandHorizontalSchemeMPI::ForwardEliminationMPI(InType &local_matrix, | |
| 147 | const std::vector<int> &global_to_local, size_t n, | ||
| 148 | size_t cols, int rank, int size) { | ||
| 149 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 12 times.
|
84 | for (size_t k = 0; k < n; ++k) { |
| 150 | // определение процесса-владельца ведущей строки | ||
| 151 | 72 | int owner_process = static_cast<int>(k) % size; | |
| 152 | |||
| 153 | 72 | std::vector<double> pivot_row(cols); | |
| 154 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
|
72 | if (rank == owner_process) { |
| 155 | 36 | int local_k = global_to_local[k]; | |
| 156 |
2/4✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
|
36 | if (local_k >= 0 && static_cast<size_t>(local_k) < local_matrix.size()) { |
| 157 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | pivot_row = local_matrix[static_cast<size_t>(local_k)]; |
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | // рассылка ведущей строки всем процессам для исключения | ||
| 162 |
1/2✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
|
72 | MPI_Bcast(pivot_row.data(), static_cast<int>(cols), MPI_DOUBLE, owner_process, MPI_COMM_WORLD); |
| 163 | |||
| 164 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
|
72 | if (std::abs(pivot_row[k]) < 1e-10) { |
| 165 | return false; | ||
| 166 | } | ||
| 167 | |||
| 168 | 72 | EliminateColumnMPI(local_matrix, global_to_local, k, n, cols, pivot_row); | |
| 169 | } | ||
| 170 | return true; | ||
| 171 | } | ||
| 172 | |||
| 173 | 72 | void ShilinNGaussBandHorizontalSchemeMPI::EliminateColumnMPI(InType &local_matrix, | |
| 174 | const std::vector<int> &global_to_local, size_t k, | ||
| 175 | size_t n, size_t cols, | ||
| 176 | const std::vector<double> &pivot_row) { | ||
| 177 | // исключение элементов в локальных строках | ||
| 178 |
2/2✓ Branch 0 taken 250 times.
✓ Branch 1 taken 72 times.
|
322 | for (size_t i = 0; i < local_matrix.size(); ++i) { |
| 179 | size_t global_i = GetGlobalIndex(global_to_local, i, n); | ||
| 180 | |||
| 181 |
4/4✓ Branch 0 taken 107 times.
✓ Branch 1 taken 143 times.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 44 times.
|
250 | if (global_i > k && std::abs(local_matrix[i][k]) > 1e-10) { |
| 182 | 63 | double factor = local_matrix[i][k] / pivot_row[k]; | |
| 183 |
2/2✓ Branch 0 taken 394 times.
✓ Branch 1 taken 63 times.
|
457 | for (size_t j = k; j < cols; ++j) { |
| 184 | 394 | local_matrix[i][j] -= factor * pivot_row[j]; | |
| 185 | } | ||
| 186 | } | ||
| 187 | } | ||
| 188 | 72 | } | |
| 189 | |||
| 190 | ✗ | size_t ShilinNGaussBandHorizontalSchemeMPI::GetGlobalIndex(const std::vector<int> &global_to_local, size_t local_idx, | |
| 191 | size_t n) { | ||
| 192 | // восстановление глобального индекса из локального | ||
| 193 | 250 | const int local_idx_int = static_cast<int>(local_idx); | |
| 194 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1097 times.
✗ Branch 3 not taken.
|
1097 | for (size_t gi = 0; gi < n; ++gi) { |
| 195 |
4/8✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 613 times.
✓ Branch 5 taken 484 times.
✓ Branch 6 taken 363 times.
✓ Branch 7 taken 250 times.
|
1097 | if (global_to_local[gi] >= 0 && global_to_local[gi] == local_idx_int) { |
| 196 | return gi; | ||
| 197 | } | ||
| 198 | } | ||
| 199 | return 0; | ||
| 200 | } | ||
| 201 | |||
| 202 | 12 | std::vector<double> ShilinNGaussBandHorizontalSchemeMPI::BackSubstitutionMPI(const InType &local_matrix, | |
| 203 | const std::vector<int> &global_to_local, | ||
| 204 | size_t n, size_t cols, int rank, | ||
| 205 | int size) { | ||
| 206 | // обратный ход с синхронизацией между процессами | ||
| 207 | 12 | std::vector<double> x(n, 0.0); | |
| 208 | |||
| 209 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 12 times.
|
84 | for (int i = static_cast<int>(n) - 1; i >= 0; --i) { |
| 210 | double sum = 0.0; | ||
| 211 | 72 | int owner_process = i % size; | |
| 212 | |||
| 213 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
|
72 | if (rank == owner_process) { |
| 214 |
1/2✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
|
36 | int local_i = global_to_local[static_cast<size_t>(i)]; |
| 215 |
2/4✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
|
36 | if (local_i >= 0 && static_cast<size_t>(local_i) < local_matrix.size()) { |
| 216 |
2/2✓ Branch 0 taken 107 times.
✓ Branch 1 taken 36 times.
|
143 | for (size_t j = static_cast<size_t>(i) + 1; j < n; ++j) { |
| 217 | 107 | sum += local_matrix[static_cast<size_t>(local_i)][j] * x[j]; | |
| 218 | } | ||
| 219 | 36 | x[static_cast<size_t>(i)] = (local_matrix[static_cast<size_t>(local_i)][cols - 1] - sum) / | |
| 220 | local_matrix[static_cast<size_t>(local_i)][static_cast<size_t>(i)]; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | // рассылка вычисленного значения для использования в следующих итерациях | ||
| 225 |
1/2✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
|
72 | MPI_Bcast(&x[static_cast<size_t>(i)], 1, MPI_DOUBLE, owner_process, MPI_COMM_WORLD); |
| 226 | } | ||
| 227 | |||
| 228 | 12 | return x; | |
| 229 | } | ||
| 230 | |||
| 231 | 12 | bool ShilinNGaussBandHorizontalSchemeMPI::PostProcessingImpl() { | |
| 232 | 12 | int rank = 0; | |
| 233 | 12 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 234 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | return (rank == 0) ? !GetOutput().empty() : true; |
| 235 | } | ||
| 236 | |||
| 237 | } // namespace shilin_n_gauss_band_horizontal_scheme | ||
| 238 |