What is the optimal way to use additional data fields in functors in Thrust?

322 views Asked by At

What is the proper (or optimal) way to use some constant data in functors used in thrust algorithms like thrust::transform? The naive way I used was simply allocate required arrays inside the functor's operator() method, like this:

struct my_functor {

    __host__ __device__
    float operator()(thrust::tuple<float, float> args) {

        float A[2][10] = {
            { 4.0, 1.0, 8.0, 6.0, 3.0, 2.0, 5.0, 8.0, 6.0, 7.0 },
            { 4.0, 1.0, 8.0, 6.0, 7.0, 9.0, 5.0, 1.0, 2.0, 3.6 }};

        float x1 = thrust::get<0>(args);
        float x2 = thrust::get<1>(args);

        float result = 0.0;
        for (int i = 0; i < 10; ++i)
            result += x1 * A[0][i] + x2 * A[1][i];

        return result;
    }
}

But it seems not very elegant or efficient way. Now I have to develop relatively complicated functor with some matrices (constant, like in the example above) and additional methods used in the functor's operator() method. What is the optimal way to solve such a problem? Thanks.

1

There are 1 answers

1
talonmies On

From your last comment, it is clear that what you are really asking about here is functor parameter initialisation. CUDA uses the C++ object model, so structures have class semantics and behaviour. So your example functor

struct my_functor {
    __host__ __device__
    float operator()(thrust::tuple<float, float> args) const {
        float A[2] = {50., 55.6};

        float x1 = thrust::get<0>(args);
        float x2 = thrust::get<1>(args);

        return x1 * A[0]+ x2 * A[1];
    }
}

can be re-written with an empty constructor with intialisation lists to transform hardcoded constants within the functor into runtime assignable values:

struct my_functor {
    float A0, A1;

    __host__ __device__
    my_functor(float _a0, _a1) : A0(_a0), A1(_a1) { }

    __host__ __device__
    float operator()(thrust::tuple<float, float> args) const {
        float x1 = thrust::get<0>(args);
        float x2 = thrust::get<1>(args);

        return x1 * A0 + x2 * A1;
    }
}

You can instantiate as many versions of the functor, each with different constant values, to do whatever it is you are using the functors for in conjunction with the thrust library.