33struct IsScalar<Eigen::Matrix<double, N, 1, Eigen::ColMajor, N, 1>>
38template <std::
size_t IndexInTuple,
typename Tuple>
41 auto const& value = std::get<IndexInTuple>(tuple);
43 if constexpr (
IsScalar<std::remove_cvref_t<
decltype(value)>>::value)
49 return value[component];
59 template <
typename Function,
typename TupleOfArgs,
60 typename PerturbationStrategy, std::size_t PerturbedArgIdx,
61 std::size_t... AllArgIdcs>
62 auto operator()(Function
const& f, TupleOfArgs
const& args,
63 PerturbationStrategy
const& pert_strat,
64 std::integral_constant<std::size_t, PerturbedArgIdx>,
65 Eigen::Index
const perturbed_arg_component,
66 std::index_sequence<AllArgIdcs...>)
const
68 auto const value_plus = f(pert_strat.perturbIf(
69 std::bool_constant<PerturbedArgIdx == AllArgIdcs>{},
70 std::get<AllArgIdcs>(args), 1.0, perturbed_arg_component)...);
72 auto const value_minus = f(pert_strat.perturbIf(
73 std::bool_constant<PerturbedArgIdx == AllArgIdcs>{},
74 std::get<AllArgIdcs>(args), -1.0, perturbed_arg_component)...);
76 auto const pert = pert_strat.getPerturbation(
78 args, perturbed_arg_component));
81 decltype(value_plus) deriv = (value_plus - value_minus) / (2 * pert);
91template <
typename Value>
99 template <
typename Function,
typename TupleOfArgs,
100 typename PerturbationStrategy, std::size_t PerturbedArgIdx,
101 std::size_t... AllArgIdcs>
103 PerturbationStrategy
const& pert_strat,
104 std::integral_constant<std::size_t, PerturbedArgIdx>,
105 Eigen::Index
const perturbed_arg_component,
106 std::index_sequence<AllArgIdcs...>)
const
108 auto const value_plus = f(pert_strat.perturbIf(
109 std::bool_constant<PerturbedArgIdx == AllArgIdcs>{},
110 std::get<AllArgIdcs>(args), 1.0, perturbed_arg_component)...);
112 auto const pert = pert_strat.getPerturbation(
114 args, perturbed_arg_component));
135 auto const pert = std::abs(value) *
rel_eps_;
137 if (std::abs(pert) >= std::abs(
min_pert_))
145 template <
typename T>
146 static T
const&
perturbIf(std::false_type, T
const& value,
153 double perturbIf(std::true_type,
double value,
double const plus_or_minus,
162 Eigen::Matrix<double, N, 1, Eigen::ColMajor, N, 1>
const& vec,
163 double const plus_or_minus,
164 Eigen::Index comp)
const
166 Eigen::Vector<double, N> vec_pert = vec;
182 template <
typename Function,
typename... Args>
184 Function
const& , Args
const&... )
195 template <
typename Function,
typename... Args>
207template <
typename DerivativeStrategy>
216 template <
typename Function,
typename... Args>
217 auto operator()(Function
const& f, Args
const&... args)
const
219 auto const d_by_dScalar =
220 DerivativeStrategy::createDByDScalar(f, args...);
224 std::forward_as_tuple(args...),
226 std::make_index_sequence<
sizeof...(Args)>{});
230 template <
typename Function,
typename TupleOfArgs,
typename DByDScalar,
231 std::size_t... AllArgIdcs>
233 DByDScalar
const& d_by_dScalar,
234 std::index_sequence<AllArgIdcs...> all_arg_idcs)
const
238 std::tuple_element_t<AllArgIdcs, TupleOfArgs>>>{},
239 f, args, d_by_dScalar,
240 std::integral_constant<std::size_t, AllArgIdcs>{},
245 template <
typename Function,
typename TupleOfArgs,
typename DByDScalar,
246 std::size_t... AllArgIdcs, std::size_t PerturbedArgIdx>
248 std::true_type , Function
const& f,
249 TupleOfArgs
const& args, DByDScalar
const& d_by_dScalar,
250 std::integral_constant<std::size_t, PerturbedArgIdx> perturbed_arg_idx,
251 std::index_sequence<AllArgIdcs...> all_arg_idcs)
const
253 constexpr Eigen::Index component_does_not_matter = -1;
255 return d_by_dScalar(f, args,
pert_strat_, perturbed_arg_idx,
256 component_does_not_matter, all_arg_idcs);
260 template <
typename Function,
typename TupleOfArgs,
typename DByDScalar,
261 std::size_t... AllArgIdcs, std::size_t PerturbedArgIdx>
263 std::false_type , Function
const& f,
264 TupleOfArgs
const& args, DByDScalar
const& d_by_dScalar,
265 std::integral_constant<std::size_t, PerturbedArgIdx> perturbed_arg_idx,
266 std::index_sequence<AllArgIdcs...> all_arg_idcs)
const
268 using VectorialArg = std::remove_cvref_t<
269 std::tuple_element_t<PerturbedArgIdx, TupleOfArgs>>;
270 constexpr int N = VectorialArg::RowsAtCompileTime;
272 static_assert(
N != Eigen::Dynamic);
273 static_assert(VectorialArg::ColsAtCompileTime == 1,
274 "Row vectors are not supported, yet. If you implement "
275 "support for them, make sure to test your implementation "
279 f, args, d_by_dScalar,
280 std::make_integer_sequence<Eigen::Index, N>{}, perturbed_arg_idx,
284 template <
typename Function,
typename TupleOfArgs,
typename DByDScalar,
285 Eigen::Index... PerturbedArgComponents, std::size_t... AllArgIdcs,
286 std::size_t PerturbedArgIdx>
288 Function
const& f, TupleOfArgs
const& args,
289 DByDScalar
const& d_by_dScalar,
290 std::integer_sequence<Eigen::Index, PerturbedArgComponents...>,
291 std::integral_constant<std::size_t, PerturbedArgIdx> perturbed_arg_idx,
292 std::index_sequence<AllArgIdcs...> all_arg_idcs)
const
295 d_by_dScalar(f, args,
pert_strat_, perturbed_arg_idx,
296 PerturbedArgComponents, all_arg_idcs)...
double getScalarOrVectorComponent(Tuple const &tuple, Eigen::Index component)
static detail::ComputeDerivativeWrtOneScalar_CD createDByDScalar(Function const &, Args const &...)
static auto createDByDScalar(Function const &f, Args const &... args)
auto differentiateWrtScalarOrVectorialArgument(std::false_type, Function const &f, TupleOfArgs const &args, DByDScalar const &d_by_dScalar, std::integral_constant< std::size_t, PerturbedArgIdx > perturbed_arg_idx, std::index_sequence< AllArgIdcs... > all_arg_idcs) const
detail::DefaultPerturbationStrategy pert_strat_
auto operator()(Function const &f, Args const &... args) const
NumericalDerivative(RelativeEpsilon const &rel_eps, MinimumPerturbation const &min_pert)
auto differentiateWrtScalarOrVectorialArgument(std::true_type, Function const &f, TupleOfArgs const &args, DByDScalar const &d_by_dScalar, std::integral_constant< std::size_t, PerturbedArgIdx > perturbed_arg_idx, std::index_sequence< AllArgIdcs... > all_arg_idcs) const
auto differentiateWrtAllVectorComponents(Function const &f, TupleOfArgs const &args, DByDScalar const &d_by_dScalar, std::integer_sequence< Eigen::Index, PerturbedArgComponents... >, std::integral_constant< std::size_t, PerturbedArgIdx > perturbed_arg_idx, std::index_sequence< AllArgIdcs... > all_arg_idcs) const
auto differentiate(Function const &f, TupleOfArgs const &args, DByDScalar const &d_by_dScalar, std::index_sequence< AllArgIdcs... > all_arg_idcs) const
auto operator()(Function const &f, TupleOfArgs const &args, PerturbationStrategy const &pert_strat, std::integral_constant< std::size_t, PerturbedArgIdx >, Eigen::Index const perturbed_arg_component, std::index_sequence< AllArgIdcs... >) const
ComputeDerivativeWrtOneScalar_FD(Value &&unperturbed_value)
Value operator()(Function const &f, TupleOfArgs const &args, PerturbationStrategy const &pert_strat, std::integral_constant< std::size_t, PerturbedArgIdx >, Eigen::Index const perturbed_arg_component, std::index_sequence< AllArgIdcs... >) const
static T const & perturbIf(std::false_type, T const &value, double const, Eigen::Index)
double perturbIf(std::true_type, double value, double const plus_or_minus, Eigen::Index) const
DefaultPerturbationStrategy(RelativeEpsilon const &rel_eps, MinimumPerturbation const &min_pert)
double getPerturbation(double const value) const
Eigen::Vector< double, N > perturbIf(std::true_type, Eigen::Matrix< double, N, 1, Eigen::ColMajor, N, 1 > const &vec, double const plus_or_minus, Eigen::Index comp) const