|
| 1 | +# sorting_network_cpp |
| 2 | + |
| 3 | +sorting_network_cpp offers templated implementations of various types of [sorting networks](https://en.wikipedia.org/wiki/Sorting_network) which can drastically improve performance for small problem sizes of simple data compared to regular sorting algorithms (e.g. `std::sort`). |
| 4 | + |
| 5 | +Following listing shows the execution time for different algorithms to sort one million arrays of each 32 random `float` values on an AMD Ryzen 7 2700x @3.70 GHz (compiled with clang 12.0.0 `-O3`): |
| 6 | + |
| 7 | +| algorithm | time (ms) | speedup vs `std::sort` | |
| 8 | +|-----------------------------|:---------:|:----------------------:| |
| 9 | +| Batcher Odd Even Merge Sort | 74.10 | 8.4 | |
| 10 | +| Bitonic Merge Sort | 86.53 | 7.2 | |
| 11 | +| Bose Nelson Sort | 73.05 | 8.6 | |
| 12 | +| Bubble Sort | 185.58 | 3.3 | |
| 13 | +| Insertion Sort | 189.93 | 3.3 | |
| 14 | +| std::sort | 628.74 | 1 | |
| 15 | + |
| 16 | +An interactive overview of performance measurements for the sorting networks on different data types and problem sizes can be found [here](https://raw.githack.com/quxflux/sorting_network_cpp/master/doc/data_explorer.htm). |
| 17 | + |
| 18 | +## Usage |
| 19 | + |
| 20 | +A single class `sorting_network` is available which encapsulates the implementation of the different sorting networks. |
| 21 | + |
| 22 | +Following listing gives a few examples: |
| 23 | + |
| 24 | +```cpp |
| 25 | +#include <sorting_network_cpp/sorting_network.hpp> |
| 26 | + |
| 27 | +#include <array> |
| 28 | +#include <cstdint> |
| 29 | + |
| 30 | +void example() |
| 31 | +{ |
| 32 | + using namespace quxflux::sorting_net; |
| 33 | + |
| 34 | + static constexpr std::size_t N = 16; |
| 35 | + |
| 36 | + { |
| 37 | + std::array<int, N> my_array; |
| 38 | + // fill array... |
| 39 | + |
| 40 | + sorting_network<N>{}(my_array.begin()); |
| 41 | + // my_array is now sorted |
| 42 | + } |
| 43 | + |
| 44 | + { |
| 45 | + int data[N]; |
| 46 | + // fill array... |
| 47 | + |
| 48 | + // raw pointers work as well... |
| 49 | + sorting_network<N>{}(data); |
| 50 | + // data is now sorted |
| 51 | + } |
| 52 | + |
| 53 | + { |
| 54 | + int data[N]; |
| 55 | + |
| 56 | + // by default std::less<T> is used as comparator, custom comparators |
| 57 | + // may be passed as follows: |
| 58 | + |
| 59 | + // custom comparators |
| 60 | + sorting_network<N>{}(data, compare_and_swap<int, std::less<int>>{}); |
| 61 | + |
| 62 | + // function objects |
| 63 | + struct predicate |
| 64 | + { |
| 65 | + constexpr bool operator()(const int a, const int b) const { return a < b; } |
| 66 | + }; |
| 67 | + |
| 68 | + sorting_network<N>{}(data, compare_and_swap<int, predicate>{}); |
| 69 | + } |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +When no `type` is explicitly specified as template argument for `sorting_network`, the `type::bose_nelson_sort` is used. |
| 74 | + |
| 75 | +Available network types ATM are: |
| 76 | +* `insertion_sort` |
| 77 | +* `bubble_sort` |
| 78 | +* `bose_nelson_sort` |
| 79 | +* `batcher_odd_even_merge_sort` |
| 80 | +* `bitonic_merge_sort` |
| 81 | +* `size_optimized_sort` |
| 82 | + |
| 83 | +Following example shows how to specify a different `type` than the default one: |
| 84 | + |
| 85 | +```cpp |
| 86 | +quxflux::sorting_net::sorting_network<N, quxflux::sorting_net::type::bitonic_merge_sort>()(std::begin(data_to_be_sorted)); |
| 87 | +``` |
| 88 | +## Using custom compare and swap implementations |
| 89 | + |
| 90 | +The compare and swap operation is the fundamental element a sorting network is composed of. The default implementation works well on scalar types, but if you want to specify a custom implementation (e.g. when hardware intrinsics should be used) you may do this by providing a compare and swap functor to the `sorting_network::operator()` as in following example: |
| 91 | + |
| 92 | +```cpp |
| 93 | +#include <sorting_network_cpp/sorting_network.hpp> |
| 94 | + |
| 95 | +#include <array> |
| 96 | + |
| 97 | +void example(std::array<float,3>& arr) |
| 98 | +{ |
| 99 | + quxflux::sorting_net::sorting_network<3>{}(arr, [](float& a, float& b){ |
| 100 | + const auto b_cpy = b; |
| 101 | + b = std::max(a, b); |
| 102 | + a = std::min(a, b_cpy); |
| 103 | + }); |
| 104 | +} |
| 105 | +``` |
| 106 | +
|
| 107 | +## Requirements |
| 108 | +A compiler with C++17 support |
| 109 | +
|
| 110 | +## Dependencies |
| 111 | +For the bare sorting functionality no dependencies are required. If you want to run the tests, the needed dependencies will be installed via conan. |
| 112 | +
|
| 113 | +## Limitations |
| 114 | +* Depending on the implementation of the comparator the performance advantage of a sorting net compared to a regular sorting algorithm (e.g. `std::sort`) may diminish or even result in worse performance. This can be seen in the [interactive benchmark results overview](https://raw.githack.com/quxflux/sorting_network_cpp/master/doc/data_explorer.htm) for the data type `Vec2i Z-order` which causes in most cases all variants of sorting networks being outperformed by `std::sort` (see [src/benchmark.cpp](src/benchmark.cpp) for the implementation of the aforementioned data type). |
| 115 | +* msvc will fail compiling larger `insertion_sort` networks in certain (unknown) configurations with `fatal error C1202: recursive type or function dependency context too complex` |
| 116 | +
|
| 117 | +## References / Acknowledgements |
| 118 | +* ["A Sorting Problem"](https://dl.acm.org/doi/pdf/10.1145/321119.321126) by Bose et al. |
| 119 | +* ["Sorting networks and their applications"](https://core.ac.uk/download/pdf/192393620.pdf) by Batcher |
| 120 | +* [Vectorized/Static-Sort](https://github.com/Vectorized/Static-Sort) adaption for Bose-Nelson sort |
| 121 | +* [HS Flensburg](https://www.inf.hs-flensburg.de/lang/algorithmen/sortieren/networks/oemen.htm) explanation for Batcher's odd-even mergesort |
| 122 | +* [HS Flensburg](https://www.inf.hs-flensburg.de/lang/algorithmen/sortieren/bitonic/oddn.htm) explanation for bitonic sort |
| 123 | +* [SortHunter](https://github.com/bertdobbelaere/SorterHunter) for size optimized sorting networks |
| 124 | +* [Google Test](https://github.com/google/googletest) for testing |
| 125 | +* [Chart.js](https://www.chartjs.org/) and [Papa Parse](https://www.papaparse.com/) for the visualization of benchmark results |
| 126 | +
|
| 127 | +## License |
| 128 | +[GPLv3](LICENSE) |
0 commit comments