Dune-Functions 2.11
Loading...
Searching...
No Matches
polynomial.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3
4// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file AUTHORS.md
5// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
6
7#ifndef DUNE_FUNCTIONS_ANALYTICFUNCTIONS_POLYNOMIAL_HH
8#define DUNE_FUNCTIONS_ANALYTICFUNCTIONS_POLYNOMIAL_HH
9
10#include <cmath>
11#include <initializer_list>
12#include <vector>
13
14
15#include <dune/common/hybridutilities.hh>
16
17namespace Dune {
18namespace Functions {
19
20namespace Impl {
21
22 // Compute coefficients of derivative of polynomial.
23 // Overload for std::vector
24 template<class K, class Allocator>
25 auto polynomialDerivativeCoefficients(const std::vector<K, Allocator>& coefficients) {
26 if (coefficients.size()==0)
27 return std::vector<K, Allocator>();
28 std::vector<K, Allocator> dpCoefficients(coefficients.size()-1);
29 for (size_t i=1; i<coefficients.size(); ++i)
30 dpCoefficients[i-1] = coefficients[i]*K(i);
31 return dpCoefficients;
32 }
33
34 // Compute coefficients of derivative of polynomial.
35 // Overload for std::array
36 template<class K, std::size_t n>
37 auto polynomialDerivativeCoefficients(const std::array<K, n>& coefficients) {
38 if constexpr (n==0)
39 return coefficients;
40 else
41 {
42 std::array<K, n-1> dpCoefficients;
43 for (size_t i=1; i<coefficients.size(); ++i)
44 dpCoefficients[i-1] = coefficients[i]*K(i);
45 return dpCoefficients;
46 }
47 }
48
49 // Compute coefficients of derivative of polynomial.
50 // Helper function for the std::integer_sequence overload.
51 // With C++20 this can be avoided, because lambda function
52 // can partially specify template arguments which allows
53 // to do the same inline.
54 template<class I, I i0, I... i, class J, J j0, J... j>
55 auto polynomialDerivativeCoefficientsHelper(std::integer_sequence<I, i0, i...>, std::integer_sequence<J, j0, j...>) {
56 return std::integer_sequence<I, i*I(j)...>();
57 }
58
59 // Compute coefficients of derivative of polynomial.
60 // Overload for std::integer_sequence
61 template<class I, I... i>
62 auto polynomialDerivativeCoefficients(std::integer_sequence<I, i...> coefficients) {
63 if constexpr (sizeof...(i)==0)
64 return coefficients;
65 else
66 return polynomialDerivativeCoefficientsHelper(coefficients, std::make_index_sequence<sizeof...(i)>());
67 }
68
69 // Compute coefficients of derivative of polynomial.
70 // Overload for std::tuple
71 template<class...T>
72 auto polynomialDerivativeCoefficients(const std::tuple<T...>& coefficients) {
73 if constexpr (sizeof...(T)==0)
74 return coefficients;
75 else
76 {
77 // Notice that std::multiplies<void> has issues with signed types.
78 // E.g., `decltype(-2,2ul)` is `long unsigned int`.
79 // Hence the same is deduced as return type in std::multiplies.
80 // To avoid this, we explicitly pass the exponent `i+1` as signed type.
81 // If the coefficient is signed, both types are now signed and
82 // so is the deduced result type of std::multiplies.
83 auto mult = Dune::Hybrid::hybridFunctor(std::multiplies());
84 return Dune::unpackIntegerSequence([&](auto... i) {
85 using signed_type = std::conditional_t<std::is_same_v<std::size_t, long unsigned int>,
86 long signed int, signed int>;
87 return std::tuple(mult(std::get<i+1>(coefficients),
88 std::integral_constant<signed_type, (signed_type)(i+1)>()) ...);
89 }, std::make_index_sequence<sizeof...(T)-1>());
90 }
91 }
92
93} // namespace Impl in Dune::Functions::
94
95
96
123template<class K, class C=std::vector<K>>
125{
126 template<class CC>
127 struct IsIntegerSequence : public std::false_type {};
128
129 template<class I, I... i>
130 struct IsIntegerSequence<std::integer_sequence<I, i...>> : public std::true_type {};
131
141 template <typename Coefficient>
142 static void add(K& y, const Coefficient &c)
143 {
144 if constexpr (!IsIntegralConstant<Coefficient>::value)
145 {
146 if (c!=0)
147 y += c;
148 }
149 else
150 y += c;
151 }
152
153public:
154
156 using Coefficients = C;
157
159 Polynomial() = default;
160
170 coefficients_(std::move(coefficients))
171 {}
172
178 K operator() (const K& x) const
179 {
180 using namespace Dune::Indices;
181
182 auto n = Dune::Hybrid::size(coefficients_);
183
184 // Explicitly handling the corner case of an empty coefficient set
185 // allows to save one multiplication.
186 return Hybrid::ifElse(Hybrid::equal_to(n, _0),
187 [&](auto id) { /* then */
188 // No coefficients at all
189 return K(0);
190 },
191 [&](auto id) { /* else */
192 // Do the Horner scheme knowing that there is at least one coefficient
193 K y = Hybrid::elementAt(coefficients_, Hybrid::minus(id(n), _1) );
194 Dune::Hybrid::forEach(Dune::range(Hybrid::minus(id(n), _1) ), [&](auto i)
195 {
196 y *= x;
197 // Do y+= _next coefficient_, unless that coefficient is std::integral_constant<0>.
198 add(y,Hybrid::elementAt(coefficients_, Hybrid::minus(Hybrid::minus(id(n),_2), i)));
199 });
200 return y;
201 });
202 }
203
205 bool operator==(const Polynomial& other) const
206 {
207 if constexpr (IsIntegerSequence<Coefficients>::value)
208 return true;
209 else
210 return coefficients()==other.coefficients();
211 }
212
222 friend auto derivative(const Polynomial& p)
223 {
224 auto derivativeCoefficients = Impl::polynomialDerivativeCoefficients(p.coefficients());
225 using DerivativeCoefficients = decltype(derivativeCoefficients);
226 return Polynomial<K, DerivativeCoefficients>(std::move(derivativeCoefficients));
227 }
228
231 {
232 return coefficients_;
233 }
234
235private:
236 Coefficients coefficients_;
237};
238
239
240
241template<class K>
243
244template<class K, std::size_t n>
246
247template<class K, K... ci>
248Polynomial(std::integer_sequence<K, ci...>) -> Polynomial<K, std::integer_sequence<K,ci...>>;
249
250template<class K>
251Polynomial(std::initializer_list<K>) -> Polynomial<K, std::vector<K>>;
252
253
254
267template<class K, class Coefficients>
268auto makePolynomial(Coefficients coefficients)
269{
270 return Polynomial<K, Coefficients>(std::move(coefficients));
271}
272
282template<class K, class C>
283auto makePolynomial(std::initializer_list<C> coefficients)
284{
285 return Polynomial<K>(std::move(coefficients));
286}
287
288
289
290
291
292}} // namespace Dune::Functions
293
294
295
296#endif // DUNE_FUNCTIONS_ANALYTICFUNCTIONS_POLYNOMIAL_HH
friend auto derivative(const Polynomial &p)
Obtain derivative of Polynomial function.
Definition polynomial.hh:222
Definition monomialset.hh:19
Definition monomialset.hh:19
Polynomial(std::vector< K >) -> Polynomial< K, std::vector< K > >
auto makePolynomial(Coefficients coefficients)
Create Polynomial.
Definition polynomial.hh:268
A univariate polynomial implementation.
Definition polynomial.hh:125
Polynomial()=default
Default constructor.
K operator()(const K &x) const
Evaluate polynomial using the Horner scheme.
Definition polynomial.hh:178
C Coefficients
The type of the stored coefficient container.
Definition polynomial.hh:156
const Coefficients & coefficients() const
Obtain reference to coefficient vector.
Definition polynomial.hh:230
Polynomial(Coefficients coefficients)
Create from container of coefficients.
Definition polynomial.hh:169
bool operator==(const Polynomial &other) const
Comparison of coefficients.
Definition polynomial.hh:205