@@ -46,15 +46,15 @@ void dbscan(MPI_Comm comm, ExecutionSpace const &space,
46
46
47
47
ARBORX_ASSERT (eps > 0 );
48
48
ARBORX_ASSERT (core_min_size >= 2 );
49
- if (core_min_size > 2 )
50
- Kokkos::abort (" minPts > 2 is not supported yet" );
51
49
52
50
using Point = typename Points::value_type;
53
51
static_assert (GeometryTraits::is_point_v<Point >);
54
52
static_assert (
55
53
std::is_same_v<typename GeometryTraits::coordinate_type<Point >::type,
56
54
Coordinate>);
57
55
56
+ bool const is_special_case = (core_min_size == 2 );
57
+
58
58
Points points{primitives}; // NOLINT
59
59
int const n_local = points.size ();
60
60
@@ -65,8 +65,13 @@ void dbscan(MPI_Comm comm, ExecutionSpace const &space,
65
65
Kokkos::View<int *, MemorySpace> ghost_ids (prefix + " ghost_ids" , 0 );
66
66
Kokkos::View<Point *, MemorySpace> ghost_points (prefix + " ghost_points" , 0 );
67
67
Kokkos::View<int *, MemorySpace> ghost_ranks (prefix + " ghost_ranks" , 0 );
68
- Details::forwardNeighbors (comm, space, points, eps, ghost_points, ghost_ids,
69
- ghost_ranks);
68
+ // For minPts=2 case, we only need to fetch the ponts within eps distance.
69
+ // For minPts>2, we need points within 2*eps distance to allow to use the
70
+ // local DBSCAN algorithm to determine core points.
71
+ Details::forwardNeighbors (
72
+ comm, space, points,
73
+ (is_special_case ? eps : std::nextafter (2 * eps, 10 * eps)), ghost_points,
74
+ ghost_ids, ghost_ranks);
70
75
int const n_ghost = ghost_points.size ();
71
76
72
77
// Step 2: do local DBSCAN
@@ -142,13 +147,36 @@ void dbscan(MPI_Comm comm, ExecutionSpace const &space,
142
147
Kokkos::resize (space, ghost_labels, num_compressed);
143
148
Details::communicateNeighborDataBack (comm, space, ghost_ranks, ghost_ids,
144
149
ghost_labels);
150
+ Kokkos::resize (ghost_ranks, 0 ); // free space
145
151
146
152
// Step 5: process multi-labeled indices
147
153
Kokkos::View<Details::MergePair *, MemorySpace> local_merge_pairs (
148
154
prefix + " local_merge_pairs" , 0 );
149
- Details::computeMergePairs (space, labels, ghost_ids, ghost_labels,
150
- local_merge_pairs);
155
+ if (is_special_case)
156
+ {
157
+ Details::computeMergePairs (space, Details::CCSCorePoints{}, labels,
158
+ ghost_ids, ghost_labels, local_merge_pairs);
159
+ }
160
+ else
161
+ {
162
+ BoundingVolumeHierarchy bvh (
163
+ space, Details::UnifiedPoints<Points, decltype (ghost_points)>{
164
+ points, ghost_points});
165
+
166
+ Kokkos::View<int *, MemorySpace> num_neigh (prefix + " num_neighbors" ,
167
+ n_local);
168
+ bvh.query (space,
169
+ Experimental::attach_indices (
170
+ Experimental::make_intersects (points, eps)),
171
+ Details::CountUpToN<MemorySpace>{num_neigh, core_min_size});
172
+
173
+ Details::computeMergePairs (
174
+ space, Details::DBSCANCorePoints<MemorySpace>{num_neigh, core_min_size},
175
+ labels, ghost_ids, ghost_labels, local_merge_pairs);
176
+ }
151
177
sortAndFilterMergePairs (space, local_merge_pairs);
178
+ Kokkos::resize (ghost_ids, 0 ); // free space
179
+ Kokkos::resize (ghost_labels, 0 ); // free space
152
180
153
181
// Step 6: communicate merge pairs (all-to-all)
154
182
Kokkos::View<Details::MergePair *, MemorySpace> global_merge_pairs (
0 commit comments