BSplinebasis
Loading...
Searching...
No Matches
interpolation.h
1/*
2 * This file contains additional numerical interpolation routines for the
3 * splines. The linear algebra routines can be supplied via the implementation
4 * of a Solver class (a subclass of internal::ISolver<T>. Implementations based
5 * on armadillo and eigen are provided and can be used by defining
6 * BSPLINE_INTERPOLATION_USE_ARMADILLO or
7 * BSPLINE_INTERPOLATION_USE_EIGEN , respectively.
8 *
9 * ########################################################################
10 * The contents of this file is free and unencumbered software released into the
11 * public domain. For more information, please refer to <http://unlicense.org/>
12 * ########################################################################
13 */
14
15#ifndef BSPLINE_INTERPOLATION_INTERPOLATION_H
16#define BSPLINE_INTERPOLATION_INTERPOLATION_H
17
18#include <bspline/Spline.h>
19#include <bspline/exceptions/BSplineException.h>
20#include <bspline/internal/misc.h>
21#include <bspline/support/Support.h>
22
23#ifdef BSPLINE_INTERPOLATION_USE_EIGEN
24#include <eigen3/Eigen/Dense>
25#endif
26
27#ifdef BSPLINE_INTERPOLATION_USE_ARMADILLO
28#include <armadillo>
29#endif
30
35using namespace bspline::exceptions;
36
43enum class Node { FIRST, LAST };
44
51template <typename T>
52struct Boundary {
54 Node node = Node::FIRST;
56 size_t derivative = 1;
58 T value = static_cast<T>(0);
59};
60
61#ifndef BSPLINE_DOXYGEN_IGNORE
62namespace internal {
72template <typename T>
73class ISolver {
74 public:
78 ISolver() = default;
79
85 ISolver([[maybe_unused]] size_t problemsize){};
86 virtual ~ISolver() = default;
87
95 virtual T &M(size_t i, size_t j) = 0;
96
103 virtual T &b(size_t i) = 0;
104
108 virtual void solve() = 0;
109
116 virtual T &x(size_t i) = 0;
117};
118
127template <typename T, size_t order>
128std::array<Boundary<T>, order - 1> defaultBoundaries() {
129 static_assert(order >= 1, "Order may not be zero.");
130 std::array<Boundary<T>, order - 1> ret;
131 for (size_t i = 0; i < order - 1; i++) {
132 if (i % 2 == 0) {
133 ret[i] = Boundary<T>{/*.node = */ Node::FIRST,
134 /*.derivative = */ i / 2 + 1,
135 /*.value = */ static_cast<T>(0)};
136 } else {
137 ret[i] = Boundary<T>{/*.node = */ Node::LAST,
138 /*.derivative = */ (i - 1) / 2 + 1,
139 /*.value = */ static_cast<T>(0)};
140 }
141 }
142 return ret;
143}
144} // end namespace internal
145
147#endif // BSPLINE_DOXYGEN_IGNORE
148
167template <typename T, size_t order, class Solver>
169 Support<T> x, const std::vector<T> &y,
170 const std::array<Boundary<T>, order - 1> &boundaries =
171 internal::defaultBoundaries<T, order>()) {
172 static_assert(order >= 1, "Order may not be zero.");
173 static_assert(std::is_base_of<internal::ISolver<T>, Solver>::value,
174 "Solver must be a subclass of internal::ISolver<T>.");
175
176 if (x.size() != y.size()) {
177 throw BSplineException(ErrorCode::INCONSISTENT_DATA);
178 }
179
180 if (x.size() < 2) {
181 throw BSplineException(
182 ErrorCode::UNDETERMINED,
183 "At least two grid points needed for interpolation.");
184 }
185
186 constexpr size_t NUM_COEFFS = order + 1;
187
188 Solver s(NUM_COEFFS * (x.size() - 1));
189
190 size_t row_counter = 0;
191 {
192 const T dx1 = (x[0] - x[1]) / static_cast<T>(2);
193 {
194 T power_of_dx1 = static_cast<T>(1);
195 for (size_t i = 0; i <= order; i++) {
197 power_of_dx1 *= dx1;
198 }
199 s.b(row_counter) = y.front();
200 row_counter++;
201 }
202
203 for (const auto &bo : boundaries) {
204 if (bo.derivative == 0 || bo.derivative > order) {
205 throw BSplineException(ErrorCode::UNDETERMINED,
206 "Unsupported order of the derivative.");
207 }
208 if (bo.node == Node::FIRST) {
209 T power_of_dx1 = static_cast<T>(1);
210 for (size_t i = bo.derivative; i <= order; i++) {
211 s.M(row_counter, i) =
212 bspline::internal::facultyRatio<T>(i, i - bo.derivative) *
214 power_of_dx1 *= dx1;
215 }
216 s.b(row_counter) = bo.value;
217 row_counter++;
218 }
219 }
220 }
221
222 for (size_t c = 1; c + 1 < x.size(); c++) {
223 const T dx1 = (x[c] - x[c - 1]) / static_cast<T>(2);
224 const T dx2 = (x[c] - x[c + 1]) / static_cast<T>(2);
225
226 {
227 T power_of_dx1 = static_cast<T>(1);
228 for (size_t i = 0; i <= order; i++) {
229 s.M(row_counter, NUM_COEFFS * (c - 1) + i) = power_of_dx1;
230 power_of_dx1 *= dx1;
231 }
232 s.b(row_counter) = y[c];
233 row_counter++;
234 }
235
236 {
237 T power_of_dx2 = static_cast<T>(1);
238 for (size_t i = 0; i <= order; i++) {
240 power_of_dx2 *= dx2;
241 }
242 s.b(row_counter) = y[c];
243 row_counter++;
244 }
245
246 for (size_t deriv = 1; deriv < order; deriv++) {
247 T power_of_dx1 = static_cast<T>(1);
248 T power_of_dx2 = static_cast<T>(1);
249 for (size_t i = deriv; i <= order; i++) {
250 s.M(row_counter, NUM_COEFFS * (c - 1) + i) =
251 bspline::internal::facultyRatio<T>(i, i - deriv) * power_of_dx1;
252 s.M(row_counter, NUM_COEFFS * c + i) =
253 -bspline::internal::facultyRatio<T>(i, i - deriv) * power_of_dx2;
254 power_of_dx1 *= dx1;
255 power_of_dx2 *= dx2;
256 }
257 row_counter++;
258 }
259 }
260
261 {
262 const T dx2 = (x.back() - x[x.size() - 2]) / static_cast<T>(2);
263 {
264 T power_of_dx2 = static_cast<T>(1);
265 for (size_t i = 0; i <= order; i++) {
266 s.M(row_counter, NUM_COEFFS * (x.size() - 2) + i) = power_of_dx2;
267 power_of_dx2 *= dx2;
268 }
269 s.b(row_counter) = y.back();
270 row_counter++;
271 }
272
273 for (const auto &bo : boundaries) {
274 if (bo.node == Node::LAST) {
275 T power_of_dx2 = static_cast<T>(1);
276 for (size_t i = bo.derivative; i <= order; i++) {
277 s.M(row_counter, NUM_COEFFS * (x.size() - 2) + i) =
278 bspline::internal::facultyRatio<T>(i, i - bo.derivative) *
280 power_of_dx2 *= dx2;
281 }
282 s.b(row_counter) = bo.value;
283 row_counter++;
284 }
285 }
286 }
287
288 if (row_counter != NUM_COEFFS * (x.size() - 1)) {
289 throw BSplineException(ErrorCode::UNDETERMINED);
290 }
291
292 s.solve();
293
294 std::vector<std::array<T, NUM_COEFFS>> coeffs((x.size() - 1));
295 for (size_t i = 0; i + 1 < x.size(); i++) {
296 std::array<T, NUM_COEFFS> &coeffsi = coeffs[i];
297 for (size_t j = 0; j < NUM_COEFFS; j++)
298 coeffsi[j] = s.x(NUM_COEFFS * i + j);
299 }
300 return bspline::Spline<T, order>(std::move(x), std::move(coeffs));
301}
302
303#ifdef BSPLINE_INTERPOLATION_USE_ARMADILLO
304
322template <size_t order>
324 Support<double> x, const std::vector<double> &y,
325 const std::array<Boundary<double>, order - 1> &boundaries =
326 internal::defaultBoundaries<double, order>()) {
327 class ArmadilloSolver final : public internal::ISolver<double> {
328 private:
329 arma::mat _M;
330 arma::vec _b, _x;
331
332 public:
334 : _M(arma::mat(problemsize, problemsize, arma::fill::zeros)),
335 _b(arma::vec(problemsize, arma::fill::zeros)){};
336 ~ArmadilloSolver() override = default;
337 double &M(size_t i, size_t j) override { return _M(i, j); };
338 double &b(size_t i) override { return _b(i); };
339 void solve() override { _x = arma::solve(_M, _b); };
340 double &x(size_t i) override { return _x(i); };
341 };
342
344 boundaries);
345}
346#endif
347
348#ifdef BSPLINE_INTERPOLATION_USE_EIGEN
367template <typename T, size_t order>
369 Support<T> x, const std::vector<T> &y,
370 const std::array<Boundary<T>, order - 1> &boundaries =
371 internal::defaultBoundaries<T, order>()) {
372 using DeMat = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;
373 using DeVec = Eigen::Matrix<T, Eigen::Dynamic, 1>;
374
375 class EigenSolver final : public internal::ISolver<T> {
376 private:
377 DeMat _M;
378 DeVec _b, _x;
379
380 public:
382 : _M(DeMat::Zero(problemsize, problemsize)),
383 _b(DeVec::Zero(problemsize)){};
384 ~EigenSolver() override = default;
385 T &M(size_t i, size_t j) override { return _M(i, j); };
386 T &b(size_t i) override { return _b(i); };
387 void solve() override { _x = _M.colPivHouseholderQr().solve(_b); };
388 T &x(size_t i) override { return _x(i); };
389 };
390
392}
393
394#endif
395
396} // namespace bspline::interpolation
397#endif // SPLINE_INTERPOLATION_H
The main exception class.
Definition BSplineException.h:84
Represents a global Grid.
Definition Grid.h:27
size_t size() const
Returns the number of elements of the Grid.
Definition Grid.h:169
const T & back() const
Returns a reference to the last element of the Grid.
Definition Grid.h:244
const T & front() const
Returns a reference to the first element of the Grid.
Definition Grid.h:231
Represents the Spline's Support.
Definition Support.h:33
Exceptions and error codes.
Definition BSplineException.h:19
Code to interpolate data using the bspline::Spline.
Definition interpolation.h:34
bspline::Spline< T, order > interpolateUsingEigen(Support< T > x, const std::vector< T > &y, const std::array< Boundary< T >, order - 1 > &boundaries=internal::defaultBoundaries< T, order >())
Interpolation using eigen solver.
Definition interpolation.h:368
bspline::Spline< T, order > interpolate(Support< T > x, const std::vector< T > &y, const std::array< Boundary< T >, order - 1 > &boundaries=internal::defaultBoundaries< T, order >())
Interpolation using generic Solver.
Definition interpolation.h:168
Node
Node marker for boundary conditions.
Definition interpolation.h:43
bspline::Spline< double, order > interpolateUsingArmadillo(Support< double > x, const std::vector< double > &y, const std::array< Boundary< double >, order - 1 > &boundaries=internal::defaultBoundaries< double, order >())
Interpolation using armadillo Solver.
Definition interpolation.h:323
A boundary condition.
Definition interpolation.h:52
T value
Definition interpolation.h:58
size_t derivative
Definition interpolation.h:56
Node node
Definition interpolation.h:54