Reputation: 932
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;
}
};
Upvotes: 4
Views: 872
Reputation: 72348
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);
}
};
i.e. 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]
Upvotes: 1