ALFI
Advanced Library for Function Interpolation
Loading...
Searching...
No Matches
polyeqv.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <iostream>
5#include <cmath>
6
7#include "../config.h"
8#include "../poly.h"
9#include "../util/misc.h"
10
11namespace alfi::spline {
12 template <typename Number = DefaultNumber, template <typename, typename...> class Container = DefaultContainer>
14 public:
22
29
37
38 static Container<Number> compute_coeffs(
39 const Container<Number>& X,
40 const Container<Number>& Y,
43 ) {
44 if (X.size() != Y.size()) {
45 std::cerr << "Error in function " << __FUNCTION__
46 << ": Vectors X (of size " << X.size()
47 << ") and Y (of size " << Y.size()
48 << ") are not the same size. Returning an empty array..." << std::endl;
49 return {};
50 }
51
52 const SizeT n = X.size();
53
54 if (n == 0) {
55 return {};
56 }
57
58 if (n <= 4) {
60 }
61
62 Container<Number> coeffs(n * (n - 1)); // n coefficients for n-1 segments
63
64 switch (optimization_type) {
66#if defined(_OPENMP) && !defined(ALFI_DISABLE_OPENMP)
67#pragma omp parallel for
68#endif
69 for (SizeT i = 0; i < n - 1; ++i) {
70 auto X_i = X;
71 for (auto& x : X_i) {
72 x -= X[i];
73 }
74 Container<Number> P_i;
75 switch (polynomial_type) {
76 case PolynomialType::LAGRANGE: P_i = poly::lagrange(X_i, Y); break;
78 case PolynomialType::NEWTON: P_i = poly::newton(X_i, Y); break;
79 }
80 std::move(P_i.begin(), P_i.end(), coeffs.begin() + (i * n));
81 coeffs[i*n+n-1] = Y[i];
82 }
83 break;
84 }
86 Container<Number> P;
87 switch (polynomial_type) {
88 case PolynomialType::LAGRANGE: P = poly::lagrange(X, Y); break;
90 case PolynomialType::NEWTON: P = poly::newton(X, Y); break;
91 }
92
93 const static auto binomials = [](SizeT m) {
94 Container<Container<Number>> C(m + 1);
95 for (SizeT i = 0; i <= m; ++i) {
96 C[i].resize(i + 1);
97 C[i][0] = C[i][i] = 1;
98 for (SizeT j = 1; j <= i / 2; ++j) {
99 C[i][j] = C[i][i-j] = C[i-1][j-1] + C[i-1][j];
100 }
101 }
102 return C;
103 };
104
105 const auto C = binomials(n - 1);
106
107#if defined(_OPENMP) && !defined(ALFI_DISABLE_OPENMP)
108#pragma omp parallel for
109#endif
110 for (SizeT i = 0; i < n - 1; ++i) {
111 coeffs[i*n] = P[0];
112 for (SizeT k = 1; k < n - 1; ++k) {
113 Number r = 0;
114 for (SizeT j = 0; j < k; ++j) {
115 r += ((((k - j) & 1) == 0) ? 1 : -1) * coeffs[i*n+j] * C[n-1-j][k-j];
116 r *= X[i];
117 }
118 coeffs[i*n+k] = P[k] - r;
119 }
120 coeffs[i*n+n-1] = Y[i];
121 }
122 break;
123 }
124 }
125 return coeffs;
126 }
127
128 PolyEqvSpline() = default;
129
130 template <typename ContainerXType>
131 PolyEqvSpline(ContainerXType&& X,
132 const Container<Number>& Y,
135 construct(std::forward<ContainerXType>(X), Y, polynomial_type, optimization_type);
136 }
137
138 PolyEqvSpline(const PolyEqvSpline& other) = default;
139 PolyEqvSpline(PolyEqvSpline&& other) noexcept = default;
140
141 PolyEqvSpline& operator=(const PolyEqvSpline& other) = default;
142 PolyEqvSpline& operator=(PolyEqvSpline&& other) noexcept = default;
143
144 template <typename ContainerXType>
145 void construct(ContainerXType&& X,
146 const Container<Number>& Y,
151 if (coeffs.empty() && !X.empty()) {
152 std::cerr << "Error in function " << __FUNCTION__
153 << ": failed to construct coefficients. Not changing the object..." << std::endl;
154 return;
155 }
156 _polynomial_type = polynomial_type;
157 _optimization_type = optimization_type;
158 _evaluation_type = evaluation_type;
159 _X = std::forward<ContainerXType>(X);
160 _coeffs = std::move(coeffs);
161 }
162
163 Number eval(Number x) const {
164 return eval(x, std::distance(_X.begin(), util::misc::first_leq_or_begin(_X.begin(), _X.end(), x)));
165 }
166 Number eval(Number x, SizeT segment) const {
167 if (_coeffs.empty()) {
168 return NAN;
169 } else if (_coeffs.size() == 1) {
170 return _coeffs[0];
171 }
172
173 segment = std::clamp(segment, static_cast<SizeT>(0), static_cast<SizeT>(_X.size() - 2));
174
175 x = x - _X[segment];
176
177 const SizeT n = _X.size();
178
179 Number result = _coeffs[segment*n];
180
181 if (std::isnan(result)) {
182 switch (_evaluation_type) {
185 result = 0;
186 break;
188 return result;
189 }
190 }
191
192 for (SizeT i = 1; i < n; ++i) {
193 result *= x;
194 Number current = _coeffs[segment*n+i];
195 if (std::isnan(current)) {
196 switch (_evaluation_type) {
198 result = 0;
199 [[fallthrough]];
201 current = 0;
202 break;
204 return current;
205 }
206 }
207 result += current;
208 }
209
210 return result;
211 }
212
213 Container<Number> eval(const Container<Number>& xx, bool sorted = true) const {
214 Container<Number> result(xx.size());
215 if (sorted) {
216 for (SizeT i = 0, i_x = 0; i < xx.size(); ++i) {
217 const Number x = xx[i];
218 while (i_x + 1 < _X.size() && x >= _X[i_x+1])
219 ++i_x;
220 result[i] = eval(x, i_x);
221 }
222 } else {
223 for (SizeT i = 0; i < xx.size(); ++i) {
224 result[i] = eval(xx[i]);
225 }
226 }
227 return result;
228 }
229
230 Number operator()(Number x) const {
231 return eval(x);
232 }
233 Container<Number> operator()(const Container<Number>& xx) const {
234 return eval(xx);
235 }
236
238 return _polynomial_type;
239 }
240
242 return _optimization_type;
243 }
244
246 return _evaluation_type;
247 }
248
249 const Container<Number>& X() const & {
250 return _X;
251 }
252 Container<Number>&& X() && {
253 return std::move(_X);
254 }
255
256 const Container<Number>& coeffs() const & {
257 return _coeffs;
258 }
259 Container<Number>&& coeffs() && {
260 return std::move(_coeffs);
261 }
262
263 std::pair<SizeT, SizeT> segment(SizeT index) const {
264 return {_X.size()*index, _X.size()*(index+1)};
265 }
266
267 private:
268 PolynomialType _polynomial_type = PolynomialType::Default;
269 OptimizationType _optimization_type = OptimizationType::Default;
270 EvaluationType _evaluation_type = EvaluationType::Default;
271 Container<Number> _X = {};
272 Container<Number> _coeffs = {};
273 };
274}
static Container< Number > compute_coeffs(const Container< Number > &X, const Container< Number > &Y, PolynomialType polynomial_type=PolynomialType::Default, OptimizationType optimization_type=OptimizationType::Default)
Definition polyeqv.h:38
PolynomialType polynomial_type() const
Definition polyeqv.h:237
Container< Number > eval(const Container< Number > &xx, bool sorted=true) const
Definition polyeqv.h:213
PolyEqvSpline & operator=(PolyEqvSpline &&other) noexcept=default
Container< Number > && coeffs() &&
Definition polyeqv.h:259
std::pair< SizeT, SizeT > segment(SizeT index) const
Definition polyeqv.h:263
PolyEqvSpline(ContainerXType &&X, const Container< Number > &Y, PolynomialType polynomial_type=PolynomialType::Default, OptimizationType optimization_type=OptimizationType::Default)
Definition polyeqv.h:131
PolyEqvSpline(const PolyEqvSpline &other)=default
PolyEqvSpline(PolyEqvSpline &&other) noexcept=default
Number eval(Number x) const
Definition polyeqv.h:163
void construct(ContainerXType &&X, const Container< Number > &Y, PolynomialType polynomial_type=PolynomialType::Default, OptimizationType optimization_type=OptimizationType::Default, EvaluationType evaluation_type=EvaluationType::Default)
Definition polyeqv.h:145
PolynomialType
Definition polyeqv.h:15
@ IMPROVED_LAGRANGE
Definition polyeqv.h:17
Number eval(Number x, SizeT segment) const
Definition polyeqv.h:166
EvaluationType
Definition polyeqv.h:30
@ NOT_IGNORE_NANS
Definition polyeqv.h:33
@ IGNORE_NANS_AND_PREVIOUS
Definition polyeqv.h:31
PolyEqvSpline & operator=(const PolyEqvSpline &other)=default
const Container< Number > & X() const &
Definition polyeqv.h:249
Number operator()(Number x) const
Definition polyeqv.h:230
EvaluationType evaluation_type() const
Definition polyeqv.h:245
Container< Number > && X() &&
Definition polyeqv.h:252
OptimizationType optimization_type() const
Definition polyeqv.h:241
OptimizationType
Definition polyeqv.h:23
const Container< Number > & coeffs() const &
Definition polyeqv.h:256
Container< Number > operator()(const Container< Number > &xx) const
Definition polyeqv.h:233
Container< Number > newton(const Container< Number > &X, const Container< Number > &Y)
Definition poly.h:249
Container< Number > lagrange(const Container< Number > &X, const Container< Number > &Y)
Definition poly.h:36
Container< Number > imp_lagrange(const Container< Number > &X, const Container< Number > &Y)
Definition poly.h:126
Definition cubic.h:13
Iterator first_leq_or_begin(Iterator begin, Iterator end, const T &value)
Definition misc.h:27
Container< Number > simple_spline(const Container< Number > &X, const Container< Number > &Y, SizeT degree)
Definition spline.h:10
ALFI_DEFAULT_NUMBER DefaultNumber
Definition config.h:17
ALFI_SIZE_TYPE SizeT
Definition config.h:22
ALFI_DEFAULT_CONTAINER< Number > DefaultContainer
Definition config.h:20