Напишите функцию с транспонированием в качестве аргумента с библиотекой Eigen 3 - PullRequest
0 голосов
/ 03 сентября 2018

Я хочу написать функцию, которая может принимать:

  1. плотный массив / матрица или
  2. транспонирование плотного массива / матрицы.

Можно ли избежать идеальной пересылки?

Я пытался использовать DenseBase аргумент типа. Но это не может принять транспонирование матрицы.

Мне не нравится использовать идеальную пересылку, потому что реализация проверки типов с помощью sfinae была бы утомительной.

Текущее решение:

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

using namespace Eigen;

template <typename U>
auto f(U&& x) {
    auto x2 = std::forward<U>(x);
    auto max_x = x2.colwise().maxCoeff().eval();
    x2 = x2.rowwise() + max_x;
    return max_x;
}

int main() {
    Array<float, 3, 3> M1;
    M1 << 1, 2, 3, 
          4, 5, 6, 
          7, 8, 9;
    std::cout << M1 << "\n";
    // auto here might cause problem later ...
    // see eigen.tuxfamily.org/dox/TopicPitfalls.html
    auto max_x = f(M1.transpose());
    std::cout << M1 << "\n";
    std::cout << max_x << "\n";
}

Результат:

// original
1 2 3
4 5 6
7 8 9
// Increase each row by max of the row.
 4  5  6
10 11 12
16 17 18
// Max of each row (not a column vector).
3 6 9

Я пробовал EigenBase со следующими строками:

template <typename U>
auto f(EigenBase<U>& x) {
...

Ошибка компилятора:

test4.cpp:20:32: error: cannot bind non-const lvalue reference of type ‘Eigen::EigenBase<Eigen::Transpose<Eigen::Array<float, 3, 3> > >&’ to an rvalue of type ‘Eigen::EigenBase<Eigen::Transpose<Eigen::Array<float, 3, 3> > >’
     auto max_x = f(M1.transpose());
                    ~~~~~~~~~~~~^~

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

Используйте автоматический тип, чтобы сохранить выражение транспонирования перед вызовом функции.

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

using namespace Eigen;

template <typename Derived>
auto f(DenseBase<Derived>& x) {
    auto max_x = x.colwise().maxCoeff().eval();
    x = x.rowwise() + max_x;
    return max_x;
}

int main() {
    Array<float, 3, 3> M1, M2;
    M1 << 1, 2, 3, 
          4, 5, 6, 
          7, 8, 9;
    M2 = M1;
    std::cout << M1 << "\n";

    std::cout << "no transpose\n";
    Array<float, 3, 1> max_x = f(M1);
    std::cout << M1 << "\n";
    std::cout << max_x << "\n";

    std::cout << "transpose\n";
    auto m2_t = M2.transpose();
    Array<float, 1, 3> max_x2 = f(m2_t);
    std::cout << M2 << "\n";
    std::cout << max_x2 << "\n";
}

Результат:

1 2 3
4 5 6
7 8 9
no transpose
 8 10 12
11 13 15
14 16 18
7
8
9
transpose
 4  5  6
10 11 12
16 17 18
3 6 9
0 голосов
/ 03 сентября 2018

Перегрузка функции с помощью ссылки на lvalue и аргумента ссылки на rvalue, похоже, решает эту проблему.

Я сомневаюсь, что транспонирование - это единственное, что генерирует временное выражение c ++. Если я хочу, чтобы транспонированная версия возвращала транспонированный результат (столбец вместо вектора строки), а нетранспонированная версия возвращала нетранспонированный результат, это не решило бы это.

Спасибо kmdreko за указатели.

Тест:

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

using namespace Eigen;

template <typename Derived>
auto f(DenseBase<Derived>& x) {
    auto max_x = x.colwise().maxCoeff().eval();
    x = x.rowwise() + max_x;
    return max_x;
}

template <typename Derived>
auto f(DenseBase<Derived>&& x) {
    return f(x).transpose().eval();
}

int main() {
    Array<float, 3, 3> M1, M2;
    M1 << 1, 2, 3, 
          4, 5, 6, 
          7, 8, 9;
    M2 = M1;
    std::cout << M1 << "\n";

    std::cout << "no transpose\n";
    Array<float, 3, 1> max_x = f(M1);
    std::cout << M1 << "\n";
    std::cout << max_x << "\n";

    std::cout << "transpose\n";
    Array<float, 1, 3> max_x2 = f(M2.transpose());
    std::cout << M2 << "\n";
    std::cout << max_x2 << "\n";
}

Результат:

1 2 3
4 5 6
7 8 9
no transpose
 8 10 12
11 13 15
14 16 18
// returns column vector
7
8
9
transpose
 4  5  6
10 11 12
16 17 18
// returns row vector
3 6 9
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...