ALFI
Advanced Library for Function Interpolation
Loading...
Searching...
No Matches
misc.h
Go to the documentation of this file.
1#pragma once
2
3#include <iostream>
4
5#include "config.h"
6#include "dist.h"
7#include "util/numeric.h"
8
9namespace alfi::misc {
10 template <typename Number = DefaultNumber, template <typename, typename...> class Container = DefaultContainer>
11 Container<Number> barycentric(
12 const Container<Number>& X,
13 const Container<Number>& Y,
14 const Container<Number>& xx,
16 const Number& epsilon = std::numeric_limits<Number>::epsilon()
17 ) {
18 if (X.size() != Y.size()) {
19 std::cerr << "Error in function " << __FUNCTION__
20 << ": Vectors X (of size " << X.size()
21 << ") and Y (of size " << Y.size()
22 << ") are not the same size. Returning an empty array..." << std::endl;
23 return {};
24 }
25
26 if (X.empty()) {
27 std::cerr << "Error in function " << __FUNCTION__
28 << ": Vectors X and Y are empty. Cannot interpolate. Returning an empty array..." << std::endl;
29 return {};
30 }
31
32 const auto N = X.size();
33
34 // barycentric weights
35 Container<Number> W(N);
36 if (dist_type == dist::Type::UNIFORM) {
37 W[0] = 1;
38 for (SizeT j = 1; j <= N / 2; ++j) {
39 W[j] = -W[j-1] * (static_cast<Number>(N - j)) / static_cast<Number>(j);
40 }
41 for (SizeT j = N / 2 + 1; j < N; ++j) {
42 if (W[j-1] < 0) {
43 W[j] = std::abs(W[N-1-j]);
44 } else {
45 W[j] = -std::abs(W[N-1-j]);
46 }
47 }
48 // TODO: Investigate if normalization is needed.
49 // Normalization is needed because the middle weights grow as O(2^n),
50 // while the edges grow as O(1). Dividing by 2^(N/2) balances the exponents,
51 // reducing numerical instability.
52 // const Number norm_factor = std::pow(static_cast<Number>(2), static_cast<Number>(N / 2));
53 // for (SizeT j = 0; j < N; ++j) {
54 // W[j] /= norm_factor;
55 // }
56 } else if (dist_type == dist::Type::CHEBYSHEV || dist_type == dist::Type::CHEBYSHEV_STRETCHED) {
57 for (SizeT j = 0; j < N; ++j) {
58 W[j] = (j % 2 == 0 ? 1 : -1) * std::sin(((2 * static_cast<Number>(j) + 1) * M_PI) / (2 * static_cast<Number>(N)));
59 }
60 } else if (dist_type == dist::Type::CHEBYSHEV_AUGMENTED) {
61 W[0] = 1 / static_cast<Number>(2);
62 for (SizeT j = 1; j < N - 1; ++j) {
63 W[j] = (j % 2 == 0 ? 1 : -1) / ((N - 2) * std::sin(((static_cast<Number>(2*j - 1) * M_PI) / static_cast<Number>(2*N - 4))));
64 }
65 W[N-1] = (N % 2 == 0 ? -1 : 1) / static_cast<Number>(2);
66 } else if (dist_type == dist::Type::CHEBYSHEV_2) {
67 for (SizeT j = 0; j < N; ++j) {
68 W[j] = (j % 2 == 0 ? 1 : -1);
69 if (j == 0 || j == N - 1) {
70 W[j] /= 2;
71 }
72 }
73 } else if (dist_type == dist::Type::CHEBYSHEV_3 || dist_type == dist::Type::CHEBYSHEV_3_STRETCHED) {
74 for (SizeT j = 0; j < N; ++j) {
75 W[j] = (j % 2 == 0 ? 1 : -1) * std::cos((static_cast<Number>(2*j) * M_PI) / static_cast<Number>(2*N - 1) / 2);
76 if (j == 0) {
77 W[j] /= 2;
78 }
79 }
80 } else if (dist_type == dist::Type::CHEBYSHEV_4 || dist_type == dist::Type::CHEBYSHEV_4_STRETCHED) {
81 for (SizeT j = 0; j < N; ++j) {
82 W[j] = (j % 2 == 0 ? 1 : -1) * std::sin((static_cast<Number>(2*j + 1) * M_PI) / static_cast<Number>(2*N - 1) / 2);
83 if (j == N - 1) {
84 W[j] /= 2;
85 }
86 }
87 } else {
88 // The factor scales the weights to prevent excessive growth or shrinkage, reducing numerical instability.
89 // TODO: Investigate if normalization is needed and refine the scaling factor.
90 // const Number norm_factor = (X[N-1] - X[0]) / static_cast<Number>(2);
91 for (SizeT j = 0; j < N; ++j) {
92 W[j] = 1;
93 for (SizeT k = 0; k < N; ++k) {
94 if (j != k) {
95 // c[i] *= norm_factor / (X[j] - X[k]); // with normalization
96 W[j] /= (X[j] - X[k]);
97 }
98 }
99 }
100 }
101
102 const auto nn = xx.size();
103
104 Container<Number> result(nn);
105
106#if defined(_OPENMP) && !defined(ALFI_DISABLE_OPENMP)
107#pragma omp parallel for
108#endif
109 for (SizeT k = 0; k < nn; ++k) {
110 Number numerator = 0, denominator = 0;
111 SizeT exact_idx = N;
112
113 for (SizeT i = 0; i < N; ++i) {
114 if (util::numeric::are_equal(xx[k], X[i], epsilon)) {
115 exact_idx = i;
116 break;
117 }
118 const auto x_diff = xx[k] - X[i];
119 const auto temp = W[i] / x_diff;
120 numerator += temp * Y[i];
121 denominator += temp;
122 }
123
124 if (exact_idx != N) {
125 result[k] = Y[exact_idx];
126 } else {
127 result[k] = numerator / denominator;
128 }
129 }
130
131 return result;
132 }
133}
Type
Definition dist.h:9
@ UNIFORM
Definition dist.h:11
@ CHEBYSHEV_3_STRETCHED
Definition dist.h:19
@ CHEBYSHEV_4
Definition dist.h:20
@ CHEBYSHEV_4_STRETCHED
Definition dist.h:21
@ GENERAL
Definition dist.h:10
@ CHEBYSHEV_STRETCHED
Definition dist.h:15
@ CHEBYSHEV_AUGMENTED
Definition dist.h:16
@ CHEBYSHEV_3
Definition dist.h:18
@ CHEBYSHEV_2
Definition dist.h:17
@ CHEBYSHEV
Definition dist.h:14
Definition misc.h:9
Container< Number > barycentric(const Container< Number > &X, const Container< Number > &Y, const Container< Number > &xx, dist::Type dist_type=dist::Type::GENERAL, const Number &epsilon=std::numeric_limits< Number >::epsilon())
Definition misc.h:11
bool are_equal(const Number &a, const Number &b, const Number &epsilon=std::numeric_limits< Number >::epsilon())
Definition numeric.h:9
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