David Pfau
David Pfau

Reputation: 813

Foreach loops over Eigen matrices?

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

Answers (4)

iNFINITEi
iNFINITEi

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

Toby Speight
Toby Speight

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

Simmovation
Simmovation

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

mty
mty

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

Related Questions