smooth
A C++ library for Lie theory
Loading...
Searching...
No Matches
autodiff.hpp
Go to the documentation of this file.
1// Copyright (C) 2022 Petter Nilsson. MIT License.
2
3#pragma once
4
10// TODO switch to autodiff::Real when it supports atan2
11// https://github.com/autodiff/autodiff/issues/185
12
13#include <algorithm>
14#include <utility>
15
16#include <autodiff/forward/dual.hpp>
17#include <autodiff/forward/dual/eigen.hpp>
18
19#define SMOOTH_DIFF_AUTODIFF
20
21#include "smooth/detail/traits.hpp"
22#include "smooth/detail/utils.hpp"
23#include "smooth/detail/wrt_impl.hpp"
24#include "smooth/manifolds.hpp"
25
26SMOOTH_BEGIN_NAMESPACE
27
29template<typename T>
30struct detail::scalar_trait<autodiff::Dual<T, T>>
31{
32 // \cond
33 static constexpr bool value = true;
34 // \endcond
35};
36
37namespace diff {
38
46template<std::size_t K = 1>
47 requires(K >= 1 && K <= 2)
48auto dr_autodiff(auto && f, auto && x)
49{
50 using Result = decltype(std::apply(f, x));
51 using Scalar = ::smooth::Scalar<Result>;
52 using Eigen::Matrix;
53
54 static_assert(Manifold<Result>, "f(x) is not a Manifold");
55
56 using AdScalar = autodiff::HigherOrderDual<K, Scalar>;
57
58 Result F = std::apply(f, x);
59
60 static constexpr auto Nx = wrt_Dof<decltype(x)>();
61 static constexpr auto Ny = Dof<Result>;
62 const Eigen::Index nx = std::apply([](auto &&... args) { return (dof(args) + ...); }, x);
63 const Eigen::Index ny = dof(F);
64
65 // cast F and x to ad types
66 const auto x_ad = wrt_cast<AdScalar>(x);
67 CastT<AdScalar, Result> F_ad = cast<AdScalar>(F);
68
69 if constexpr (K == 1) {
70 // zero-valued tangent element
71 Matrix<AdScalar, Nx, 1> a_ad = Matrix<AdScalar, Nx, 1>::Zero(nx);
72
73 // function to differentiate
74 const auto f_ad = [&](Matrix<AdScalar, Nx, 1> & var) -> Matrix<AdScalar, Ny, 1> {
75 return rminus<CastT<AdScalar, Result>>(std::apply(f, wrt_rplus(x_ad, var)), F_ad);
76 };
77
78 Matrix<Scalar, Ny, Nx> J(ny, nx);
79
80 J = autodiff::jacobian(f_ad, autodiff::wrt(a_ad), autodiff::at(a_ad));
81 return std::make_pair(std::move(F), std::move(J));
82 } else if constexpr (K == 2) {
83 // function to differentiate
84 const auto f_ad =
85 [&f, &x_ad, &F_ad](Matrix<AdScalar, Nx, 1> & var1, Matrix<AdScalar, Nx, 1> & var2) -> Matrix<AdScalar, Ny, 1> {
86 return rminus(std::apply(f, wrt_rplus(wrt_rplus(x_ad, var1), var2)), F_ad);
87 };
88
89 Matrix<Scalar, Ny, Nx> J(ny, nx);
90 Matrix<Scalar, Nx, std::min(Nx, Ny) == -1 ? -1 : Nx * Ny> H(nx, nx * ny);
91
92 // zero-valued tangent elements
93 Matrix<AdScalar, Nx, 1> a_ad1 = Matrix<AdScalar, Nx, 1>::Zero(nx);
94 Matrix<AdScalar, Nx, 1> a_ad2 = Matrix<AdScalar, Nx, 1>::Zero(nx);
95
96 const auto a_wrt1 = autodiff::wrt(a_ad1);
97 const auto a_wrt2 = autodiff::wrt(a_ad2);
98
99 autodiff::detail::ForEachWrtVar(a_wrt1, [&](auto && i, auto && xi) constexpr {
100 autodiff::detail::ForEachWrtVar(a_wrt2, [&](auto && j, auto && xj) constexpr {
101 const auto u = autodiff::detail::eval(f_ad, autodiff::at(a_ad1, a_ad2), autodiff::wrt(xi, xj));
102 for (auto k = 0u; k < ny; ++k) {
103 J(k, i) = static_cast<double>(autodiff::detail::derivative<1>(u[k]));
104 H(j, k * nx + i) = autodiff::detail::derivative<2>(u[k]);
105 }
106 });
107 });
108
109 return std::make_tuple(std::move(F), std::move(J), std::move(H));
110 }
111}
112
113} // namespace diff
114
115SMOOTH_END_NAMESPACE
auto dr_autodiff(auto &&f, auto &&x)
Automatic differentiation in tangent space using the autodiff library.
Definition autodiff.hpp:48
Class-external Manifold interface defined through the traits::man trait class.
Definition manifold.hpp:31
typename traits::man< M >::Scalar Scalar
Manifold scalar type.
Definition manifold.hpp:88
Eigen::Index dof(const M &m)
Manifold degrees of freedom (tangent space dimension)
Definition manifold.hpp:145
Tangent< M > rminus(const M &g1, const Mo &g2)
Manifold right-minus.
Definition manifold.hpp:172
typename traits::man< M >::template CastT< NewScalar > CastT
Cast'ed type.
Definition manifold.hpp:100
Meta header to include all Manifold concept model specifications.