特征中的模板协方差函数



我的一个项目需要一个模板化的协方差函数,即以MatrixXd、ArrayXXf和/或其.block((作为输入,并返回一个表达式用于进一步的计算。

q1.作为验证,我下面的尝试似乎有效,但它实际上返回了一个Eigen表达式吗?(编辑:@Darhuuk确认没有;幸运的是,C++14或更高版本不是问题!(

q2.很明显,我需要一个"内部矩阵",而不是我在关于模板函数的Eigen文档中遇到的内部RowVector。因此,我的问题是,应该如何创建一个内部MatrixType z=x.rowwise((-x.colwise((.mmean((,以便函数可以返回(z.transpose((*z(/(x.rows((-1(?内部行向量用于特征手册中的协方差示例(https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html)

q3.最后,当将模板化函数添加到具有头文件的类中时,我如何找到需要使用哪些Eigen类型来显式实例化模板,例如MatrixXd、ArrayXXd的.block((或Map?我所能找到的只是使用简单数据类型的示例(例如,将C++模板函数定义存储在.CPP文件中(

template <typename Derived>
Matrix<typename Derived::Scalar, Derived::ColsAtCompileTime, Derived::ColsAtCompileTime>  
SampleCov( const DenseBase<Derived>& x )
{
typedef typename internal::plain_row_type<Derived>::type RowVectorType;
const RowVectorType x_mean = x.colwise().mean();
return ((x.rowwise() - x_mean).matrix().transpose() * (x.rowwise() - x_mean).matrix()) / (x.rows()-1);
}

您的函数显式返回Matrix对象,因此不返回表达式对象。解决这个问题的一种方法是让编译器为您推导返回类型(因为表达式对象将是一些巨大的模板化混乱(:

template <typename Derived>
auto SampleCov (DenseBase<Derived> const & x) {
auto const x_mean = x.colwise().mean();
return ((x.rowwise() - x_mean).matrix().transpose()
* (x.rowwise() - x_mean).matrix()) / (x.rows() - 1);
}

这是假设您使用的是C++14或更高版本。对于只使用auto作为返回类型的C++11,您需要一个尾随返回类型:

template <typename Derived>
auto SampleCov (DenseBase<Derived> const & x)
-> decltype(((x.rowwise() - x.colwise().mean()).matrix().transpose()
* (x.rowwise() - x.colwise().mean()).matrix()) / (x.rows() - 1)) {
auto const x_mean = x.colwise().mean();
return ((x.rowwise() - x_mean).matrix().transpose()
* (x.rowwise() - x_mean).matrix()) / (x.rows() - 1);
}

请注意,我删除了RowVectorTypetypedef,因为我没有看到这一点。

关于问题2,我认为上面的例子解决了这个问题,因为没有更明确命名的类型了。返回类型和函数内部的auto都负责处理这一问题。

最后,问题3。这取决于你到底想做什么。根据你所说的,以上函数似乎不适用于MatrixXd对象或调用MatrixXd::block()返回的对象。

对我来说,这并不能真正表明你需要显式的模板实例化,这正是你所要求的。

相反,您可以简单地使SampleCov的参数类型更通用:

template <typename T>
auto SampleCovGeneric (T const & x) {
auto const x_mean = x.colwise().mean();
return ((x.rowwise() - x_mean).matrix().transpose()
* (x.rowwise() - x_mean).matrix()) / (x.rows() - 1);
}

只要你能呼叫colwise()matrix()。。。对于类型为T的对象,可以继续。无论如何,这可能是一种更好的方法,因为现在可以将特征表达式传递给SampleCovGeneric。例如:

Eigen::MatrixXd a(2,2);
// aTranspose is NOT a matrix object!
// Its type is Eigen::Transpose<Eigen::Matrix<double, Dynamic, Dynamic>>.
auto aTranspose = a.transpose();
/* Note use of auto and eval() calls!
* See https://eigen.tuxfamily.org/dox/TopicPitfalls.html.
*/
auto b = SampleCov(aTranspose.eval()).eval();
auto c = SampleCovGeneric(aTranspose).eval();

在上面的示例中,SampleCov期望类型为DenseBase<Derived>的对象。但CCD_ 13不是这样的类型。因此,我们必须首先明确地评估(即实际计算(转置。根据SampleCov内部发生的情况,这是一个无用的计算。例如,假设计算的第一件事是变元(x(及其转置。在这种情况下,那将只是原来的a再次。但是,如果转置已经被求值,那么Eigen就看不到这一点,需要计算转置的转置。

另一方面,SampleCovGeneric接受任何类型,因此不需要首先评估aTranspose。这(可能(允许Eigen"看穿"一堆计算,从而以更优化的方式计算结果。参见例如。https://eigen.tuxfamily.org/dox/TopicLazyEvaluation.html.

如果你真的需要,你可以显式地实例化模板,这样它们就可以在header&源文件。大概是这样的:

/* Header */
#pragma once
#include <utility>
// Reduce trailing return type mess a little
template <class T>
using SampleCovResultType = decltype(((std::declval<T const &>().rowwise()
- std::declval<T const &>().colwise().mean()).matrix().transpose()
* (std::declval<T const &>().rowwise()
- std::declval<T const &>().colwise().mean()).matrix())
/ (std::declval<T const &>().rows() - 1));
template <typename T>
auto SampleCov (T const & x) -> SampleCovResultType<T>;
// Explicit template declaration
extern template
auto SampleCov<Eigen::MatrixXd> (Eigen::MatrixXd const & x)
-> SampleCovResultType<Eigen::MatrixXd>;
/* Source */
#include "SampleCov.h"
template <class T>
auto SampleCov (T const & x) -> SampleCovResultType<T> {
auto const x_mean = x.colwise().mean();
return ((x.rowwise() - x_mean).matrix().transpose()
* (x.rowwise() - x_mean).matrix()) / (x.rows() - 1);
}
// Explicit template definition
template
auto SampleCov<Eigen::MatrixXd> (Eigen::MatrixXd const & x)
-> SampleCovResultType<Eigen::MatrixXd>;

我认为你不能只使用auto作为返回类型。由于函数定义被放在一个单独的源文件中,编译器看不到函数体,因此在调用函数时无法推断返回类型。所以您必须使用尾随返回类型。

但请注意以下内容:

显式实例化声明(外部模板(防止隐式实例化:否则会导致隐式实例化必须使用显式实例化程序中其他地方提供的定义。

即,如果您尝试使用类型T调用SampleCov,而您没有显式实例化其SampleCov,则编译将失败。

注意:以上所有代码都未经测试。打字错误的几率很高:(。

编辑:

  • 正在修复丢失的模板参数
  • 删除了有关呼叫matrix()的备注。我想知道它是否评估了表达式,而你不希望它这样做。AFAIK,它没有,基于例如ArrayBase的文档
  • 添加了有关显式实例化的信息

最新更新