Элегантный способ работы элементов с циклами for на матрице Eigen3, используя современный C ++ - PullRequest
0 голосов
/ 24 августа 2018

Я хочу выполнить некоторую операцию с элементами в матрице, в зависимости от положения каждого элемента.

Я знаю, что по умолчанию Eigen matrix является главным по столбцу, поэтому для циклического перемещения по матрице,внешний цикл for предназначен для каждого столбца, а внутренний цикл for предназначен для каждой строки.У меня есть 4 вида выражений для присваивания m(r,c), в зависимости от значений r и c.Ниже показан некоторый псевдокод:

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 

Я также сделал подробные коды C ++ ниже.Я не эксперт по C ++, поэтому я не уверен, элегантен ли мой код или нет.Не могли бы вы дать мне знать, как его улучшить?Я бы предпочел использовать возможные современные функции C ++ 14 или C ++ 17.

#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
                }
            }
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 24 августа 2018

Вот решение, использующее лямбда-функтор:

void some_operation_on_matrix(Eigen::MatrixXd& out, int some_r, int some_c)
{
  out = Eigen::MatrixXd::NullaryExpr(out.rows(), out.cols(),
    [&](Eigen::Index r, Eigen::Index c)
    {
        if(c == some_c)
            if(r == some_r)
                return 1.0; // some expr A
            else
                return 2.0; // some expr B
        else
            if(r == some_r)
                return 3.0; // some expr C
            else
                return 4.0; // some expr D 
     });
}

Вероятно, более эффективным (если все выражения постоянны) будет

out.setConstant(D);
out.row(some_r).setConstant(C);
out.col(some_c).setConstant(B);
out(some_r, some_c) = A;
0 голосов
/ 24 августа 2018

Я бы немного изменил логику вашего цикла

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
                }
            }
        }
    }
}

Таким образом, оператор if if (c == some_c) должен оцениваться только для всех m.cols, а не для всех m.cols * m.rows.

Вы можете извлечь второй цикл for в функции

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(...);
        }
    }
}

и

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);           
        }
    }
}
...