select functor from a set at run time

Hello,
The idea is to have a library of functors with different implementations. In the main program, I would have a string that is selecting the functor of interest, and the whole program should work with the chosen functor. Below, you will find an example of what I’m looking for. It is obviously not working (out of scope; same instance name). One could include the transform algorithm into the switch. It is not an option since the main application has more code. It will be duplicated in each switch case and at several places. I would be thankful for any hints on how I could solve the problem. Thank you.

struct functor_minus : public thrust::binary_function<float,float,float>
{
    const float a;

    functor_minus(float _a) : a(_a) {}

    __host__ __device__
        float operator()(const float& x, const float& y) const { 
            return x - a * y;
        }
};


struct functor_plus : public thrust::binary_function<float,float,float>
{
    const float a;

    functor_plus(float _a) : a(_a) {}

    __host__ __device__
        float operator()(const float& x, const float& y) const { 
            return x + a * y;
        }
};


int main(int argc, char const *argv[])
{
	int N = 10000;

	thrust::device_vector<float> d_X(N);
    thrust::fill(d_X.begin(), d_X.end(), 0.5);

    thrust::device_vector<float> d_Y(N);
    thrust::fill(d_Y.begin(), d_Y.end(), 1.5);

    thrust::device_vector<float> d_R(N);

    int select_functor = 1;

    switch(select_functor) {
	    case 1 :{
	    	functor_minus FUNCTOR(0.3); 
	        break;      
	    }
	    case 2 :{
	    	functor_plus FUNCTOR(0.5); 
	        break;      
	    }
	             
	}

    
    thrust::transform( d_X.begin(), d_X.end(), d_Y.begin(), d_R.begin(), FUNCTOR );

	return 0;
}
1 Like

You could put the switch case inside the functor:

https://stackoverflow.com/questions/23391914/using-polymorphic-functors-inside-functions-in-thrust/23462283#23462283

I suppose there will be objections to that (“I don’t want to pay the cost of the runtime boolean test”).

Another possible approach is to dispatch via selectable device function pointers.

https://stackoverflow.com/questions/34879789/thrust-transform-throws-error-bulk-kernel-by-value-an-illegal-memory-access-w

(The first code example in the answer there is the relevant one. The second one, which uses templating for device function pointer capture, will not work for runtime dispatch).

I personally wouldn’t assume which one is faster/better based on a simple heuristic like whether or not there is runtime boolean decision making. The function pointer approach impacts the compiler’s ability to perform optimization.

Thank you, Robert! I think the switch in the functor is not possible in my case, because the user selected functors have different constructors. At least I don’t see a possibility. The Polymorphism in device code, as in your example, appears to be a reasonable solution. He he, but readability is for me becoming important then. So now I’m considering to use templating nevertheless. I hope running several executables will be less effort.

It’s not obvious to me that the constructor question is any different for the 2nd example than it is for the first. I think you could define a superset of initializing parameters, and solve the constructor problem that way.

I suppose polymorphism might be another approach, but I haven’t thought about that carefully for your case:

https://stackoverflow.com/questions/22988244/polymorphism-and-derived-classes-in-cuda-cuda-thrust/23476510#23476510