Program Listing for File constraint.h¶
↰ Return to documentation for file (manif/ceres/constraint.h)
#ifndef _MANIF_MANIF_CERES_CONSTRAINT_H_
#define _MANIF_MANIF_CERES_CONSTRAINT_H_
#include <Eigen/Core>
#include <Eigen/Cholesky>
#include <Eigen/Eigenvalues>
namespace manif {
template <typename _LieGroup>
class CeresConstraintFunctor
{
  using LieGroup = _LieGroup;
  using Tangent  = typename _LieGroup::Tangent;
  template <typename _Scalar>
  using LieGroupTemplate = typename LieGroup::template LieGroupTemplate<_Scalar>;
  template <typename _Scalar>
  using TangentTemplate = typename Tangent::template TangentTemplate<_Scalar>;
public:
  MANIF_MAKE_ALIGNED_OPERATOR_NEW_COND_TYPE(Tangent)
  using Covariance = Eigen::Matrix<double, LieGroup::DoF, LieGroup::DoF>;
  using InformationMatrix = Covariance;
  template <typename... Args>
  CeresConstraintFunctor(Args&&... args)
    : measurement_(std::forward<Args>(args)...)
    , measurement_covariance_(Covariance::Identity())
  {
    computeInformationMatrix();
  }
  template <typename... Args>
  CeresConstraintFunctor(const Tangent& measurement,
                         const Covariance& measurement_covariance = Covariance::Identity())
    : measurement_(measurement)
    , measurement_covariance_(measurement_covariance)
  {
    computeInformationMatrix();
  }
  virtual ~CeresConstraintFunctor() = default;
  template<typename T>
  bool operator()(const T* const past_raw,
                  const T* const futur_raw,
                  T* residuals_raw) const
  {
    const Eigen::Map<const LieGroupTemplate<T>> state_past(past_raw);
    const Eigen::Map<const LieGroupTemplate<T>> state_future(futur_raw);
    Eigen::Map<TangentTemplate<T>> residuals(residuals_raw);
    residuals = measurement_.template cast<T>() - (state_future - state_past);
//    residuals =
//      measurement_.exp().template cast<T>()
//        .between(state_past.between(state_future)).log();
    residuals.coeffs() = measurement_sqrt_info_upper_.template cast<T>() * residuals.coeffs();
    return true;
  }
  Tangent getMeasurement() const;
  void setMeasurement(const Tangent& measurement);
  Covariance getMeasurementCovariance() const;
  void setMeasurementCovariance(const Covariance covariance);
protected:
  void computeInformationMatrix();
protected:
  Tangent measurement_;
  Covariance measurement_covariance_;
  InformationMatrix measurement_sqrt_info_upper_;
};
template <typename _LieGroup>
typename CeresConstraintFunctor<_LieGroup>::Tangent
CeresConstraintFunctor<_LieGroup>::getMeasurement() const
{
  return measurement_;
}
template <typename _LieGroup>
void CeresConstraintFunctor<_LieGroup>::setMeasurement(
    const Tangent& measurement)
{
  measurement_ = measurement;
}
template <typename _LieGroup>
typename CeresConstraintFunctor<_LieGroup>::Covariance
CeresConstraintFunctor<_LieGroup>::getMeasurementCovariance() const
{
  return measurement_covariance_;
}
template <typename _LieGroup>
void CeresConstraintFunctor<_LieGroup>::setMeasurementCovariance(
    const Covariance covariance)
{
  // Ensuring symmetry
  measurement_covariance_ = covariance.template selfadjointView<Eigen::Upper>();
  computeInformationMatrix();
}
template <typename _LieGroup>
void CeresConstraintFunctor<_LieGroup>::computeInformationMatrix()
{
  // compute square root information upper matrix
  // ensuring symmetry
  const InformationMatrix info =
      measurement_covariance_.inverse().template selfadjointView<Eigen::Upper>();
  // Normal Cholesky factorization
  Eigen::LLT<InformationMatrix> llt_of_info(info);
  InformationMatrix R = llt_of_info.matrixU();
  // Factorization not good enough
  if (! info.isApprox(R.transpose() * R, 1e-6))
  {
    Eigen::SelfAdjointEigenSolver<InformationMatrix> es(info);
    Eigen::VectorXd eval = es.eigenvalues().real().cwiseMax(1e-6);
    R = eval.cwiseSqrt().asDiagonal() * es.eigenvectors().real().transpose();
  }
  measurement_sqrt_info_upper_ = R;
}
} /* namespace manif */
#endif /* _MANIF_MANIF_CERES_CONSTRAINT_H_ */
