AutoDiffJacobian Эйгена, нужна помощь, чтобы получить учебный пример для работы
Я пользуюсь AutoDiffScalar от Eigen с большим успехом и теперь хотел бы перейти к AutoDiffJacobian вместо того, чтобы делать это самостоятельно. Поэтому я создал учебный пример после изучения AutoDiffJacobian.h, но что-то не так.
Функтор:
template <typename Scalar>
struct adFunctor
{
typedef Eigen::Matrix<Scalar, 3, 1> InputType;
typedef Eigen::Matrix<Scalar, 2, 1> ValueType;
typedef Eigen::Matrix<Scalar,
ValueType::RowsAtCompileTime,
InputType::RowsAtCompileTime> JacobianType;
enum {
InputsAtCompileTime = InputType::RowsAtCompileTime,
ValuesAtCompileTime = ValueType::RowsAtCompileTime
};
adFunctor() {}
size_t inputs() const { return InputsAtCompileTime; }
void operator() (const InputType &input,
ValueType *output) const
{
Scalar s1 = Scalar(0), s2 = Scalar(0);
/* Some operations to test the AD. */
for (int i = 0; i < 3; i++)
{
s1 += log(input(i));
s2 += sqrt(input(i));
}
(*output)(0) = s1;
(*output)(1) = s2;
}
};
Использование:
Eigen::Matrix<double, 3, 1> in;
in << 1,2,3;
Eigen::Matrix<double, 2, 1> out;
Eigen::AutoDiffJacobian< adFunctor<double> > adjac;
adjac(in, &out);
Ошибка, которая получена из этого следующим образом:
/usr/include/eigen3/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h: In instantiation of ‘void Eigen::AutoDiffJacobian<Functor>::operator()(const InputType&, Eigen::AutoDiffJacobian<Functor>::ValueType*, Eigen::AutoDiffJacobian<Functor>::JacobianType*) const [with Functor = adFunctor<double>; Eigen::AutoDiffJacobian<Functor>::InputType = Eigen::Matrix<double, 3, 1>; Eigen::AutoDiffJacobian<Functor>::ValueType = Eigen::Matrix<double, 2, 1>; Eigen::AutoDiffJacobian<Functor>::JacobianType = Eigen::Matrix<double, 2, 3, 0, 2, 3>]’:
/home/emifre/Git/autodiff-test/src/autodiff_test.cpp:55:17: required from here
/usr/include/eigen3/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h:69:24: error: no matching function for call to ‘Eigen::AutoDiffJacobian<adFunctor<double> >::operator()(Eigen::AutoDiffJacobian<adFunctor<double> >::ActiveInput&, Eigen::AutoDiffJacobian<adFunctor<double> >::ActiveValue*) const’
Functor::operator()(ax, &av);
~~~~~~~~~~~~~~~~~~~^~~~~~~~~
/home/emifre/Git/autodiff-test/src/autodiff_test.cpp:27:8: note: candidate: void adFunctor<Scalar>::operator()(const InputType&, adFunctor<Scalar>::ValueType*) const [with Scalar = double; adFunctor<Scalar>::InputType = Eigen::Matrix<double, 3, 1>; adFunctor<Scalar>::ValueType = Eigen::Matrix<double, 2, 1>]
void operator() (const InputType &input,
^~~~~~~~
/home/emifre/Git/autodiff-test/src/autodiff_test.cpp:27:8: note: no known conversion for argument 2 from ‘Eigen::AutoDiffJacobian<adFunctor<double> >::ActiveValue* {aka Eigen::Matrix<Eigen::AutoDiffScalar<Eigen::Matrix<double, 3, 1> >, 2, 1, 0, 2, 1>*}’ to ‘adFunctor<double>::ValueType* {aka Eigen::Matrix<double, 2, 1>*}’
Из этой ошибки кажется, что у меня почему-то нет правильных типов для моего функтора для второго вызова функтора в AutoDiffJacobian.h, но первый вызов к нему работает. Я надеюсь, что кто-то здесь имеет представление, почему и может помочь, может быть, я просто неправильно понял использование.
РЕДАКТИРОВАТЬ: компилируемый пример, который показывает проблему:
#include <Eigen/Dense>
#include <unsupported/Eigen/AutoDiff>
/*
* Testing differentiation that will produce a Jacobian, using functors and the
* AutoDiffJacobian helper.
*/
template <typename Scalar>
struct adFunctor
{
typedef Eigen::Matrix<Scalar, 3, 1> InputType;
typedef Eigen::Matrix<Scalar, 2, 1> ValueType;
typedef Eigen::Matrix<Scalar,
ValueType::RowsAtCompileTime,
InputType::RowsAtCompileTime> JacobianType;
enum {
InputsAtCompileTime = InputType::RowsAtCompileTime,
ValuesAtCompileTime = ValueType::RowsAtCompileTime
};
adFunctor() {}
size_t inputs() const { return InputsAtCompileTime; }
void operator() (const InputType &input,
ValueType *output) const
{
Scalar s1 = Scalar(0), s2 = Scalar(0);
/* Some operations to test the AD. */
for (int i = 0; i < 3; i++)
{
s1 += log(input(i));
s2 += sqrt(input(i));
}
(*output)(0) = s1;
(*output)(1) = s2;
}
};
int main(int argc, char *argv[])
{
Eigen::Matrix<double, 3, 1> in;
in << 1,2,3;
Eigen::Matrix<double, 2, 1> out;
Eigen::AutoDiffJacobian< adFunctor<double> > adjac;
adjac(in, &out);
return 0;
}
2 ответа
Окей, после долгих испытаний я получил его на работу. Я просто неправильно понял ошибку компилятора, который прямо сказал об этом, я пропустил шаблон для самого оператора.
Это просто нужно изменить на:
template <typename T1, typename T2>
void operator() (const T1 &input, T2 *output) const
Теперь это работает как удовольствие! Я надеюсь, что кто-то, кроме меня, может использовать это.
Может быть, уже слишком поздно для ответа. Я публикую свое решение здесь. Причина, по которой компиляция не удалась, заключается в том, что внутри класса шаблона AutoDiffScalar требуется пользовательская функция для реализации operator() с аргументами, которые являются векторами с ActiveScalar в качестве скаляров. Вызов пользовательской функции внутри AutoDiffJacobian — перегрузка ActiveType ActiveScalar — это тип AutoDiffScalar<...>.
Поэтому пользовательский класс должен предоставлять перегрузку операторов (), которые принимают такие аргументы. Кроме того, им также требуется перегрузка, которая принимает необработанные InputType/ValueType. Вызов пользовательской функции внутри AutoDiffJacobian — перегрузка OriginalType
Затем, чтобы иметь их обоих, лучше иметь реализацию шаблона, например,
template<typename T>
void operator()(const Eigen::Matrix<T, InputsAtCompileTime, 1>& x,
Eigen::Matrix<T, ValuesAtCompileTime,1>* v) const{
// Computation codes here ...
}
Это лучше, чем решение от @Korken, которое принимает любой тип.