简体   繁体   中英

Custom min operator for thrust::tuple in reduction

I'm trying to run a min reduction on a zip iterator, but using a custom operator to only take into consideration the second field from the tuple (the first field is a key, while the second field, the value, is actually relevant for the reduction)

However, I can't get it to work, and is currently computing a result that is present in the vector

The following code reproduces the problem:

#include <thrust/device_vector.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/tuple.h>
#include <thrust/sequence.h>

typedef thrust::tuple<unsigned int, unsigned int> DereferencedIteratorTuple;

struct tuple_snd_min{
  __host__ __device__ 
  bool operator()(const DereferencedIteratorTuple& lhs,
                  const DereferencedIteratorTuple& rhs){
    return (thrust::get<1>(lhs) < thrust::get<1>(rhs));
  }
};


void f(){
    thrust::device_vector<unsigned int> X(10);
    thrust::device_vector<unsigned int> Y(10);

    thrust::sequence(X.begin(), X.end());
    thrust::sequence(Y.begin(), Y.end());

    X[0] = 5;
    Y[0] = 5;
    X[1] = 50;

    // X: 5 50 2 3 4 5 6 7 8 9
    // Y: 5 1  2 3 4 5 6 7 8 9

    typedef thrust::device_vector<unsigned int>::iterator UIntIterator;
    typedef thrust::tuple<UIntIterator, UIntIterator> IteratorTuple;

    thrust::zip_iterator<IteratorTuple> first = 
        thrust::make_zip_iterator(thrust::make_tuple(X.begin(), Y.begin()));

    thrust::tuple<unsigned int, unsigned int> init = first[0];
    thrust::tuple<unsigned int, unsigned int> min = 
        thrust::reduce(first, first + 10, init, tuple_snd_min());

    printf("(%d,%d)\n", thrust::get<0>(min), thrust::get<1>(min));
    // should return (50,1)
    // returns (0,0)   
}

Thanks to Jared Hoberock's comment, I was able to fix this.

typedef thrust::tuple<unsigned int, unsigned int> DereferencedIteratorTuple;

struct tuple_snd_min{
  __host__ __device__ 
  const DereferencedIteratorTuple& operator()(const DereferencedIteratorTuple& lhs, const DereferencedIteratorTuple& rhs)
  {
    if(thrust::get<1>(lhs) < thrust::get<1>(rhs)) return lhs;
    else return rhs;
  }
};

This seems to have been caused by a misunderstanding about which operation the functor in reduce call must implement. As per the documentation , the functor must be a model of a binary function , whose output must be convertible to the input type. This is where your functor fails. Rather than this

struct tuple_snd_min{
  __host__ __device__ 
  bool operator()(const DereferencedIteratorTuple& lhs,
                  const DereferencedIteratorTuple& rhs){
    return (thrust::get<1>(lhs) < thrust::get<1>(rhs));
  }
};

your functor would need to be defined something like this:

struct tuple_snd_min{
  __host__ __device__ 
  int operator()(const DereferencedIteratorTuple& lhs,
                  const DereferencedIteratorTuple& rhs){
    return (thrust::get<1>(lhs) < thrust::get<1>(rhs)) ?
             thrust::get<1>(lhs) : thrust::get<1>(rhs);
  }
};

ie the function should return a value rather than act as a predicate.

[This answer was assembled from comments and posted as a community wiki entry to get this question off the unanswered queue]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM