I'm refactoring thrust code by converting from an AoS to SoA approach to take advantage of memory coalescing. To that end, I have two vectors that are reduced by a common key, and which are then used to calculate the values for an output vector. The original code did this with a single functor, which I'd like to emulate.
Essentially:
Oᵢ = Rᵢ / Sᵢ, where Rᵢ and Sᵢ are vectors reduced by the same key, and Oᵢ is the corresponding output vector.
Below is code that exemplifies what I'm trying to do:
typedef tuple<int,int> Tuple;
struct BinaryTupleOp : public thrust::binary_function<Tuple const &, Tuple const &, int>
{
__host__ __device__
int operator()(Tuple const & lhs, Tuple const & rhs) const {
// get<0> = vals, get<1> = other_vals
return (get<0>(lhs) + get<0>(rhs)) / (get<1>(lhs) + get<1>(rhs));
}
};
int main(int argc, char ** argv)
{
const int N = 7;
device_vector<int> keys(N);
keys[0] = 1; // represents sorted keys
keys[1] = 1;
keys[2] = 2;
keys[3] = 2;
keys[4] = 3;
keys[5] = 3;
keys[6] = 3;
device_vector<int> vals(N);
vals[0] = 6; // just some random numbers
vals[1] = 3;
vals[2] = 9;
vals[3] = 4;
vals[4] = 6;
vals[5] = 1;
vals[6] = 5;
device_vector<int> other_vals(N);
other_vals[0] = 4; // more randomness
other_vals[1] = 1;
other_vals[2] = 3;
other_vals[3] = 6;
other_vals[4] = 2;
other_vals[5] = 5;
other_vals[6] = 7;
device_vector<int> new_keys(N);
device_vector<int> output(N);
typedef device_vector<int>::iterator Iterator;
thrust::pair<Iterator, Iterator> new_end;
thrust::equal_to<int> binary_pred;
new_end = thrust::reduce_by_key(keys.begin(), keys.end(),
make_zip_iterator(make_tuple(vals.begin(), other_vals.begin())),
new_keys.begin(),
output.begin(),
binary_pred,
BinaryTupleOp() );
Iterator i = new_keys.begin();
Iterator j = output.begin();
for (;
i != new_end.first;
i++, j++ ) {
std::cout << "key " << *i << " sum " << *j << endl;
}
return 0;
}
Unfortunately this yields such errors as error: no operator "=" matches these operands
, error: no suitable conversion function from "InputValueType" to "TemporaryType" exists
, and error: no suitable conversion function from "const thrust::tuple<int, int, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type>" to "int" exists
. I've played around with parameter type variants in the functor since I think that's the ultimate source of the problem, but to no avail.
As a workaround I'll probably break out the two reductions separately, then use a transform to create the output vector. (Which maybe suggests linking together various transform_reduce()
calls, but it seems I'd want the inverse, something like a reduce_transform()
, which doesn't exist, AFAIK.)
Meanwhile, what am I doing wrong?