| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "kutuzov_i_convex_hull_jarvis/stl/include/ops_stl.hpp" | ||
| 2 | |||
| 3 | #include <cmath> | ||
| 4 | #include <cstddef> | ||
| 5 | #include <limits> | ||
| 6 | #include <thread> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "kutuzov_i_convex_hull_jarvis/common/include/common.hpp" | ||
| 10 | |||
| 11 | namespace kutuzov_i_convex_hull_jarvis { | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | |||
| 15 | struct BestCandidate { | ||
| 16 | size_t index; | ||
| 17 | double x; | ||
| 18 | double y; | ||
| 19 | }; | ||
| 20 | |||
| 21 | inline unsigned GetNumThreads() { | ||
| 22 | 48 | const unsigned hw = std::thread::hardware_concurrency(); | |
| 23 | 48 | return (hw == 0) ? 1 : hw; | |
| 24 | } | ||
| 25 | |||
| 26 | inline double DistanceSquared(double a_x, double a_y, double b_x, double b_y) { | ||
| 27 | 56 | return ((a_x - b_x) * (a_x - b_x)) + ((a_y - b_y) * (a_y - b_y)); | |
| 28 | } | ||
| 29 | |||
| 30 | inline double CrossProduct(double o_x, double o_y, double a_x, double a_y, double b_x, double b_y) { | ||
| 31 | ✗ | return ((a_x - o_x) * (b_y - o_y)) - ((a_y - o_y) * (b_x - o_x)); | |
| 32 | } | ||
| 33 | |||
| 34 | BestCandidate FindLeftmostInRange(const InType &points, size_t start, size_t end) { | ||
| 35 | size_t best_idx = start; | ||
| 36 | 96 | double best_x = std::get<0>(points[start]); | |
| 37 | 96 | double best_y = std::get<1>(points[start]); | |
| 38 | |||
| 39 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 96 times.
|
160 | for (size_t i = start + 1; i < end; ++i) { |
| 40 | 64 | double px = std::get<0>(points[i]); | |
| 41 | 64 | double py = std::get<1>(points[i]); | |
| 42 |
3/6✓ Branch 0 taken 24 times.
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
64 | if ((px < best_x) || (px == best_x && py < best_y)) { |
| 43 | best_x = px; | ||
| 44 | best_y = py; | ||
| 45 | best_idx = i; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | return {.index = best_idx, .x = best_x, .y = best_y}; | ||
| 50 | } | ||
| 51 | |||
| 52 | 288 | BestCandidate FindBestCandidateInRange(const InType &points, size_t start, size_t end, size_t current_idx, | |
| 53 | double current_x, double current_y, double epsilon) { | ||
| 54 | 288 | BestCandidate best{.index = current_idx, .x = current_x, .y = current_y}; | |
| 55 | |||
| 56 |
2/2✓ Branch 0 taken 496 times.
✓ Branch 1 taken 288 times.
|
784 | for (size_t i = start; i < end; ++i) { |
| 57 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 424 times.
|
496 | if (i == current_idx) { |
| 58 | 72 | continue; | |
| 59 | } | ||
| 60 | |||
| 61 | const auto &p = points[i]; | ||
| 62 | 424 | double px = std::get<0>(p); | |
| 63 | 424 | double py = std::get<1>(p); | |
| 64 | |||
| 65 | 424 | double cross = ((best.x - current_x) * (py - current_y)) - ((best.y - current_y) * (px - current_x)); | |
| 66 | |||
| 67 |
4/4✓ Branch 0 taken 384 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 312 times.
✓ Branch 3 taken 72 times.
|
424 | if (cross < -epsilon || |
| 68 | 312 | (std::abs(cross) < epsilon && | |
| 69 | 312 | ((px - current_x) * (px - current_x)) + ((py - current_y) * (py - current_y)) > | |
| 70 |
2/2✓ Branch 0 taken 296 times.
✓ Branch 1 taken 16 times.
|
312 | ((best.x - current_x) * (best.x - current_x)) + ((best.y - current_y) * (best.y - current_y)))) { |
| 71 | 336 | best.index = i; | |
| 72 | 336 | best.x = px; | |
| 73 | 336 | best.y = py; | |
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | 288 | return best; | |
| 78 | } | ||
| 79 | |||
| 80 | 72 | BestCandidate FindGlobalBest(const std::vector<BestCandidate> &locals, size_t current_idx, double current_x, | |
| 81 | double current_y, double epsilon) { | ||
| 82 | 72 | size_t global_idx = locals[0].index; | |
| 83 | 72 | double global_x = locals[0].x; | |
| 84 | 72 | double global_y = locals[0].y; | |
| 85 | |||
| 86 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 72 times.
|
288 | for (size_t i = 1; i < locals.size(); ++i) { |
| 87 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
|
216 | if (locals[i].index == current_idx) { |
| 88 | ✗ | continue; | |
| 89 | } | ||
| 90 | |||
| 91 | double cross = | ||
| 92 | 216 | ((global_x - current_x) * (locals[i].y - current_y)) - ((global_y - current_y) * (locals[i].x - current_x)); | |
| 93 | |||
| 94 |
4/4✓ Branch 0 taken 168 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 112 times.
✓ Branch 3 taken 56 times.
|
216 | if (cross < -epsilon || |
| 95 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 32 times.
|
56 | (std::abs(cross) < epsilon && DistanceSquared(current_x, current_y, locals[i].x, locals[i].y) > |
| 96 | DistanceSquared(current_x, current_y, global_x, global_y))) { | ||
| 97 | global_idx = locals[i].index; | ||
| 98 | global_x = locals[i].x; | ||
| 99 | global_y = locals[i].y; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | 72 | return {.index = global_idx, .x = global_x, .y = global_y}; | |
| 104 | } | ||
| 105 | |||
| 106 | } // anonymous namespace | ||
| 107 | |||
| 108 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | KutuzovITestConvexHullSTL::KutuzovITestConvexHullSTL(const InType &in) { |
| 109 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 110 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | GetInput() = in; |
| 111 | GetOutput() = {}; | ||
| 112 | 24 | } | |
| 113 | |||
| 114 | ✗ | double KutuzovITestConvexHullSTL::DistanceSquared(double a_x, double a_y, double b_x, double b_y) { | |
| 115 | ✗ | return kutuzov_i_convex_hull_jarvis::DistanceSquared(a_x, a_y, b_x, b_y); | |
| 116 | } | ||
| 117 | |||
| 118 | ✗ | double KutuzovITestConvexHullSTL::CrossProduct(double o_x, double o_y, double a_x, double a_y, double b_x, double b_y) { | |
| 119 | ✗ | return kutuzov_i_convex_hull_jarvis::CrossProduct(o_x, o_y, a_x, a_y, b_x, b_y); | |
| 120 | } | ||
| 121 | |||
| 122 | 24 | size_t KutuzovITestConvexHullSTL::FindLeftmostPoint(const InType &input) { | |
| 123 | const size_t n = input.size(); | ||
| 124 | const unsigned num_threads = GetNumThreads(); | ||
| 125 | |||
| 126 | 24 | std::vector<BestCandidate> locals(num_threads); | |
| 127 | |||
| 128 | 24 | std::vector<std::thread> threads; | |
| 129 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | threads.reserve(num_threads); |
| 130 | |||
| 131 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 24 times.
|
120 | for (unsigned tid = 0; tid < num_threads; ++tid) { |
| 132 | 96 | size_t start = (tid * n) / num_threads; | |
| 133 | 96 | size_t end = ((tid + 1) * n) / num_threads; | |
| 134 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
|
96 | if (start >= end) { |
| 135 | ✗ | locals[tid] = {.index = 0, .x = std::numeric_limits<double>::max(), .y = 0.0}; | |
| 136 | ✗ | continue; | |
| 137 | } | ||
| 138 | |||
| 139 |
1/2✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
|
192 | threads.emplace_back([&, tid, start, end]() { locals[tid] = FindLeftmostInRange(input, start, end); }); |
| 140 | } | ||
| 141 | |||
| 142 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 24 times.
|
120 | for (auto &t : threads) { |
| 143 |
1/2✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
|
96 | t.join(); |
| 144 | } | ||
| 145 | |||
| 146 | size_t global_idx = 0; | ||
| 147 | double global_x = std::numeric_limits<double>::max(); | ||
| 148 | double global_y = 0.0; | ||
| 149 | |||
| 150 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 24 times.
|
120 | for (unsigned i = 0; i < num_threads; ++i) { |
| 151 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 32 times.
|
96 | if (locals[i].x > global_x) { |
| 152 | 64 | continue; | |
| 153 | } | ||
| 154 |
4/6✓ Branch 0 taken 8 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
|
32 | if (locals[i].x < global_x || (locals[i].x == global_x && locals[i].y < global_y)) { |
| 155 | 24 | global_idx = locals[i].index; | |
| 156 | global_x = locals[i].x; | ||
| 157 | 24 | global_y = locals[i].y; | |
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | 24 | return global_idx; | |
| 162 | 24 | } | |
| 163 | |||
| 164 | ✗ | bool KutuzovITestConvexHullSTL::IsBetterPoint(double cross, double epsilon, double current_x, double current_y, | |
| 165 | double i_x, double i_y, double next_x, double next_y) { | ||
| 166 | ✗ | if (cross < -epsilon) { | |
| 167 | return true; | ||
| 168 | } | ||
| 169 | ✗ | if (std::abs(cross) < epsilon) { | |
| 170 | ✗ | return DistanceSquared(current_x, current_y, i_x, i_y) > DistanceSquared(current_x, current_y, next_x, next_y); | |
| 171 | } | ||
| 172 | return false; | ||
| 173 | } | ||
| 174 | |||
| 175 | 24 | bool KutuzovITestConvexHullSTL::ValidationImpl() { | |
| 176 | 24 | return true; | |
| 177 | } | ||
| 178 | 24 | bool KutuzovITestConvexHullSTL::PreProcessingImpl() { | |
| 179 | 24 | return true; | |
| 180 | } | ||
| 181 | |||
| 182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | bool KutuzovITestConvexHullSTL::RunImpl() { |
| 183 | const auto &points = GetInput(); | ||
| 184 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if (points.size() < 3) { |
| 185 | ✗ | GetOutput() = points; | |
| 186 | ✗ | return true; | |
| 187 | } | ||
| 188 | |||
| 189 | auto &output = GetOutput(); | ||
| 190 | output.clear(); | ||
| 191 | |||
| 192 | 24 | const double epsilon = 1e-9; | |
| 193 | const size_t n = points.size(); | ||
| 194 | |||
| 195 | 24 | const size_t leftmost_idx = FindLeftmostPoint(points); | |
| 196 | |||
| 197 | const unsigned num_threads = GetNumThreads(); | ||
| 198 | 24 | std::vector<BestCandidate> locals(num_threads); | |
| 199 | |||
| 200 | 24 | size_t current_idx = leftmost_idx; | |
| 201 | 24 | double current_x = std::get<0>(points[current_idx]); | |
| 202 | 24 | double current_y = std::get<1>(points[current_idx]); | |
| 203 | |||
| 204 | while (true) { | ||
| 205 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 64 times.
|
72 | output.push_back(points[current_idx]); |
| 206 | |||
| 207 | 72 | std::vector<std::thread> threads; | |
| 208 |
1/2✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
|
72 | threads.reserve(num_threads); |
| 209 | |||
| 210 |
2/2✓ Branch 0 taken 288 times.
✓ Branch 1 taken 72 times.
|
360 | for (unsigned tid = 0; tid < num_threads; ++tid) { |
| 211 | 288 | size_t start = (tid * n) / num_threads; | |
| 212 | 288 | size_t end = ((tid + 1) * n) / num_threads; | |
| 213 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 288 times.
|
288 | if (start >= end) { |
| 214 | ✗ | continue; | |
| 215 | } | ||
| 216 | |||
| 217 |
1/2✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
|
288 | threads.emplace_back([&, tid, start, end]() { |
| 218 | 288 | locals[tid] = FindBestCandidateInRange(points, start, end, current_idx, current_x, current_y, epsilon); | |
| 219 | 288 | }); | |
| 220 | } | ||
| 221 | |||
| 222 |
2/2✓ Branch 0 taken 288 times.
✓ Branch 1 taken 72 times.
|
360 | for (auto &t : threads) { |
| 223 |
1/2✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
|
288 | t.join(); |
| 224 | } | ||
| 225 | |||
| 226 | 72 | BestCandidate global = FindGlobalBest(locals, current_idx, current_x, current_y, epsilon); | |
| 227 | |||
| 228 | 72 | current_idx = global.index; | |
| 229 | 72 | current_x = global.x; | |
| 230 | 72 | current_y = global.y; | |
| 231 | |||
| 232 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
|
72 | if (current_idx == leftmost_idx) { |
| 233 | break; | ||
| 234 | } | ||
| 235 | 72 | } | |
| 236 | |||
| 237 | return true; | ||
| 238 | } | ||
| 239 | |||
| 240 | 24 | bool KutuzovITestConvexHullSTL::PostProcessingImpl() { | |
| 241 | 24 | return true; | |
| 242 | } | ||
| 243 | |||
| 244 | } // namespace kutuzov_i_convex_hull_jarvis | ||
| 245 |