有没有办法“强制” 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了解这种方法的详细信息。

【讨论】:

啊,我认为我看到了表达式是如何工作的......它在编译时被评估,如果IsGLCompatiblefalse,那么有一个专门化“修复" 调用函数之前的参数。不过,我没有看到如何使用 Ref 模板类。 假设您只能映射顺序存储的主要列矩阵,然后您将vMAT_cast 函数声明为vMAT_cast(Ref&lt;MatrixXd,0,Stride&lt;0,0&gt; &gt; matrix); 任何与MatrixXd 不“相似”的表达式都将被评估。如果vMAT_Array 支持跨步,则将其声明为:vMAT_cast(Ref&lt;MatrixXd&gt; matrix) 感谢您的澄清……我的困难是我不提前知道图书馆用户可能想要投射什么类型的矩阵。我的 Objective-C 库正在尝试使用 vMAT_Array *'s 作为“ref”类型,您可以轻松地从函数、方法等传递和返回。所以也许我需要深入研究源代码对于 Eigen Ref 的东西在某个时候?但是因为我可以(大部分)理解你概述的第一种方法是如何工作的,我想我会先尝试一下。 (目前我还在到处撒.eval()……)

以上是关于有没有办法“强制” MatrixBase::eval 在模板函数参数上发生?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在锁定该文件之前强制更新 SVN 文件?

有没有办法强制显示工具提示?

有没有办法强制 Xcode 机器人进行干净的结帐?

有没有办法强制程序只使用 1 个线程?

有没有办法在 UcanAccess 中强制从磁盘读取?

有没有办法强制浏览器刷新/下载图像?