Skip to content

Commit

Permalink
Merge pull request #1213 from aprokop/experimental_mst
Browse files Browse the repository at this point in the history
Move MinimumSpanningTree and WeightedEdge to Experimenal namespace
  • Loading branch information
aprokop authored Feb 6, 2025
2 parents fee3d77 + 6e14ede commit f26ef0a
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 63 deletions.
2 changes: 1 addition & 1 deletion benchmarks/dbscan/dbscan_timpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ bool ArborXBenchmark::run(ArborXBenchmark::Parameters const &params)
{

Kokkos::Profiling::pushRegion("ArborX::MST::total");
ArborX::Details::MinimumSpanningTree<MemorySpace> mst(
ArborX::Experimental::MinimumSpanningTree<MemorySpace> mst(
exec_space, primitives, params.core_min_size);
Kokkos::Profiling::popRegion();

Expand Down
4 changes: 2 additions & 2 deletions src/cluster/ArborX_Dendrogram.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct Dendrogram

template <typename ExecutionSpace>
Dendrogram(ExecutionSpace const &exec_space,
Kokkos::View<Details::WeightedEdge *, MemorySpace> edges)
Kokkos::View<Experimental::WeightedEdge *, MemorySpace> edges)
: _parents("ArborX::Dendrogram::parents", 0)
, _parent_heights("ArborX::Dendrogram::parent_heights", 0)
{
Expand Down Expand Up @@ -81,7 +81,7 @@ struct Dendrogram
template <typename ExecutionSpace>
void splitEdges(
ExecutionSpace const &exec_space,
Kokkos::View<Details::WeightedEdge *, MemorySpace> edges,
Kokkos::View<Experimental::WeightedEdge *, MemorySpace> edges,
Kokkos::View<Details::UnweightedEdge *, MemorySpace> unweighted_edges,
Kokkos::View<float *, MemorySpace> weights)
{
Expand Down
62 changes: 32 additions & 30 deletions src/cluster/ArborX_MinimumSpanningTree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@
#include <Kokkos_Core.hpp>
#include <Kokkos_Profiling_ScopedRegion.hpp>

namespace ArborX::Details
namespace ArborX::Experimental
{

template <class MemorySpace, BoruvkaMode Mode = BoruvkaMode::MST>
template <class MemorySpace,
Details::BoruvkaMode Mode = Details::BoruvkaMode::MST>
struct MinimumSpanningTree
{
using memory_space = MemorySpace;
Expand Down Expand Up @@ -69,11 +70,11 @@ struct MinimumSpanningTree
bvh.query(
space,
Experimental::attach_indices(Experimental::make_nearest(points, k)),
MaxDistance<Points, decltype(core_distances)>{points,
core_distances});
Details::MaxDistance<Points, decltype(core_distances)>{
points, core_distances});
Kokkos::Profiling::popRegion();

MutualReachability<decltype(core_distances)> mutual_reachability{
Details::MutualReachability<decltype(core_distances)> mutual_reachability{
core_distances};
Kokkos::Profiling::pushRegion("ArborX::MST::boruvka");
doBoruvka(space, bvh, mutual_reachability);
Expand All @@ -82,11 +83,11 @@ struct MinimumSpanningTree
else
{
Kokkos::Profiling::pushRegion("ArborX::MST::boruvka");
doBoruvka(space, bvh, Euclidean{});
doBoruvka(space, bvh, Details::Euclidean{});
Kokkos::Profiling::popRegion();
}

finalizeEdges(space, bvh, edges);
Details::finalizeEdges(space, bvh, edges);

Kokkos::Profiling::popRegion();
}
Expand All @@ -107,7 +108,7 @@ struct MinimumSpanningTree
Kokkos::view_alloc(space, Kokkos::WithoutInitializing,
"ArborX::MST::tree_parents"),
2 * n - 1);
findParents(space, bvh, tree_parents);
Details::findParents(space, bvh, tree_parents);

Kokkos::Profiling::pushRegion("ArborX::MST::initialize_node_labels");
Kokkos::View<int *, MemorySpace> labels(
Expand All @@ -118,7 +119,7 @@ struct MinimumSpanningTree
Kokkos::subview(labels, std::make_pair((decltype(n))0, n)));
Kokkos::Profiling::popRegion();

Kokkos::View<DirectedEdge *, MemorySpace> component_out_edges(
Kokkos::View<Details::DirectedEdge *, MemorySpace> component_out_edges(
Kokkos::view_alloc(space, Kokkos::WithoutInitializing,
"ArborX::MST::component_out_edges"),
n);
Expand Down Expand Up @@ -169,7 +170,7 @@ struct MinimumSpanningTree

Kokkos::View<int *, MemorySpace> sided_parents("ArborX::MST::sided_parents",
0);
if constexpr (Mode == BoruvkaMode::HDBSCAN)
if constexpr (Mode == Details::BoruvkaMode::HDBSCAN)
{
KokkosExt::reallocWithoutInitializing(space, edges_mapping, n - 1);
KokkosExt::reallocWithoutInitializing(space, sided_parents, n - 1);
Expand All @@ -189,16 +190,16 @@ struct MinimumSpanningTree
std::to_string(num_components));

// Propagate leaf node labels to internal nodes
reduceLabels(space, tree_parents, labels);
Details::reduceLabels(space, tree_parents, labels);

constexpr auto inf = KokkosExt::ArithmeticTraits::infinity<float>::value;
constexpr DirectedEdge uninitialized_edge;
constexpr Details::DirectedEdge uninitialized_edge;
Kokkos::deep_copy(space, component_out_edges, uninitialized_edge);
Kokkos::deep_copy(space, weights, inf);
Kokkos::deep_copy(space, radii, inf);
resetSharedRadii(space, bvh, labels, metric, radii);

FindComponentNearestNeighbors(
Details::FindComponentNearestNeighbors(
space, bvh, labels, weights, component_out_edges, metric, radii,
lower_bounds, std::bool_constant<use_shared_radii>());
retrieveEdges(space, labels, weights, component_out_edges);
Expand All @@ -207,48 +208,49 @@ struct MinimumSpanningTree
updateLowerBounds(space, labels, component_out_edges, lower_bounds);
}

UpdateComponentsAndEdges<decltype(labels), decltype(component_out_edges),
decltype(edges), decltype(edges_mapping),
decltype(num_edges), Mode>
Details::UpdateComponentsAndEdges<
decltype(labels), decltype(component_out_edges), decltype(edges),
decltype(edges_mapping), decltype(num_edges), Mode>
f{labels, component_out_edges, edges, edges_mapping, num_edges};

// For every component C and a found shortest edge `(u, w)`, add the
// edge to the list of MST edges.
Kokkos::parallel_for(
"ArborX::MST::update_unidirectional_edges",
Kokkos::RangePolicy<ExecutionSpace, UnidirectionalEdgesTag>(space, 0,
n),
Kokkos::RangePolicy<ExecutionSpace, Details::UnidirectionalEdgesTag>(
space, 0, n),
f);

int num_edges_host;
Kokkos::deep_copy(space, num_edges_host, num_edges);
space.fence();

if constexpr (Mode == BoruvkaMode::HDBSCAN)
if constexpr (Mode == Details::BoruvkaMode::HDBSCAN)
{
Kokkos::parallel_for(
"ArborX::MST::update_bidirectional_edges",
Kokkos::RangePolicy<ExecutionSpace, BidirectionalEdgesTag>(space, 0,
n),
Kokkos::RangePolicy<ExecutionSpace, Details::BidirectionalEdgesTag>(
space, 0, n),
f);

if (iterations > 1)
updateSidedParents(space, labels, edges, edges_mapping, sided_parents,
edges_start, edges_end);
Details::updateSidedParents(space, labels, edges, edges_mapping,
sided_parents, edges_start, edges_end);
else
{
Kokkos::Profiling::ScopedRegion guard(
"ArborX::MST::compute_vertex_parents");
assignVertexParents(space, labels, component_out_edges, edges_mapping,
bvh, dendrogram_parents);
Details::assignVertexParents(space, labels, component_out_edges,
edges_mapping, bvh, dendrogram_parents);
}
}

// For every component C and a found shortest edge `(u, w)`, merge C
// with the component that w belongs to by updating the labels
Kokkos::parallel_for(
"ArborX::MST::update_labels",
Kokkos::RangePolicy<ExecutionSpace, LabelsTag>(space, 0, n), f);
Kokkos::RangePolicy<ExecutionSpace, Details::LabelsTag>(space, 0, n),
f);

num_components = static_cast<int>(n) - num_edges_host;

Expand All @@ -267,17 +269,17 @@ struct MinimumSpanningTree
Kokkos::resize(component_out_edges, 0);
Kokkos::resize(tree_parents, 0);

if constexpr (Mode == BoruvkaMode::HDBSCAN)
if constexpr (Mode == Details::BoruvkaMode::HDBSCAN)
{

// Done with the recursion as there are no more alpha edges. Assign
// all current edges to the root chain.
Kokkos::deep_copy(space,
Kokkos::subview(sided_parents,
std::make_pair(edges_start, edges_end)),
ROOT_CHAIN_VALUE);
Details::ROOT_CHAIN_VALUE);

computeParents(space, edges, sided_parents, dendrogram_parents);
Details::computeParents(space, edges, sided_parents, dendrogram_parents);

KokkosExt::reallocWithoutInitializing(space, dendrogram_parent_heights,
n - 1);
Expand All @@ -293,6 +295,6 @@ struct MinimumSpanningTree
}
};

} // namespace ArborX::Details
} // namespace ArborX::Experimental

#endif
4 changes: 2 additions & 2 deletions src/cluster/detail/ArborX_BoruvkaHelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class DirectedEdge
, weight{weight}
{}
KOKKOS_DEFAULTED_FUNCTION constexpr DirectedEdge() = default;
KOKKOS_FUNCTION explicit constexpr operator WeightedEdge()
KOKKOS_FUNCTION explicit constexpr operator Experimental::WeightedEdge()
{
return {source(), target(), weight};
}
Expand Down Expand Up @@ -453,7 +453,7 @@ struct UpdateComponentsAndEdges

// append new edge at the "end" of the array (akin to
// std::vector::push_back)
auto const edge = static_cast<WeightedEdge>(_out_edges(i));
auto const edge = static_cast<Experimental::WeightedEdge>(_out_edges(i));
auto const back =
Kokkos::atomic_fetch_inc(&_num_edges()); // atomic post-increment
_edges(back) = edge;
Expand Down
4 changes: 2 additions & 2 deletions src/cluster/detail/ArborX_WeightedEdge.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <Kokkos_Macros.hpp>
#include <Kokkos_MinMax.hpp>

namespace ArborX::Details
namespace ArborX::Experimental
{

struct WeightedEdge
Expand Down Expand Up @@ -48,6 +48,6 @@ struct WeightedEdge
}
};

} // namespace ArborX::Details
} // namespace ArborX::Experimental

#endif
2 changes: 1 addition & 1 deletion test/tstCompileOnlyWeightedEdges.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ static_assert(test_directed_edges()); // avoid warning unused function

KOKKOS_FUNCTION constexpr bool test_weighted_edges()
{
using ArborX::Details::WeightedEdge;
using ArborX::Experimental::WeightedEdge;

static_assert(WeightedEdge{1, 2, 3} < WeightedEdge{1, 2, 4});

Expand Down
11 changes: 6 additions & 5 deletions test/tstDendrogram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

BOOST_AUTO_TEST_SUITE(Dendrogram)

using ArborX::Details::WeightedEdge;
using ArborX::Experimental::WeightedEdge;
namespace tt = boost::test_tools;

namespace
Expand Down Expand Up @@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(dendrogram_union_find, DeviceType,
ARBORX_DEVICE_TYPES)
{
using ExecutionSpace = typename DeviceType::execution_space;
using ArborX::Details::WeightedEdge;
using ArborX::Experimental::WeightedEdge;

ExecutionSpace space;

Expand Down Expand Up @@ -121,7 +121,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(dendrogram_boruvka, DeviceType,
int const n = 3000;
auto points = ArborXTest::make_random_cloud<ArborX::Point<3>>(space, n);

MinimumSpanningTree<MemorySpace, BoruvkaMode::HDBSCAN> mst(space, points);
ArborX::Experimental::MinimumSpanningTree<MemorySpace, BoruvkaMode::HDBSCAN>
mst(space, points);
ArborX::Experimental::Dendrogram<MemorySpace> dendrogram(space, mst.edges);

// Because the dendrogram in the MST is permuted, we need to reorder it in the
Expand Down Expand Up @@ -209,8 +210,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(dendrogram_boruvka_same_weights, DeviceType,

// minpts = 5 is the first value that leads to the test failure with N = 4
int const minpts = 5;
MinimumSpanningTree<MemorySpace, BoruvkaMode::HDBSCAN> mst(space, points,
minpts);
ArborX::Experimental::MinimumSpanningTree<MemorySpace, BoruvkaMode::HDBSCAN>
mst(space, points, minpts);
ArborX::Experimental::Dendrogram<MemorySpace> dendrogram(space, mst.edges);

// Check that the dendrogram is binary
Expand Down
Loading

0 comments on commit f26ef0a

Please sign in to comment.