From 35c838d26c388c2ece61d8196a5ba2676daffb0c Mon Sep 17 00:00:00 2001 From: Simon Giraudot Date: Thu, 12 Mar 2020 12:21:21 +0100 Subject: [PATCH] Improve doc from review with new example for parallel KD tree --- .../Spatial_searching/Spatial_searching.txt | 24 +++++--- .../doc/Spatial_searching/examples.txt | 1 + .../examples/Spatial_searching/CMakeLists.txt | 14 +++-- .../nearest_neighbor_searching.cpp | 3 - .../Spatial_searching/parallel_kdtree.cpp | 56 +++++++++++++++++++ 5 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 Spatial_searching/examples/Spatial_searching/parallel_kdtree.cpp diff --git a/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt b/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt index b621d7372de..ccee85bab3f 100644 --- a/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt +++ b/Spatial_searching/doc/Spatial_searching/Spatial_searching.txt @@ -407,6 +407,23 @@ higher dimensions. \cgalExample{Spatial_searching/splitter_worst_cases.cpp} +\subsection Spatial_searchingExampleParallel Example for Parallel Neighbor Search + +In order to speed-up the construction of the `kd` tree, the child +branches of each internal node can be computed in parallel, by calling +`Kd_tree::build()`. On a quad-core processor, the +parallel construction is experimentally 2 to 3 times faster than the +sequential version, depending on the point cloud. The parallel version +requires the executable to be linked against the Intel TBB library. + +One query on the `kd` tree is purely sequential, but several queries +can be done in parallel. + +The following example shows how to build the `kd` tree in parallel and +how to perform parallel queries: + +\cgalExample{Spatial_searching/parallel_kdtree.cpp} + \section Performance Performance \subsection OrthogonalPerfomance Performance of the Orthogonal Search @@ -480,13 +497,6 @@ to the nearest nodes exceeds the distance to the nearest point found with a factor 1/ (1+\f$ \epsilon\f$). Priority search supports next neighbor search, standard search does not. -In order to speed-up the construction of the `kd` tree, the child -branches of each internal node can be computed in parallel, by calling -`Kd_tree::build()`. On a quad-core processor, the -parallel construction is experimentally 2 to 3 times faster than the -sequential version, depending on the point cloud. The parallel version -requires the executable to be linked against the Intel TBB library. - In order to speed-up the internal distance computations in nearest neighbor searching in high dimensional space, the approximate searching package supports orthogonal distance computation. Orthogonal distance diff --git a/Spatial_searching/doc/Spatial_searching/examples.txt b/Spatial_searching/doc/Spatial_searching/examples.txt index bf31eef0ad3..597aa1893f9 100644 --- a/Spatial_searching/doc/Spatial_searching/examples.txt +++ b/Spatial_searching/doc/Spatial_searching/examples.txt @@ -18,4 +18,5 @@ \example Spatial_searching/weighted_Minkowski_distance.cpp \example Spatial_searching/splitter_worst_cases.cpp \example Spatial_searching/searching_sphere_orthogonally.cpp +\example Spatial_searching/parallel_kdtree.cpp */ diff --git a/Spatial_searching/examples/Spatial_searching/CMakeLists.txt b/Spatial_searching/examples/Spatial_searching/CMakeLists.txt index 1f5a7059a65..d4fc80181d2 100644 --- a/Spatial_searching/examples/Spatial_searching/CMakeLists.txt +++ b/Spatial_searching/examples/Spatial_searching/CMakeLists.txt @@ -43,11 +43,6 @@ create_single_source_cgal_program( "iso_rectangle_2_query.cpp" ) create_single_source_cgal_program( "nearest_neighbor_searching.cpp" ) -find_package( TBB QUIET ) -if(TBB_FOUND) - cgal_target_use_TBB(nearest_neighbor_searching) -endif() - create_single_source_cgal_program( "searching_with_circular_query.cpp" ) create_single_source_cgal_program( "searching_with_point_with_info.cpp" ) @@ -82,3 +77,12 @@ else() message(STATUS "will not be compiled as they use CGAL::Epick_d which requires the Eigen library.") endif() + +find_package( TBB QUIET ) +if(TBB_FOUND) + create_single_source_cgal_program( "parallel_kdtree.cpp" ) + cgal_target_use_TBB(parallel_kdtree) +else() + message(STATUS "parallel_kdtree.cpp requires TBB and will not be compiled") +endif() + diff --git a/Spatial_searching/examples/Spatial_searching/nearest_neighbor_searching.cpp b/Spatial_searching/examples/Spatial_searching/nearest_neighbor_searching.cpp index 4dc40cd9176..8055c8be058 100644 --- a/Spatial_searching/examples/Spatial_searching/nearest_neighbor_searching.cpp +++ b/Spatial_searching/examples/Spatial_searching/nearest_neighbor_searching.cpp @@ -20,9 +20,6 @@ int main() { Tree tree(points.begin(), points.end()); - // The tree can be built in parallel - tree.build(); - Point_d query(0,0); // Initialize the search structure, and search all N points diff --git a/Spatial_searching/examples/Spatial_searching/parallel_kdtree.cpp b/Spatial_searching/examples/Spatial_searching/parallel_kdtree.cpp new file mode 100644 index 00000000000..a14612a5f22 --- /dev/null +++ b/Spatial_searching/examples/Spatial_searching/parallel_kdtree.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +#include +#include + +using Kernel = CGAL::Simple_cartesian; +using Point_3 = Kernel::Point_3; + +using Traits = CGAL::Search_traits_3; +using Neighbor_search = CGAL::Orthogonal_k_neighbor_search; +using Tree = Neighbor_search::Tree; +using Point_with_distance = Neighbor_search::Point_with_transformed_distance; + +using Generator = CGAL::Random_points_in_sphere_3; + +int main() +{ + const unsigned int N = 1000; + const unsigned int k = 6; + + // Generate N points in a sphere + std::vector points; + points.reserve (N); + Generator generator; + for (unsigned int i = 0; i < N; ++ i) + points.push_back (*(generator++)); + + // Build tree in parallel + Tree tree(points.begin(), points.end()); + tree.build(); + + // Query tree in parallel + std::vector > neighbors (points.size()); + tbb::parallel_for (tbb::blocked_range (0, points.size()), + [&](const tbb::blocked_range& r) + { + for (std::size_t s = r.begin(); s != r.end(); ++ s) + { + // Neighbor search can be instantiated from + // several threads at the same time + Neighbor_search search (tree, points[s], k); + neighbors[s].reserve(k); + + // neighbor search returns a set of pair of + // point and distance , here we + // keep the points only + for (const Point_with_distance& pwd : search) + neighbors[s].push_back (pwd.first); + } + }); + + return 0; +}