Search code examples
c++11cudathrust

Operating on thrust::complex types with thrust::transform


I'm trying to use thrust::transform to operate on vectors of type thrust:complex<float> without success. The following example blows up during compilation with several pages of errors.

#include <cuda.h>
#include <cuda_runtime.h>
#include <cufft.h>

#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/transform.h>
#include <thrust/complex.h>

int main(int argc, char *argv[]) {

  thrust::device_vector< thrust::complex<float> > d_vec1(4);
  thrust::device_vector<float> d_vec2(4);

  thrust::fill(d_vec1.begin(), d_vec1.end(), thrust::complex<float>(1,1));

  thrust::transform(d_vec1.begin(), d_vec1.end(), d_vec2.begin(), thrust::abs< thrust::complex<float> >() );
}

I'm using CUDA 8.0 on Ubuntu Xenial and compiling with clang 3.8.0-2ubuntu4 using nvcc --std=c++11 main.cpp -o main.

Main errors appear to be:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:17:105: error: no matching function for call to ‘abs()’
 gin(), d_vec1.end(), d_vec2.begin(), thrust::abs< thrust::complex<float> >() );

and

/usr/local/cuda-8.0/bin/../targets/x86_64-linux/include/thrust/detail/complex/arithmetic.h:143:20: note:   template argument deduction/substitution failed:
main.cpp:17:105: note:   candidate expects 1 argument, 0 provided
 gin(), d_vec1.end(), d_vec2.begin(), thrust::abs< thrust::complex<float> >() );
                                                                            ^

No problem working on real floats, but no such with complex ones. I'm thinking there's a type error that I'm missing, but I'm very much still on the steep part of the learning curve with Thrust & templates.


Solution

  • The error message is quite descriptive:

    thrust::abs<thrust::complex<...>> is a function which expects exactly one parameter, see thrust/detail/complex/arithmetic.h#L143:

    template <typename ValueType>
      __host__ __device__
      inline ValueType abs(const complex<ValueType>& z){
      return hypot(z.real(),z.imag());
    }
    

    For your use case, you need to wrap that function by a functor:

    struct complex_abs_functor
    {
        template <typename ValueType>
        __host__ __device__
        ValueType operator()(const thrust::complex<ValueType>& z)
        {
            return thrust::abs(z);
        }
    };
    

    Finally, employ that functor here:

    thrust::transform(d_vec1.begin(),
                      d_vec1.end(),
                      d_vec2.begin(),
                      complex_abs_functor());