num_diff.hpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /// @file
  2. /// Numerical differentiation using finite differences
  3. #ifndef SOPHUS_NUM_DIFF_HPP
  4. #define SOPHUS_NUM_DIFF_HPP
  5. #include <functional>
  6. #include <type_traits>
  7. #include <utility>
  8. #include "types.hpp"
  9. namespace Sophus {
  10. namespace details {
  11. template <class Scalar>
  12. class Curve {
  13. public:
  14. template <class Fn>
  15. static auto num_diff(Fn curve, Scalar t, Scalar h) -> decltype(curve(t)) {
  16. using ReturnType = decltype(curve(t));
  17. static_assert(std::is_floating_point<Scalar>::value,
  18. "Scalar must be a floating point type.");
  19. static_assert(IsFloatingPoint<ReturnType>::value,
  20. "ReturnType must be either a floating point scalar, "
  21. "vector or matrix.");
  22. return (curve(t + h) - curve(t - h)) / (Scalar(2) * h);
  23. }
  24. };
  25. template <class Scalar, int N, int M>
  26. class VectorField {
  27. public:
  28. static Eigen::Matrix<Scalar, N, M> num_diff(
  29. std::function<Sophus::Vector<Scalar, N>(Sophus::Vector<Scalar, M>)>
  30. vector_field,
  31. Sophus::Vector<Scalar, M> const& a, Scalar eps) {
  32. static_assert(std::is_floating_point<Scalar>::value,
  33. "Scalar must be a floating point type.");
  34. Eigen::Matrix<Scalar, N, M> J;
  35. Sophus::Vector<Scalar, M> h;
  36. h.setZero();
  37. for (int i = 0; i < M; ++i) {
  38. h[i] = eps;
  39. J.col(i) =
  40. (vector_field(a + h) - vector_field(a - h)) / (Scalar(2) * eps);
  41. h[i] = Scalar(0);
  42. }
  43. return J;
  44. }
  45. };
  46. template <class Scalar, int N>
  47. class VectorField<Scalar, N, 1> {
  48. public:
  49. static Eigen::Matrix<Scalar, N, 1> num_diff(
  50. std::function<Sophus::Vector<Scalar, N>(Scalar)> vector_field,
  51. Scalar const& a, Scalar eps) {
  52. return details::Curve<Scalar>::num_diff(std::move(vector_field), a, eps);
  53. }
  54. };
  55. } // namespace details
  56. /// Calculates the derivative of a curve at a point ``t``.
  57. ///
  58. /// Here, a curve is a function from a Scalar to a Euclidean space. Thus, it
  59. /// returns either a Scalar, a vector or a matrix.
  60. ///
  61. template <class Scalar, class Fn>
  62. auto curveNumDiff(Fn curve, Scalar t,
  63. Scalar h = Constants<Scalar>::epsilonSqrt())
  64. -> decltype(details::Curve<Scalar>::num_diff(std::move(curve), t, h)) {
  65. return details::Curve<Scalar>::num_diff(std::move(curve), t, h);
  66. }
  67. /// Calculates the derivative of a vector field at a point ``a``.
  68. ///
  69. /// Here, a vector field is a function from a vector space to another vector
  70. /// space.
  71. ///
  72. template <class Scalar, int N, int M, class ScalarOrVector, class Fn>
  73. Eigen::Matrix<Scalar, N, M> vectorFieldNumDiff(
  74. Fn vector_field, ScalarOrVector const& a,
  75. Scalar eps = Constants<Scalar>::epsilonSqrt()) {
  76. return details::VectorField<Scalar, N, M>::num_diff(std::move(vector_field),
  77. a, eps);
  78. }
  79. } // namespace Sophus
  80. #endif // SOPHUS_NUM_DIFF_HPP