Eigen是一个非常方便的库,可以简洁,直观的方式表达数学公式。我知道Eigen具有惰性评估概念,可以表示表达式类中的一系列操作,并在必要时对其进行有效评估。我也知道Eigen可以和MKL一起使用。但是,我很好奇可以将哪种表达式转换为MKL cblas调用。在什么条件下,它们不可转让?是否有任何一般规则可以帮助我弄清楚什么是可转让的?
通常情况下,我对以下情况感到好奇:
MatrixXd A, B, C;
VectorXd a, b, c;
double w1, w2, w3;
b += w1 * A * a; // can be done through dgemv
b += w1 * A.transpose() * a; // can be done through dgemv
C += w2 * A * B; // can be done through dgemm
C += w2 * A.transpose() * B; // can be done through dgemm
C += w2 * A. topRows(5).transpose() * B; // can be done through dgemm
D = A * B * C; // cannot be done in one func call through cblas
注意:注释不是特征传递结果。相反,这是理想的结果。我不确定Eigen是否可以转移它们。
还有另一个问题:Eigen何时会在这些操作链中分配临时内存?是否有任何一般规则可以帮助我弄清楚是否有任何分配?
答案 0 :(得分:2)
要完成chtz答案,您的所有假设都是正确的(假设您添加了.noalias()
装饰器),更常见的是任何看起来像gemv / gemm的表达式或子表达式都将转为单个调用,包括转置您可以在此unit test中查找临时数量的示例,因此0
表示单个类似blas的呼叫,1
表示临时将是在blas-like call之前或之后创建等等。
答案 1 :(得分:1)
首先,为了避免示例中的临时性,您需要编写
b.noalias() += w1 * A * a;
这是因为Eigen无法在编译时告诉b
,A
和a
没有别名,因此将产品评估为临时产品。
See here for details
Godbolt-demo:https://godbolt.org/g/VSfekp(请注意,-DEIGEN_USE_BLAS
基本上等同于-DEIGEN_USE_MKL_ALL
,但是Godbolt目前不支持MKL。
根据您的实际问题:要确定操作是否需要临时操作,您可以使用-DEIGEN_RUNTIME_NO_MALLOC
编译并围绕您认为不应分配的部分
Eigen::set_is_malloc_allowed(false); // mallocs after this cause assertions
// some code
Eigen::set_is_malloc_allowed(true); // mallocs are allowed again
当然,这要求结果对象在输入该部分之前具有正确的大小。
此外,这对固定大小的表达式没有帮助,因为它们永远不会分配堆内存,但对于使用MKL的固定大小的表达式,通常效率低于Eigen(取决于大小,将完全展开必要的操作)。