Program Listing for File tangent_base.h

Return to documentation for file (manif/impl/tangent_base.h)

#ifndef _MANIF_MANIF_TANGENT_BASE_H_
#define _MANIF_MANIF_TANGENT_BASE_H_

#include "manif/impl/macro.h"
#include "manif/impl/traits.h"
#include "manif/impl/generator.h"
#include "manif/impl/random.h"
#include "manif/impl/bracket.h"
#include "manif/impl/vee.h"
#include "manif/impl/eigen.h"

#include "manif/constants.h"

#include <tl/optional.hpp>

namespace manif {

template <class _Derived>
struct TangentBase
{
  static constexpr int Dim     = internal::traits<_Derived>::Dim;
  static constexpr int RepSize = internal::traits<_Derived>::RepSize;
  static constexpr int DoF     = internal::traits<_Derived>::DoF;

  using Scalar   = typename internal::traits<_Derived>::Scalar;
  using LieGroup = typename internal::traits<_Derived>::LieGroup;
  using Tangent  = typename internal::traits<_Derived>::Tangent;
  using DataType = typename internal::traits<_Derived>::DataType;
  using Jacobian = typename internal::traits<_Derived>::Jacobian;
  using LieAlg   = typename internal::traits<_Derived>::LieAlg;

  using InnerWeightsMatrix = Jacobian;

  using OptJacobianRef = tl::optional<Eigen::Ref<Jacobian>>;

  template <typename _Scalar>
  using TangentTemplate = typename internal::traitscast<Tangent, _Scalar>::cast;

protected:

  MANIF_DEFAULT_CONSTRUCTOR(TangentBase)

public:

  _Derived& operator =(const TangentBase& t);

  template <typename _DerivedOther>
  _Derived& operator =(const TangentBase<_DerivedOther>& t);

  template <typename _EigenDerived>
  _Derived& operator =(const Eigen::MatrixBase<_EigenDerived>& v);

  DataType& coeffs();
  const DataType& coeffs() const;

  Scalar* data();
  const Scalar* data() const;

  template <class _NewScalar>
  TangentTemplate<_NewScalar> cast() const;

  // Common Tangent API

  _Derived& setZero();

  _Derived& setRandom();

  template <typename _EigenDerived>
  _Derived& setVee(const Eigen::MatrixBase<_EigenDerived>& a);

  // Minimum API
  // Those functions must be implemented in the Derived class !

  LieAlg generator(const int i) const;

  InnerWeightsMatrix innerWeights() const;

  template <typename _DerivedOther>
  Scalar inner(const TangentBase<_DerivedOther>& t) const;

  Scalar weightedNorm() const;

  Scalar squaredWeightedNorm() const;

  LieAlg hat() const;

  LieGroup exp(OptJacobianRef J_m_t =
                OptJacobianRef{}) const;

  MANIF_DEPRECATED
  LieGroup retract(OptJacobianRef J_m_t =
                    OptJacobianRef{}) const;

  LieGroup rplus(const LieGroup& m,
                 OptJacobianRef J_mout_t = {},
                 OptJacobianRef J_mout_m = {}) const;

  LieGroup lplus(const LieGroup& m,
                 OptJacobianRef J_mout_t = {},
                 OptJacobianRef J_mout_m = {}) const;

  LieGroup plus(const LieGroup& m,
                OptJacobianRef J_mout_t = {},
                OptJacobianRef J_mout_m = {}) const;

  template <typename _DerivedOther>
  Tangent plus(const TangentBase<_DerivedOther>& t,
               OptJacobianRef J_mout_ta = {},
               OptJacobianRef J_mout_tb = {}) const;

  template <typename _DerivedOther>
  Tangent minus(const TangentBase<_DerivedOther>& t,
                OptJacobianRef J_mout_ta = {},
                OptJacobianRef J_mout_tb = {}) const;

  Jacobian rjac() const;

  Jacobian ljac() const;

  template <typename U = _Derived>
  typename std::enable_if<
    internal::has_rjacinv<U>::value,
    typename TangentBase<U>::Jacobian>::type rjacinv() const;

  template <typename U = _Derived>
  typename std::enable_if<
    ! internal::has_rjacinv<U>::value,
    typename TangentBase<U>::Jacobian>::type rjacinv() const;

  template <typename U = _Derived>
  typename std::enable_if<
    internal::has_ljacinv<U>::value,
    typename TangentBase<U>::Jacobian>::type ljacinv() const;

  template <typename U = _Derived>
  typename std::enable_if<
    ! internal::has_ljacinv<U>::value,
    typename TangentBase<U>::Jacobian>::type ljacinv() const;

  Jacobian smallAdj() const;

  template <typename _DerivedOther>
  Tangent bracket(const TangentBase<_DerivedOther>& b) const;

  template <typename _EigenDerived>
  bool isApprox(const Eigen::MatrixBase<_EigenDerived>& v,
                const Scalar eps = Constants<Scalar>::eps) const;

  template <typename _DerivedOther>
  bool isApprox(const TangentBase<_DerivedOther>& t,
                const Scalar eps = Constants<Scalar>::eps) const;

  // Some operators

  // Copy assignment

  template <typename T>
  auto operator <<(T&& v)
  ->decltype( std::declval<DataType>().operator<<(std::forward<T>(v)) );

  // Math

  Tangent operator -() const;

  LieGroup operator +(const LieGroup& m) const;

  template <typename _DerivedOther>
  _Derived& operator +=(const TangentBase<_DerivedOther>& t);

  template <typename _DerivedOther>
  _Derived& operator -=(const TangentBase<_DerivedOther>& t);

  template <typename _EigenDerived>
  _Derived& operator +=(const Eigen::MatrixBase<_EigenDerived>& v);

  template <typename _EigenDerived>
  _Derived& operator -=(const Eigen::MatrixBase<_EigenDerived>& v);

  Tangent operator *=(const Scalar scalar);

  Tangent operator /=(const Scalar scalar);

  auto operator [](const unsigned int i) const -> decltype(coeffs()[i]){
    return coeffs()[i];
  }

  auto operator [](const unsigned int i) -> decltype(coeffs()[i]){
    return coeffs()[i];
  }

  constexpr unsigned int size() const {
    return RepSize;
  }

  // static helpers

  static Tangent Zero();
  static Tangent Random();
  static LieAlg Generator(const int i);
  static InnerWeightsMatrix InnerWeights();

  template <typename _DerivedOther>
  static Tangent Bracket(
    const TangentBase<_Derived>& a, const TangentBase<_DerivedOther>& b
  );

  template <typename _EigenDerived>
  static Tangent Vee(const Eigen::MatrixBase<_EigenDerived>& alg);

protected:

  inline _Derived& derived() & noexcept { return *static_cast< _Derived* >(this); }
  inline const _Derived& derived() const & noexcept { return *static_cast< const _Derived* >(this); }
};

template <typename _Derived>
constexpr int TangentBase<_Derived>::Dim;
template <typename _Derived>
constexpr int TangentBase<_Derived>::DoF;
template <typename _Derived>
constexpr int TangentBase<_Derived>::RepSize;

// Copy

template <typename _Derived>
_Derived&
TangentBase<_Derived>::operator =(const TangentBase& t)
{
  coeffs() = t.coeffs();
  return derived();
}

template <typename _Derived>
template <typename _DerivedOther>
_Derived&
TangentBase<_Derived>::operator =(const TangentBase<_DerivedOther>& t)
{
  coeffs() = t.coeffs();
  return derived();
}

template <typename _Derived>
template <typename _EigenDerived>
_Derived&
TangentBase<_Derived>::operator =(const Eigen::MatrixBase<_EigenDerived>& v)
{
  coeffs() = v;
  return derived();
}

template <typename _Derived>
typename TangentBase<_Derived>::DataType&
TangentBase<_Derived>::coeffs()
{
  return derived().coeffs();
}

template <typename _Derived>
const typename TangentBase<_Derived>::DataType&
TangentBase<_Derived>::coeffs() const
{
  return derived().coeffs();
}

template <class _Derived>
typename TangentBase<_Derived>::Scalar*
TangentBase<_Derived>::data()
{
  return derived().coeffs().data();
}

template <class _Derived>
const typename TangentBase<_Derived>::Scalar*
TangentBase<_Derived>::data() const
{
  return derived().coeffs().data();
}

template <typename _Derived>
template <class _NewScalar>
typename TangentBase<_Derived>::template TangentTemplate<_NewScalar>
TangentBase<_Derived>::cast() const
{
  return TangentTemplate<_NewScalar>(coeffs().template cast<_NewScalar>());
}

template <class _Derived>
_Derived& TangentBase<_Derived>::setZero()
{
  coeffs().setZero();
  return derived();
}

template <class _Derived>
_Derived& TangentBase<_Derived>::setRandom()
{
  internal::RandomEvaluator<
      typename internal::traits<_Derived>::Base>(
        derived()).run();

  return derived();
}

template <class _Derived>
template <typename _EigenDerived>
_Derived& TangentBase<_Derived>::setVee(const Eigen::MatrixBase<_EigenDerived>& a) {
  internal::VeeEvaluator<typename internal::traits<_Derived>::Base>(derived()).run(a);
  return derived();
}

template <class _Derived>
typename TangentBase<_Derived>::LieGroup
TangentBase<_Derived>::exp(OptJacobianRef J_m_t) const
{
  return derived().exp(J_m_t);
}

template <class _Derived>
typename TangentBase<_Derived>::LieGroup
TangentBase<_Derived>::retract(OptJacobianRef J_m_t) const
{
  return derived().exp(J_m_t);
}

template <typename _Derived>
typename TangentBase<_Derived>::LieAlg
TangentBase<_Derived>::generator(const int i) const
{
  return Generator(i);
}

template <typename _Derived>
typename TangentBase<_Derived>::InnerWeightsMatrix
TangentBase<_Derived>::innerWeights() const
{
  return InnerWeights();
}

template <typename _Derived>
template <typename _DerivedOther>
typename TangentBase<_Derived>::Scalar
TangentBase<_Derived>::inner(const TangentBase<_DerivedOther>& t) const
{
  return (coeffs().transpose() * InnerWeights() * t.coeffs())(0);
}

template <class _Derived>
typename TangentBase<_Derived>::Scalar
TangentBase<_Derived>::weightedNorm() const
{
  using std::sqrt;
  return sqrt( squaredWeightedNorm() );
}

template <class _Derived>
typename TangentBase<_Derived>::Scalar
TangentBase<_Derived>::squaredWeightedNorm() const
{
  return (coeffs().transpose() * InnerWeights() * coeffs())(0);
}

template <class _Derived>
typename TangentBase<_Derived>::LieAlg
TangentBase<_Derived>::hat() const
{
  return derived().hat();
}

template <class _Derived>
typename TangentBase<_Derived>::LieGroup
TangentBase<_Derived>::rplus(const LieGroup& m,
                             OptJacobianRef J_mout_t,
                             OptJacobianRef J_mout_m) const
{
  return m.rplus(derived(), J_mout_m, J_mout_t);
}

template <class _Derived>
typename TangentBase<_Derived>::LieGroup
TangentBase<_Derived>::lplus(const LieGroup& m,
                             OptJacobianRef J_mout_t,
                             OptJacobianRef J_mout_m) const
{
  return m.lplus(derived(), J_mout_m, J_mout_t);
}

template <class _Derived>
typename TangentBase<_Derived>::LieGroup
TangentBase<_Derived>::plus(const LieGroup& m,
                            OptJacobianRef J_mout_t,
                            OptJacobianRef J_mout_m) const
{
  return m.lplus(derived(), J_mout_m, J_mout_t);
}

template <class _Derived>
template <typename _DerivedOther>
typename TangentBase<_Derived>::Tangent
TangentBase<_Derived>::plus(const TangentBase<_DerivedOther>& t,
                            OptJacobianRef J_mout_ta,
                            OptJacobianRef J_mout_tb) const
{
  if (J_mout_ta)
    J_mout_ta->setIdentity();

  if (J_mout_tb)
    J_mout_tb->setIdentity();

  return *this + t;
}

template <class _Derived>
template <typename _DerivedOther>
typename TangentBase<_Derived>::Tangent
TangentBase<_Derived>::minus(const TangentBase<_DerivedOther>& t,
                             OptJacobianRef J_mout_ta,
                             OptJacobianRef J_mout_tb) const
{
  if (J_mout_ta)
    J_mout_ta->setIdentity();

  if (J_mout_tb)
  {
    J_mout_tb->setIdentity();
    (*J_mout_tb) *= Scalar(-1);
  }

  return *this - t;
}

template <class _Derived>
typename TangentBase<_Derived>::Jacobian
TangentBase<_Derived>::rjac() const
{
  return derived().rjac();
}

template <class _Derived>
typename TangentBase<_Derived>::Jacobian
TangentBase<_Derived>::ljac() const
{
  return derived().ljac();
}


template <class _Derived>
template <typename U>
typename std::enable_if<
  internal::has_rjacinv<U>::value,
  typename TangentBase<U>::Jacobian>::type
TangentBase<_Derived>::rjacinv() const
{
  return derived().rjacinv();
}

template <class _Derived>
template <typename U>
typename std::enable_if<
  ! internal::has_rjacinv<U>::value,
  typename TangentBase<U>::Jacobian>::type
TangentBase<_Derived>::rjacinv() const
{
  return derived().rjac().inverse();
}

template <class _Derived>
template <typename U>
typename std::enable_if<
  internal::has_ljacinv<U>::value,
  typename TangentBase<U>::Jacobian>::type
TangentBase<_Derived>::ljacinv() const
{
  return derived().ljacinv();
}

template <class _Derived>
template <typename U>
typename std::enable_if<
  ! internal::has_ljacinv<U>::value,
  typename TangentBase<U>::Jacobian>::type
TangentBase<_Derived>::ljacinv() const
{
  return derived().ljac().inverse();
}

template <class _Derived>
typename TangentBase<_Derived>::Jacobian
TangentBase<_Derived>::smallAdj() const
{
  return derived().smallAdj();
}

template <typename _Derived>
template <typename _DerivedOther>
typename TangentBase<_Derived>::Tangent TangentBase<_Derived>::bracket(
  const TangentBase<_DerivedOther>& b
) const {
  return internal::BracketEvaluator<
    typename internal::traits<_Derived>::Base,
    typename internal::traits<_DerivedOther>::Base
  >(derived(), b.derived()).run();
}

template <typename _Derived>
template <typename _EigenDerived>
bool TangentBase<_Derived>::isApprox(
    const Eigen::MatrixBase<_EigenDerived>& t,
    const Scalar eps) const
{
  using std::min;
  bool result = false;

  if (min(coeffs().norm(), t.norm()) < eps)
  {
    result = ((coeffs() - t).isZero(eps));
  }
  else
  {
    result = (coeffs().isApprox(t, eps));
  }

  return result;
}

template <typename _Derived>
template <typename _DerivedOther>
bool TangentBase<_Derived>::isApprox(
    const TangentBase<_DerivedOther>& t,
    const Scalar eps) const
{
  return isApprox(t.coeffs(), eps);
}

// Operators

template <typename _Derived>
template <typename T>
auto TangentBase<_Derived>::operator <<(T&& v)
->decltype( std::declval<DataType>().operator<<(std::forward<T>(v)) )
{
  return coeffs().operator<<(std::forward<T>(v));
}

// Static helper

template <class _Derived>
typename TangentBase<_Derived>::Tangent
TangentBase<_Derived>::Zero()
{
  static const Tangent t(DataType::Zero());
  return t;
}

template <class _Derived>
typename TangentBase<_Derived>::Tangent
TangentBase<_Derived>::Random()
{
  return Tangent().setRandom();
}

template <typename _Derived>
typename TangentBase<_Derived>::LieAlg
TangentBase<_Derived>::Generator(const int i)
{
  return internal::GeneratorEvaluator<
      typename internal::traits<_Derived>::Base>::run(i);
}

template <typename _Derived>
typename TangentBase<_Derived>::InnerWeightsMatrix
TangentBase<_Derived>::InnerWeights()
{
  return internal::InnerWeightsEvaluator<
      typename internal::traits<_Derived>::Base>::run();
}

template <typename _Derived>
template <typename _DerivedOther>
typename TangentBase<_Derived>::Tangent TangentBase<_Derived>::Bracket(
  const TangentBase<_Derived>& a, const TangentBase<_DerivedOther>& b
) {
  return a.bracket(b);
}

template <typename _Derived>
template <typename _EigenDerived>
typename TangentBase<_Derived>::Tangent TangentBase<_Derived>::Vee(
  const Eigen::MatrixBase<_EigenDerived>& alg
) {
  return Tangent().setVee(alg);
}

// Math

template <typename _Derived>
typename TangentBase<_Derived>::Tangent
TangentBase<_Derived>::operator -() const
{
  return Tangent(-coeffs());
}

template <typename _Derived>
typename TangentBase<_Derived>::LieGroup
TangentBase<_Derived>::operator +(const LieGroup& m) const
{
  return m.lplus(derived());
}

template <typename _Derived>
template <typename _DerivedOther>
_Derived& TangentBase<_Derived>::operator +=(
    const TangentBase<_DerivedOther>& t)
{
  coeffs() += t.coeffs();
  return derived();
}

template <typename _Derived>
template <typename _DerivedOther>
_Derived& TangentBase<_Derived>::operator -=(
    const TangentBase<_DerivedOther>& t)
{
  coeffs() -= t.coeffs();
  return derived();
}

template <typename _Derived, typename _DerivedOther>
typename TangentBase<_Derived>::Tangent
operator +(const TangentBase<_Derived>& ta,
           const TangentBase<_DerivedOther>& tb)
{
  typename TangentBase<_Derived>::Tangent tc(ta);
  return tc += tb;
}

template <typename _Derived, typename _DerivedOther>
typename TangentBase<_Derived>::Tangent
operator -(const TangentBase<_Derived>& ta,
           const TangentBase<_DerivedOther>& tb)
{
  typename TangentBase<_Derived>::Tangent tc(ta);
  return tc -= tb;
}

template <typename _Derived>
template <typename _EigenDerived>
_Derived& TangentBase<_Derived>::operator +=(
    const Eigen::MatrixBase<_EigenDerived>& v)
{
  coeffs() += v;
  return derived();
}

template <typename _Derived>
template <typename _EigenDerived>
_Derived& TangentBase<_Derived>::operator -=(
    const Eigen::MatrixBase<_EigenDerived>& v)
{
  coeffs() -= v;
  return derived();
}

template <typename _Derived, typename _EigenDerived>
typename TangentBase<_Derived>::Tangent
operator +(const TangentBase<_Derived>& t,
           const Eigen::MatrixBase<_EigenDerived>& v)
{
  typename TangentBase<_Derived>::Tangent ret(t);
  return ret += v;
}

template <typename _Derived, typename _EigenDerived>
typename TangentBase<_Derived>::Tangent
operator -(const TangentBase<_Derived>& t,
           const Eigen::MatrixBase<_EigenDerived>& v)
{
  typename TangentBase<_Derived>::Tangent ret(t);
  return ret -= v;
}

template <typename _EigenDerived, typename _Derived>
auto
operator +(const Eigen::MatrixBase<_EigenDerived>& v,
           const TangentBase<_Derived>& t)
-> decltype(v + t.coeffs())
{
  return v + t.coeffs();
}

template <typename _EigenDerived, typename _Derived>
auto
operator -(const Eigen::MatrixBase<_EigenDerived>& v,
           const TangentBase<_Derived>& t)
-> decltype(v - t.coeffs())
{
  return v - t.coeffs();
}

template <typename _Derived>
typename TangentBase<_Derived>::Tangent
TangentBase<_Derived>::operator *=(const Scalar scalar)
{
  coeffs() *= scalar;
  return derived();
}

template <typename _Derived>
typename TangentBase<_Derived>::Tangent
TangentBase<_Derived>::operator /=(const Scalar scalar)
{
  coeffs() /= scalar;
  return derived();
}

template <typename _Derived>
typename TangentBase<_Derived>::Tangent
operator *(const TangentBase<_Derived>& t,
           const typename _Derived::Scalar scalar)
{
  typename TangentBase<_Derived>::Tangent ret(t);
  return ret *= scalar;
}

template <typename _Derived>
typename TangentBase<_Derived>::Tangent
operator *(const typename _Derived::Scalar scalar,
           const TangentBase<_Derived>& t)
{
  return t * scalar;
}

template <typename _Derived>
typename TangentBase<_Derived>::Tangent
operator /(const TangentBase<_Derived>& t,
           const typename _Derived::Scalar scalar)
{
  typename TangentBase<_Derived>::Tangent ret(t);
  return ret /= scalar;
}

template <class _DerivedOther>
typename TangentBase<_DerivedOther>::Tangent
operator *(const typename TangentBase<_DerivedOther>::Jacobian& J,
           const TangentBase<_DerivedOther>& t)
{
  return typename TangentBase<_DerivedOther>::Tangent(
        typename TangentBase<_DerivedOther>::DataType(J*t.coeffs()));
}

template <typename _Derived, typename _DerivedOther>
bool operator ==(
    const TangentBase<_Derived>& ta,
    const TangentBase<_DerivedOther>& tb)
{
  return ta.isApprox(tb);
}

template <typename _Derived, typename _EigenDerived>
bool operator ==(
    const TangentBase<_Derived>& t,
    const Eigen::MatrixBase<_EigenDerived>& v)
{
  return t.isApprox(v);
}

template <typename _Derived, typename _DerivedOther>
bool operator !=(
    const TangentBase<_Derived>& ta,
    const TangentBase<_DerivedOther>& tb)
{
  return !(ta == tb);
}

template <typename _Derived, typename _EigenDerived>
bool operator !=(
    const TangentBase<_Derived>& t,
    const Eigen::MatrixBase<_EigenDerived>& v)
{
  return !(t == v);
}

// Utils

template <typename _Stream, typename _Derived>
_Stream& operator << (
    _Stream& s,
    const manif::TangentBase<_Derived>& m)
{
  s << m.coeffs().transpose();
  return s;
}

} /* namespace manif */

#endif /* _MANIF_MANIF_TANGENT_BASE_H_ */