| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "kutuzov_i_convex_hull_jarvis/all/include/ops_all.hpp" | ||
| 2 | |||
| 3 | #include <mpi.h> | ||
| 4 | #include <omp.h> | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <cmath> | ||
| 8 | #include <cstddef> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "kutuzov_i_convex_hull_jarvis/common/include/common.hpp" | ||
| 12 | |||
| 13 | namespace kutuzov_i_convex_hull_jarvis { | ||
| 14 | |||
| 15 | double KutuzovITestConvexHullALL::s_curr_x = 0.0; | ||
| 16 | double KutuzovITestConvexHullALL::s_curr_y = 0.0; | ||
| 17 | double KutuzovITestConvexHullALL::s_epsilon = 1e-9; | ||
| 18 | |||
| 19 | ✗ | double KutuzovITestConvexHullALL::DistanceSquared(double a_x, double a_y, double b_x, double b_y) { | |
| 20 | 10 | return ((a_x - b_x) * (a_x - b_x)) + ((a_y - b_y) * (a_y - b_y)); | |
| 21 | } | ||
| 22 | |||
| 23 | ✗ | double KutuzovITestConvexHullALL::CrossProduct(double o_x, double o_y, double a_x, double a_y, double b_x, double b_y) { | |
| 24 | 18 | return ((a_x - o_x) * (b_y - o_y)) - ((a_y - o_y) * (b_x - o_x)); | |
| 25 | } | ||
| 26 | |||
| 27 | ✗ | bool KutuzovITestConvexHullALL::IsBetterPoint(double cross, double epsilon, double current_x, double current_y, | |
| 28 | double i_x, double i_y, double next_x, double next_y) { | ||
| 29 | ✗ | if (cross < -epsilon) { | |
| 30 | return true; | ||
| 31 | } | ||
| 32 |
2/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
14 | if (std::abs(cross) < epsilon) { |
| 33 | ✗ | return DistanceSquared(current_x, current_y, i_x, i_y) > DistanceSquared(current_x, current_y, next_x, next_y); | |
| 34 | } | ||
| 35 | return false; | ||
| 36 | } | ||
| 37 | |||
| 38 | 6 | void KutuzovITestConvexHullALL::LeftmostReduce(void *invec, void *inoutvec, const int *len, MPI_Datatype * /*unused*/) { | |
| 39 | auto *in = static_cast<double *>(invec); | ||
| 40 | auto *inout = static_cast<double *>(inoutvec); | ||
| 41 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | for (int i = 0; i < *len; ++i) { |
| 42 | 6 | const auto idx = static_cast<ptrdiff_t>(3) * static_cast<ptrdiff_t>(i); | |
| 43 | 6 | double x_in = in[idx]; | |
| 44 | 6 | double y_in = in[idx + 1]; | |
| 45 | 6 | double x_io = inout[idx]; | |
| 46 | 6 | double y_io = inout[idx + 1]; | |
| 47 |
3/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
|
6 | if (x_in < x_io || (x_in == x_io && y_in < y_io)) { |
| 48 | ✗ | inout[idx] = x_in; | |
| 49 | ✗ | inout[idx + 1] = y_in; | |
| 50 | ✗ | inout[idx + 2] = in[idx + 2]; | |
| 51 | } | ||
| 52 | } | ||
| 53 | 6 | } | |
| 54 | |||
| 55 | 18 | void KutuzovITestConvexHullALL::NextReduce(void *invec, void *inoutvec, const int *len, MPI_Datatype * /*unused*/) { | |
| 56 | auto *in = static_cast<double *>(invec); | ||
| 57 | auto *inout = static_cast<double *>(inoutvec); | ||
| 58 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
|
36 | for (int i = 0; i < *len; ++i) { |
| 59 | 18 | const auto idx = static_cast<ptrdiff_t>(3) * static_cast<ptrdiff_t>(i); | |
| 60 | 18 | double ax = inout[idx]; | |
| 61 | 18 | double ay = inout[idx + 1]; | |
| 62 | 18 | double bx = in[idx]; | |
| 63 | 18 | double by = in[idx + 1]; | |
| 64 | 18 | double cross = CrossProduct(s_curr_x, s_curr_y, ax, ay, bx, by); | |
| 65 |
3/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
|
28 | if (IsBetterPoint(cross, s_epsilon, s_curr_x, s_curr_y, bx, by, ax, ay)) { |
| 66 | 4 | inout[idx] = bx; | |
| 67 | 4 | inout[idx + 1] = by; | |
| 68 | 4 | inout[idx + 2] = in[idx + 2]; | |
| 69 | } | ||
| 70 | } | ||
| 71 | 18 | } | |
| 72 | |||
| 73 | 6 | void KutuzovITestConvexHullALL::BuildTypes() { | |
| 74 | 6 | MPI_Type_contiguous(3, MPI_DOUBLE, &type_leftmost_); | |
| 75 | 6 | MPI_Type_commit(&type_leftmost_); | |
| 76 | 6 | type_next_ = type_leftmost_; | |
| 77 | 6 | } | |
| 78 | |||
| 79 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | KutuzovITestConvexHullALL::KutuzovITestConvexHullALL(const InType &in) { |
| 80 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 81 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | GetInput() = in; |
| 82 | GetOutput() = {}; | ||
| 83 | 6 | } | |
| 84 | |||
| 85 | 6 | size_t KutuzovITestConvexHullALL::FindLeftmostPoint(const InType &input, size_t start, size_t end) { | |
| 86 | 6 | std::array<double, 3> local_lm{}; | |
| 87 | 6 | std::array<double, 3> global_lm{}; | |
| 88 | 6 | local_lm[0] = std::get<0>(input[0]); | |
| 89 | 6 | local_lm[1] = std::get<1>(input[0]); | |
| 90 | local_lm[2] = 0.0; | ||
| 91 | |||
| 92 | 6 | #pragma omp parallel default(none) shared(input, start, end, local_lm) | |
| 93 | { | ||
| 94 | size_t li = 0; | ||
| 95 | double lx = std::get<0>(input[li]); | ||
| 96 | double ly = std::get<1>(input[li]); | ||
| 97 | |||
| 98 | #pragma omp for nowait | ||
| 99 | for (size_t i = start; i < end; ++i) { | ||
| 100 | double x = std::get<0>(input[i]); | ||
| 101 | double y = std::get<1>(input[i]); | ||
| 102 | if (x < lx || (x == lx && y < ly)) { | ||
| 103 | li = i; | ||
| 104 | lx = x; | ||
| 105 | ly = y; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | #pragma omp critical | ||
| 109 | { | ||
| 110 | if (lx < local_lm[0] || (lx == local_lm[0] && ly < local_lm[1])) { | ||
| 111 | local_lm[0] = lx; | ||
| 112 | local_lm[1] = ly; | ||
| 113 | local_lm[2] = static_cast<double>(li); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | 6 | MPI_Allreduce(local_lm.data(), global_lm.data(), 1, type_leftmost_, op_leftmost_, MPI_COMM_WORLD); | |
| 119 | 6 | return static_cast<size_t>(global_lm[2]); | |
| 120 | } | ||
| 121 | |||
| 122 | 18 | size_t KutuzovITestConvexHullALL::FindNextPoint(const InType &input, size_t n, size_t current, double current_x, | |
| 123 | double current_y, double epsilon, size_t start, size_t end) { | ||
| 124 | 18 | size_t next = (current + 1) % n; | |
| 125 | 18 | double next_x = std::get<0>(input[next]); | |
| 126 | 18 | double next_y = std::get<1>(input[next]); | |
| 127 | |||
| 128 | 18 | #pragma omp parallel default(none) \ | |
| 129 | shared(input, n, current, current_x, current_y, start, end, epsilon, next, next_x, next_y) | ||
| 130 | { | ||
| 131 | size_t local_next = (current + 1) % n; | ||
| 132 | double local_next_x = std::get<0>(input[local_next]); | ||
| 133 | double local_next_y = std::get<1>(input[local_next]); | ||
| 134 | |||
| 135 | #pragma omp for nowait | ||
| 136 | for (size_t i = start; i < end; ++i) { | ||
| 137 | if (i == current) { | ||
| 138 | continue; | ||
| 139 | } | ||
| 140 | double i_x = std::get<0>(input[i]); | ||
| 141 | double i_y = std::get<1>(input[i]); | ||
| 142 | double cross = CrossProduct(current_x, current_y, local_next_x, local_next_y, i_x, i_y); | ||
| 143 | if (IsBetterPoint(cross, epsilon, current_x, current_y, i_x, i_y, local_next_x, local_next_y)) { | ||
| 144 | local_next = i; | ||
| 145 | local_next_x = i_x; | ||
| 146 | local_next_y = i_y; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | #pragma omp critical | ||
| 151 | { | ||
| 152 | double cross = CrossProduct(current_x, current_y, next_x, next_y, local_next_x, local_next_y); | ||
| 153 | if (IsBetterPoint(cross, epsilon, current_x, current_y, local_next_x, local_next_y, next_x, next_y)) { | ||
| 154 | next = local_next; | ||
| 155 | next_x = local_next_x; | ||
| 156 | next_y = local_next_y; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | 18 | s_curr_x = current_x; | |
| 162 | 18 | s_curr_y = current_y; | |
| 163 | 18 | s_epsilon = epsilon; | |
| 164 | |||
| 165 | 18 | std::array<double, 3> local_cand{next_x, next_y, static_cast<double>(next)}; | |
| 166 | 18 | std::array<double, 3> global_cand{}; | |
| 167 | |||
| 168 | 18 | MPI_Allreduce(local_cand.data(), global_cand.data(), 1, type_next_, op_next_, MPI_COMM_WORLD); | |
| 169 | |||
| 170 | 18 | return static_cast<size_t>(global_cand[2]); | |
| 171 | } | ||
| 172 | |||
| 173 | 6 | bool KutuzovITestConvexHullALL::ValidationImpl() { | |
| 174 | 6 | return true; | |
| 175 | } | ||
| 176 | |||
| 177 | 6 | bool KutuzovITestConvexHullALL::PreProcessingImpl() { | |
| 178 | 6 | int flag = 0; | |
| 179 | 6 | MPI_Initialized(&flag); | |
| 180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (flag == 0) { |
| 181 | ✗ | MPI_Init_thread(nullptr, nullptr, MPI_THREAD_FUNNELED, nullptr); | |
| 182 | } | ||
| 183 | |||
| 184 | 6 | MPI_Comm_rank(MPI_COMM_WORLD, &rank_); | |
| 185 | 6 | MPI_Comm_size(MPI_COMM_WORLD, &size_); | |
| 186 | |||
| 187 | 6 | BuildTypes(); | |
| 188 | |||
| 189 | 6 | MPI_Op_create(reinterpret_cast<MPI_User_function *>(LeftmostReduce), 1, &op_leftmost_); | |
| 190 | 6 | MPI_Op_create(reinterpret_cast<MPI_User_function *>(NextReduce), 1, &op_next_); | |
| 191 | |||
| 192 | auto &input = GetInput(); | ||
| 193 | 6 | auto n = static_cast<int>(input.size()); | |
| 194 | |||
| 195 | 6 | MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 196 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (rank_ != 0) { |
| 197 | 3 | input.resize(static_cast<size_t>(n)); | |
| 198 | } | ||
| 199 | |||
| 200 | 6 | std::vector<double> coords(static_cast<size_t>(2) * static_cast<size_t>(n)); | |
| 201 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (rank_ == 0) { |
| 202 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 3 times.
|
23 | for (int i = 0; i < n; ++i) { |
| 203 | 20 | coords[(2 * static_cast<size_t>(i))] = std::get<0>(input[static_cast<size_t>(i)]); | |
| 204 | 20 | coords[(2 * static_cast<size_t>(i)) + 1] = std::get<1>(input[static_cast<size_t>(i)]); | |
| 205 | } | ||
| 206 | } | ||
| 207 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | MPI_Bcast(coords.data(), static_cast<int>(coords.size()), MPI_DOUBLE, 0, MPI_COMM_WORLD); |
| 208 | |||
| 209 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (rank_ != 0) { |
| 210 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 3 times.
|
23 | for (int i = 0; i < n; ++i) { |
| 211 | 20 | const auto idx = static_cast<size_t>(i); | |
| 212 | input[idx] = {coords[2 * idx], coords[(2 * idx) + 1]}; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | 6 | return true; | |
| 217 | } | ||
| 218 | |||
| 219 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | bool KutuzovITestConvexHullALL::RunImpl() { |
| 220 | auto &input = GetInput(); | ||
| 221 | const auto n = static_cast<size_t>(input.size()); | ||
| 222 | |||
| 223 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (n < 3) { |
| 224 | ✗ | GetOutput() = input; | |
| 225 | ✗ | return true; | |
| 226 | } | ||
| 227 | |||
| 228 | 6 | const size_t start = (n * static_cast<size_t>(rank_)) / static_cast<size_t>(size_); | |
| 229 | 6 | const size_t end = (n * (static_cast<size_t>(rank_) + 1)) / static_cast<size_t>(size_); | |
| 230 | const double epsilon = 1e-9; | ||
| 231 | |||
| 232 | 6 | const size_t leftmost = FindLeftmostPoint(input, start, end); | |
| 233 | |||
| 234 | size_t current = leftmost; | ||
| 235 | 6 | double current_x = std::get<0>(input[current]); | |
| 236 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | double current_y = std::get<1>(input[current]); |
| 237 | |||
| 238 | auto &output = GetOutput(); | ||
| 239 | output.clear(); | ||
| 240 | |||
| 241 | while (true) { | ||
| 242 | output.push_back(input[current]); | ||
| 243 | |||
| 244 | 18 | const size_t next = FindNextPoint(input, n, current, current_x, current_y, epsilon, start, end); | |
| 245 | |||
| 246 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
|
18 | if (next == leftmost) { |
| 247 | break; | ||
| 248 | } | ||
| 249 | |||
| 250 | current = next; | ||
| 251 | 12 | current_x = std::get<0>(input[current]); | |
| 252 | 12 | current_y = std::get<1>(input[current]); | |
| 253 | 12 | } | |
| 254 | |||
| 255 | return true; | ||
| 256 | } | ||
| 257 | |||
| 258 | 6 | bool KutuzovITestConvexHullALL::PostProcessingImpl() { | |
| 259 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (op_leftmost_ != MPI_OP_NULL) { |
| 260 | 6 | MPI_Op_free(&op_leftmost_); | |
| 261 | } | ||
| 262 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (op_next_ != MPI_OP_NULL) { |
| 263 | 6 | MPI_Op_free(&op_next_); | |
| 264 | } | ||
| 265 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (type_leftmost_ != MPI_DATATYPE_NULL) { |
| 266 | 6 | MPI_Type_free(&type_leftmost_); | |
| 267 | } | ||
| 268 | 6 | return true; | |
| 269 | } | ||
| 270 | // Comment for CI | ||
| 271 | } // namespace kutuzov_i_convex_hull_jarvis | ||
| 272 |