| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "ilin_a_algorithm_graham/all/include/ops_all.hpp" | ||
| 2 | |||
| 3 | #include <mpi.h> | ||
| 4 | #include <tbb/blocked_range.h> | ||
| 5 | #include <tbb/parallel_reduce.h> | ||
| 6 | #include <tbb/parallel_sort.h> | ||
| 7 | |||
| 8 | #include <array> | ||
| 9 | #include <cstddef> | ||
| 10 | #include <utility> | ||
| 11 | #include <vector> | ||
| 12 | |||
| 13 | #include "ilin_a_algorithm_graham/common/include/common.hpp" | ||
| 14 | |||
| 15 | namespace ilin_a_algorithm_graham { | ||
| 16 | |||
| 17 | namespace { | ||
| 18 | double Orient(const Point &p, const Point &q, const Point &r) { | ||
| 19 | 330 | return ((q.x - p.x) * (r.y - p.y)) - ((q.y - p.y) * (r.x - p.x)); | |
| 20 | } | ||
| 21 | |||
| 22 | double DistanceSq(const Point &p, const Point &q) { | ||
| 23 | 58 | double dx = p.x - q.x; | |
| 24 | 58 | double dy = p.y - q.y; | |
| 25 | 58 | return (dx * dx) + (dy * dy); | |
| 26 | } | ||
| 27 | |||
| 28 | 6 | Point FindLowestLeftmostParallel(const std::vector<Point> &points) { | |
| 29 | 6 | return tbb::parallel_reduce(tbb::blocked_range<size_t>(0, points.size()), points[0], | |
| 30 | 6 | [&](const tbb::blocked_range<size_t> &r, Point init) { | |
| 31 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
|
72 | for (size_t i = r.begin(); i < r.end(); ++i) { |
| 32 |
4/6✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
|
36 | if (points[i].y < init.y || (points[i].y == init.y && points[i].x < init.x)) { |
| 33 | ✗ | init = points[i]; | |
| 34 | } | ||
| 35 | } | ||
| 36 | return init; | ||
| 37 | 6 | }, [](const Point &a, const Point &b) { | |
| 38 | ✗ | if (a.y < b.y || (a.y == b.y && a.x < b.x)) { | |
| 39 | ✗ | return a; | |
| 40 | } | ||
| 41 | ✗ | return b; | |
| 42 | 6 | }); | |
| 43 | } | ||
| 44 | |||
| 45 | class PointComparator { | ||
| 46 | public: | ||
| 47 |
2/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
12 | explicit PointComparator(const Point &p0) : p0_(p0) {} |
| 48 | |||
| 49 | 242 | bool operator()(const Point &a, const Point &b) const { | |
| 50 | double o = Orient(p0_, a, b); | ||
| 51 |
2/2✓ Branch 0 taken 184 times.
✓ Branch 1 taken 58 times.
|
242 | if (o != 0.0) { |
| 52 | 184 | return o > 0; | |
| 53 | } | ||
| 54 | 58 | return DistanceSq(p0_, a) < DistanceSq(p0_, b); | |
| 55 | } | ||
| 56 | |||
| 57 | private: | ||
| 58 | Point p0_; | ||
| 59 | }; | ||
| 60 | |||
| 61 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | void GrahamScan(const std::vector<Point> &sorted, const Point &p0, std::vector<Point> &hull) { |
| 62 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (sorted.empty()) { |
| 63 | hull.push_back(p0); | ||
| 64 | ✗ | return; | |
| 65 | } | ||
| 66 | 6 | hull.reserve(sorted.size() + 1); | |
| 67 | hull.push_back(p0); | ||
| 68 | hull.push_back(sorted[0]); | ||
| 69 | |||
| 70 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 6 times.
|
60 | for (size_t i = 1; i < sorted.size(); ++i) { |
| 71 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 6 times.
|
94 | while (hull.size() >= 2) { |
| 72 | 88 | Point p = hull[hull.size() - 2]; | |
| 73 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 48 times.
|
88 | Point q = hull[hull.size() - 1]; |
| 74 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 48 times.
|
88 | if (Orient(p, q, sorted[i]) <= 0.0) { |
| 75 | hull.pop_back(); | ||
| 76 | } else { | ||
| 77 | break; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | hull.push_back(sorted[i]); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } // namespace | ||
| 84 | |||
| 85 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | IlinAGrahamALL::IlinAGrahamALL(const InType &in) { |
| 86 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 87 | GetInput() = in; | ||
| 88 | 6 | } | |
| 89 | |||
| 90 | 6 | bool IlinAGrahamALL::ValidationImpl() { | |
| 91 | 6 | return !GetInput().points.empty(); | |
| 92 | } | ||
| 93 | |||
| 94 | 6 | bool IlinAGrahamALL::PreProcessingImpl() { | |
| 95 | 6 | points_ = GetInput().points; | |
| 96 | hull_.clear(); | ||
| 97 | 6 | return true; | |
| 98 | } | ||
| 99 | |||
| 100 | 6 | bool IlinAGrahamALL::RunImpl() { | |
| 101 | 6 | int rank = -1; | |
| 102 | 6 | int size = -1; | |
| 103 | 6 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 104 | 6 | MPI_Comm_size(MPI_COMM_WORLD, &size); | |
| 105 | |||
| 106 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (points_.size() < 3) { |
| 107 | ✗ | hull_ = points_; | |
| 108 | ✗ | return true; | |
| 109 | } | ||
| 110 | |||
| 111 | 6 | Point local_p0 = FindLowestLeftmostParallel(points_); | |
| 112 | |||
| 113 | 6 | std::array<double, 2> local_min = {local_p0.y, local_p0.x}; | |
| 114 | 6 | std::array<double, 2> global_min = {}; | |
| 115 | |||
| 116 | 6 | MPI_Allreduce(local_min.data(), global_min.data(), 2, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); | |
| 117 | |||
| 118 | Point global_p0{}; | ||
| 119 | 6 | global_p0.y = global_min[0]; | |
| 120 | 6 | global_p0.x = global_min[1]; | |
| 121 | |||
| 122 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | std::vector<Point> sorted; |
| 123 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | sorted.reserve(points_.size()); |
| 124 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 6 times.
|
42 | for (const Point &p : points_) { |
| 125 |
4/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
|
36 | if (p.x != global_p0.x || p.y != global_p0.y) { |
| 126 | sorted.push_back(p); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 |
2/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | tbb::parallel_sort(sorted.begin(), sorted.end(), PointComparator(global_p0)); |
| 131 | |||
| 132 | 6 | int local_count = static_cast<int>(sorted.size()); | |
| 133 |
1/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6 | std::vector<int> counts(size); |
| 134 |
2/6✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
6 | std::vector<int> displs(size); |
| 135 | |||
| 136 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | MPI_Allgather(&local_count, 1, MPI_INT, counts.data(), 1, MPI_INT, MPI_COMM_WORLD); |
| 137 | |||
| 138 | int total_count = 0; | ||
| 139 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
|
18 | for (int i = 0; i < size; ++i) { |
| 140 | 12 | displs[i] = total_count; | |
| 141 | 12 | total_count += counts[i]; | |
| 142 | } | ||
| 143 | |||
| 144 |
1/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6 | std::vector<double> send_buffer(static_cast<size_t>(local_count) * 2); |
| 145 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 6 times.
|
36 | for (int i = 0; i < local_count; ++i) { |
| 146 | 30 | send_buffer[(static_cast<size_t>(i) * 2)] = sorted[i].x; | |
| 147 | 30 | send_buffer[(static_cast<size_t>(i) * 2) + 1] = sorted[i].y; | |
| 148 | } | ||
| 149 | |||
| 150 |
1/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6 | std::vector<double> recv_buffer(static_cast<size_t>(total_count) * 2); |
| 151 |
1/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6 | std::vector<int> recv_counts(size); |
| 152 |
1/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6 | std::vector<int> recv_displs(size); |
| 153 | |||
| 154 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
|
18 | for (int i = 0; i < size; ++i) { |
| 155 | 12 | recv_counts[i] = counts[i] * 2; | |
| 156 | 12 | recv_displs[i] = displs[i] * 2; | |
| 157 | } | ||
| 158 | |||
| 159 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | MPI_Allgatherv(send_buffer.data(), local_count * 2, MPI_DOUBLE, recv_buffer.data(), recv_counts.data(), |
| 160 | recv_displs.data(), MPI_DOUBLE, MPI_COMM_WORLD); | ||
| 161 | |||
| 162 | 6 | std::vector<Point> global_sorted; | |
| 163 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | global_sorted.reserve(static_cast<size_t>(total_count)); |
| 164 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 6 times.
|
66 | for (int i = 0; i < total_count; ++i) { |
| 165 |
1/2✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
|
60 | size_t idx = (static_cast<size_t>(i) * 2); |
| 166 |
1/2✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
|
60 | global_sorted.push_back({recv_buffer[idx], recv_buffer[idx + 1]}); |
| 167 | } | ||
| 168 | |||
| 169 |
1/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6 | tbb::parallel_sort(global_sorted.begin(), global_sorted.end(), PointComparator(global_p0)); |
| 170 | |||
| 171 | 6 | std::vector<Point> hull; | |
| 172 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | GrahamScan(global_sorted, global_p0, hull); |
| 173 | |||
| 174 | 6 | hull_ = std::move(hull); | |
| 175 | |||
| 176 | return true; | ||
| 177 | } | ||
| 178 | |||
| 179 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | bool IlinAGrahamALL::PostProcessingImpl() { |
| 180 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (hull_.empty()) { |
| 181 | return false; | ||
| 182 | } | ||
| 183 | 6 | GetOutput() = hull_; | |
| 184 | 6 | return true; | |
| 185 | } | ||
| 186 | |||
| 187 | } // namespace ilin_a_algorithm_graham | ||
| 188 |