version 0.4
nonlinearoperator.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2024 The Ikarus Developers mueller@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
10#pragma once
11#include <functional>
12
13#include <dune/common/hybridutilities.hh>
14
16
17namespace Ikarus {
18
19 namespace Impl {
30 template <class F, class Tuple, std::size_t... I>
31 constexpr decltype(auto) applyAndRemoveRefererenceWrapper(F&& f, Tuple&& t, std::index_sequence<I...>) {
32 return std::invoke(
33 std::forward<F>(f),
34 std::get<I>(std::forward<Tuple>(t)).get()...); //.get gets the impl type of std::referenceWrapper
35 }
36
46 template <class F, class Tuple>
47 constexpr decltype(auto) applyAndRemoveReferenceWrapper(F&& f, Tuple&& t) {
48 return applyAndRemoveRefererenceWrapper(
49 std::forward<F>(f), std::forward<Tuple>(t),
50 std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
51 }
52
60 template <typename T>
61 auto forwardasReferenceWrapperIfIsReference(T&& t) {
62 if constexpr (std::is_lvalue_reference_v<decltype(t)>)
63 return std::ref(t);
64 else
65 return t;
66 }
67
78 template <class Pars, class Tuple, std::size_t... I>
79 constexpr decltype(auto) makeTupleOfValuesAndReferences(Tuple&& t, Pars&& p, std::index_sequence<I...>) {
80 return std::make_tuple(
81 forwardasReferenceWrapperIfIsReference(applyAndRemoveReferenceWrapper(std::get<I>(t), p.args))...);
82 }
83
89 template <typename... Args>
90 struct Functions {
91 std::tuple<std::reference_wrapper<std::remove_reference_t<Args>>...> args;
92 };
93
99 template <typename... Args>
100 struct Parameter {
101 std::tuple<std::reference_wrapper<std::remove_reference_t<Args>>...> args;
102 };
103
104 } // namespace Impl
105
113 template <typename... Args>
114 auto parameter(Args&&... args) {
115 return Impl::Parameter<Args&&...>{std::forward_as_tuple(std::forward<Args>(args)...)};
116 }
117
125 template <typename... Args>
126 auto functions(Args&&... args) {
127 return Impl::Functions<Args&&...>{std::forward_as_tuple(std::forward<Args>(args)...)};
128 }
129
139 template <typename... DerivativeArgs, typename... ParameterArgs>
140 auto initResults(const Impl::Functions<DerivativeArgs...>& derivativesFunctions,
141 const Impl::Parameter<ParameterArgs...>& parameterI) {
142 return Impl::makeTupleOfValuesAndReferences(
143 derivativesFunctions.args, parameterI,
144 std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<decltype(derivativesFunctions.args)>>>{});
145 }
146
153 template <typename TypeListOne, typename TypeListTwo>
155 public:
156 NonLinearOperator([[maybe_unused]] const TypeListOne& derivativesFunctions,
157 [[maybe_unused]] const TypeListTwo& args) {
158 static_assert(!sizeof(TypeListOne),
159 "This type should not be instantiated. check that your arguments satisfies the template below");
160 }
161 };
162
170 template <typename... DerivativeArgs, typename... ParameterArgs>
171 class NonLinearOperator<Impl::Functions<DerivativeArgs...>, Impl::Parameter<ParameterArgs...>> {
172 public:
173 using FunctionReturnValues
174 = std::tuple<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>...>;
175 using ParameterValues = std::tuple<ParameterArgs...>;
176
182 template <int n>
183 using FunctionReturnType = std::tuple_element_t<n, FunctionReturnValues>;
184
190 template <int n>
191 using ParameterValue = std::remove_cvref_t<std::tuple_element_t<n, ParameterValues>>;
192
193 using ValueType
194 = std::remove_cvref_t<std::tuple_element_t<0, FunctionReturnValues>>;
195 using DerivativeType
196 = std::remove_cvref_t<std::tuple_element_t<1, FunctionReturnValues>>;
197
204 explicit NonLinearOperator(const Impl::Functions<DerivativeArgs...>& derivativesFunctions,
205 const Impl::Parameter<ParameterArgs...>& parameterI)
206 : derivatives_{derivativesFunctions.args},
207 args_{parameterI.args},
208 derivativesEvaluated_(initResults(derivativesFunctions, parameterI)) {}
209
215 void updateAll() {
216 Dune::Hybrid::forEach(
217 Dune::Hybrid::integralRange(Dune::index_constant<sizeof...(DerivativeArgs)>()), [&](const auto i) {
218 std::get<i>(derivativesEvaluated_) = Impl::applyAndRemoveReferenceWrapper(std::get<i>(derivatives_), args_);
219 });
220 }
221
227 template <int n>
228 void update() {
229 std::get<n>(derivativesEvaluated_) = Impl::applyAndRemoveReferenceWrapper(std::get<n>(derivatives_), args_);
230 }
231
239 auto& value() requires(sizeof...(DerivativeArgs) > 0) { return nthDerivative<0>(); }
240
248 auto& derivative() requires(sizeof...(DerivativeArgs) > 1) { return nthDerivative<1>(); }
249
257 auto& secondDerivative() requires(sizeof...(DerivativeArgs) > 2) { return nthDerivative<2>(); }
258
265 template <int n>
266 auto& nthDerivative() requires(sizeof...(DerivativeArgs) > n) {
267 if constexpr (requires { std::get<n>(derivativesEvaluated_).get(); })
268 return std::get<n>(derivativesEvaluated_).get();
269 else
270 return std::get<n>(derivativesEvaluated_);
271 }
272
278 auto& lastParameter() { return nthParameter<sizeof...(ParameterArgs) - 1>(); }
284 auto& firstParameter() requires(sizeof...(ParameterArgs) > 0) { return nthParameter<0>(); }
290 auto& secondParameter() requires(sizeof...(ParameterArgs) > 1) { return nthParameter<1>(); }
297 template <int n>
298 auto& nthParameter() requires(sizeof...(ParameterArgs) >= n) {
299 return std::get<n>(args_).get();
300 }
301
308 template <int... Derivatives>
309 auto subOperator() {
310 return Ikarus::NonLinearOperator(functions(std::get<Derivatives>(derivatives_)...),
311 Impl::applyAndRemoveReferenceWrapper(parameter<ParameterArgs...>, args_));
312 }
313
314 private:
315 using FunctionReturnValuesWrapper = std::tuple<std::conditional_t<
316 std::is_reference_v<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>>,
317 std::reference_wrapper<std::remove_reference_t<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>>>,
318 std::remove_cvref_t<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>>>...>;
319 std::tuple<std::conditional_t<std::is_reference_v<DerivativeArgs>,
320 std::reference_wrapper<std::remove_reference_t<DerivativeArgs>>,
321 std::remove_reference_t<DerivativeArgs>>...>
322 derivatives_;
323 std::tuple<std::conditional_t<std::is_reference_v<ParameterArgs>,
324 std::reference_wrapper<std::remove_reference_t<ParameterArgs>>,
325 std::remove_reference_t<ParameterArgs>>...>
326 args_;
327 FunctionReturnValuesWrapper derivativesEvaluated_{};
328 };
329} // namespace Ikarus
Contains stl-like type traits.
std::invoke_result_t< Fun, Args... > ReturnType
Type trait to obtain the return type of a callable type when given specific arguments.
Definition: traits.hh:63
Definition: simpleassemblers.hh:21
auto functions(Args &&... args)
Creates a Functions object.
Definition: nonlinearoperator.hh:126
auto parameter(Args &&... args)
Creates a Parameter object.
Definition: nonlinearoperator.hh:114
auto initResults(const Impl::Functions< DerivativeArgs... > &derivativesFunctions, const Impl::Parameter< ParameterArgs... > &parameterI)
Initializes the results for functions and parameters.
Definition: nonlinearoperator.hh:140
Represents a NonLinearOperator class for handling nonlinear operators.
Definition: nonlinearoperator.hh:154
NonLinearOperator(const TypeListOne &derivativesFunctions, const TypeListTwo &args)
Definition: nonlinearoperator.hh:156