0

Suppose I write the following:

func(Eigen::SparseMatrixBase<double> & A){
    for(int i = 0; i < A.outerSize(); i++)
        for(Eigen::SparseMatrixBase<double>::InnerIterator it(A,i);it;++it)
            // do something
}

This function does not work, since SparseMatrixBase cannot initialize an inner iterator.

So, I define the function for both RowMajor and ColMajor, then I try to template these functions:

template<class Mat, class MatI>
func(Mat & A){
    for(int i = 0; i < A.outerSize(); i++)
        for(MatI it(A,i);it;++it)
            //do something

func<Eigen::SparseMatrix<double,Eigen::RowMajor>,ditto::InnerIterator>(Arowmajor);
func<...,...>(Acolmajor);

And when I compile:

error: cannot convert Eigen::SparseMatrix<double,RowMajor> & 
to Eigen::SparseMatrix<double,0,int> &

Then, I change the types:

func<Eigen::SparseMatrix<double,0,int>,ditto::InnerIterator>(Arowmajor)

And the error? the inverse of the previous:

error: cannot convert Eigen::SparseMatrix<double,0,int> & 
to Eigen::SparseMatrix<double,RowMajor> & 


What is the proper way to handle iteration and templating with the Eigen classes?

Chris
  • 28,822
  • 27
  • 83
  • 158

1 Answers1

2

Instead of explicitly using two template parameters, you can use a single one to represent the SparseMatrix type and use its InnerIterator as so:

#include <Eigen/SparseCore>
#include <iostream>

using namespace Eigen;

template<class Mat>
void func(Mat & A, double d)
{
    for (int i = 0; i < A.outerSize(); i++)
        for (typename Mat::InnerIterator it(A, i); it; ++it)
            it.valueRef() = d;
}

int main()
{
    SparseMatrix<double> sm(3, 3);
    sm.setIdentity();

    std::cout << sm << "\n\n";

    func(sm, 3.2);

    std::cout << sm << "\n\n";

    return 0;
}

Note that this will not compile for expressions, such as func(sm * 2.0, 3.2); as that is an expression template and does not have an InnerIterator. There are ways to write templated functions that will accept an expression, but those are more complicated and tend to require more knowledge of the inner workings of Eigen (see e.g. here).

Chris
  • 28,822
  • 27
  • 83
  • 158
Avi Ginsburg
  • 10,323
  • 3
  • 29
  • 56
  • Can I add one edit? before `Mat::InnerIterator`, I had to add `typename Mat::InnerIterator` to get this to work. The CLang error message was not clear, but when I compiled with G++, discovered the issue immediately. – Chris Mar 11 '18 at 11:37
  • that being said, I don't understand why it would be necessary to add `typename`--that seems like a decoration to avoid compiler logic, rather than a necessity. – Chris Mar 11 '18 at 11:39
  • @bordeo Yes, be my guest. [My bad](https://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords). My bad habits are supported by using Visual Studio. – Avi Ginsburg Mar 11 '18 at 11:53