Thrust Vector::max_element and float2/Complex

I am looking for a way to use max_element on a float2 variable I have. I want to find the max element of the x and y parts of the float2 separately. I am currently splitting the float2 into two floats and then using thrust::max_element but this seems inefficient.

since thrust max_element returns an iterator to the max element, and you want to find two separate maxima, it would be necessary to return two separate iterators. You won’t be able to do that with (a single call to) max_element.

It should be possible to do this with a single call to thrust::reduce, but it will require the use of zip_iterator along with an appropriate double-max-finding functor.

Here’s a worked example:

$ cat t1153.cu
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/copy.h>
#include <thrust/reduce.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/iterator/counting_iterator.h>

#include <iostream>

const int dsize = 32;
typedef thrust::tuple<float2, int, int> my_tuple;

struct func
{
  __host__ __device__
  my_tuple operator()(const my_tuple &lhs, const my_tuple &rhs)  {
    my_tuple temp;
    if (thrust::get<0>(lhs).x > thrust::get<0>(rhs).x){
      thrust::get<0>(temp).x = thrust::get<0>(lhs).x;
      thrust::get<1>(temp) = thrust::get<1>(lhs);}
    else{
      thrust::get<0>(temp).x = thrust::get<0>(rhs).x;
      thrust::get<1>(temp) = thrust::get<1>(rhs);}
    if (thrust::get<0>(lhs).y > thrust::get<0>(rhs).y){
      thrust::get<0>(temp).y = thrust::get<0>(lhs).y;
      thrust::get<2>(temp) = thrust::get<2>(lhs);}
    else{
      thrust::get<0>(temp).y = thrust::get<0>(rhs).y;
      thrust::get<2>(temp) = thrust::get<2>(rhs);}
    return temp;
    }
};

int main(){

  thrust::host_vector<float2> h_data(dsize);

  for (int i = 0; i < dsize; i++){
    h_data[i].x = rand()/(float)RAND_MAX;
    h_data[i].y = rand()/(float)RAND_MAX;}
  thrust::device_vector<float2> d_data = h_data;
  thrust::device_vector<int> x_idx(dsize);
  thrust::device_vector<int> y_idx(dsize);
  my_tuple init;
  thrust::get<0>(init).x = -1;
  thrust::get<0>(init).y = -1;
  thrust::get<1>(init) = -1;
  thrust::get<2>(init) = -1;
  my_tuple result = thrust::reduce(thrust::make_zip_iterator(thrust::make_tuple(d_data.begin(), thrust::counting_iterator<int>(0), thrust::counting_iterator<int>(0))), thrust::make_zip_iterator(thrust::make_tuple(d_data.end(), thrust::counting_iterator<int>(dsize), thrust::counting_iterator<int>(dsize))), init, func());
  std::cout << "Max of .x component: " << thrust::get<0>(result).x << " index: " << thrust::get<1>(result) << std::endl;
  std::cout << "Max of .y component: " << thrust::get<0>(result).y << " index: " << thrust::get<2>(result) << std::endl;
  return 0;
}
$ nvcc -o t1153 t1153.cu
$ ./t1153
Max of .x component: 0.998924 index: 14
Max of .y component: 0.972775 index: 18
$