Reputation: 813
Is it possible to use the foreach syntax of C++11 with Eigen matrices? For instance, if I wanted to compute the sum of a matrix (I know there's a builtin function for this, I just wanted a simple example) I'd like to do something like
Matrix2d a;
a << 1, 2,
3, 4;
double sum = 0.0;
for(double d : a) {
sum += d;
}
However Eigen doesn't seem to allow it. Is there a more natural way to do a foreach loop over elements of an Eigen matrix?
Upvotes: 12
Views: 8259
Reputation: 1534
STL style iterator support has been added to Eigen in version 3.4.
See https://eigen.tuxfamily.org/dox-devel/group__TutorialSTL.html
For OP's question, you can do the following:
Matrix2d A;
A << 1, 2,
3, 4;
double sum = 0.0;
for(auto x : A.reshaped())
sum += x;
Upvotes: 2
Reputation: 30762
For your particular case, it's more useful to obtain start and end iterators yourself, and pass both iterators to a standard algorithm:
auto const sum = std::accumulate(a.data(), a.data()+a.size(), 0.0);
If you have another function that really needs range-based for
, you need to provide implementations of begin()
and end()
in the same namespace as the type (for argument-dependent lookup). I'll use C++14 here, to save typing:
namespace Eigen
{
auto begin(Matrix2d& m) { return m.data(); }
auto end(Matrix2d& m) { return m.data()+m.size(); }
auto begin(Matrix2d const& m) { return m.data(); }
auto end(Matrix2d const& m) { return m.data()+m.size(); }
}
Upvotes: 3
Reputation: 253
Range-based for loops need the methods .begin()
and .end()
to be implemented on that type, which they are not for Eigen matrices. However, as a pointer is also a valid random access iterator in C++, the methods .data()
and .data() + .size()
can be used for the begin and end functions for any of the STL algorithms.
Upvotes: 3
Reputation: 800
A pointer to the data array of the matrix can be obtained using the member function .data()
.
The size of the data array can also be obtained using the member function .size()
.
Using these two, we now have the pointers to the first element and end of the array as a.data()
and a.data()+a.size()
.
Also, we know that an std::vector
can be initialized using iterators (or array pointers in our case).
Thus, we can obtain a vector of doubles that wraps the matrix elements with std::vector<double>(a.data(), a.data()+a.size())
.
This vector can be used with the range-based for loop syntax that is included in your code snippet as:
Matrix2d a;
a << 1, 2,
3, 4;
double sum = 0.0;
for(double d : std::vector<double>(a.data(), a.data()+a.size())) {
sum += d;
}
Upvotes: 0