Template Numerical Library: Sorting

Template Numerical Library version\ main:0b2c40fb1

Loading...
Searching...
No Matches
Sorting

# Introduction

TNL offers several different parallel algorithms for sorting of arrays (or vectors) and also sorting based on user defined swapping. The latter is more general but also less efficient.

# Sorting of arrays and vectors

The sorting of arrays and vectors is accessible via the following functions:

- TNL::Algorithms::ascendingSort for sorting elements of array in ascending order,
- TNL::Algorithms::descendingSort for sorting elements of array in descending order,
- TNL::Algorithms::sort for sorting with user defined ordering.

The following example demonstrates the use of ascending and descending sort:

1#include <iostream>
2#include <TNL/Containers/Array.h>
3#include <TNL/Algorithms/sort.h>
4
5using namespace TNL;
6using namespace TNL::Containers;
7using namespace TNL::Algorithms;
8
9template< typename ArrayT >
10void
11 sort( ArrayT& array )
12{
13 const int size = 10;
14
15 /****
16 * Fill the array with random integers.
17 */
18 Array< int > aux_array( size );
19 srand( size + 2021 );
20 parallelFor< Devices::Host >(
21 0,
22 size,
23 [ & ]( int i )
24 {
25 aux_array[ i ] = std::rand() % ( 2 * size );
26 } );
27 array = aux_array;
28
29 std::cout << "Random array: " << array << '\n';
30
31 /****
32 * Sort the array in ascending order.
33 */
34 ascendingSort( array );
35 std::cout << "Array sorted in ascending order:" << array << '\n';
36
37 /***
38 * Sort the array in descending order.
39 */
40 descendingSort( array );
41 std::cout << "Array sorted in descending order:" << array << '\n';
42}
43
44int
45main( int argc, char* argv[] )
46{
47 /***
48 * Firstly, test the sorting on CPU.
49 */
50 std::cout << "Sorting on CPU ...\n";
51 Array< int, Devices::Host > host_array;
52 sort( host_array );
53
54#ifdef __CUDACC__
55 /***
56 * And then also on GPU.
57 */
58 std::cout << "Sorting on GPU ...\n";
59 Array< int, Devices::Cuda > cuda_array;
60 sort( cuda_array );
61#endif
62 return EXIT_SUCCESS;
63}
std::cout
TNL::Containers::Array
Array is responsible for memory management, access to array elements, and general array operations.
Definition Array.h:65
TNL::Algorithms
Namespace for fundamental TNL algorithms.
Definition AtomicOperations.h:15
TNL::Algorithms::parallelFor
std::enable_if_t< std::is_integral_v< Begin > &&std::is_integral_v< End > > parallelFor(const Begin &begin, const End &end, typename Device::LaunchConfiguration launch_config, Function f, FunctionArgs... args)
Parallel for-loop function for 1D range specified with integral values.
Definition parallelFor.h:41
TNL::Algorithms::descendingSort
void descendingSort(Array &array, const Sorter &sorter=Sorter{})
Function for sorting elements of array or vector in descending order.
Definition sort.h:69
TNL::Algorithms::sort
void sort(Array &array, const Compare &compare, const Sorter &sorter=Sorter{})
Function for sorting elements of array or vector based on a user defined comparison lambda function.
Definition sort.h:111
TNL::Algorithms::ascendingSort
void ascendingSort(Array &array, const Sorter &sorter=Sorter{})
Function for sorting elements of array or vector in ascending order.
Definition sort.h:38
TNL::Containers
Namespace for TNL containers.
Definition Array.h:17
TNL
The main TNL namespace.
Definition AtomicOperations.h:15
std::rand
T rand(T... args)

Here we create an array with random sequence of integers using the parallelFor function and then we sort the array in ascending order using ascendingSort and descending order using the descendingSort.

The result looks as follows:

Sorting on CPU ...
Random array: [ 5, 1, 15, 5, 0, 11, 2, 14, 14, 8 ]
Array sorted in ascending order:[ 0, 1, 2, 5, 5, 8, 11, 14, 14, 15 ]
Array sorted in descending order:[ 15, 14, 14, 11, 8, 5, 5, 2, 1, 0 ]

How to achieve the same result with user defined ordering is demonstrated by the following example:

1#include <iostream>
2#include <TNL/Containers/Array.h>
3#include <TNL/Algorithms/sort.h>
4
5using namespace TNL;
6using namespace TNL::Containers;
7using namespace TNL::Algorithms;
8
9template< typename ArrayT >
10void
11 sort( ArrayT& array )
12{
13 const int size = 10;
14
15 /****
16 * Fill the array with random integers.
17 */
18 Array< int > aux_array( size );
19 srand( size + 2021 );
20 parallelFor< Devices::Host >(
21 0,
22 size,
23 [ & ]( int i )
24 {
25 aux_array[ i ] = std::rand() % ( 2 * size );
26 } );
27 array = aux_array;
28
29 std::cout << "Random array: " << array << '\n';
30
31 /****
32 * Sort the array in ascending order.
33 */
34 sort(
35 array,
36 [] __cuda_callable__( int a, int b )
37 {
38 return a < b;
39 } );
40 std::cout << "Array sorted in ascending order:" << array << '\n';
41
42 /***
43 * Sort the array in descending order.
44 */
45 sort(
46 array,
47 [] __cuda_callable__( int a, int b )
48 {
49 return a > b;
50 } );
51 std::cout << "Array sorted in descending order:" << array << '\n';
52}
53
54int
55main( int argc, char* argv[] )
56{
57 /***
58 * Firstly, test the sorting on CPU.
59 */
60 std::cout << "Sorting on CPU ...\n";
61 Array< int, Devices::Host > host_array;
62 sort( host_array );
63
64#ifdef __CUDACC__
65 /***
66 * And then also on GPU.
67 */
68 std::cout << "Sorting on GPU ...\n";
69 Array< int, Devices::Cuda > cuda_array;
70 sort( cuda_array );
71#endif
72 return EXIT_SUCCESS;
73}
__cuda_callable__
#define __cuda_callable__
Definition Macros.h:49

The result looks as follows:

Sorting on CPU ...
Random array: [ 5, 1, 15, 5, 0, 11, 2, 14, 14, 8 ]
Array sorted in ascending order:[ 0, 1, 2, 5, 5, 8, 11, 14, 14, 15 ]
Array sorted in descending order:[ 15, 14, 14, 11, 8, 5, 5, 2, 1, 0 ]

The same way, one can sort also TNL::Containers::ArrayView, TNL::Containers::Vector and TNL::Containers::VectorView.

# Sorting with user-defined swapping

1#include <iostream>
2#include <TNL/Containers/Array.h>
3#include <TNL/Algorithms/sort.h>
4
5using namespace TNL;
6using namespace TNL::Containers;
7using namespace TNL::Algorithms;
8
9template< typename ArrayT >
10void
11 sort( ArrayT& array )
12{
13 const int size = 10;
14
15 /****
16 * Fill the array with random integers.
17 */
18 Array< int > aux_array( size );
19 srand( size + 2021 );
20 parallelFor< Devices::Host >(
21 0,
22 size,
23 [ & ]( int i )
24 {
25 aux_array[ i ] = std::rand() % ( 2 * size );
26 } );
27 array = aux_array;
28
29 /***
30 * Prepare second array holding elements positions.
31 */
32 ArrayT index( size );
33 index.forAllElements(
34 [] __cuda_callable__( int idx, int& value )
35 {
36 value = idx;
37 } );
38 std::cout << "Random array: " << array << '\n';
39 std::cout << "Index array: " << index << '\n';
40
41 /***
42 * Sort the array `array` and apply the same permutation on the array `identity`.
43 */
44 auto array_view = array.getView();
45 auto index_view = index.getView();
46 sort< typename ArrayT::DeviceType, // device on which the sorting will be performed
47 typename ArrayT::IndexType >( // type used for indexing
48 0,
49 size, // range of indexes
50 [ = ] __cuda_callable__( int i, int j ) -> bool { // comparison lambda function
51 return array_view[ i ] < array_view[ j ];
52 },
53 [ = ] __cuda_callable__( int i, int j ) mutable { // lambda function for swapping of elements
54 TNL::swap( array_view[ i ], array_view[ j ] );
55 TNL::swap( index_view[ i ], index_view[ j ] );
56 } );
57 std::cout << "Sorted array: " << array << '\n';
58 std::cout << "Index: " << index << '\n';
59}
60
61int
62main( int argc, char* argv[] )
63{
64 /***
65 * Firstly, test the sorting on CPU.
66 */
67 std::cout << "Sorting on CPU ...\n";
68 Array< int, Devices::Host > host_array;
69 sort( host_array );
70
71#ifdef __CUDACC__
72 /***
73 * And then also on GPU.
74 */
75 std::cout << "Sorting on GPU ...\n";
76 Array< int, Devices::Cuda > cuda_array;
77 sort( cuda_array );
78#endif
79 return EXIT_SUCCESS;
80}
TNL::swap
__cuda_callable__ constexpr void swap(Type &a, Type &b) noexcept
This function swaps values of two parameters.
Definition Math.h:518

In this example, we fill array array with random numbers and array index with numbers equal to position of an element in the array. We want to sort the array array and permute the index array correspondingly. This is achieved by calling a variant of the sort function, which does not accept an array-like data structure, but only range of indexes and two lambda functions. The first lambda function defines the ordering of the elements by comparing elements of array array. The second lambda function is responsible for swapping elements. Note that we do not swap only elements of array array, but also index array.

The result looks as follows:

Sorting on CPU ...
Random array: [ 5, 1, 15, 5, 0, 11, 2, 14, 14, 8 ]
Index array: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Sorted array: [ 0, 1, 2, 5, 5, 8, 11, 14, 14, 15 ]
Index: [ 4, 1, 6, 3, 0, 9, 5, 8, 7, 2 ]