Search code examples
c++eigeneigen3

Eigen vertical stacking rows into Matrix


I would like to create a matrix of size 2N x 9 where N is a dynamic value by vertical stacking 2N 1x9 matrices.

Here's what I tried doing.

using CoefficientMatrix = Eigen::Matrix<T, Eigen::Dynamic, 9>;
using CoefficientRow = Eigen::Matrix<T, 1, 9>;

CoefficientMatrix A(2*N, 9);

for (int i = 0; i < N; i++) {
    CoefficientRow ax;
    CoefficientRow ay;
    // fill in ax and ay
    A << ax, ay;
}

But, I get the following runtime error.

Assertion failed: (((m_row+m_currentBlockRows) == m_xpr.rows() || m_xpr.cols() == 0) && m_col == m_xpr.cols() && "Too few coefficients passed to comma initializer (operator<<)"), function finished, file /usr/local/include/eigen3/Eigen/src/Core/CommaInitializer.h, line 120.

I tried parsing through the assertion syntax but I'm not sure what those internal variable names are referring to in terms of my code (new to Eigen).

Thanks for any assistance.


Solution

  • TLDR: Write something like this:

    CoefficientMatrix A(2*N, 9);
    
    for (int i = 0; i < N; i++) {
        CoefficientRow ax;
        CoefficientRow ay;
        // fill in ax and ay
        A.row(2*i)   = ax;
        A.row(2*i+1) = ay;
    }
    

    The reason of your error is (as Avi explained) that the operator<< is intended to fill an entire matrix at once. In fact, calling operator<<(Array &A, Array const &b) assigns b to the top-left corner of A and returns a proxy-object which holds a reference to A and keeps track of how much entries of A already got assigned to (stored in m_row, m_currentBlockRows, m_col) and overloads operator, which assigns the next expression to the corresponding position of a and increases the position accordingly. Finally, when that proxy object gets destructed (which usually happens "at the ;") the destructor checks if all entries of A have been filled (and raises a failed assertion, if not).

    If you prefer to use the << , syntax you could also write:

        A.middleRows<2>(2*i) << ax, ay;
    

    With optimizations enabled that should generate the same code as the simple implementation above (so choose whichever is easier to read for you).


    N.B.: You could technically (ab)use the CommaInitializer in a loop, by constructing it outside the loop, assigning it to a variable and then only use the , operator inside the loop. I'll intentionally won't give more details on how to do that ...