16 #ifndef OPENKALMAN_FINITEDIFFERENCELINEARIZATION_HPP 17 #define OPENKALMAN_FINITEDIFFERENCELINEARIZATION_HPP 34 std::invocable<Function, InDelta, PsDelta...> and
35 (not
wrapped_mean<std::invoke_result_t<Function, InDelta, PsDelta...>>) and
36 (not
std::is_reference_v<InDelta>) and (((not
std::is_reference_v<PsDelta>) and ...)) and
40 template<
typename Function,
typename InDelta,
typename ... PsDelta>
53 template<
typename Function,
typename InDelta,
typename ... PsDelta, std::size_t order>
55 order <= 2>> : std::true_type {};
62 std::invocable<Function, InDelta, PsDelta...> and
63 (not
wrapped_mean<std::invoke_result_t<Function, InDelta, PsDelta...>>) and
64 (not
std::is_reference_v<InDelta>) and (((not
std::is_reference_v<PsDelta>) and ...)) and
68 template<
typename Function,
typename InDelta,
typename ... PsDelta>
75 #ifndef __cpp_concepts 76 static_assert((transformation_input<InDelta> and ... and transformation_input<PsDelta>));
77 static_assert(std::is_invocable_v<Function, InDelta, PsDelta...>);
78 static_assert(not
wrapped_mean<std::invoke_result_t<Function, InDelta, PsDelta...>>,
79 "For finite difference linearization, the tests function cannot return a wrapped matrix.");
80 static_assert(not std::is_reference_v<InDelta>);
81 static_assert(((not std::is_reference_v<PsDelta>) and ...));
87 template<std::size_t term,
typename...Inputs>
88 auto jac_term(
const std::tuple<Inputs...>& inputs)
const 90 using Term = decltype(std::get<term>(inputs));
92 constexpr
auto width = index_dimension_of_v<Term, 0>;
93 auto& col = std::get<term>(inputs);
94 return apply_columnwise<width>([&](std::size_t i) {
95 const Scalar h = std::get<term>(deltas)[i];
96 const Scalar x = col[i];
98 const auto fp =
Mean {std::apply(transformation, inputs)};
100 const auto fm =
Mean {std::apply(transformation, inputs)};
102 return make_self_contained((fp - fm)/(2*h));
108 #ifdef __cpp_concepts 109 template<
typename...Inputs, std::size_t...terms> requires (
sizeof...(Inputs) ==
sizeof...(terms))
111 template<
typename...Inputs, std::size_t...terms, std::enable_if_t<
sizeof...(Inputs) ==
sizeof...(terms),
int> = 0>
113 auto jacobian_impl(
const std::tuple<Inputs...>& inputs, std::index_sequence<terms...>)
const 115 return std::tuple {jac_term<terms>(inputs) ...};
119 template<std::size_t term, std::size_t i, std::size_t j,
typename...Inputs>
120 auto h_j(
const std::tuple<Inputs...>& inputs)
const 123 const Scalar hi = std::get<term>(deltas)[i];
124 auto& col = std::get<term>(inputs);
125 const Scalar xi = col[i];
127 if constexpr (i == j)
129 const auto f0 =
Mean {std::apply(transformation, inputs)};
131 const auto fp =
Mean {std::apply(transformation, inputs)};
133 const auto fm =
Mean {std::apply(transformation, inputs)};
137 auto ret {make_self_contained(((fp - f0) - (f0 - fm)) / (hi * hi))};
142 const Scalar hj = std::get<term>(deltas)[j];
143 const Scalar xj = col[j];
146 const auto fpp =
Mean {std::apply(transformation, inputs)};
148 const auto fpm =
Mean {std::apply(transformation, inputs)};
150 const auto fmm =
Mean {std::apply(transformation, inputs)};
152 const auto fmp =
Mean {std::apply(transformation, inputs)};
155 auto ret {make_self_contained(((fpp - fpm) - (fmp - fmm)) / (4 * hi * hj))};
161 template<std::size_t term, std::size_t i,
typename...Inputs, std::size_t...js>
162 auto h_i(
const std::tuple<Inputs...>& inputs, std::index_sequence<js...>)
const 164 using A = equivalent_self_contained_t<decltype(h_j<term, 0, 0>(inputs))>;
165 return std::array<
A,
sizeof...(js)> {h_j<term, i, js>(inputs)...};
169 template<std::size_t term,
typename...Inputs, std::size_t...is>
170 auto h_k(
const std::tuple<Inputs...>& inputs, std::index_sequence<is...>)
const 172 constexpr
auto j_size = index_dimension_of_v<decltype(std::get<term>(inputs)), 0>;
173 using A = decltype(h_i<term, 0>(std::move(inputs), std::make_index_sequence<j_size> {}));
174 return std::array<
A,
sizeof...(is)> {h_i<term, is>(inputs, std::make_index_sequence<j_size> {})...};
179 template<std::size_t term,
typename...Inputs, std::size_t...ks>
180 auto h_term(
const std::tuple<Inputs...>& inputs, std::index_sequence<ks...>)
const 182 using Term = decltype(std::get<term>(inputs));
183 const auto t = h_k<term>(inputs, std::make_index_sequence<index_dimension_of_v<Term, 0>> {});
187 return std::array<V,
sizeof...(ks)> {
188 apply_coefficientwise<V>([&t](std::size_t i, std::size_t j) {
return t[i][j][ks]; })...};
193 template<
typename...Inputs, std::size_t...terms>
194 auto hessian_impl(
const std::tuple<Inputs...>& inputs, std::index_sequence<terms...>)
const 196 static_assert(
sizeof...(Inputs) ==
sizeof...(terms));
197 constexpr
auto k_size = index_dimension_of_v<std::invoke_result_t<Function, Inputs...>, 0>;
198 return std::tuple {h_term<terms>(inputs, std::make_index_sequence<k_size> {})...};
206 #ifdef __cpp_concepts 209 template<
typename T,
typename In,
typename ... Ps, std::enable_if_t<
210 (transformation_input<In> and ... and transformation_input<Ps>),
int> = 0>
213 : transformation(std::forward<T>(trans)), deltas(std::forward<In>(in_delta), std::forward<Ps>(ps_delta)...) {}
217 #ifdef __cpp_concepts 218 template<transformation_input<vector_space_descriptor_of_t<InDelta, 0>> In, perturbation ... Perturbations>
219 requires (
sizeof...(Perturbations) <=
sizeof...(PsDelta)) and (
sizeof...(Perturbations) == 0 or
223 template<
typename In,
typename ... Perturbations, std::enable_if_t<
224 transformation_input<In, vector_space_descriptor_of_t<InDelta, 0>> and
225 (perturbation<Perturbations> and ...) and (
sizeof...(Perturbations) <=
sizeof...(PsDelta)) and
226 (
sizeof...(Perturbations) == 0 or
232 return transformation(std::forward<In>(in), std::forward<Perturbations>(ps)...);
237 #ifdef __cpp_concepts 238 template<transformation_input<vector_space_descriptor_of_t<InDelta, 0>> In, perturbation ... Perturbations>
239 requires (
sizeof...(Perturbations) <=
sizeof...(PsDelta)) and (
sizeof...(Perturbations) == 0 or
243 template<
typename In,
typename ... Perturbations, std::enable_if_t<
244 transformation_input<In, vector_space_descriptor_of_t<InDelta, 0>> and
245 (perturbation<Perturbations> and ...) and (
sizeof...(Perturbations) <=
sizeof...(PsDelta)) and
246 (
sizeof...(Perturbations) == 0 or
252 return jacobian_impl(
255 std::make_index_sequence<1 +
sizeof...(ps)> {});
260 #ifdef __cpp_concepts 261 template<transformation_input<vector_space_descriptor_of_t<InDelta, 0>> In, perturbation ... Perturbations>
262 requires (
sizeof...(Perturbations) <=
sizeof...(PsDelta)) and (
sizeof...(Perturbations) == 0 or
266 template<
typename In,
typename ... Perturbations, std::enable_if_t<
267 transformation_input<In, vector_space_descriptor_of_t<InDelta, 0>> and
268 (perturbation<Perturbations> and ...) and (
sizeof...(Perturbations) <=
sizeof...(PsDelta)) and
269 (
sizeof...(Perturbations) == 0 or
273 auto hessian(In&& in, Perturbations&&...ps)
const 278 std::make_index_sequence<1 +
sizeof...(ps)> {});
283 Function transformation;
285 const std::tuple<
const InDelta,
const PsDelta...> deltas;
294 #ifdef __cpp_concepts 296 std::invocable<Function, InDelta, PsDelta...> and
297 (not
wrapped_mean<std::invoke_result_t<Function, InDelta, PsDelta...>>) and
298 (not std::is_reference_v<InDelta>) and (((not std::is_reference_v<PsDelta>) and ...))
300 template<
typename Function,
typename InDelta,
typename ... PsDelta, std::enable_if_t<
301 (transformation_input<InDelta> and ... and transformation_input<PsDelta>) and
302 std::is_invocable_v<Function, InDelta, PsDelta...> and
303 (not
wrapped_mean<std::invoke_result_t<Function, InDelta, PsDelta...>>) and
304 (not std::is_reference_v<InDelta>) and (((not std::is_reference_v<PsDelta>) and ...)),
int> = 0>
312 #endif //OPENKALMAN_FINITEDIFFERENCELINEARIZATION_HPP A set of one or more column vectors, each representing a statistical mean.
Definition: forward-class-declarations.hpp:477
typename scalar_type_of< T >::type scalar_type_of_t
helper template for scalar_type_of.
Definition: scalar_type_of.hpp:54
constexpr bool wrapped_mean
Specifies that T is a wrapped mean (i.e., its row fixed_pattern have at least one type that requires ...
Definition: object-types.hpp:52
Definition: tuple_reverse.hpp:103
Definition: TransformationTraits.hpp:136
FiniteDifferenceLinearization(T &&trans, In &&in_delta, Ps &&... ps_delta)
Constructor.
Definition: FiniteDifferenceLinearization.hpp:212
constexpr bool transformation_input
T is an acceptable input to a tests.
Definition: TransformationTraits.hpp:158
decltype(auto) constexpr to_dense_object(Arg &&arg)
Convert the argument to a dense, writable matrix of a particular scalar type.
Definition: to_dense_object.hpp:37
auto jacobian(In &&in, Perturbations &&...ps) const
Returns a tuple of the Jacobians for the input and each perturbation term.
Definition: FiniteDifferenceLinearization.hpp:250
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
auto hessian(In &&in, Perturbations &&...ps) const
Returns a tuple of Hessian matrices for the input and each perturbation term.
Definition: FiniteDifferenceLinearization.hpp:273
auto operator()(In &&in, Perturbations &&... ps) const
Applies the tests.
Definition: FiniteDifferenceLinearization.hpp:230
The dimension of an index for a matrix, expression, or array.
Definition: index_dimension_of.hpp:34
A tests which calculates the first and second Taylor derivatives using finite differences.
Definition: FiniteDifferenceLinearization.hpp:42
Definition: basics.hpp:48
A matrix with typed rows and columns.
Definition: forward-class-declarations.hpp:448