Eigen unaryExpr (): получить индекс элемента - PullRequest
2 голосов
/ 29 марта 2019

Я знаю, что в Eigen я могу использовать unaryExpr(), чтобы применить пользовательскую функцию к моим собственным матрицам и векторам, например,

Eigen::VectorXd vec(4);
vec.unaryExpr([](double d) {
    return d * cos(d);
});

для применения пользовательских функций к Eigen::VectorXd. Но есть ли способ получить положение текущего элемента в моем векторе? Я хочу иметь возможность сделать что-то вроде этого:

Eigen::VectorXd vec(4);
vec.unaryExpr([](double d, int index) {
     return index * d;
 });

, который, например, умножил бы каждую запись в векторе на его позицию.

Ответы [ 3 ]

1 голос
/ 29 марта 2019

Вы можете обойти, используя нулевое выражение:

VectorXd v;
v = VectorXd::NullaryExpr([&v](Index i) { return v(i)*i; });

Вы можете сделать почти все с нулевым выражением: https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html

1 голос
/ 31 марта 2019

Помимо использования нулевого выражения, предложенного @ggael, вы также можете использовать двоичное выражение вместе с LinSpaced(size, 0, size-1):

VectorXd v; // some input vector

v = v.binaryExpr(VectorXd::LinSpaced(v.size(), 0, v.size()-1),
                 [](double d, double i){return d*i;});
// or much simpler and more efficient in this case:
v = v.cwiseProduct(VectorXd::LinSpaced(v.size(), 0, v.size()-1));

В достаточно последних версиях Eigen, LinSpaced должно быть векторизовано (хотя есть некоторые пограничные случаи относительно последнего элемента).Конечно, binaryExpr векторизуется, только если переданный функтор векторизован.

Примечание: если вы выполняете в основном поэлементные операции, рассмотрите возможность использования ArrayXd вместо VectorXd.

0 голосов
/ 29 марта 2019

То, что вы намереваетесь сделать, это не что иное, как обычный цикл for:

for (int i = 0; i < vec.size(); ++i)
   vec(i) *= i;

Так почему бы не сделать все просто? Если он должен использоваться для создания объектов, поместите его в вспомогательную функцию (шаблон).

Кроме того, что может сделать, так это полагаться на внутренний порядок оценки Эйгена. Кажется, это работает, но я не уверен, буду ли я полагаться на это:

struct CountingUnaryFct {
   double operator()(double d) const { return d*index++; }
   mutable int index = 0;
};

vec.unaryExpr(CountingUnaryFct{});

Это хак со значительным уродством, поскольку он обманывает шаблон unaryExpr, который требует, чтобы его функциональный объект имел const -квалифицированный член operator()(double) const (невозможно с mutable -lambda, следовательно, функция объект), чтобы принять экземпляр, который действительно изменяет свое состояние под капотом. Но опять же, похоже, он работает надежно, по крайней мере, на одномерных матрицах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...