【问题标题】:Workaround for resizing Eigen::Ref调整 Eigen::Ref 大小的解决方法
【发布时间】:2017-09-21 08:52:12
【问题描述】:

我想使用 Eigen::Ref 来获得使用 Eigen::Matrix 参数的非模板函数。我的问题是,在这些函数中,我可能必须调整 Eigen::Ref 引用的矩阵的大小。我知道,一般而言,不应调整 Eigen::Ref 的大小,因为它可以映射到表达式或矩阵块,但在我的情况下,我确信 Eigen::Ref 背后的内容是 Eigen::Matrix。

为了说明这一点:

#include "Eigen/Dense"

void add(Eigen::Ref<Eigen::MatrixXd> M, const Eigen::Ref<const Eigen::MatrixXd> &A, const Eigen::Ref<const Eigen::MatrixXd> &B) {
  M=A+B;
}

int main() {
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor, 32, 32> M(2,3);
  Eigen::Matrix<double, 2, 2> A;
  Eigen::Matrix<double, 2, 2> B;

  add(M,A,B);
}

在运行时给出:

void Eigen::DenseBase<Derived>::resize(Eigen::Index, Eigen::Index) [with Derived = Eigen::Ref<Eigen::Matrix<double, -1, -1> >; Eigen::Index = long int]: Assertion `rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."' failed.

我试图欺骗它:

void add(Eigen::Ref<Eigen::MatrixXd> M, const Eigen::Ref<const Eigen::MatrixXd> &A, const Eigen::Ref<const Eigen::MatrixXd> &B) {
  Eigen::Ref<Eigen::Matrix<double,2,2>> MM(M);
  MM=A+B;
}

但我在运行时得到:

Eigen::internal::variable_if_dynamic<T, Value>::variable_if_dynamic(T) [with T = long int; int Value = 2]: Assertion `v == T(Value)' failed.

那么,我能做些什么来处理这个问题?在 Eigen 文档中,使用 MatrixBase 作为参数的模板函数解决了调整大小的问题,但对于 Eigen::Ref?

【问题讨论】:

  • 如果您确定它引用了Eigen::MatrixXd,为什么不传递Eigen::MatrixXd &amp; M
  • 抱歉,没有完全阅读您的问题。假设 32 并不总是相同,您可以将其作为模板参数传递。否则,我看不到实现此功能的安全方法。
  • 我不想要模板函数,因为我希望它是虚拟的...
  • main 中的MMaxRowsAtCompileTimeMaxColsAtCompileTime 不会存储在Ref 对象中。并且实际的行数和列数将被复制到Ref。所以没有办法安全地调整Ref 对象的大小。 M 对象在编译时是否始终具有固定的最大大小?
  • 不,M 并不总是具有相同的最大尺寸。实际上,我什至可以将 Eigen::Matrix 作为 M,但在这种情况下,我确信在我的 add 函数等效项中不会发生调整大小。我知道没有“安全”的方式来调整 Eigen::Ref 的大小,但我想告诉 Eigen 相信我!

标签: c++ matrix eigen eigen3


【解决方案1】:

这是一个使用成员函数指针和粗暴强制转换的 hacky 解决方案:

#include <iostream>
#include <Eigen/Core>
template<class MatrixType>
struct ResizableRef
{
    typedef typename MatrixType::Scalar Scalar;
    class MatrixDummy;
    typedef void (MatrixDummy::*ResizeFunctor)(Eigen::Index rows, Eigen::Index Cols);
    typedef Scalar* (MatrixDummy::*DataGetter)();

    MatrixDummy *m;
    const ResizeFunctor resizer;
    const DataGetter getData;

    template<class Derived>
    ResizableRef(Eigen::MatrixBase<Derived>& M)
      : m(reinterpret_cast<MatrixDummy*>(&M))
      , resizer(reinterpret_cast<ResizeFunctor>((void (Derived::*)(Eigen::Index, Eigen::Index)) &Derived::resize))
      , getData(reinterpret_cast<DataGetter>((Scalar* (Derived::*)()) &Derived::data))
    { }

    template<class Derived>
    ResizableRef& operator=(const Eigen::EigenBase<Derived>& other)
    {
        (m->*resizer)(other.rows(), other.cols());
        MatrixType::Map((m->*getData)(), other.rows(), other.cols()) = other;
    }
};

void foo(ResizableRef<Eigen::MatrixXd> A)
{
    A = Eigen::Matrix2d::Identity();
}

int main(int argc, char *argv[])
{
    using namespace Eigen;
    MatrixXd A;
    Matrix<double, Dynamic, Dynamic, Eigen::ColMajor, 20, 12> B;
    Matrix<double, 2, Dynamic, Eigen::ColMajor, 2, 4> C;
    Matrix2d D;
    foo(A);
    foo(B);
    foo(C);
    foo(D);

    std::cout << A << "\n\n" << B << "\n\n" << C << "\n\n" << D << '\n';
}

这可能会违反严格的别名规则,我通常建议重新考虑您的设计。但是,它应该可以在没有不必要的运行时分配的情况下工作,并且可以安全地防止一些错误用法:

    MatrixXf fail1;
    Matrix3d fail2;
    foo(fail1); // fails at compile time
    foo(fail2); // fails at runtime

【讨论】:

    猜你喜欢
    • 2011-02-23
    • 2014-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 2014-01-10
    • 2014-07-30
    • 2016-08-31
    相关资源
    最近更新 更多