假设我们有一个这样的数组:
0, 0, 0, 1, 2, 2, 2, 3, 3, 4, ...
我想得到每个值的每个第一次出现的索引,所以在这个例子中[0,3,4,7,9]。对数组进行排序,所有可能的值都是已知且连续的。
我可能的解决方案是为此数组中的每个元素使用内核,并使用atomicmin来保存最低的索引。但我认为可以采用更好的方法。
答案 0 :(得分:6)
如果您提供索引矢量,只需拨打thrust::unique_by_key()
即可执行此操作。通过thrust::sequence()
。这是一个有效的例子:
$ cat t3.cu
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <thrust/unique.h>
#include <thrust/sequence.h>
#include <iostream>
int main(){
int keys[] = {0, 0, 0, 1, 2, 2, 2, 3, 3, 4};
int ks = sizeof(keys)/sizeof(keys[0]);
thrust::device_vector<int> d_keys(keys, keys+ks);
thrust::device_vector<int> d_result(ks);
thrust::sequence(d_result.begin(), d_result.end());
int rs = (thrust::unique_by_key(d_keys.begin(), d_keys.end(), d_result.begin())).first - d_keys.begin();
thrust::copy_n(d_result.begin(), rs, std::ostream_iterator<int>(std::cout, ","));
std::cout << std::endl;
}
$ nvcc -arch=sm_35 -o t3 t3.cu
$ ./t3
0,3,4,7,9,
$
此处发生的重要活动是流压缩,推力为各种用例提供nice set of routines。例如,此操作也可以使用thrust::unique_copy()
完成,在这种情况下,由于某些额外的代码复杂性,您可以省去thrust::sequence()
调用(它将被thrust::counting_iterator
替换与您的数据和适当的选择函子一起压缩,但它仍然需要相同长度的输出向量。
答案 1 :(得分:3)
正如@tera指出的那样,您可以将一个数字与前一个数字进行比较,以确定它是否是唯一数字序列中的第一个匹配项。您可以编写内核来为此条件生成掩码,以使掩码数组包含第一次出现的数字的索引和负数(如-1,因为它不能是索引)。之后,使用推力通过使用谓词来计算非-1值。然后使用与上面相同的谓词从掩码中复制这些值。最后,将结果复制回主持人。
以下是上述方法的示例实现。
#include <iostream>
#include <cuda_runtime.h>
#include <thrust/device_vector.h>
#include <thrust/count.h>
#include <thrust/copy.h>
using namespace std;
//Copy index
__global__ void is_first_occurence(int* input, int* is, int count)
{
const int tid = blockIdx.x * blockDim.x + threadIdx.x;
if(tid<count)
{
if(tid == 0)
{
is[0] = 0;
}
else if(input[tid] != input[tid-1])
{
is[tid] = tid;
}
else
{
is[tid] = -1;
}
}
}
struct isFirst
{
__host__ __device__ bool operator()(const int x)
{
return (x != -1);
}
};
int main(int argc, char** argv)
{
const int count = 13;
std::vector<int> arr = { 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4 ,4 };
thrust::device_vector<int> arr_d = arr;
thrust::device_vector<int> mask_d(arr_d.size());
int* pArr = thrust::raw_pointer_cast(arr_d.data() );
int* pMask = thrust::raw_pointer_cast(mask_d.data() );
dim3 block(16);
dim3 grid((count + block.x -1)/block.x);
is_first_occurence<<<grid,block>>>(pArr, pMask, count);
cudaDeviceSynchronize();
int num_unique = thrust::count_if(mask_d.begin(), mask_d.end(), isFirst());
thrust::copy_if(mask_d.begin(), mask_d.end(), arr_d.begin(), isFirst());
std::vector<int> unique_indices(num_unique);
thrust::copy(arr_d.begin(), arr_d.begin() + num_unique, unique_indices.begin());
for(auto i:unique_indices)
{
cout<<i<<endl;
}
return 0;
}
使用以下命令进行编译和测试:
nvcc -o get_unique get_unique.cu -std = c ++ 11 -arch = sm_61