#c #eigen #eigen3
#c #eigen #eigen3
Вопрос:
Я знаю, что в собственном я могу использовать 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;
});
который, например, умножил бы каждую запись в векторе на ее позицию.
Ответ №1:
Помимо использования нулевого выражения, как предложено @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));
В достаточно последних версиях собственного, LinSpaced
должно быть векторизовано (хотя есть некоторые пограничные случаи, касающиеся последнего элемента). binaryExpr
векторизируется, конечно, только в том случае, если переданный функтор векторизован.
Примечание: Если вы выполняете в основном поэлементные операции, рассмотрите возможность использования ArrayXd
вместо VectorXd
.
Ответ №2:
Вы можете обойти это с помощью нулевого выражения:
VectorXd v;
v = VectorXd::NullaryExpr([amp;v](Index i) { return v(i)*i; });
Вы можете сделать почти все с помощью нулевого выражения: https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html
Ответ №3:
То, что вы собираетесь сделать, не что иное, как обычный цикл for:
for (int i = 0; i < vec.size(); i)
vec(i) *= i;
Так почему бы не упростить задачу? Если предполагается, что его можно использовать для создания объектов, оберните его во вспомогательную функцию (шаблон).
Кроме того, что вы можете сделать, так это полагаться на внутренний порядок вычисления в Eigen. Кажется, это работает, но я не уверен, стал бы я на это полагаться:
struct CountingUnaryFct {
double operator()(double d) const { return d*index ; }
mutable int index = 0;
};
vec.unaryExpr(CountingUnaryFct{});
Это довольно уродливый взлом, поскольку он обманывает unaryExpr
шаблон, который требует, чтобы его объект function имел const
-квалифицированный член operator()(double) const
(это невозможно с mutable
-лямбдой, следовательно, объект function), чтобы принять экземпляр, который фактически изменяет свое состояние под капотом. Но опять же, кажется, что это работает надежно, по крайней мере, на одномерных матрицах.
Комментарии:
1. Я бы настоятельно рекомендовал отказаться от второго решения. Хотя на данный момент это, вероятно, работает, нет никакой гарантии в отношении порядка, в котором вычисляются коэффициенты — в будущем это вполне может происходить параллельно, например.