OpenKalman
LinearizedTransform.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2017-2021 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
16 #ifndef OPENKALMAN_LINEARIZEDTRANSFORM_HPP
17 #define OPENKALMAN_LINEARIZEDTRANSFORM_HPP
18 
19 
20 namespace OpenKalman
21 {
22  namespace oin = OpenKalman::internal;
23 
29  template<unsigned int order = 1>
31 
32 
33  namespace internal
34  {
35  template<unsigned int order, typename F>
36  struct needs_additive_correction<LinearizedTransform<order>, F> : std::bool_constant<
37  (order >= 2) and linearized_function<F, 2>> {};
38  }
39 
40 
41  template<unsigned int order>
42  class LinearizedTransform : public oin::LinearTransformBase<LinearizedTransform<order>>
43  {
45  friend Base;
46 
47 
53  template<typename Trans>
54  struct TransformModel
55  {
56 
57  private:
58 
59  template<typename MeanType, typename Hessian, typename Cov, std::size_t...ints>
60  static auto construct_mean(const Hessian& hessian, const Cov& P, std::index_sequence<ints...>)
61  {
62  return MeanType {0.5 * trace(P * hessian[ints])...};
63  }
64 
65 
66  template<std::size_t i, std::size_t...js, typename Hessian, typename Cov>
67  static constexpr auto construct_cov_row(const Hessian& hessian, const Cov& P)
68  {
69  return std::tuple {0.5 * trace(P * hessian[i] * P * hessian[js])...};
70  }
71 
72 
73  template<typename CovType, typename Hessian, typename Cov, std::size_t...is, std::size_t...js>
74  static auto construct_cov(const Hessian& hessian, const Cov& P, std::index_sequence<is...>, std::index_sequence<js...>)
75  {
76  auto mat = std::tuple_cat(construct_cov_row<is, js...>(hessian, P)...);
77  return std::make_from_tuple<CovType>(std::move(mat));
78  }
79 
80 
81  /*
82  * \brief Add second-order moment terms, based on Hessian matrices (a tensor of order (1,2)).
83  * \tparam Hessian An array of Hessian matrices. Must be accessible by bracket index, as in hessian[i].
84  * Each matrix is a regular matrix type.
85  * \tparam Dist Input or noise distribution.
86  * \return
87  */
88  template<typename OutputCoeffs, typename Hessian, typename Dist>
89  static auto second_order_term(const Hessian& hessian, const Dist& x)
90  {
91  constexpr auto output_dim = std::tuple_size_v<Hessian>;
92  static_assert(output_dim == coordinates::dimension_of_v<OutputCoeffs>);
93  static_assert(order >= 2);
94 
95  // Convert input distribution type to output distribution types, and initialize mean and covariance:
97  using MeanOut = dense_writable_matrix_t<CovIn, Layout::none, scalar_type_of_t<CovIn>, std::tuple<Dimensions<output_dim>, Axis>>;
98  constexpr TriangleType tri = triangle_type_of_v<typename MatrixTraits<std::decay_t<CovIn>>::template TriangularAdapterFrom<>>;
99  using CovOut = typename MatrixTraits<std::decay_t<CovIn>>::template SelfAdjointMatrixFrom<tri, output_dim>;
100 
101  auto P = covariance_of(x);
102  const std::make_index_sequence<output_dim> ints;
103  auto mean_terms = construct_mean<Mean<OutputCoeffs, MeanOut>>(hessian, P, ints);
104  auto cov_terms = construct_cov<Covariance<OutputCoeffs, CovOut>>(hessian, P, ints, ints);
105  return GaussianDistribution {std::move(mean_terms), std::move(cov_terms)};
106  }
107 
108 
109  template<typename OutputCoeffs, typename T1, typename T2, std::size_t...I>
110  static auto zip_tuples_impl(T1&& t1, T2&& t2, std::index_sequence<I...>)
111  {
112  static_assert(order >= 2);
113  return make_self_contained((second_order_term<OutputCoeffs>(
114  std::get<I>(std::forward<T1>(t1)), std::get<I>(std::forward<T2>(t2))) + ...));
115  }
116 
117 
118  template<typename OutputCoeffs, typename T1, typename T2>
119  static constexpr auto zip_tuples(T1&& t1, T2&& t2)
120  {
121  static_assert(order >= 2);
122  constexpr auto s = std::tuple_size_v<std::decay_t<T1>>;
123  static_assert(s == std::tuple_size_v<std::decay_t<T2>>);
124  return zip_tuples_impl<OutputCoeffs>(std::forward<T1>(t1), std::forward<T2>(t2), std::make_index_sequence<s> {});
125  }
126 
127  public:
128 
133  TransformModel(const Trans& t) : transformation(t) {}
134 
135 
141 #ifdef __cpp_concepts
142  template<transformation_input InputMean, perturbation ... NoiseMean>
143 #else
144  template<typename InputMean, typename ... NoiseMean, std::enable_if_t<transformation_input<InputMean> and
145  (perturbation<NoiseMean> and ...), int> = 0>
146 #endif
147  auto operator()(const InputMean& x, const NoiseMean& ... n) const
148  {
149  return std::tuple {transformation(x, n...), transformation.jacobian(x, n...)};
150  }
151 
152 
158 #ifdef __cpp_concepts
159  template<gaussian_distribution InputDist, gaussian_distribution ... Noise> requires (order >= 2)
160 #else
161  template<typename InputDist, typename ... Noise, std::enable_if_t<
162  gaussian_distribution<InputDist> and (gaussian_distribution<Noise> and ...) and (order >= 2), int> = 0>
163 #endif
164  auto add_correction(const InputDist& x, const Noise& ... n) const
165  {
166  using In_Mean = typename DistributionTraits<InputDist>::Mean;
167  using Out_Mean = std::invoke_result_t<Trans, In_Mean>;
168  using OutputCoeffs = vector_space_descriptor_of_t<Out_Mean, 0>;
169  auto hessians = transformation.hessian(mean_of(x), mean_of(n)...);
170 
171  return make_self_contained(zip_tuples<OutputCoeffs>(std::move(hessians), std::forward_as_tuple(x, n...)));
172  }
173 
174  private:
175 
176  const Trans& transformation;
177 
178  };
179 
180  };
181 
182 
183 }
184 
185 #endif //OPENKALMAN_LINEARIZEDTRANSFORM_HPP
typename nested_object_of< T >::type nested_object_of_t
Helper type for nested_object_of.
Definition: nested_object_of.hpp:66
TriangleType
The type of a triangular matrix.
Definition: global-definitions.hpp:60
constexpr bool transformation_input
T is an acceptable input to a tests.
Definition: TransformationTraits.hpp:158
A linearized transform, using a 1st or 2nd order Taylor approximation of a linear tests...
Definition: LinearizedTransform.hpp:30
A Gaussian distribution, defined in terms of a Mean and a Covariance.
Definition: GaussianDistribution.hpp:42
The root namespace for OpenKalman.
Definition: basics.hpp:34
typename vector_space_descriptor_of< T, N >::type vector_space_descriptor_of_t
helper template for vector_space_descriptor_of.
Definition: vector_space_descriptor_of.hpp:56
std::decay_t< decltype(make_dense_object< T, layout, S >(std::declval< D >()))> dense_writable_matrix_t
An alias for a dense, writable matrix, patterned on parameter T.
Definition: dense_writable_matrix_t.hpp:38
constexpr bool gaussian_distribution
T is a Gaussian distribution.
Definition: object-types.hpp:182
Mean(V &&) -> Mean< Dimensions< index_dimension_of_v< V, 0 >>, passable_t< V >>
Deduce template parameters from a typed_matrix_nestable, assuming untyped coordinates::pattern.
Definition: LinearTransformBase.hpp:45
constexpr bool linearized_function
A linearized function (with defined Jacobian and optionally Hessian functions).
Definition: TransformationTraits.hpp:53
decltype(auto) constexpr trace(Arg &&arg)
Take the trace of a matrix.
Definition: trace.hpp:35
Definition: basics.hpp:48
Definition: LinearTransformBase.hpp:31