调整Eigen :: Ref大小的解决方法 [英] Workaround for resizing Eigen::Ref
问题描述
我想使用Eigen :: Ref使用Eigen :: Matrix参数来具有非模板函数.我的问题是在这些函数中,我可能必须调整Eigen :: Ref引用的矩阵的大小.我知道,一般而言,不应调整Eigen :: Ref的大小,因为它可以映射到表达式或矩阵块,但就我而言,我确定Eigen :: Ref背后的内容是Eigen :: Matrix.
I want to use Eigen::Ref to have non-template functions using Eigen::Matrix arguments. My problem is that in these functions, I may have to resize the matrices referenced by the Eigen::Ref. I understand that for generality an Eigen::Ref should not be resized because it can map to an expression or a matrix block, but In my case, I am sure that what is behind my Eigen::Ref is an 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?而言,解决了调整大小的问题.
So, what could I do to handle this? In the Eigen documentation, the problem of resizing is addressed for template functions using MatrixBase as arguments, but for Eigen::Ref?
推荐答案
这是一个使用成员函数指针和残酷强制转换的hacky解决方案:
Here is a hacky solution using member function pointers and brutal casting:
#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';
}
这可能会违反严格的别名规则,我通常建议您重新考虑您的设计.但是,它应该在没有不必要的运行时分配的情况下工作,并且可以安全地避免某些错误的用法:
This likely breaks strict aliasing rules and I would generally advise to re-think your design. It should however work without unnecessary run-time allocations, and it is safe against some wrong usages:
MatrixXf fail1;
Matrix3d fail2;
foo(fail1); // fails at compile time
foo(fail2); // fails at runtime
这篇关于调整Eigen :: Ref大小的解决方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!