| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #ifndef CERES_PUBLIC_PRODUCT_MANIFOLD_H_ |
| #define CERES_PUBLIC_PRODUCT_MANIFOLD_H_ |
|
|
| #include <algorithm> |
| #include <array> |
| #include <cassert> |
| #include <cstddef> |
| #include <numeric> |
| #include <tuple> |
| #include <type_traits> |
| #include <utility> |
|
|
| #include "ceres/internal/eigen.h" |
| #include "ceres/internal/fixed_array.h" |
| #include "ceres/internal/port.h" |
| #include "ceres/manifold.h" |
|
|
| namespace ceres { |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename Manifold0, typename Manifold1, typename... ManifoldN> |
| class ProductManifold final : public Manifold { |
| public: |
| |
| |
| |
| |
| |
| template <typename... Args, |
| std::enable_if_t<std::is_constructible< |
| std::tuple<Manifold0, Manifold1, ManifoldN...>, |
| Args...>::value>* = nullptr> |
| explicit ProductManifold(Args&&... manifolds) |
| : ProductManifold{std::make_index_sequence<kNumManifolds>{}, |
| std::forward<Args>(manifolds)...} {} |
|
|
| int AmbientSize() const override { return ambient_size_; } |
| int TangentSize() const override { return tangent_size_; } |
|
|
| bool Plus(const double* x, |
| const double* delta, |
| double* x_plus_delta) const override { |
| return PlusImpl( |
| x, delta, x_plus_delta, std::make_index_sequence<kNumManifolds>{}); |
| } |
|
|
| bool Minus(const double* y, |
| const double* x, |
| double* y_minus_x) const override { |
| return MinusImpl( |
| y, x, y_minus_x, std::make_index_sequence<kNumManifolds>{}); |
| } |
|
|
| bool PlusJacobian(const double* x, double* jacobian_ptr) const override { |
| MatrixRef jacobian(jacobian_ptr, AmbientSize(), TangentSize()); |
| jacobian.setZero(); |
| internal::FixedArray<double> buffer(buffer_size_); |
|
|
| return PlusJacobianImpl( |
| x, jacobian, buffer, std::make_index_sequence<kNumManifolds>{}); |
| } |
|
|
| bool MinusJacobian(const double* x, double* jacobian_ptr) const override { |
| MatrixRef jacobian(jacobian_ptr, TangentSize(), AmbientSize()); |
| jacobian.setZero(); |
| internal::FixedArray<double> buffer(buffer_size_); |
|
|
| return MinusJacobianImpl( |
| x, jacobian, buffer, std::make_index_sequence<kNumManifolds>{}); |
| } |
|
|
| private: |
| static constexpr std::size_t kNumManifolds = 2 + sizeof...(ManifoldN); |
|
|
| template <std::size_t... Indices, typename... Args> |
| explicit ProductManifold(std::index_sequence<Indices...>, Args&&... manifolds) |
| : manifolds_{std::forward<Args>(manifolds)...}, |
| buffer_size_{(std::max)( |
| {(Dereference(std::get<Indices>(manifolds_)).TangentSize() * |
| Dereference(std::get<Indices>(manifolds_)).AmbientSize())...})}, |
| ambient_sizes_{ |
| Dereference(std::get<Indices>(manifolds_)).AmbientSize()...}, |
| tangent_sizes_{ |
| Dereference(std::get<Indices>(manifolds_)).TangentSize()...}, |
| ambient_offsets_{ExclusiveScan(ambient_sizes_)}, |
| tangent_offsets_{ExclusiveScan(tangent_sizes_)}, |
| ambient_size_{ |
| std::accumulate(ambient_sizes_.begin(), ambient_sizes_.end(), 0)}, |
| tangent_size_{ |
| std::accumulate(tangent_sizes_.begin(), tangent_sizes_.end(), 0)} {} |
|
|
| template <std::size_t Index0, std::size_t... Indices> |
| bool PlusImpl(const double* x, |
| const double* delta, |
| double* x_plus_delta, |
| std::index_sequence<Index0, Indices...>) const { |
| if (!Dereference(std::get<Index0>(manifolds_)) |
| .Plus(x + ambient_offsets_[Index0], |
| delta + tangent_offsets_[Index0], |
| x_plus_delta + ambient_offsets_[Index0])) { |
| return false; |
| } |
|
|
| return PlusImpl(x, delta, x_plus_delta, std::index_sequence<Indices...>{}); |
| } |
|
|
| static constexpr bool PlusImpl(const double* , |
| const double* , |
| double* , |
| std::index_sequence<>) noexcept { |
| return true; |
| } |
|
|
| template <std::size_t Index0, std::size_t... Indices> |
| bool MinusImpl(const double* y, |
| const double* x, |
| double* y_minus_x, |
| std::index_sequence<Index0, Indices...>) const { |
| if (!Dereference(std::get<Index0>(manifolds_)) |
| .Minus(y + ambient_offsets_[Index0], |
| x + ambient_offsets_[Index0], |
| y_minus_x + tangent_offsets_[Index0])) { |
| return false; |
| } |
|
|
| return MinusImpl(y, x, y_minus_x, std::index_sequence<Indices...>{}); |
| } |
|
|
| static constexpr bool MinusImpl(const double* , |
| const double* , |
| double* , |
| std::index_sequence<>) noexcept { |
| return true; |
| } |
|
|
| template <std::size_t Index0, std::size_t... Indices> |
| bool PlusJacobianImpl(const double* x, |
| MatrixRef& jacobian, |
| internal::FixedArray<double>& buffer, |
| std::index_sequence<Index0, Indices...>) const { |
| if (!Dereference(std::get<Index0>(manifolds_)) |
| .PlusJacobian(x + ambient_offsets_[Index0], buffer.data())) { |
| return false; |
| } |
|
|
| jacobian.block(ambient_offsets_[Index0], |
| tangent_offsets_[Index0], |
| ambient_sizes_[Index0], |
| tangent_sizes_[Index0]) = |
| MatrixRef( |
| buffer.data(), ambient_sizes_[Index0], tangent_sizes_[Index0]); |
|
|
| return PlusJacobianImpl( |
| x, jacobian, buffer, std::index_sequence<Indices...>{}); |
| } |
|
|
| static constexpr bool PlusJacobianImpl( |
| const double* , |
| MatrixRef& , |
| internal::FixedArray<double>& , |
| std::index_sequence<>) noexcept { |
| return true; |
| } |
|
|
| template <std::size_t Index0, std::size_t... Indices> |
| bool MinusJacobianImpl(const double* x, |
| MatrixRef& jacobian, |
| internal::FixedArray<double>& buffer, |
| std::index_sequence<Index0, Indices...>) const { |
| if (!Dereference(std::get<Index0>(manifolds_)) |
| .MinusJacobian(x + ambient_offsets_[Index0], buffer.data())) { |
| return false; |
| } |
|
|
| jacobian.block(tangent_offsets_[Index0], |
| ambient_offsets_[Index0], |
| tangent_sizes_[Index0], |
| ambient_sizes_[Index0]) = |
| MatrixRef( |
| buffer.data(), tangent_sizes_[Index0], ambient_sizes_[Index0]); |
|
|
| return MinusJacobianImpl( |
| x, jacobian, buffer, std::index_sequence<Indices...>{}); |
| } |
|
|
| static constexpr bool MinusJacobianImpl( |
| const double* , |
| MatrixRef& , |
| internal::FixedArray<double>& , |
| std::index_sequence<>) noexcept { |
| return true; |
| } |
|
|
| template <typename T, std::size_t N> |
| static std::array<T, N> ExclusiveScan(const std::array<T, N>& values) { |
| std::array<T, N> result; |
| T init = 0; |
|
|
| |
| for (std::size_t i = 0; i != N; ++i) { |
| result[i] = init; |
| init += values[i]; |
| } |
|
|
| return result; |
| } |
|
|
| |
| template <typename... Types> |
| struct Void { |
| using type = void; |
| }; |
|
|
| template <typename T, typename E = void> |
| struct IsDereferenceable : std::false_type {}; |
|
|
| template <typename T> |
| struct IsDereferenceable<T, typename Void<decltype(*std::declval<T>())>::type> |
| : std::true_type {}; |
|
|
| template <typename T, |
| std::enable_if_t<!IsDereferenceable<T>::value>* = nullptr> |
| static constexpr decltype(auto) Dereference(T& value) { |
| return value; |
| } |
|
|
| |
| |
| template <typename T, |
| std::enable_if_t<IsDereferenceable<T>::value>* = nullptr> |
| static constexpr decltype(auto) Dereference(T& value) { |
| return *value; |
| } |
|
|
| template <typename T> |
| static constexpr decltype(auto) Dereference(T* p) { |
| assert(p != nullptr); |
| return *p; |
| } |
|
|
| std::tuple<Manifold0, Manifold1, ManifoldN...> manifolds_; |
| int buffer_size_; |
| std::array<int, kNumManifolds> ambient_sizes_; |
| std::array<int, kNumManifolds> tangent_sizes_; |
| std::array<int, kNumManifolds> ambient_offsets_; |
| std::array<int, kNumManifolds> tangent_offsets_; |
| int ambient_size_; |
| int tangent_size_; |
| }; |
|
|
| #ifdef CERES_HAS_CPP17 |
| |
| |
| |
| |
| |
| |
| template <typename Manifold0, typename Manifold1, typename... Manifolds> |
| ProductManifold(Manifold0&&, Manifold1&&, Manifolds&&...) |
| -> ProductManifold<Manifold0, Manifold1, Manifolds...>; |
| #endif |
|
|
| } |
|
|
| #endif |
|
|