I have a sorted integer array on the device, e.g.:
[0,0,0,1,1,2,2]
And I want the offsets to each element in another array:
[0,3,5]
(since the first 0 is at position 0, the first 1 at position 3 and so on) I know how many different elements there will be beforehand. How would you implement this efficiently in CUDA? I'm not asking for code, but a high level description of the algorithm you would implement to compute this transformation. I already hat a look at the various functions in the thrust name space, but could not think of any combination of thrust functions to achieve this. Also, does this transformation have a widely accepted name?
You can solve this in Thrust using thrust::unique_by_key_copy
with thrust::counting_iterator
. The idea is to treat your integer array as the keys
argument to unique_by_key_copy
and to use a sequence of ascending integers (i.e., counting_iterator
) as the values
. unique_by_key_copy
will compact the values array into the indices of each unique key
:
#include <thrust/device_vector.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/discard_iterator.h>
#include <thrust/unique.h>
#include <thrust/copy.h>
#include <iterator>
#include <iostream>
int main()
{
thrust::device_vector<int> keys(7);
keys[0] = 0; keys[1] = 0; keys[2] = 0;
keys[3] = 1; keys[4] = 1; keys[5] = 2; keys[6] = 2;
std::cout << "keys before unique_by_key_copy: [ ";
thrust::copy(keys.begin(), keys.end(), std::ostream_iterator<int>(std::cout," "));
std::cout << "]" << std::endl;
thrust::device_vector<int> offsets(3);
thrust::unique_by_key_copy(keys.begin(), keys.end(), // keys
thrust::make_counting_iterator(0), // [0, 1, 2, 3, ...] are the values
thrust::make_discard_iterator(), // discard the compacted keys
offsets.begin()); // the offsets are the values
std::cout << "offsets after unique_by_key_copy: [ ";
thrust::copy(offsets.begin(), offsets.end(), std::ostream_iterator<int>(std::cout," "));
std::cout << "]" << std::endl;
return 0;
}
Here's the output:
$ nvcc test.cu -run
keys before unique_by_key_copy: [ 0 0 0 1 1 2 2 ]
offsets after unique_by_key_copy: [ 0 3 5 ]