I am working on code for a library that uses Eigen extensively, and frequently maps Eigen::Matrix
objects with an NSObject
subclass of my own design (vMAT_Array
). Working with the library often requires marshaling matrices into vMAT_Array
instances to they can be passed around, etc.
I have a vMAT_cast
template function which handles this:
template <typename EigenObjectType>
vMAT_Array * vMAT_cast(EigenObjectType matrix)
{
return Map<EigenObjectType>(matrix).matA;
}
The problem with this function is that it does not interact correctly with Eigen's lazy evaluation semantics. Take for example the unit test code below:
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");
Notice the explicit .eval()
calls on most of the arguments to vMAT_cast
. These are necessary because the template function tries (at compile time) to expand into code using one of Eigen's lazy expression templates, which generates lovely error messages like this one:
/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()
~~~~~~ ^
I suspect there is template-fu that would "force" the MatrixBase::eval
to happen, but I lack knowledge of it. Can anyone enlighten me?