| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "gaivoronskiy_m_grachem_method/mpi/include/ops_mpi.hpp" | ||
| 2 | |||
| 3 | #include <mpi.h> | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cmath> | ||
| 7 | #include <cstddef> | ||
| 8 | #include <stack> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "gaivoronskiy_m_grachem_method/common/include/common.hpp" | ||
| 12 | |||
| 13 | namespace gaivoronskiy_m_grachem_method { | ||
| 14 | |||
| 15 | namespace { | ||
| 16 | int Orientation(const Point &p, const Point &q, const Point &r) { | ||
| 17 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 97 times.
|
238 | double val = ((q.y - p.y) * (r.x - q.x)) - ((q.x - p.x) * (r.y - q.y)); |
| 18 | constexpr double kEps = 1e-9; | ||
| 19 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 97 times.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 484 times.
|
745 | if (std::abs(val) < kEps) { |
| 20 | return 0; | ||
| 21 | } | ||
| 22 |
4/4✓ Branch 0 taken 44 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 286 times.
|
612 | return (val > 0) ? 1 : 2; |
| 23 | } | ||
| 24 | |||
| 25 | double DistSquare(const Point &p1, const Point &p2) { | ||
| 26 | 23 | return ((p1.x - p2.x) * (p1.x - p2.x)) + ((p1.y - p2.y) * (p1.y - p2.y)); | |
| 27 | } | ||
| 28 | |||
| 29 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 484 times.
|
507 | bool Compare(const Point &p1, const Point &p2, const Point &p0) { |
| 30 | int o = Orientation(p0, p1, p2); | ||
| 31 | if (o == 0) { | ||
| 32 | 23 | return DistSquare(p0, p1) < DistSquare(p0, p2); | |
| 33 | } | ||
| 34 | 484 | return (o == 2); | |
| 35 | } | ||
| 36 | } // namespace | ||
| 37 | |||
| 38 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | GaivoronskiyMGrahamScanMPI::GaivoronskiyMGrahamScanMPI(const InType &in) { |
| 39 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 40 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | GetInput() = in; |
| 41 | GetOutput().clear(); | ||
| 42 | 12 | } | |
| 43 | |||
| 44 | 12 | bool GaivoronskiyMGrahamScanMPI::ValidationImpl() { | |
| 45 | 12 | int rank = 0; | |
| 46 | 12 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 47 | |||
| 48 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 49 | 6 | return GetInput().size() >= 3; | |
| 50 | } | ||
| 51 | return true; | ||
| 52 | } | ||
| 53 | |||
| 54 | 12 | bool GaivoronskiyMGrahamScanMPI::PreProcessingImpl() { | |
| 55 | 12 | int rank = 0; | |
| 56 | 12 | int size = 0; | |
| 57 | 12 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 58 | 12 | MPI_Comm_size(MPI_COMM_WORLD, &size); | |
| 59 | |||
| 60 | 12 | int n_points = 0; | |
| 61 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 62 | 6 | points_ = GetInput(); | |
| 63 | 6 | n_points = static_cast<int>(points_.size()); | |
| 64 | } | ||
| 65 | |||
| 66 | 12 | MPI_Bcast(&n_points, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 67 | |||
| 68 | 12 | int base_size = n_points / size; | |
| 69 | 12 | int remainder = n_points % size; | |
| 70 | |||
| 71 | 12 | std::vector<int> send_counts(size); | |
| 72 |
1/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
12 | std::vector<int> displs(size); |
| 73 | |||
| 74 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
|
36 | for (int i = 0; i < size; i++) { |
| 75 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6 times.
|
42 | send_counts[i] = (base_size + (i < remainder ? 1 : 0)) * 2; |
| 76 | 24 | displs[i] = (i * base_size + std::min(i, remainder)) * 2; | |
| 77 | } | ||
| 78 | |||
| 79 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | int local_size = send_counts[rank] / 2; |
| 80 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | local_points_.resize(local_size); |
| 81 | |||
| 82 | 12 | std::vector<double> flat_points; | |
| 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 | flat_points.resize(static_cast<size_t>(n_points) * 2); |
| 85 |
2/2✓ Branch 0 taken 93 times.
✓ Branch 1 taken 6 times.
|
99 | for (int i = 0; i < n_points; i++) { |
| 86 | 93 | flat_points[static_cast<size_t>(i) * 2] = points_[i].x; | |
| 87 | 93 | flat_points[(static_cast<size_t>(i) * 2) + 1] = points_[i].y; | |
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 |
1/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
12 | std::vector<double> local_flat(static_cast<size_t>(local_size) * 2); |
| 92 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | MPI_Scatterv(flat_points.data(), send_counts.data(), displs.data(), MPI_DOUBLE, local_flat.data(), send_counts[rank], |
| 93 | MPI_DOUBLE, 0, MPI_COMM_WORLD); | ||
| 94 | |||
| 95 |
2/2✓ Branch 0 taken 93 times.
✓ Branch 1 taken 12 times.
|
105 | for (int i = 0; i < local_size; i++) { |
| 96 | 93 | local_points_[i].x = local_flat[static_cast<size_t>(i) * 2]; | |
| 97 | 93 | local_points_[i].y = local_flat[(static_cast<size_t>(i) * 2) + 1]; | |
| 98 | } | ||
| 99 | |||
| 100 | 12 | return true; | |
| 101 | } | ||
| 102 | |||
| 103 | 18 | std::vector<double> GaivoronskiyMGrahamScanMPI::PointsToFlat(const std::vector<Point> &points) { | |
| 104 | 18 | std::vector<double> flat_data(points.size() * 2); | |
| 105 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 18 times.
|
106 | for (size_t i = 0; i < points.size(); i++) { |
| 106 | 88 | flat_data[(i * 2)] = points[i].x; | |
| 107 | 88 | flat_data[(i * 2) + 1] = points[i].y; | |
| 108 | } | ||
| 109 | 18 | return flat_data; | |
| 110 | } | ||
| 111 | |||
| 112 | 12 | std::vector<Point> GaivoronskiyMGrahamScanMPI::FlatToPoints(const std::vector<double> &flat_data, int num_points) { | |
| 113 | 12 | std::vector<Point> points(num_points); | |
| 114 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 12 times.
|
100 | for (int i = 0; i < num_points; i++) { |
| 115 | 88 | points[i].x = flat_data[static_cast<size_t>(i) * 2]; | |
| 116 | 88 | points[i].y = flat_data[(static_cast<size_t>(i) * 2) + 1]; | |
| 117 | } | ||
| 118 | 12 | return points; | |
| 119 | } | ||
| 120 | |||
| 121 | 12 | void GaivoronskiyMGrahamScanMPI::GatherAndMergeHulls(const std::vector<Point> &local_hull, int rank, int size) { | |
| 122 | 12 | int local_hull_size = static_cast<int>(local_hull.size()); | |
| 123 |
1/2✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
12 | std::vector<int> hull_sizes(size); |
| 124 | |||
| 125 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | MPI_Gather(&local_hull_size, 1, MPI_INT, hull_sizes.data(), 1, MPI_INT, 0, MPI_COMM_WORLD); |
| 126 | |||
| 127 |
1/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
12 | std::vector<int> displs(size); |
| 128 |
1/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
12 | std::vector<int> recv_counts(size); |
| 129 | int total_hull_points = 0; | ||
| 130 | |||
| 131 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 132 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
|
18 | for (int i = 0; i < size; i++) { |
| 133 | 12 | recv_counts[i] = hull_sizes[i] * 2; | |
| 134 | 12 | displs[i] = total_hull_points * 2; | |
| 135 | 12 | total_hull_points += hull_sizes[i]; | |
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | std::vector<double> local_hull_flat = PointsToFlat(local_hull); |
| 140 | |||
| 141 | 12 | std::vector<double> all_hulls_flat; | |
| 142 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 143 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | all_hulls_flat.resize(static_cast<size_t>(total_hull_points) * 2); |
| 144 | } | ||
| 145 | |||
| 146 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | MPI_Gatherv(local_hull_flat.data(), local_hull_size * 2, MPI_DOUBLE, all_hulls_flat.data(), recv_counts.data(), |
| 147 | displs.data(), MPI_DOUBLE, 0, MPI_COMM_WORLD); | ||
| 148 | |||
| 149 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 150 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | std::vector<Point> combined_points = FlatToPoints(all_hulls_flat, total_hull_points); |
| 151 |
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.
|
12 | hull_ = GrahamScan(combined_points); |
| 152 | } | ||
| 153 | 12 | } | |
| 154 | |||
| 155 | 12 | void GaivoronskiyMGrahamScanMPI::BroadcastResult(int rank) { | |
| 156 | 12 | int result_size = 0; | |
| 157 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 158 | 6 | result_size = static_cast<int>(hull_.size()); | |
| 159 | } | ||
| 160 | 12 | MPI_Bcast(&result_size, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 161 | |||
| 162 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank != 0) { |
| 163 | 6 | hull_.resize(result_size); | |
| 164 | } | ||
| 165 | |||
| 166 | 12 | std::vector<double> result_flat; | |
| 167 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 168 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | result_flat = PointsToFlat(hull_); |
| 169 | } else { | ||
| 170 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | result_flat.resize(static_cast<size_t>(result_size) * 2); |
| 171 | } | ||
| 172 | |||
| 173 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | MPI_Bcast(result_flat.data(), result_size * 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); |
| 174 | |||
| 175 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank != 0) { |
| 176 |
1/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
12 | hull_ = FlatToPoints(result_flat, result_size); |
| 177 | } | ||
| 178 | 12 | } | |
| 179 | |||
| 180 | 12 | bool GaivoronskiyMGrahamScanMPI::RunImpl() { | |
| 181 | 12 | int rank = 0; | |
| 182 | 12 | int size = 0; | |
| 183 | 12 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 184 | 12 | MPI_Comm_size(MPI_COMM_WORLD, &size); | |
| 185 | |||
| 186 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | std::vector<Point> local_hull; |
| 187 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (!local_points_.empty()) { |
| 188 |
1/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
24 | local_hull = GrahamScan(local_points_); |
| 189 | } | ||
| 190 | |||
| 191 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | GatherAndMergeHulls(local_hull, rank, size); |
| 192 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | BroadcastResult(rank); |
| 193 | |||
| 194 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | GetOutput() = hull_; |
| 195 | |||
| 196 | 12 | return true; | |
| 197 | } | ||
| 198 | |||
| 199 | 12 | bool GaivoronskiyMGrahamScanMPI::PostProcessingImpl() { | |
| 200 | 12 | return GetOutput().size() >= 3; | |
| 201 | } | ||
| 202 | |||
| 203 | 14 | size_t GaivoronskiyMGrahamScanMPI::FindLowestPoint(const std::vector<Point> &pts) { | |
| 204 | size_t min_idx = 0; | ||
| 205 |
2/2✓ Branch 0 taken 123 times.
✓ Branch 1 taken 14 times.
|
137 | for (size_t i = 1; i < pts.size(); i++) { |
| 206 |
6/6✓ Branch 0 taken 100 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 93 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 1 times.
|
123 | if (pts[i].y < pts[min_idx].y || (pts[i].y == pts[min_idx].y && pts[i].x < pts[min_idx].x)) { |
| 207 | min_idx = i; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | 14 | return min_idx; | |
| 211 | } | ||
| 212 | |||
| 213 | 14 | size_t GaivoronskiyMGrahamScanMPI::RemoveCollinearPoints(std::vector<Point> &pts, const Point &p0) { | |
| 214 | size_t m = 1; | ||
| 215 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 14 times.
|
125 | for (size_t i = 1; i < pts.size(); i++) { |
| 216 |
4/4✓ Branch 0 taken 109 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 97 times.
|
123 | while (i < pts.size() - 1 && Orientation(p0, pts[i], pts[i + 1]) == 0) { |
| 217 | i++; | ||
| 218 | } | ||
| 219 | 111 | pts[m] = pts[i]; | |
| 220 | 111 | m++; | |
| 221 | } | ||
| 222 | 14 | return m; | |
| 223 | } | ||
| 224 | |||
| 225 | 13 | std::vector<Point> GaivoronskiyMGrahamScanMPI::BuildConvexHull(const std::vector<Point> &pts, size_t num_points) { | |
| 226 | std::stack<Point> s; | ||
| 227 | s.push(pts[0]); | ||
| 228 | s.push(pts[1]); | ||
| 229 | s.push(pts[2]); | ||
| 230 | |||
| 231 |
2/2✓ Branch 0 taken 84 times.
✓ Branch 1 taken 13 times.
|
97 | for (size_t i = 3; i < num_points; i++) { |
| 232 |
1/2✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
|
84 | Point top = s.top(); |
| 233 | s.pop(); | ||
| 234 |
1/2✓ Branch 0 taken 129 times.
✗ Branch 1 not taken.
|
129 | while (!s.empty() && Orientation(s.top(), top, pts[i]) != 2) { |
| 235 |
1/2✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
|
45 | top = s.top(); |
| 236 | s.pop(); | ||
| 237 | } | ||
| 238 | s.push(top); | ||
| 239 | s.push(pts[i]); | ||
| 240 | } | ||
| 241 | |||
| 242 | 13 | std::vector<Point> result; | |
| 243 |
2/2✓ Branch 0 taken 78 times.
✓ Branch 1 taken 13 times.
|
91 | while (!s.empty()) { |
| 244 | result.push_back(s.top()); | ||
| 245 | s.pop(); | ||
| 246 | } | ||
| 247 | |||
| 248 | std::ranges::reverse(result); | ||
| 249 | 13 | return result; | |
| 250 | } | ||
| 251 | |||
| 252 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | std::vector<Point> GaivoronskiyMGrahamScanMPI::GrahamScan(const std::vector<Point> &points) { |
| 253 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (points.empty()) { |
| 254 | ✗ | return {}; | |
| 255 | } | ||
| 256 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (points.size() < 3) { |
| 257 | 4 | return points; | |
| 258 | } | ||
| 259 | |||
| 260 | 14 | std::vector<Point> pts = points; | |
| 261 | |||
| 262 | 14 | size_t min_idx = FindLowestPoint(pts); | |
| 263 | std::swap(pts[0], pts[min_idx]); | ||
| 264 | 14 | const Point p0_local = pts[0]; | |
| 265 | |||
| 266 | 14 | std::sort(pts.begin() + 1, pts.end(), | |
| 267 |
14/24✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 250 times.
✓ Branch 5 taken 90 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 23 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 23 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 19 times.
✓ Branch 23 taken 70 times.
|
503 | [&p0_local](const Point &p1, const Point &p2) { return Compare(p1, p2, p0_local); }); |
| 268 | |||
| 269 | 14 | size_t m = RemoveCollinearPoints(pts, p0_local); | |
| 270 | |||
| 271 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
|
14 | if (m < 3) { |
| 272 | return pts; | ||
| 273 | } | ||
| 274 | |||
| 275 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | return BuildConvexHull(pts, m); |
| 276 | } | ||
| 277 | |||
| 278 | ✗ | std::vector<Point> GaivoronskiyMGrahamScanMPI::MergeHulls(const std::vector<Point> &hull1, | |
| 279 | const std::vector<Point> &hull2) { | ||
| 280 | ✗ | std::vector<Point> combined = hull1; | |
| 281 | ✗ | combined.insert(combined.end(), hull2.begin(), hull2.end()); | |
| 282 | ✗ | return GrahamScan(combined); | |
| 283 | } | ||
| 284 | |||
| 285 | } // namespace gaivoronskiy_m_grachem_method | ||
| 286 |