small_gicp
sort_omp.hpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright 2024 Kenji Koide
2 // SPDX-License-Identifier: MIT
3 #pragma once
4 
5 #include <algorithm>
6 
7 #ifdef _MSC_VER
8 #pragma message("warning: Task-based OpenMP parallelism is not well supported on windows.")
9 #pragma message("warning: Thus, OpenMP-based downsampling is only partially parallelized on windows.")
10 #endif
11 
12 namespace small_gicp {
13 
18 template <typename RandomAccessIterator, typename Compare>
19 void merge_sort_omp_impl(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp) {
20  const size_t n = std::distance(first, last);
21  if (n < 1024) {
22  std::sort(first, last, comp);
23  return;
24  }
25 
26  auto center = first + n / 2;
27 
28 #pragma omp task
29  merge_sort_omp_impl(first, center, comp);
30 
31 #pragma omp task
32  merge_sort_omp_impl(center, last, comp);
33 
34 #pragma omp taskwait
35  std::inplace_merge(first, center, last, comp);
36 }
37 
44 template <typename RandomAccessIterator, typename Compare>
45 void merge_sort_omp(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp, int num_threads) {
46 #ifndef _MSC_VER
47 #pragma omp parallel num_threads(num_threads)
48  {
49 #pragma omp single nowait
50  { merge_sort_omp_impl(first, last, comp); }
51  }
52 #else
53  std::stable_sort(first, last, comp);
54 #endif
55 }
56 
61 template <typename RandomAccessIterator, typename Compare>
62 void quick_sort_omp_impl(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp) {
63  const std::ptrdiff_t n = std::distance(first, last);
64  if (n < 1024) {
65  std::sort(first, last, comp);
66  return;
67  }
68 
69  const auto median3 = [&](const auto& a, const auto& b, const auto& c, const Compare& comp) {
70  return comp(a, b) ? (comp(b, c) ? b : (comp(a, c) ? c : a)) : (comp(a, c) ? a : (comp(b, c) ? c : b));
71  };
72 
73  const int offset = n / 8;
74  const auto m1 = median3(*first, *(first + offset), *(first + offset * 2), comp);
75  const auto m2 = median3(*(first + offset * 3), *(first + offset * 4), *(first + offset * 5), comp);
76  const auto m3 = median3(*(first + offset * 6), *(first + offset * 7), *(last - 1), comp);
77 
78  auto pivot = median3(m1, m2, m3, comp);
79  auto middle1 = std::partition(first, last, [&](const auto& val) { return comp(val, pivot); });
80  auto middle2 = std::partition(middle1, last, [&](const auto& val) { return !comp(pivot, val); });
81 
82 #pragma omp task
83  quick_sort_omp_impl(first, middle1, comp);
84 
85 #pragma omp task
86  quick_sort_omp_impl(middle2, last, comp);
87 }
88 
94 template <typename RandomAccessIterator, typename Compare>
95 void quick_sort_omp(RandomAccessIterator first, RandomAccessIterator last, const Compare& comp, int num_threads) {
96 #ifndef _MSC_VER
97 #pragma omp parallel num_threads(num_threads)
98  {
99 #pragma omp single nowait
100  { quick_sort_omp_impl(first, last, comp); }
101  }
102 #else
103  std::sort(first, last, comp);
104 #endif
105 }
106 
107 } // namespace small_gicp
Definition: flat_container.hpp:12
void merge_sort_omp_impl(RandomAccessIterator first, RandomAccessIterator last, const Compare &comp)
Implementation of merge sort with OpenMP parallelism. Do not call this directly. Use merge_sort_omp i...
Definition: sort_omp.hpp:19
void quick_sort_omp_impl(RandomAccessIterator first, RandomAccessIterator last, const Compare &comp)
Implementation of quick sort with OpenMP parallelism. Do not call this directly. Use quick_sort_omp i...
Definition: sort_omp.hpp:62
void quick_sort_omp(RandomAccessIterator first, RandomAccessIterator last, const Compare &comp, int num_threads)
Quick sort with OpenMP parallelism.
Definition: sort_omp.hpp:95
void merge_sort_omp(RandomAccessIterator first, RandomAccessIterator last, const Compare &comp, int num_threads)
Merge sort with OpenMP parallelism.
Definition: sort_omp.hpp:45