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#include "../util/spline.h"
11
12namespace alfi::spline {
13 template <typename Number = DefaultNumber, template <typename, typename...> class Container = DefaultContainer>
15 public:
23
30
38
39 static Container<Number> compute_coeffs(
40 const Container<Number>& X,
41 const Container<Number>& Y,
44 ) {
45 if (X.size() != Y.size()) {
46 std::cerr << "Error in function " << __FUNCTION__
47 << ": Vectors X (of size " << X.size()
48 << ") and Y (of size " << Y.size()
49 << ") are not the same size. Returning an empty array..." << std::endl;
50 return {};
51 }
52
53 const SizeT n = X.size();
54
55 if (n == 0) {
56 return {};
57 }
58
59 if (n <= 4) {
61 }
62
63 Container<Number> coeffs(n * (n - 1)); // n coefficients for n-1 segments
64
65 switch (optimization_type) {
67#if defined(_OPENMP) && !defined(ALFI_DISABLE_OPENMP)
68#pragma omp parallel for
69#endif
70 for (SizeT i = 0; i < n - 1; ++i) {
71 auto X_i = X;
72 for (auto& x : X_i) {
73 x -= X[i];
74 }
75 Container<Number> P_i;
76 switch (polynomial_type) {
77 case PolynomialType::LAGRANGE: P_i = poly::lagrange(X_i, Y); break;
79 case PolynomialType::NEWTON: P_i = poly::newton(X_i, Y); break;
80 }
81 std::move(P_i.begin(), P_i.end(), coeffs.begin() + (i * n));
82 coeffs[i*n+n-1] = Y[i];
83 }
84 break;
85 }
87 Container<Number> P;
88 switch (polynomial_type) {
89 case PolynomialType::LAGRANGE: P = poly::lagrange(X, Y); break;
91 case PolynomialType::NEWTON: P = poly::newton(X, Y); break;
92 }
93#if defined(_OPENMP) && !defined(ALFI_DISABLE_OPENMP)
94#pragma omp parallel for
95#endif
96 for (SizeT i = 0; i < n - 1; ++i) {
97 for (SizeT j = 0; j < n; ++j) {
98 coeffs[i*n+j] = P[j];
99 }
100 for (SizeT k = 0; k < n - 1; ++k) {
101 for (SizeT j = 1; j < n - k; ++j) {
102 coeffs[i*n+j] += coeffs[i*n+j-1] * X[i];
103 }
104 }
105 coeffs[i*n+n-1] = Y[i];
106 }
107 break;
108 }
109 }
110 return coeffs;
111 }
112
113 PolyEqvSpline() = default;
114
115 template <typename ContainerXType>
116 PolyEqvSpline(ContainerXType&& X, const Container<Number>& Y, OptimizationType optimization_type)
117 : PolyEqvSpline(std::forward<ContainerXType>(X), Y, PolynomialType::Default, optimization_type) {}
118
119 template <typename ContainerXType>
127
128 PolyEqvSpline(const PolyEqvSpline& other) = default;
129 PolyEqvSpline(PolyEqvSpline&& other) noexcept = default;
130
131 PolyEqvSpline& operator=(const PolyEqvSpline& other) = default;
132 PolyEqvSpline& operator=(PolyEqvSpline&& other) noexcept = default;
133
134 template <typename ContainerXType>
135 void construct(ContainerXType&& X,
136 const Container<Number>& Y,
141 if (coeffs.empty() && !X.empty()) {
142 std::cerr << "Error in function " << __FUNCTION__
143 << ": failed to construct coefficients. Not changing the object..." << std::endl;
144 return;
145 }
146 _polynomial_type = polynomial_type;
147 _optimization_type = optimization_type;
148 _evaluation_type = evaluation_type;
149 _X = std::forward<ContainerXType>(X);
150 _coeffs = std::move(coeffs);
151 }
152
153 Number eval(const Number& x) const {
154 return eval(x, std::distance(_X.begin(), util::misc::first_leq_or_begin(_X.begin(), _X.end(), x)));
155 }
156 Number eval(const Number& x, SizeT segment) const {
157 if (_coeffs.empty()) {
158 return NAN;
159 } else if (_coeffs.size() == 1) {
160 return _coeffs[0];
161 }
162
163 segment = std::clamp(segment, static_cast<SizeT>(0), static_cast<SizeT>(_X.size() - 2));
164
165 const Number x_seg = x - _X[segment];
166
167 const SizeT n = _X.size();
168
169 Number result = _coeffs[segment*n];
170
171 if (std::isnan(result)) {
172 switch (_evaluation_type) {
175 result = 0;
176 break;
178 return result;
179 }
180 }
181
182 for (SizeT i = 1; i < n; ++i) {
183 result *= x_seg;
184 Number current = _coeffs[segment*n+i];
185 if (std::isnan(current)) {
186 switch (_evaluation_type) {
188 result = 0;
189 [[fallthrough]];
191 current = 0;
192 break;
194 return current;
195 }
196 }
197 result += current;
198 }
199
200 return result;
201 }
202
203 Container<Number> eval(const Container<Number>& xx, bool sorted = true) const {
204 Container<Number> result(xx.size());
205 if (sorted) {
206 for (SizeT i = 0, i_x = 0; i < xx.size(); ++i) {
207 const Number& x = xx[i];
208 while (i_x + 1 < _X.size() && x >= _X[i_x+1])
209 ++i_x;
210 result[i] = eval(x, i_x);
211 }
212 } else {
213 for (SizeT i = 0; i < xx.size(); ++i) {
214 result[i] = eval(xx[i]);
215 }
216 }
217 return result;
218 }
219
220 Number operator()(const Number& x) const {
221 return eval(x);
222 }
223 Container<Number> operator()(const Container<Number>& xx) const {
224 return eval(xx);
225 }
226
228 return _polynomial_type;
229 }
230
232 return _optimization_type;
233 }
234
236 return _evaluation_type;
237 }
238
239 const Container<Number>& X() const & {
240 return _X;
241 }
242 Container<Number>&& X() && {
243 return std::move(_X);
244 }
245
246 const Container<Number>& coeffs() const & {
247 return _coeffs;
248 }
249 Container<Number>&& coeffs() && {
250 return std::move(_coeffs);
251 }
252
253 std::pair<SizeT, SizeT> segment(SizeT index) const {
254 return {_X.size()*index, _X.size()*(index+1)};
255 }
256
257 private:
258 PolynomialType _polynomial_type = PolynomialType::Default;
259 OptimizationType _optimization_type = OptimizationType::Default;
260 EvaluationType _evaluation_type = EvaluationType::Default;
261 Container<Number> _X = {};
262 Container<Number> _coeffs = {};
263 };
264}
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:39
PolynomialType polynomial_type() const
Definition polyeqv.h:227
Container< Number > eval(const Container< Number > &xx, bool sorted=true) const
Definition polyeqv.h:203
PolyEqvSpline & operator=(PolyEqvSpline &&other) noexcept=default
PolyEqvSpline(ContainerXType &&X, const Container< Number > &Y, OptimizationType optimization_type)
Definition polyeqv.h:116
Container< Number > && coeffs() &&
Definition polyeqv.h:249
std::pair< SizeT, SizeT > segment(SizeT index) const
Definition polyeqv.h:253
Number operator()(const Number &x) const
Definition polyeqv.h:220
Number eval(const Number &x, SizeT segment) const
Definition polyeqv.h:156
PolyEqvSpline(ContainerXType &&X, const Container< Number > &Y, PolynomialType polynomial_type=PolynomialType::Default, OptimizationType optimization_type=OptimizationType::Default, EvaluationType evaluation_type=EvaluationType::Default)
Definition polyeqv.h:120
PolyEqvSpline(const PolyEqvSpline &other)=default
PolyEqvSpline(PolyEqvSpline &&other) noexcept=default
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:135
PolynomialType
Definition polyeqv.h:16
@ IMPROVED_LAGRANGE
Definition polyeqv.h:18
Number eval(const Number &x) const
Definition polyeqv.h:153
EvaluationType
Definition polyeqv.h:31
@ NOT_IGNORE_NANS
Definition polyeqv.h:34
@ IGNORE_NANS_AND_PREVIOUS
Definition polyeqv.h:32
PolyEqvSpline & operator=(const PolyEqvSpline &other)=default
const Container< Number > & X() const &
Definition polyeqv.h:239
EvaluationType evaluation_type() const
Definition polyeqv.h:235
Container< Number > && X() &&
Definition polyeqv.h:242
OptimizationType optimization_type() const
Definition polyeqv.h:231
OptimizationType
Definition polyeqv.h:24
const Container< Number > & coeffs() const &
Definition polyeqv.h:246
Container< Number > operator()(const Container< Number > &xx) const
Definition polyeqv.h:223
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:14
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:11
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