version 0.4.1
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
19namespace 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(std::forward<F>(f),
33 std::get<I>(std::forward<Tuple>(t)).get()...); //.get gets the impl type of std::referenceWrapper
34 }
35
45 template <class F, class Tuple>
46 constexpr decltype(auto) applyAndRemoveReferenceWrapper(F&& f, Tuple&& t) {
47 return applyAndRemoveRefererenceWrapper(
48 std::forward<F>(f), std::forward<Tuple>(t),
49 std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
50 }
51
59 template <typename T>
60 auto forwardasReferenceWrapperIfIsReference(T&& t) {
61 if constexpr (std::is_lvalue_reference_v<decltype(t)>)
62 return std::ref(t);
63 else
64 return t;
65 }
66
77 template <class Pars, class Tuple, std::size_t... I>
78 constexpr decltype(auto) makeTupleOfValuesAndReferences(Tuple&& t, Pars&& p, std::index_sequence<I...>) {
79 return std::make_tuple(
80 forwardasReferenceWrapperIfIsReference(applyAndRemoveReferenceWrapper(std::get<I>(t), p.args))...);
81 }
82
88 template <typename... Args>
89 struct Functions
90 {
91 std::tuple<std::reference_wrapper<std::remove_reference_t<Args>>...> args;
92 };
93
99 template <typename... Args>
100 struct Parameter
101 {
102 std::tuple<std::reference_wrapper<std::remove_reference_t<Args>>...> args;
103 };
104
105} // namespace Impl
106
114template <typename... Args>
115auto parameter(Args&&... args) {
116 return Impl::Parameter<Args&&...>{std::forward_as_tuple(std::forward<Args>(args)...)};
117}
118
126template <typename... Args>
127auto functions(Args&&... args) {
128 return Impl::Functions<Args&&...>{std::forward_as_tuple(std::forward<Args>(args)...)};
129}
130
140template <typename... DerivativeArgs, typename... ParameterArgs>
141auto initResults(const Impl::Functions<DerivativeArgs...>& derivativesFunctions,
142 const Impl::Parameter<ParameterArgs...>& parameter) {
143 return Impl::makeTupleOfValuesAndReferences(
144 derivativesFunctions.args, parameter,
145 std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<decltype(derivativesFunctions.args)>>>{});
146}
147
154template <typename TypeListOne, typename TypeListTwo>
156{
157public:
158 NonLinearOperator([[maybe_unused]] const TypeListOne& derivativesFunctions,
159 [[maybe_unused]] const TypeListTwo& args) {
160 static_assert(!sizeof(TypeListOne),
161 "This type should not be instantiated. check that your arguments satisfies the template below");
162 }
163};
164
172template <typename... DerivativeArgs, typename... ParameterArgs>
173class NonLinearOperator<Impl::Functions<DerivativeArgs...>, Impl::Parameter<ParameterArgs...>>
174{
175public:
176 using FunctionReturnValues =
177 std::tuple<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>...>;
178 using ParameterValues = std::tuple<ParameterArgs...>;
179
185 template <int n>
186 using FunctionReturnType = std::tuple_element_t<n, FunctionReturnValues>;
187
193 template <int n>
194 using ParameterValue = std::remove_cvref_t<std::tuple_element_t<n, ParameterValues>>;
195
196 using ValueType =
197 std::remove_cvref_t<std::tuple_element_t<0, FunctionReturnValues>>;
198 using DerivativeType =
199 std::remove_cvref_t<std::tuple_element_t<1, FunctionReturnValues>>;
200
207 explicit NonLinearOperator(const Impl::Functions<DerivativeArgs...>& derivativesFunctions,
208 const Impl::Parameter<ParameterArgs...>& parameterI)
209 : derivatives_{derivativesFunctions.args},
210 args_{parameterI.args},
211 derivativesEvaluated_(initResults(derivativesFunctions, parameterI)) {}
212
218 void updateAll() {
219 Dune::Hybrid::forEach(
220 Dune::Hybrid::integralRange(Dune::index_constant<sizeof...(DerivativeArgs)>()), [&](const auto i) {
221 std::get<i>(derivativesEvaluated_) = Impl::applyAndRemoveReferenceWrapper(std::get<i>(derivatives_), args_);
222 });
223 }
224
230 template <int n>
231 void update() {
232 std::get<n>(derivativesEvaluated_) = Impl::applyAndRemoveReferenceWrapper(std::get<n>(derivatives_), args_);
233 }
234
242 auto& value()
243 requires(sizeof...(DerivativeArgs) > 0)
244 {
245 return nthDerivative<0>();
246 }
247
255 auto& derivative()
256 requires(sizeof...(DerivativeArgs) > 1)
257 {
258 return nthDerivative<1>();
259 }
260
268 auto& secondDerivative()
269 requires(sizeof...(DerivativeArgs) > 2)
270 {
271 return nthDerivative<2>();
272 }
273
280 template <int n>
281 auto& nthDerivative()
282 requires(sizeof...(DerivativeArgs) > n)
283 {
284 if constexpr (requires { std::get<n>(derivativesEvaluated_).get(); })
285 return std::get<n>(derivativesEvaluated_).get();
286 else
287 return std::get<n>(derivativesEvaluated_);
288 }
289
295 auto& lastParameter() { return nthParameter<sizeof...(ParameterArgs) - 1>(); }
301 auto& firstParameter()
302 requires(sizeof...(ParameterArgs) > 0)
303 {
304 return nthParameter<0>();
305 }
311 auto& secondParameter()
312 requires(sizeof...(ParameterArgs) > 1)
313 {
314 return nthParameter<1>();
315 }
322 template <int n>
323 auto& nthParameter()
324 requires(sizeof...(ParameterArgs) >= n)
325 {
326 return std::get<n>(args_).get();
327 }
328
335 template <int... Derivatives>
336 auto subOperator() {
337 return Ikarus::NonLinearOperator(functions(std::get<Derivatives>(derivatives_)...),
338 Impl::applyAndRemoveReferenceWrapper(parameter<ParameterArgs...>, args_));
339 }
340
341private:
342 using FunctionReturnValuesWrapper = std::tuple<std::conditional_t<
343 std::is_reference_v<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>>,
344 std::reference_wrapper<std::remove_reference_t<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>>>,
345 std::remove_cvref_t<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>>>...>;
346 std::tuple<std::conditional_t<std::is_reference_v<DerivativeArgs>,
347 std::reference_wrapper<std::remove_reference_t<DerivativeArgs>>,
348 std::remove_reference_t<DerivativeArgs>>...>
349 derivatives_;
350 std::tuple<std::conditional_t<std::is_reference_v<ParameterArgs>,
351 std::reference_wrapper<std::remove_reference_t<ParameterArgs>>,
352 std::remove_reference_t<ParameterArgs>>...>
353 args_;
354 FunctionReturnValuesWrapper derivativesEvaluated_{};
355};
356} // 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:69
Definition: simpleassemblers.hh:22
auto initResults(const Impl::Functions< DerivativeArgs... > &derivativesFunctions, const Impl::Parameter< ParameterArgs... > &parameter)
Initializes the results for functions and parameters.
Definition: nonlinearoperator.hh:141
auto functions(Args &&... args)
Creates a Functions object.
Definition: nonlinearoperator.hh:127
auto parameter(Args &&... args)
Creates a Parameter object.
Definition: nonlinearoperator.hh:115
Represents a NonLinearOperator class for handling nonlinear operators.
Definition: nonlinearoperator.hh:156
NonLinearOperator(const TypeListOne &derivativesFunctions, const TypeListTwo &args)
Definition: nonlinearoperator.hh:158