ALFI
Advanced Library for Function Interpolation
Loading...
Searching...
No Matches
step.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <iostream>
5#include <cmath>
6#include <variant>
7
8#include "../config.h"
9#include "../util/misc.h"
10
11namespace alfi::spline {
12 template <typename Number = DefaultNumber, template <typename, typename...> class Container = DefaultContainer>
13 class StepSpline {
14 public:
15 struct Types final {
16 struct Left final {};
17 struct Middle final {};
18 struct Right final {};
19 struct Fraction final {
20 explicit Fraction(Number fraction) : f(std::move(fraction)) {}
21 Number f;
22 };
23 struct Proportion final {
24 Proportion(Number left, Number right) : l(std::move(left)), r(std::move(right)) {}
25 Number l, r;
26 };
27 using Default = Left;
28 };
29
30 using Type = std::variant<typename Types::Left,
31 typename Types::Middle,
32 typename Types::Right,
33 typename Types::Fraction,
34 typename Types::Proportion>;
35
36 StepSpline() = default;
37
38 template <typename ContainerXType, typename ContainerYType>
39 StepSpline(ContainerXType&& X, ContainerYType&& Y, Type type = typename Types::Default{}) {
40 construct(std::forward<ContainerXType>(X), std::forward<ContainerYType>(Y), type);
41 }
42
43 StepSpline(const StepSpline& other) = default;
44 StepSpline(StepSpline&& other) noexcept = default;
45
46 StepSpline& operator=(const StepSpline& other) = default;
47 StepSpline& operator=(StepSpline&& other) noexcept = default;
48
49 template <typename ContainerXType, typename ContainerYType>
50 void construct(ContainerXType&& X, ContainerYType&& Y, Type type = typename Types::Default{}) {
51 if (X.size() != Y.size()) {
52 std::cerr << "Error in function " << __FUNCTION__
53 << ": Vectors X (of size " << X.size()
54 << ") and Y (of size " << Y.size()
55 << ") are not the same size. Doing nothing..." << std::endl;
56 return;
57 }
58 _type = type;
59 _X = std::forward<ContainerXType>(X);
60 _Y = std::forward<ContainerYType>(Y);
61 }
62
63 Number eval(Number x) const {
64 return eval(x, std::distance(_X.begin(), util::misc::first_leq_or_begin(_X.begin(), _X.end(), x)));
65 }
66 Number eval(Number x, SizeT segment) const {
67 if (_Y.empty()) {
68 return NAN;
69 } else if (_Y.size() == 1) {
70 return _Y[0];
71 }
72 segment = std::clamp(segment, static_cast<SizeT>(0), static_cast<SizeT>(_X.size() - 2));
73 if (x <= _X[segment]) {
74 return _Y[segment];
75 }
76 if (x >= _X[segment+1]) {
77 return _Y[segment+1];
78 }
79 return std::visit(util::misc::overload{
80 [&](const typename Types::Left&) { return _Y[segment]; },
81 [&](const typename Types::Middle&) { return (_Y[segment] + _Y[segment+1]) / 2; },
82 [&](const typename Types::Right&) { return _Y[segment+1]; },
83 [&](const typename Types::Fraction& f) { return _Y[segment] + f.f*(_Y[segment+1] - _Y[segment]); },
84 [&](const typename Types::Proportion& p) { return (p.r*_Y[segment] + p.l*_Y[segment+1]) / (p.l + p.r); },
85 }, _type);
86 }
87
88 Container<Number> eval(const Container<Number>& xx, bool sorted = true) const {
89 Container<Number> result(xx.size());
90 if (sorted) {
91 for (SizeT i = 0, i_x = 0; i < xx.size(); ++i) {
92 const Number x = xx[i];
93 while (i_x + 1 < _X.size() && x >= _X[i_x+1])
94 ++i_x;
95 result[i] = eval(x, i_x);
96 }
97 } else {
98 for (SizeT i = 0; i < xx.size(); ++i) {
99 result[i] = eval(xx[i]);
100 }
101 }
102 return result;
103 }
104
105 Number operator()(Number x) const {
106 return eval(x);
107 }
108 Container<Number> operator()(const Container<Number>& xx) const {
109 return eval(xx);
110 }
111
112 Type type() const {
113 return _type;
114 }
115
116 const Container<Number>& X() const & {
117 return _X;
118 }
119 Container<Number>&& X() && {
120 return std::move(_X);
121 }
122
123 const Container<Number>& Y() const & {
124 return _Y;
125 }
126 Container<Number>&& Y() && {
127 return std::move(_Y);
128 }
129
130 private:
131 Type _type = typename Types::Default{};
132 Container<Number> _X = {};
133 Container<Number> _Y = {};
134 };
135}
Number eval(Number x, SizeT segment) const
Definition step.h:66
Number eval(Number x) const
Definition step.h:63
std::variant< typename Types::Left, typename Types::Middle, typename Types::Right, typename Types::Fraction, typename Types::Proportion > Type
Definition step.h:30
Container< Number > eval(const Container< Number > &xx, bool sorted=true) const
Definition step.h:88
const Container< Number > & Y() const &
Definition step.h:123
Container< Number > operator()(const Container< Number > &xx) const
Definition step.h:108
StepSpline(ContainerXType &&X, ContainerYType &&Y, Type type=typename Types::Default{})
Definition step.h:39
void construct(ContainerXType &&X, ContainerYType &&Y, Type type=typename Types::Default{})
Definition step.h:50
Container< Number > && Y() &&
Definition step.h:126
Type type() const
Definition step.h:112
Number operator()(Number x) const
Definition step.h:105
StepSpline(const StepSpline &other)=default
const Container< Number > & X() const &
Definition step.h:116
StepSpline(StepSpline &&other) noexcept=default
StepSpline & operator=(const StepSpline &other)=default
StepSpline & operator=(StepSpline &&other) noexcept=default
Container< Number > && X() &&
Definition step.h:119
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
Fraction(Number fraction)
Definition step.h:20
Proportion(Number left, Number right)
Definition step.h:24
Left Default
Definition step.h:27
Definition misc.h:20