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))...);
81 }
82
88 template <typename... Args>
89 struct Functions
90 {
91 std::tuple<Args...> args;
92 };
93
99 template <typename... Args>
100 struct Parameter
101 {
102 std::tuple<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 std::tuple<DerivativeArgs...>& derivativesFunctions,
142 const std::tuple<ParameterArgs...>& parameter) {
143 return Impl::makeTupleOfValuesAndReferences(
144 derivativesFunctions, parameter,
145 std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<decltype(derivativesFunctions)>>>{});
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
180 static constexpr int numberOfFunctions = sizeof...(DerivativeArgs);
181 static constexpr int numberOfParameters = sizeof...(ParameterArgs);
182
188 template <int n>
189 using FunctionReturnType = std::tuple_element_t<n, FunctionReturnValues>;
190
196 template <int n>
197 using ParameterValue = std::remove_cvref_t<std::tuple_element_t<n, ParameterValues>>;
198
199 using ValueType =
200 std::remove_cvref_t<std::tuple_element_t<0, FunctionReturnValues>>;
201 using DerivativeType =
202 std::remove_cvref_t<std::tuple_element_t<1, FunctionReturnValues>>;
203
210 template <typename U = void>
211 requires(not std::is_rvalue_reference_v<DerivativeArgs> and ...)
212 explicit NonLinearOperator(const Impl::Functions<DerivativeArgs...>& derivativesFunctions,
213 const Impl::Parameter<ParameterArgs...>& parameterI)
214 : derivatives_{derivativesFunctions.args},
215 args_{parameterI.args},
216 derivativesEvaluated_(initResults(derivatives_, args_)) {}
217
224 template <typename Funcs>
225 explicit NonLinearOperator(const Funcs& derivativesFunctions, const Impl::Parameter<ParameterArgs...>& parameterI)
226 : derivatives_{derivativesFunctions.args},
227 args_{parameterI.args},
228 derivativesEvaluated_(initResults(derivatives_, args_)) {}
229
235 void updateAll() {
236 Dune::Hybrid::forEach(
237 Dune::Hybrid::integralRange(Dune::index_constant<sizeof...(DerivativeArgs)>()), [&](const auto i) {
238 std::get<i>(derivativesEvaluated_) = Impl::applyAndRemoveReferenceWrapper(std::get<i>(derivatives_), args_);
239 });
240 }
241
247 template <int n>
248 void update() {
249 std::get<n>(derivativesEvaluated_) = Impl::applyAndRemoveReferenceWrapper(std::get<n>(derivatives_), args_);
250 }
251
259 auto& value()
260 requires(sizeof...(DerivativeArgs) > 0)
261 {
262 return nthDerivative<0>();
263 }
264
272 auto& derivative()
273 requires(sizeof...(DerivativeArgs) > 1)
274 {
275 return nthDerivative<1>();
276 }
277
285 auto& secondDerivative()
286 requires(sizeof...(DerivativeArgs) > 2)
287 {
288 return nthDerivative<2>();
289 }
290
297 template <int n>
298 auto& nthDerivative()
299 requires(sizeof...(DerivativeArgs) > n)
300 {
301 if constexpr (requires { std::get<n>(derivativesEvaluated_).get(); })
302 return std::get<n>(derivativesEvaluated_).get();
303 else
304 return std::get<n>(derivativesEvaluated_);
305 }
306
312 auto& lastParameter() { return nthParameter<sizeof...(ParameterArgs) - 1>(); }
318 auto& firstParameter()
319 requires(sizeof...(ParameterArgs) > 0)
320 {
321 return nthParameter<0>();
322 }
328 auto& secondParameter()
329 requires(sizeof...(ParameterArgs) > 1)
330 {
331 return nthParameter<1>();
332 }
339 template <int n>
340 auto& nthParameter()
341 requires(sizeof...(ParameterArgs) >= n)
342 {
343 return std::get<n>(args_).get();
344 }
345
352 template <int... Derivatives>
353 auto subOperator() {
354 auto derivatives = derivatives_;
355 auto fs = functions([&derivatives]() -> decltype(auto) { return std::get<Derivatives>(derivatives); }()...);
356 Ikarus::NonLinearOperator<Impl::Functions<std::tuple_element_t<Derivatives, decltype(derivatives_)>...>,
357 Impl::Parameter<ParameterArgs...>>
358 subOp(std::move(fs), Impl::applyAndRemoveReferenceWrapper(parameter<ParameterArgs...>, args_));
359
360 return subOp;
361 }
362
363private:
364 using FunctionReturnValuesWrapper = std::tuple<std::conditional_t<
365 std::is_reference_v<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>>,
366 std::reference_wrapper<std::remove_reference_t<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>>>,
367 std::remove_cvref_t<Ikarus::traits::ReturnType<DerivativeArgs, ParameterArgs&...>>>...>;
368
369 std::tuple<std::conditional_t<std::is_lvalue_reference_v<DerivativeArgs>,
370 std::reference_wrapper<std::remove_reference_t<DerivativeArgs>>,
371 std::remove_reference_t<DerivativeArgs>>...>
372 derivatives_;
373
374 std::tuple<std::conditional_t<std::is_lvalue_reference_v<ParameterArgs>,
375 std::reference_wrapper<std::remove_reference_t<ParameterArgs>>,
376 std::remove_reference_t<ParameterArgs>>...>
377 args_;
378 FunctionReturnValuesWrapper derivativesEvaluated_{};
379};
380
381template <typename... DerivativeArgs, typename... ParameterArgs>
382NonLinearOperator(const Impl::Functions<DerivativeArgs&&...>& a, const Impl::Parameter<ParameterArgs...>& b)
383 -> NonLinearOperator<Impl::Functions<DerivativeArgs...>, Impl::Parameter<ParameterArgs...>>;
384} // 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:74
Definition: assemblermanipulatorbuildingblocks.hh:22
auto initResults(const std::tuple< DerivativeArgs... > &derivativesFunctions, const std::tuple< 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
NonLinearOperator(const Impl::Functions< DerivativeArgs &&... > &a, const Impl::Parameter< ParameterArgs... > &b) -> NonLinearOperator< Impl::Functions< DerivativeArgs... >, Impl::Parameter< ParameterArgs... > >
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