Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy evaluation for subset of class methods

I'm looking to make a general, lazy evaluation-esque procedure to streamline my code.

Right now, I have the ability to speed up the execution of mathematical functions - provided that I pre-process it by calling another method first. More concretely, given a function of the type:

const Eigen::MatrixXd<double, -1, -1> function_name(const Eigen::MatrixXd<double, -1, -1>& input)

I can pass this into another function, g, which will produce a new version of function_name g_p, which can be executed faster.

I would like to abstract all this busy-work away from the end-user. Ideally, I'd like to make a class such that when any function f matching function_name's method signature is called on any input (say, x), the following happens instead:

  1. The class checks if f has been called before.
  2. If it hasn't, it calls g(f), followed by g_p(x).
  3. If it has, it just calls g_p(x)

This is tricky for two reasons. The first, is I don't know how to get a reference to the current method, or if that's even possible, and pass it to g. There might be a way around this, but passing one function to the other would be simplest/cleanest for me.

The second bigger issue is how to force the calls to g. I have read about the execute around pattern, which almost works for this purpose - except that, unless I'm understanding it wrong, it would be impossible to reference f in the surrounding function calls.

Is there any way to cleanly implement my dream class? I ideally want to eventually generalize beyond the type of function_name (perhaps with templates), but can take this one step at a time. I am also open to other solution to get the same functionality.

like image 725
user650261 Avatar asked Jul 13 '18 01:07

user650261


1 Answers

I don't think a "perfect" solution is possible in C++, for the following reasons.

If the calling site says:

result = object->f(x);

as compiled this will call into the unoptimized version. At this point you're pretty much hamstrung, since there's no way in C++ to change where a function call goes, that's determined at compile-time for static linkage, and at runtime via vtable lookup for virtual (dynamic) linkage. Whatever the case, it's not something you can directly alter. Other languages do allow this, e.g. Lua, and rather ironically C++'s great-grandfather BCPL also permits it. However C++ doesn't.

TL;DR to get a workable solution to this, you need to modify either the called function, or every calling site that uses one of these.

Long answer: you'll need to do one of two things. You can either offload the problem to the called class and make all functions look something like this:

const <return_type> myclass:f(x)
{
    static auto unoptimized = [](x) -> <return_type>
    {
        // Do the optimizable heavy lifting here;
        return whatever;
    };
    static auto optimized = g(unoptimized);
    return optimized(x);
}

However I very strongly suspect this is exactly what you don't want to do, because assuming the end-user you're talking about is the author of the class, this fails your requirement to offload this from the end-user.

However, you can also solve it by using a template, but that requires modification to every place you call one of these. In essence you encapsulate the above logic in a template function, replacing unoptimized with the bare class member, and leaving most everything else alone. Then you just call the template function at the calling site, and it should work.

This does have the advantage of a relatively small change at the calling site:

result = object->f(x);

becomes either:

result = optimize(object->f, x);

or:

result = optimize(object->f)(x);

depending on how you set the optimize template up. It also has the advantage of no changes at all to the class.

So I guess it comes down to where you wan't to make the changes.

Yet another choice. Would it be an option to take the class as authored by the end user, and pass the cpp and h files through a custom pre-processor? That could go through the class and automatically make the changes outlined above, which then yields the advantage of no change needed at the calling site.

like image 127
dgnuff Avatar answered Sep 18 '22 05:09

dgnuff