ALFI
Advanced Library for Function Interpolation
Loading...
Searching...
No Matches
linear.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 "../util/misc.h"
9
10namespace alfi::spline {
11 template <typename Number = DefaultNumber, template <typename, typename...> class Container = DefaultContainer>
13 public:
14 static Container<Number> compute_coeffs(const Container<Number>& X, const Container<Number>& Y) {
15 if (X.size() != Y.size()) {
16 std::cerr << "Error in function " << __FUNCTION__
17 << ": Vectors X (of size " << X.size()
18 << ") and Y (of size " << Y.size()
19 << ") are not the same size. Returning an empty array..." << std::endl;
20 return {};
21 }
22
23 const auto n = X.size();
24
25 if (n <= 2) {
26 if (n == 0) {
27 return {};
28 } else if (n == 1) {
29 return {Y[0]};
30 } else {
31 return {(Y[1] - Y[0]) / (X[1] - X[0]), Y[0]};
32 }
33 }
34
35 Container<Number> coeffs;
36
37 coeffs.resize(2 * (n - 1));
38
39 for (SizeT i = 0; i < n - 1; ++i) {
40 coeffs[2*i] = (Y[i+1] - Y[i]) / (X[i+1] - X[i]);
41 coeffs[2*i+1] = Y[i];
42 }
43
44 return coeffs;
45 }
46
47 LinearSpline() = default;
48
49 template <typename ContainerXType>
50 LinearSpline(ContainerXType&& X, const Container<Number>& Y) {
51 construct(std::forward<ContainerXType>(X), Y);
52 }
53
54 LinearSpline(const LinearSpline& other) = default;
55 LinearSpline(LinearSpline&& other) noexcept = default;
56
57 LinearSpline& operator=(const LinearSpline& other) = default;
58 LinearSpline& operator=(LinearSpline&& other) noexcept = default;
59
60 template <typename ContainerXType>
61 void construct(ContainerXType&& X, const Container<Number>& Y) {
62 if (X.size() != Y.size()) {
63 std::cerr << "Error in function " << __FUNCTION__
64 << ": Vectors X (of size " << X.size()
65 << ") and Y (of size " << Y.size()
66 << ") are not the same size. Doing nothing..." << std::endl;
67 return;
68 }
69 auto coeffs = compute_coeffs(X, Y);
70 if (coeffs.empty() && !X.empty()) {
71 std::cerr << "Error in function " << __FUNCTION__
72 << ": failed to construct coefficients. Not changing the object..." << std::endl;
73 return;
74 }
75 _X = std::forward<ContainerXType>(X);
76 _coeffs = std::move(coeffs);
77 }
78
79 Number eval(Number x) const {
80 return eval(x, std::distance(_X.begin(), util::misc::first_leq_or_begin(_X.begin(), _X.end(), x)));
81 }
82 Number eval(Number x, SizeT segment) const {
83 if (_coeffs.empty()) {
84 return NAN;
85 } else if (_coeffs.size() == 1) {
86 return _coeffs[0];
87 }
88 segment = std::clamp(segment, static_cast<SizeT>(0), static_cast<SizeT>(_X.size() - 2));
89 x = x - _X[segment];
90 return _coeffs[2*segment] * x + _coeffs[2*segment+1];
91 }
92
93 Container<Number> eval(const Container<Number>& xx, bool sorted = true) const {
94 Container<Number> result(xx.size());
95 if (sorted) {
96 for (SizeT i = 0, i_x = 0; i < xx.size(); ++i) {
97 const Number x = xx[i];
98 while (i_x + 1 < _X.size() && x >= _X[i_x+1])
99 ++i_x;
100 result[i] = eval(x, i_x);
101 }
102 } else {
103 for (SizeT i = 0; i < xx.size(); ++i) {
104 result[i] = eval(xx[i]);
105 }
106 }
107 return result;
108 }
109
110 Number operator()(Number x) const {
111 return eval(x);
112 }
113 Container<Number> operator()(const Container<Number>& xx) const {
114 return eval(xx);
115 }
116
117 const Container<Number>& X() const & {
118 return _X;
119 }
120 Container<Number>&& X() && {
121 return std::move(_X);
122 }
123
124 const Container<Number>& coeffs() const & {
125 return _coeffs;
126 }
127 Container<Number>&& coeffs() && {
128 return std::move(_coeffs);
129 }
130
131 static std::pair<SizeT, SizeT> segment(SizeT index) {
132 return {2*index, 2*(index+1)};
133 }
134
135 private:
136 Container<Number> _X = {};
137 Container<Number> _coeffs = {};
138 };
139}
Number operator()(Number x) const
Definition linear.h:110
const Container< Number > & coeffs() const &
Definition linear.h:124
LinearSpline(const LinearSpline &other)=default
void construct(ContainerXType &&X, const Container< Number > &Y)
Definition linear.h:61
LinearSpline(LinearSpline &&other) noexcept=default
LinearSpline & operator=(const LinearSpline &other)=default
static Container< Number > compute_coeffs(const Container< Number > &X, const Container< Number > &Y)
Definition linear.h:14
const Container< Number > & X() const &
Definition linear.h:117
Container< Number > && coeffs() &&
Definition linear.h:127
LinearSpline & operator=(LinearSpline &&other) noexcept=default
LinearSpline(ContainerXType &&X, const Container< Number > &Y)
Definition linear.h:50
Container< Number > operator()(const Container< Number > &xx) const
Definition linear.h:113
Container< Number > eval(const Container< Number > &xx, bool sorted=true) const
Definition linear.h:93
Container< Number > && X() &&
Definition linear.h:120
Number eval(Number x, SizeT segment) const
Definition linear.h:82
static std::pair< SizeT, SizeT > segment(SizeT index)
Definition linear.h:131
Number eval(Number x) const
Definition linear.h:79
Definition cubic.h:13
Iterator first_leq_or_begin(Iterator begin, Iterator end, const T &value)
Definition misc.h:27
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