有没有办法“强制” MatrixBase::eval 在模板函数参数上发生?
Posted
技术标签:
【中文标题】有没有办法“强制” MatrixBase::eval 在模板函数参数上发生?【英文标题】:Is there a way to "force" MatrixBase::eval to happen on a template function argument? 【发布时间】:2013-04-17 15:18:42 【问题描述】:我正在为一个广泛使用 Eigen 的库编写代码,并且经常将 Eigen::Matrix
对象与我自己设计的 NSObject
子类 (vMAT_Array
) 进行映射。使用该库通常需要将矩阵编组为 vMAT_Array
实例,以便它们可以被传递等等。
我有一个 vMAT_cast
模板函数来处理这个问题:
template <typename EigenObjectType>
vMAT_Array * vMAT_cast(EigenObjectType matrix)
return Map<EigenObjectType>(matrix).matA;
这个函数的问题是它不能与 Eigen 的惰性求值语义正确交互。以下面的单元测试代码为例:
vMAT_Array * matM = vMAT_cast(VectorXd::LinSpaced(40, 1.0, 40.0).eval());
[matM reshape:vMAT_MakeSize(5, 8)];
Mat<double> M = matM;
Array<bool, Dynamic, Dynamic> sel = M.unaryExpr([](double elt) return (int)elt % 3 == 0; ).cast<bool>();
vMAT_Array * vecN = vMAT_pick(matM, vMAT_cast(sel));
NSLog(@"%@", vecN.dump);
vMAT_Array * vecNv = vMAT_cast(VectorXd::LinSpaced(13, 3.0, 39.0).eval());
STAssertEqualObjects(vecN, vecNv, @"Logical indexing broken");
注意.eval()
对vMAT_cast
的大多数参数的显式调用。这些是必要的,因为模板函数尝试(在编译时)使用 Eigen 的惰性表达式模板之一扩展为代码,该模板会生成如下可爱的错误消息:
/Users/Shared/Source/vMAT/vMATTests/EigenTests.mm:25:35: note: in instantiation of member function 'Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >::LinSpaced' requested here
vMAT_Array * matM = vMAT_cast(VectorXd::LinSpaced(40, 1.0, 40.0));
^
In file included from /Users/Shared/Source/vMAT/vMATTests/EigenTests.mm:11:
In file included from /Users/Shared/Source/vMAT/vMAT/vMAT.h:51:
/Users/Shared/Source/vMAT/vMAT/vMAT_Array.h:122:82: error: no member named 'data' in 'Eigen::CwiseNullaryOp<Eigen::internal::linspaced_op<double, true>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >'
data:[NSMutableData dataWithBytes:matrix.data()
~~~~~~ ^
我怀疑有 template-fu 会“强制”MatrixBase::eval
发生,但我对此缺乏了解。谁能赐教?
【问题讨论】:
【参考方案1】:您可以在 eigen/unsupported/Eigen/OpenGLSupport 模块中找到这种模板功夫。在这里,您将找到通过原始 C 指针获取向量和矩阵的 OpenGL 函数的包装器。关键是在这个测试中,我们检查表达式类型是否兼容 OpenGL:
bool IsGLCompatible = bool(XprType::Flags&LinearAccessBit)
&& bool(XprType::Flags&DirectAccessBit)
&& (XprType::IsVectorAtCompileTime || (XprType::Flags&RowMajorBit)==0)
LinearAccessBit 表示没有“步幅”,DirectAccessBit 表示有 .data() 可用。还有其他两个很明显,可能与您的情况无关。
另一个选择,可能更简单,是使用 devel 分支的新 Ref 类。我参考doc了解这种方法的详细信息。
【讨论】:
啊,我认为我看到了表达式是如何工作的......它在编译时被评估,如果IsGLCompatible
是false
,那么有一个专门化“修复" 调用函数之前的参数。不过,我没有看到如何使用 Ref
模板类。
假设您只能映射顺序存储的主要列矩阵,然后您将vMAT_cast
函数声明为vMAT_cast(Ref<MatrixXd,0,Stride<0,0> > matrix);
任何与MatrixXd
不“相似”的表达式都将被评估。如果vMAT_Array
支持跨步,则将其声明为:vMAT_cast(Ref<MatrixXd> matrix)
。
感谢您的澄清……我的困难是我不提前知道图书馆用户可能想要投射什么类型的矩阵。我的 Objective-C 库正在尝试使用 vMAT_Array *
's 作为“ref”类型,您可以轻松地从函数、方法等传递和返回。所以也许我需要深入研究源代码对于 Eigen Ref
的东西在某个时候?但是因为我可以(大部分)理解你概述的第一种方法是如何工作的,我想我会先尝试一下。 (目前我还在到处撒.eval()
……)以上是关于有没有办法“强制” MatrixBase::eval 在模板函数参数上发生?的主要内容,如果未能解决你的问题,请参考以下文章