Search code examples
c++cudathrust

Transform the type of a thrust vector


I am somewhat new to CUDA and thrust and I am currently struggeling with the following problem:

I have 2 structs carrying data.

struct S1 {
    unsigned long A, B, C;
}

struct S2 {
    double A, B, C;
}

At the start of the program I have a vector of the first struct and I want to use the GPU as well as a special functor to transform the vector of S1 to a vector of S2. The result will have the same size as the input only with elements of a different type.

I am currently using this setup:

struct Functor {
    Functor() {}

    __host__ __ device__ S2 operator() (const S1& s1) {
        // perform some operation on S1 to convert it so S2
        // here I just copy the values
        return S2{s1.A, s1.B, s1.C};
    }
}

void main() {
    std::vector<S1> input;
    // fill the 'input' vector

    // move the input to a device vector
    thrust::device_vector<S1> input_d(input);
    // empty vector for struct S2
    thrust::device_vector<S2> output_d(input.size());

    thrust::transform(input_d.begin(), input_d.end(), output_d.begin(), output_d.end(), Functor());

    return 0;
}

The functor Functor is responsible for converting S1 to S2 (simplified in this case).

This code results in a compiler error since the operator() needs 2 arguments while I only want to have one input. Looking around the web I did not find a solution that applies to my problem.


Solution

  • As already pointed out in the comments I misread the documentation (see here). The solution is to use a unary functor and another way of calling the thrust::transform.

    // this functor converts values of S1 to S1 by multiplying them with .5
    // in the actual scenario this method does perform much more useful operations
    struct Functor : public thrust::unary_function<S1, S2> {
        Functor() {}
    
        __host__ __device__ S2 operator() (const S1& s1) const {
            // very basic operations on the values of s1
            double a = s1.A * .5;
            double b = s1.B * .5;
            double c = s1.C * .5;
            return S2{a, b, c};
        }
    }
    
    

    The transform is then called as:

    thrust::host_vector<S1> tmp;
    // fill the tmp vector with S1 instances...
    
    // move the host vector to the device
    thrust::device_vector<S1> input_d;
    input_d = tmp; 
    
    // initializing the output with the same size as the input
    thrust::device_vector<S2> output_d(tmp.size()); 
    
    // calling the functor on all elements of the input and store them in the output
    thrust::transform(input_d.begin(), input_d.end(), output_d.begin(), Functor()); 
    

    Edit: Added some more code parts so it is actually working code.