CUDA推力remove_if与operlapping模板序列

时间:2014-09-18 23:45:34

标签: c++ cuda thrust

我试图根据第一个向量的值从两个thrust::device_vector<int>中删除元素。我直观地创建了以下剪辑:

thrust::device_vector<float> idxToValue(COUNT_MAX);
thrust::device_vector<int> idxSorted(COUNT_MAX);
thrust::device_vector<int> groupIdxSorted(COUNT_MAX);
int count = COUNT_MAX;
float const minThreshold = MIN_THRESHOLD;

auto idxToValueSortedIter = thrust::make_permutation_iterator(
    idxToValue.begin()
    , idxSorted.begin()
    );

auto new_end = thrust::remove_if(
    thrust::make_zip_iterator(thrust::make_tuple(idxSorted.begin(), groupIdxSorted.begin()))
    , thrust::make_zip_iterator(thrust::make_tuple(idxSorted.begin() + count, groupIdxSorted.begin() + count))
    , idxToValueSortedIter 
    , thrust::placeholders::_1 >= minThreshold
    );

count = thrust::get<0>(new_end.get_iterator_tuple()) - idxSorted.begin();

不幸的是,Thrust文件说

  

范围[模板,模板+(最后 - 第一个))不应与范围重叠[结果,结果+(最后 - 第一个))

因此,在我的情况下,idxToValueSortedIter用作模板序列,取决于idxSorted,实际上与结果重叠(相同的向量)。

有没有办法解决这个问题而不将数据复制到临时载体?

1 个答案:

答案 0 :(得分:2)

我认为你可以通过使用非模板版remove_if来做到这一点(没有模板,它对模板与输出序列的重叠没有这样的限制),并且通过你的模板(即你的排列迭代器)作为zip_iteratorremove_if的第3个成员加上适当的选择函子。这是一个有效的例子:

$ cat t572.cu
#include <iostream>
#include <thrust/device_vector.h>
#include <thrust/remove.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/iterator/permutation_iterator.h>
#include <thrust/copy.h>

#define COUNT_MAX 10
#define MIN_THRESHOLD 4.5f

struct my_functor
{
  float thresh;
  my_functor(float _thresh): thresh(_thresh) {}

  template <typename T>
  __host__ __device__
  bool operator()(T &mytuple) const {
    return thrust::get<2>(mytuple) > thresh;
  }
};

int main(){

  float h_idxToValue[COUNT_MAX] = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f};
  int   h_idxSorted[COUNT_MAX] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
  int   h_groupIdxSorted[COUNT_MAX] = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29};

  thrust::device_vector<float> idxToValue(h_idxToValue, h_idxToValue + COUNT_MAX);
  thrust::device_vector<int> idxSorted(h_idxSorted, h_idxSorted + COUNT_MAX);
  thrust::device_vector<int> groupIdxSorted(h_groupIdxSorted, h_groupIdxSorted + COUNT_MAX);
  int count = COUNT_MAX;
  float const minThreshold = MIN_THRESHOLD;

  auto new_end = thrust::remove_if(
    thrust::make_zip_iterator(thrust::make_tuple(idxSorted.begin(), groupIdxSorted.begin(), thrust::make_permutation_iterator(idxToValue.begin(), idxSorted.begin())))
    , thrust::make_zip_iterator(thrust::make_tuple(idxSorted.begin() + count, groupIdxSorted.begin() + count, thrust::make_permutation_iterator(idxToValue.begin(), idxSorted.begin() + count)))
    , my_functor(minThreshold)
    );

  count = thrust::get<0>(new_end.get_iterator_tuple()) - idxSorted.begin();

  std::cout << "count = " << count << std::endl;
  thrust::copy_n(groupIdxSorted.begin(), count, std::ostream_iterator<int>(std::cout, ","));
  std::cout << std::endl;
  return 0;
}

$ nvcc -arch=sm_20 -std=c++11 -o t572 t572.cu
$ ./t572
count = 5
25,26,27,28,29,
$

我们通常希望带有提供的仿函数的remove_if函数删除idxToValue值大于阈值(4.5)的条目。但是,由于idxSorted中的置换迭代器和反向排序序列,我们发现阈值以上的值保留,其他值被删除。上面的例子是使用CUDA 6.5和Fedora 20来利用实验性的c ++ 11支持。