Additional Algorithms
######################
The definitions of the algorithms listed below are available through the ``oneapi/dpl/algorithm``
header. All algorithms are implemented in the ``oneapi::dpl`` namespace.
* ``reduce_by_segment``: performs partial reductions on a sequence's values and keys. Each
reduction is computed with a given reduction operation for a contiguous subsequence of values, which are
determined by keys being equal according to a predicate. A return value is a pair of iterators holding
the end of the output sequences for keys and values.
For correct computation, the reduction operation should be associative. If no operation is specified,
the default operation for the reduction is ``std::plus``, and the default predicate is ``std::equal_to``.
The algorithm requires that the type of the elements used for values be default constructible. For example::
keys: [0,0,0,1,1,1]
values: [1,2,3,4,5,6]
output_keys: [0,1]
output_values: [1+2+3=6,4+5+6=15]
* ``inclusive_scan_by_segment``: performs partial prefix scans on a sequence's values. Each
scan applies to a contiguous subsequence of values, which are determined by the keys associated with the
values being equal. The return value is an iterator targeting the end of the result sequence.
For correct computation, the prefix scan operation should be associative. If no operation is specified,
the default operation is ``std::plus``, and the default predicate is ``std::equal_to``. The algorithm
requires that the type of the elements used for values be default constructible. For example::
keys: [0,0,0,1,1,1]
values: [1,2,3,4,5,6]
result: [1,1+2=3,1+2+3=6,4,4+5=9,4+5+6=15]
* ``exclusive_scan_by_segment``: performs partial prefix scans on a sequence's values. Each
scan applies to a contiguous subsequence of values that are determined by the keys associated with the values
being equal, and sets the first element to the initial value provided. The return value is an iterator
targeting the end of the result sequence.
For correct computation, the prefix scan operation should be associative. If no operation is specified,
the default operation is ``std::plus``, and the default predicate is ``std::equal_to``. For example::
keys: [0,0,0,1,1,1]
values: [1,2,3,4,5,6]
initial value: [0]
result: [0,0+1=1,0+1+2=3,0,0+4=4,0+4+5=9]
* ``binary_search``: performs a binary search of the input sequence for each of the values in
the search sequence provided. For each element of the search sequence the algorithm writes a boolean value
to the result sequence that indicates whether the search value was found in the input sequence. An iterator
to one past the last value in the result sequence is returned. The algorithm assumes the input sequence has
been sorted by the comparator provided. If no comparator is provided, then a function object that uses
``operator<`` to compare the elements is used. For example::
input sequence: [0, 2, 2, 2, 3, 3, 3, 3, 6, 6]
search sequence: [0, 2, 4, 7, 6]
result sequence: [true, true, false, false, true]
* ``lower_bound``: performs a binary search of the input sequence for each of the values in
the search sequence provided to identify the lowest index in the input sequence where the search value could
be inserted without violating the sorted ordering of the input sequence. The lowest index for each search
value is written to the result sequence, and the algorithm returns an iterator to one past the last value
written to the result sequence. If no comparator is provided, then a function object that uses ``operator<``
to compare the elements is used. For example::
input sequence: [0, 2, 2, 2, 3, 3, 3, 3, 6, 6]
search sequence: [0, 2, 4, 7, 6]
result sequence: [0, 1, 8, 10, 8]
* ``upper_bound``: performs a binary search of the input sequence for each of the values in
the search sequence provided to identify the highest index in the input sequence where the search value could
be inserted without violating the sorted ordering of the input sequence. The highest index for each search
value is written to the result sequence, and the algorithm returns an iterator to one past the last value
written to the result sequence. If no comparator is provided, then a function object that uses ``operator<``
to compare the elements is used. For example::
input sequence: [0, 2, 2, 2, 3, 3, 3, 3, 6, 6]
search sequence: [0, 2, 4, 7, 6]
result sequence: [1, 4, 8, 10, 10]
* ``sort_by_key``: performs a stable key-value sort. The algorithm sorts the sequence's keys according to
a comparioson operator. If no comparator is provided, then the elements are compared with ``operator<``.
The sequence's values are permutated according to the sorted sequence's keys. The prerequisite for correct
behavior is that the size for both keys sequence and values sequence shall be the same.
For example::
keys: [3, 5, 0, 4, 3, 0]
values: ['a', 'b', 'c', 'd', 'e', 'f']
output_keys: [0, 0, 3, 3, 4, 5]
output_values: ['c', 'f', 'a', 'e', 'd', 'b']
* ``transform_if``: performs a transform on the input sequence(s) elements and stores the result into the
corresponding position in the output sequence at each position for which the predicate applied to the
element(s) evaluates to ``true``. If the predicate evaluates to ``false``, the transform is not applied for
the elements(s), and the output sequence's corresponding position is left unmodified. There are two overloads
of this function, one for a single input sequence with a unary transform and a unary predicate, and another
for two input sequences and a binary transform and a binary predicate.
Unary example::
unary predicate: [](auto i){return i % 2 == 0;} // is even
unary transform: [](auto i){return i * 2;} // double element
input sequence: [0, 1, 2, 3, 3, 3, 4, 4, 7, 6]
original output sequence: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
final output sequence: [0, 8, 4, 6, 5, 4, 8, 8, 1, 12]
Binary example::
binary predicate: [](auto a, auto b){return a == b;} // are equal
unary transform: [](auto a, auto b){return a + b;} // sum values
input sequence1: [0, 1, 2, 3, 3, 3, 4, 4, 7, 6]
input sequence2: [5, 1, 3, 4, 3, 3, 4, 4, 7, 9]
original output sequence: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
final output sequence: [9, 2, 9, 9, 6, 6, 8, 8, 14, 9]
* ``histogram``: performs a histogram on a sequence of of input elements. Histogram counts the number of
elements which map to each of a defined set of bins. The algorithm has two overloads.
The first overload takes as input the number of bins, range minimum, and range maximum, then evenly
divides bins within that range. An input element ``a`` maps to a bin ``i`` such that
``i = floor((a - minimum) / ((maximum - minimum) / num_bins)))``.
The other overload defines ``m`` bins from a sorted sequence of ``m + 1`` user-provided boundaries
where an input element ``a`` maps to a bin ``i`` if and only if
``__boundary_first[i] <= a < __boundary_first[i + 1]``.
Input values which do not map to a defined bin are skipped silently. The algorithm counts the number of
input elements which map to each bin and outputs the result to a user-provided sequence of ``m`` output
bin counts. The user must provide sufficient output data to store each bin, and the type of the output
sequence must be sufficient to store the counts of the histogram without overflow. All input and output
sequences must be ``RandomAccessIterators``. Histogram currently only supports execution with device
policies.
Evenly divided bins example::
inputs: [9, 9, 3, 8, 4, 4, 4, 5, 1, 99]
num_bins: 5
min: 0
max: 10
output: [1, 1, 4, 0 3]
Custom range bins example::
inputs: [9, 9, 3, 8, 4, 4, 4, 5, 1, 99]
boundaries: [-1, 0, 8, 12]
output: [0, 6, 3]