【问题标题】:Lazy evaluation for subset of class methods类方法子集的惰性求值
【发布时间】:2018-12-21 08:02:28
【问题描述】:

我正在寻找一个通用的、惰性求值式的程序来简化我的代码。

现在,我有能力加快数学函数的执行速度——前提是我先调用另一个方法对其进行预处理。更具体地说,给定一个类型的函数:

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

我可以把它传递给另一个函数g,它会产生一个新版本的function_nameg_p,可以更快地执行。

我想将所有这些忙碌的工作从最终用户手中抽离出来。理想情况下,我想创建一个类,这样当在任何输入(例如,x)上调用与 function_name 的方法签名匹配的任何函数 f 时,会发生以下情况:

  1. 该类检查之前是否调用过f
  2. 如果没有,则调用g(f),然后调用g_p(x)
  3. 如果有,它只会调用g_p(x)

这很棘手,原因有两个。首先,我不知道如何获取对当前方法的引用,或者是否可能,并将其传递给g。可能有办法解决这个问题,但将一个函数传递给另一个函数对我来说是最简单/最干净的。

第二个更大的问题是如何强制调用g。我已经阅读了execute around pattern 的相关信息,它几乎可以用于此目的 - 除非我理解错误,否则无法在周围的函数调用中引用 f

有什么方法可以干净利落地实现我的梦想课程?理想情况下,我希望最终超越function_name 的类型(可能使用模板),但可以一次迈出这一步。我也愿意接受其他解决方案来获得相同的功能。

【问题讨论】:

  • 我不认为我完全理解你在做什么。 g 是一个函数,它接受一个函数指针并返回另一个函数指针?您如何/在何处/何时“生成新版本”的函数?
  • 没错。 g 是一个函数,它接受指向 f 的指针,并生成 f 的新优化版本 g_p,然后将其存储在某个地方。为了清楚起见,也许我应该调用 g_p f_p。
  • 我认为你需要给我们一个你在说什么的例子(然后 ping 我)。谢谢。
  • 如前所述,显而易见的问题是“在这种情况下,惰性评估有什么好处?”然而,我的直觉是你试图实现类似于旧 C++ 库 newmat robertnz.net/nm_intro.htm 的东西,即你想延迟评估 f 以便在某些情况下 g(f(x)) 被优化的 g_and_f( x) 改为;作为 g(f(x)) 的有效替代,惰性评估旨在解决这个问题。如果是这种情况,可能会有更好的解决方案。
  • 您希望用户如何使用您的课程? obj-&gt;invoke(f, x) 可以接受吗?

标签: c++ eigen lazy-evaluation idioms


【解决方案1】:

我认为 C++ 中不可能有一个“完美”的解决方案,原因如下。

如果调用站点说:

result = object->f(x);

编译后,这将调用未优化的版本。在这一点上,你几乎束手无策,因为在 C++ 中没有办法改变函数调用的去向,这是在编译时确定的静态链接,以及在运行时通过虚拟(动态)链接的 vtable 查找来确定。不管怎样,这不是你可以直接改变的。其他语言确实允许这样做,例如Lua,颇具讽刺意味的是,C++ 的曾祖父 BCPL 也允许这样做。但是 C++ 没有。

TL;DR 要获得可行的解决方案,您需要修改被调用函数或使用其中之一的每个调用站点。

长答案:您需要做两件事之一。您可以将问题转移到被调用的类,并使所有函数看起来像这样:

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);
}

但是我非常怀疑这正是您不想想要做的,因为假设您正在谈论的最终用户是该课程的作者,这不符合您的要求从最终用户那里卸载它。

但是,您也可以使用模板来解决它,但这需要修改您调用其中之一的每个地方。本质上,您将上述逻辑封装在模板函数中,将unoptimized 替换为裸类成员,而将其他大部分内容都放在一边。然后你只需在调用站点调用模板函数,它应该可以工作。

这确实有在调用站点相对较小的变化的优点:

result = object->f(x);

成为:

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

或:

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

取决于您如何设置optimize 模板。它还有一个优点是对类没有任何改变。

所以我想这归结为你不想做出改变。

又一个选择。是否可以选择最终用户编写的类,并通过自定义预处理器传递cpph 文件?这可以通过类并自动进行上述更改,从而产生在调用站点不需要更改的优点。

【讨论】:

  • 自定义预处理器对我的应用程序来说太痛苦了,并且无法扩展。第一个选项是太多的用户开销。第二个版本与我现在的版本非常相似。这样做的主要问题是,如果我的 f 优化版本调用另一个函数,则无法强制它调用另一个函数的优化版本。
猜你喜欢
  • 2015-08-21
  • 2014-04-30
  • 1970-01-01
  • 2017-11-01
  • 2012-08-31
  • 2011-11-03
  • 2011-02-23
  • 2013-12-30
  • 2020-05-19
相关资源
最近更新 更多