Search code examples
c++for-loopeigen3

Elegant way for element operation with for-loops on Eigen3 matrix, using modern C++


I want to do some operation with elements in a matrix, depending on the position of each element.

I know that by-default, Eigen matrix is column-major, so to loop over the matrix, the outer for-loop is for each column, and the inner for-loop is for each row. I have 4 kinds of expressions to be assigned to m(r,c), depending on the values of r and c. Some pseudo-code is shown below:

if c == some_c
    if r == some_r
        m(r,c) = some expression A
    else
        m(r,c) = some expression B
else
    if r == some_r
        m(r,c) = some expression C
    else
        m(r,c) = some expression D 

I have also made detailed c++ codes below. I am not C++ expert, so I am not sure whether my code is elegant or not. Could you please let me know how to improve it? I would prefer using possible modern C++14 or C++17 features.

#include <Eigen/Dense>

using Matrix = Eigen::MatrixXd

void some_operation_on_matrix(Matrix& m, size_t some_r, size_t some_c)
{
    for (size_t c = 0; c < m.cols(); c++) {
        for (size_t r = 0; r < m.rows(); r++) {
            if (c == some_c) {
                if (r == some_r) {
                    // m(r,c) = some expression A
                }
                else {
                    // m(r,c) = some expression B
                }
            }
            else {
                if (r == some_r) {
                    // m(r,c) = some expression C
                }
                else {
                    // m(r,c) = some expression D
                }
            }
        }
    }
}

Solution

  • I would change the logic of your loop a bit

    void some_operation_on_matrix(Matrix& m, size_t some_r, size_t some_c)
    {
        for (size_t c = 0; c < m.cols(); c++) {
            if (c == some_c) {
                for (size_t r = 0; r < m.rows(); r++) {
                    if (r == some_r) {
                        // m(r,c) = some expression A
                    }
                    else {
                        // m(r,c) = some expression B
                    }
                }
            else {
                for (size_t r = 0; r < m.rows(); r++) {
                    if (r == some_r) {
                        // m(r,c) = some expression C
                    }
                    else {
                        // m(r,c) = some expression D
                    }
                }
            }
        }
    }
    

    Thus, the if statement if (c == some_c) has only to be evaluated for all m.cols and not for all m.cols * m.rows.

    You can extract the second for loop in a function

    void innerLoop(Matrix &m, const size_t some_r, std::function expression1, std::function expression2)
    {
        for (size_t r = 0; r < m.rows(); r++) {
            if (r == some_r) {
                m(r,c) = expression1(...);
            }
            else {
                m(r,c) = expression2(...);
            }
        }
    }
    

    and

    void some_operation_on_matrix(Matrix& m, size_t some_r, size_t some_c)
    {
        for (size_t c = 0; c < m.cols(); c++) {
            if (c == some_c) {
                innerLoop(m, some_r, expressionA, expressionB);
            else {
                innerLoop(m, some_r, expressionC, expressionC);           
            }
        }
    }