| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "kiselev_i_gauss_method_horizontal_tape_scheme/mpi/include/ops_mpi.hpp" | ||
| 2 | |||
| 3 | #include <mpi.h> | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cmath> | ||
| 7 | #include <cstddef> | ||
| 8 | #include <tuple> | ||
| 9 | #include <utility> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #include "kiselev_i_gauss_method_horizontal_tape_scheme/common/include/common.hpp" | ||
| 13 | |||
| 14 | namespace kiselev_i_gauss_method_horizontal_tape_scheme { | ||
| 15 | |||
| 16 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | KiselevITestTaskMPI::KiselevITestTaskMPI(const InType &in) { |
| 17 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 18 | auto &buf = GetInput(); | ||
| 19 | InType tmp(in); | ||
| 20 | buf.swap(tmp); | ||
| 21 | GetOutput().clear(); | ||
| 22 | 28 | } | |
| 23 | |||
| 24 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | bool KiselevITestTaskMPI::ValidationImpl() { |
| 25 | const auto &a_vector = std::get<0>(GetInput()); | ||
| 26 | const auto &b_vector = std::get<1>(GetInput()); | ||
| 27 |
3/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 28 times.
|
28 | return !a_vector.empty() && a_vector.size() == b_vector.size() && GetOutput().empty(); |
| 28 | } | ||
| 29 | |||
| 30 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | bool KiselevITestTaskMPI::PreProcessingImpl() { |
| 31 | GetOutput().clear(); | ||
| 32 | 28 | return true; | |
| 33 | } | ||
| 34 | |||
| 35 | namespace { | ||
| 36 | |||
| 37 | 28 | void MakePartition(int proc, int num, std::vector<int> &cnt, std::vector<int> &disp) { | |
| 38 | 28 | cnt.assign(proc, 0); | |
| 39 | 28 | disp.assign(proc, 0); | |
| 40 | |||
| 41 | 28 | const int q_coef = num / proc; | |
| 42 | 28 | const int r_coef = num % proc; | |
| 43 | int pos = 0; | ||
| 44 | |||
| 45 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 28 times.
|
84 | for (int index = 0; index < proc; ++index) { |
| 46 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 18 times.
|
94 | cnt[index] = q_coef + (index < r_coef ? 1 : 0); |
| 47 | 56 | disp[index] = pos; | |
| 48 | 56 | pos += cnt[index]; | |
| 49 | } | ||
| 50 | 28 | } | |
| 51 | |||
| 52 | int OwnerOf(int row, const std::vector<int> &cnt, const std::vector<int> &disp) { | ||
| 53 |
2/4✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 144 times.
✗ Branch 3 not taken.
|
288 | for (std::size_t proc = 0; proc < cnt.size(); ++proc) { |
| 54 |
6/8✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 144 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 102 times.
✓ Branch 7 taken 42 times.
|
288 | if (row >= disp[proc] && row < disp[proc] + cnt[proc]) { |
| 55 | 204 | return static_cast<int>(proc); | |
| 56 | } | ||
| 57 | } | ||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | 102 | bool BuildPivotRow(int k_index, int band, int w_coef, int rank, int owner, int row0, | |
| 62 | const std::vector<double> &a_vector, const std::vector<double> &b_vector, std::vector<double> &pivot, | ||
| 63 | double &rhs_pivot) { | ||
| 64 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 51 times.
|
102 | if (rank != owner) { |
| 65 | return true; | ||
| 66 | } | ||
| 67 | |||
| 68 | 51 | const int local_k = k_index - row0; | |
| 69 |
1/2✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
|
51 | const auto row_offset = static_cast<std::size_t>(local_k) * static_cast<std::size_t>(w_coef); |
| 70 | const double *row = &a_vector[row_offset]; | ||
| 71 | |||
| 72 | 51 | const double diag = row[band]; | |
| 73 |
1/2✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
|
51 | if (diag == 0.0) { |
| 74 | return false; | ||
| 75 | } | ||
| 76 | |||
| 77 | 51 | const int right = static_cast<int>(pivot.size()) - 1 + k_index; | |
| 78 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 51 times.
|
139 | for (int j = k_index; j <= right; ++j) { |
| 79 | 88 | pivot[j - k_index] = row[j - (k_index - band)]; | |
| 80 | } | ||
| 81 | |||
| 82 | 51 | rhs_pivot = b_vector[static_cast<std::size_t>(local_k)]; | |
| 83 | 51 | return true; | |
| 84 | } | ||
| 85 | |||
| 86 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | bool ApplyElimination(int k_index, int band, int w_coef, int row0, int local_rows, const std::vector<double> &pivot, |
| 87 | double rhs_pivot, std::vector<double> &a_vector, std::vector<double> &b_vector) { | ||
| 88 | 102 | const double diag = pivot[0]; | |
| 89 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | if (diag == 0.0) { |
| 90 | return false; | ||
| 91 | } | ||
| 92 | |||
| 93 | 102 | const int right = k_index + static_cast<int>(pivot.size()) - 1; | |
| 94 | 102 | const int row_begin = std::max(row0, k_index + 1); | |
| 95 | 102 | const int row_end = std::min(row0 + local_rows - 1, k_index + band); | |
| 96 | |||
| 97 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 102 times.
|
139 | for (int index = row_begin; index <= row_end; ++index) { |
| 98 | 37 | const int local_i = index - row0; | |
| 99 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | const auto row_offset = static_cast<std::size_t>(local_i) * static_cast<std::size_t>(w_coef); |
| 100 | double *row = &a_vector[row_offset]; | ||
| 101 | |||
| 102 | 37 | const int col = k_index - (index - band); | |
| 103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (col < 0 || col >= w_coef) { |
| 104 | ✗ | continue; | |
| 105 | } | ||
| 106 | |||
| 107 | 37 | const double multiplier = row[col] / diag; | |
| 108 | 37 | row[col] = 0.0; | |
| 109 | |||
| 110 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 37 times.
|
92 | for (int j = k_index + 1; j <= right; ++j) { |
| 111 | 55 | const int idx = j - (index - band); | |
| 112 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | if (idx >= 0 && idx < w_coef) { |
| 113 | 55 | row[idx] -= multiplier * pivot[j - k_index]; | |
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | 37 | b_vector[static_cast<std::size_t>(local_i)] -= multiplier * rhs_pivot; | |
| 118 | } | ||
| 119 | |||
| 120 | return true; | ||
| 121 | } | ||
| 122 | |||
| 123 | 28 | bool EliminateForward(int num, int band, int w_coef, int rank, int row0, int local_rows, const std::vector<int> &cnt, | |
| 124 | const std::vector<int> &disp, std::vector<double> &a_vector, std::vector<double> &b_vector) { | ||
| 125 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 28 times.
|
130 | for (int k_index = 0; k_index < num; ++k_index) { |
| 126 | const int owner = OwnerOf(k_index, cnt, disp); | ||
| 127 | 102 | const int right = std::min(num - 1, k_index + band); | |
| 128 | 102 | const int length = right - k_index + 1; | |
| 129 | |||
| 130 | 102 | std::vector<double> pivot(static_cast<std::size_t>(length), 0.0); | |
| 131 | 102 | double rhs_pivot = 0.0; | |
| 132 | |||
| 133 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | if (!BuildPivotRow(k_index, band, w_coef, rank, owner, row0, a_vector, b_vector, pivot, rhs_pivot)) { |
| 134 | return false; | ||
| 135 | } | ||
| 136 | |||
| 137 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | MPI_Bcast(pivot.data(), length, MPI_DOUBLE, owner, MPI_COMM_WORLD); |
| 138 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | MPI_Bcast(&rhs_pivot, 1, MPI_DOUBLE, owner, MPI_COMM_WORLD); |
| 139 | |||
| 140 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | if (!ApplyElimination(k_index, band, w_coef, row0, local_rows, pivot, rhs_pivot, a_vector, b_vector)) { |
| 141 | return false; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | return true; | ||
| 146 | } | ||
| 147 | |||
| 148 | 28 | bool EliminateBackward(int num, int band, int w_coef, int rank, int row0, const std::vector<int> &cnt, | |
| 149 | const std::vector<int> &disp, const std::vector<double> &a_vector, | ||
| 150 | const std::vector<double> &b_vector, std::vector<double> &x_vector) { | ||
| 151 | 28 | x_vector.assign(num, 0.0); | |
| 152 | |||
| 153 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 28 times.
|
130 | for (int k_index = num - 1; k_index >= 0; --k_index) { |
| 154 | const int owner = OwnerOf(k_index, cnt, disp); | ||
| 155 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 51 times.
|
102 | const int right = std::min(num - 1, k_index + band); |
| 156 | |||
| 157 | 102 | double val = 0.0; | |
| 158 | |||
| 159 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 51 times.
|
102 | if (rank == owner) { |
| 160 | 51 | const int local_k = k_index - row0; | |
| 161 | 51 | const double *row = &a_vector[static_cast<std::size_t>(local_k) * static_cast<std::size_t>(w_coef)]; | |
| 162 | |||
| 163 | double sum = 0.0; | ||
| 164 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 51 times.
|
88 | for (int j_index = k_index + 1; j_index <= right; ++j_index) { |
| 165 | 37 | const int idx = j_index - (k_index - band); | |
| 166 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | if (idx >= 0 && idx < w_coef) { |
| 167 | 37 | sum += row[idx] * x_vector[j_index]; | |
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | 51 | const double diag = row[band]; | |
| 172 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
|
51 | if (diag == 0.0) { |
| 173 | ✗ | return false; | |
| 174 | } | ||
| 175 | |||
| 176 | 51 | val = (b_vector[static_cast<std::size_t>(local_k)] - sum) / diag; | |
| 177 | } | ||
| 178 | |||
| 179 | 102 | MPI_Bcast(&val, 1, MPI_DOUBLE, owner, MPI_COMM_WORLD); | |
| 180 | 102 | x_vector[k_index] = val; | |
| 181 | } | ||
| 182 | |||
| 183 | return true; | ||
| 184 | } | ||
| 185 | |||
| 186 | } // namespace | ||
| 187 | |||
| 188 | 28 | bool KiselevITestTaskMPI::RunImpl() { | |
| 189 | const auto &[a_in, b_in, band_in] = GetInput(); | ||
| 190 | |||
| 191 | 28 | int rank = 0; | |
| 192 | 28 | int size = 1; | |
| 193 | 28 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 194 | 28 | MPI_Comm_size(MPI_COMM_WORLD, &size); | |
| 195 | |||
| 196 | 28 | int num = 0; | |
| 197 | 28 | int band = 0; | |
| 198 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
|
28 | if (rank == 0) { |
| 199 | 14 | num = static_cast<int>(a_in.size()); | |
| 200 | 14 | band = static_cast<int>(band_in); | |
| 201 | } | ||
| 202 | |||
| 203 | 28 | MPI_Bcast(&num, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 204 | 28 | MPI_Bcast(&band, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 205 | |||
| 206 | 28 | const int w_coef = (2 * band) + 1; | |
| 207 | |||
| 208 | 28 | std::vector<int> cnt; | |
| 209 | 28 | std::vector<int> disp; | |
| 210 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | MakePartition(size, num, cnt, disp); |
| 211 | |||
| 212 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | const int local_rows = cnt[rank]; |
| 213 | 28 | const int row0 = disp[rank]; | |
| 214 | |||
| 215 |
1/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
28 | std::vector<double> a_loc(static_cast<std::size_t>(local_rows) * static_cast<std::size_t>(w_coef), 0.0); |
| 216 |
1/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
28 | std::vector<double> b_loc(static_cast<std::size_t>(local_rows), 0.0); |
| 217 | |||
| 218 |
1/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
28 | std::vector<int> cnt_a(size); |
| 219 |
1/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
28 | std::vector<int> disp_a(size); |
| 220 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 28 times.
|
84 | for (int index = 0; index < size; ++index) { |
| 221 | 56 | cnt_a[index] = cnt[index] * w_coef; | |
| 222 | 56 | disp_a[index] = disp[index] * w_coef; | |
| 223 | } | ||
| 224 | |||
| 225 | 28 | std::vector<double> send_a; | |
| 226 | 28 | std::vector<double> send_b; | |
| 227 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
|
28 | if (rank == 0) { |
| 228 |
1/4✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
14 | send_a.assign(static_cast<std::size_t>(num) * static_cast<std::size_t>(w_coef), 0.0); |
| 229 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | send_b = b_in; |
| 230 | |||
| 231 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 14 times.
|
65 | for (int index = 0; index < num; ++index) { |
| 232 |
2/2✓ Branch 0 taken 125 times.
✓ Branch 1 taken 51 times.
|
176 | for (int j_index = std::max(0, index - band); j_index <= std::min(num - 1, index + band); ++j_index) { |
| 233 | 125 | const auto row_index = static_cast<std::size_t>(index); | |
| 234 | 125 | const auto col_index = static_cast<std::size_t>(j_index); | |
| 235 | 125 | const auto band_offset = static_cast<std::size_t>(j_index - (index - band)); | |
| 236 | 125 | const auto linear_index = (row_index * static_cast<std::size_t>(w_coef)) + band_offset; | |
| 237 | |||
| 238 | 125 | send_a[linear_index] = a_in[row_index][col_index]; | |
| 239 | } | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 |
3/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
|
42 | MPI_Scatterv(rank == 0 ? send_a.data() : nullptr, cnt_a.data(), disp_a.data(), MPI_DOUBLE, a_loc.data(), cnt_a[rank], |
| 244 | MPI_DOUBLE, 0, MPI_COMM_WORLD); | ||
| 245 | |||
| 246 |
3/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
|
42 | MPI_Scatterv(rank == 0 ? send_b.data() : nullptr, cnt.data(), disp.data(), MPI_DOUBLE, b_loc.data(), local_rows, |
| 247 | MPI_DOUBLE, 0, MPI_COMM_WORLD); | ||
| 248 | |||
| 249 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
|
28 | if (!EliminateForward(num, band, w_coef, rank, row0, local_rows, cnt, disp, a_loc, b_loc)) { |
| 250 | return false; | ||
| 251 | } | ||
| 252 | |||
| 253 | 28 | std::vector<double> x_vector; | |
| 254 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
|
28 | if (!EliminateBackward(num, band, w_coef, rank, row0, cnt, disp, a_loc, b_loc, x_vector)) { |
| 255 | return false; | ||
| 256 | } | ||
| 257 | |||
| 258 | GetOutput().swap(x_vector); | ||
| 259 | 28 | return true; | |
| 260 | } | ||
| 261 | |||
| 262 | 28 | bool KiselevITestTaskMPI::PostProcessingImpl() { | |
| 263 | 28 | return !GetOutput().empty(); | |
| 264 | } | ||
| 265 | |||
| 266 | } // namespace kiselev_i_gauss_method_horizontal_tape_scheme | ||
| 267 |