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]