通过CUDA Thrust查找键的出现次数和第一次出现的键的位置

时间:2012-01-09 17:57:21

标签: cuda thrust

说我有一个按键矢量

thrust::device_vector<int> keys(10); 
keys[0] = 51; // -----> 
keys[1] = 51; 
keys[2] = 72; // -----> 
keys[3] = 72; 
keys[4] = 72; 
keys[5] = 103; //-----> 
keys[6] = 103; 
keys[7] = 504; // ------> 
keys[8] = 504 
keys[9] = 504 ; 

我事先已经知道有4个不同的键值 这个载体。我想填充两个设备阵列 pidx[4]pnum[4]

  1. pidx数组为我提供了每个不同键的第一个位置 键矢量,即上面代码片段中标有---->的位置。所以,在这个例子中,我应该有pidx[4] = {0, 2, 5, 7}

  2. pnum数组给出了每个键的出现次数。所以,在这个例子中,我应该有 pnum[4] = {2, 3, 2, 3}

  3. 如何使用CUDA Thrust执行上述操作?

4 个答案:

答案 0 :(得分:2)

这不是最佳解决方案,但我无法找到更好的方法。

// Use `unique` to grab the distinct values
thrust::device_vector<int> values(4);
thrust::unique_copy( keys.begin(), keys.end(), values.begin() );

// For each of the values use `count` to get the frequencies
for ( int i = 4; i != 0; --i )
    pnum[i] = thrust::count( keys.begin(), keys.end(), values[i] );

// Use prefix sum to get the indices
thrust::exclusive_scan( pnum.begin(), pnum.end(), pidx.begin() );

答案 1 :(得分:0)

此解决方案假定您的密钥列表已经排序。如果不是,那么只需在开头添加另一个步骤来对列表进行排序。

// generate a list of indices to correspond with the key array
thrust::device_vector<int> values(numKeys);
thrust::sequence(values.begin(), values.end());

// perform an inclusive scan to determine the minimum index for each unique key
thrust::equal_to<int> binaryPred;
thrust::minimum<int> binaryOp;
thrust::inclusive_scan_by_key(keys.begin(), keys.end(), values.begin(), values.begin(), binaryPred, binaryOp);

// find the unique indices
thrust::unique(values.begin(), values.end());

答案 2 :(得分:0)

作为替代解决方案,您可以尝试Arrayfire 图书馆。它具有针对这类问题的特殊功能:

   float keys[] = {51,51,72,72,72,103,103,504,504,504};      
   int N = sizeof(keys) / sizeof(int);

   array input(N, 1, keys);
   array values, pidx, locations;
   // unique elements in a vector and their indicies 
   setunique(values, pidx, locations, input);

   // # of unique elements
   int n_unique = pidx.elements();
   array pnum = zeros(n_unique); // empty array

   gfor(array i, n_unique) // parallel for loop
      // count the # of occurrences for each key
      pnum(i) = sum(locations == i);

   print(pidx);           
   print(pnum);

输出:

pidx =            0.0000            2.0000            5.0000            7.0000

pnum =            2.0000            3.0000            2.0000            3.0000

答案 3 :(得分:0)

您的问题是两个不同的问题:

  1. 查找向量内元素的出现次数;
  2. 查找每个键的第一个匹配位置。
  3. 在我看来,上述两点在其他所提供的答案中均未得到承认。

    问题#1 构建序列直方图的数量,请参阅https://code.google.com/p/thrust/source/browse/examples/histogram.cu。此问题的经典解决方案是首先按thrust::sort对键进行排序,然后执行thrust::reduce_by_key来计算出现次数。这已在Counting occurences of numbers in cuda arraythrust count occurence得到认可。

    问题#2 thrust::unique_by_keythrust::sequence的应用。

    这是一个完整的例子:

    #include <thrust/device_vector.h>
    #include <thrust/reduce.h>
    #include <thrust/random.h>
    #include <thrust/sort.h>
    
    /********/
    /* MAIN */
    /********/
    int main()
    {
        /**************************/
        /* SETTING UP THE PROBLEM */
        /**************************/
    
        const int N = 20;           // --- Number of elements
    
        // --- Random uniform integer distribution between 0 and 4
        thrust::default_random_engine rng;
        thrust::uniform_int_distribution<int> dist(0, 4);
    
        // --- Keys allocation and initialization
        thrust::device_vector<int> d_keys(N);
        for (size_t i = 0; i < d_keys.size(); i++) d_keys[i] = dist(rng);
    
        /****************/
        /* THE APPROACH */
        /****************/
    
        thrust::device_vector<int> d_values(N, 1);
        thrust::sort(d_keys.begin(), d_keys.end());
    
        thrust::reduce_by_key(d_keys.begin(), d_keys.end(), thrust::constant_iterator<int>(1), d_keys.begin(), d_values.begin());
    
        printf("Keys\n");
        for (int i=0; i<N; i++) std::cout << d_keys[i] << " " << d_values[i] << "\n";
        printf("\n");
    
        return 0;
    }