smooth
A C++ library for Lie theory
Loading...
Searching...
No Matches
basis.hpp
Go to the documentation of this file.
1// Copyright (C) 2021-2022 Petter Nilsson. MIT License.
2
3#pragma once
4
10#include <cassert>
11#include <limits>
12
13#include "static_matrix.hpp"
14
15SMOOTH_BEGIN_NAMESPACE
16
26template<std::size_t K, typename Scalar>
28{
30
31 if (p > K) { return ret; }
32
33 for (auto i = 0u; i < p; ++i) { ret[0][i] = Scalar(0); }
34 Scalar P1 = 1;
35 std::size_t P2 = 1;
36 for (auto j = 2u; j <= p; ++j) { P2 *= j; }
37 ret[0][p] = P1 * static_cast<Scalar>(P2);
38 for (auto i = p + 1; i <= K; ++i) {
39 P1 *= u;
40 P2 *= i;
41 P2 /= i - p;
42 ret[0][i] = P1 * static_cast<Scalar>(P2);
43 }
44
45 return ret;
46}
47
60template<std::size_t K, std::size_t P, typename Scalar>
62{
64 for (auto p = 0u; p <= P; ++p) { ret[p] = monomial_derivative<K, Scalar>(u, p)[0]; }
65 return ret;
66}
67
68namespace detail {
69
74template<std::size_t K, typename Scalar = double>
76{
78 if constexpr (K == 0) {
79 ret[0][0] = 1;
80 return ret;
81 } else {
82 const auto coeff_mat_km1 = bspline_basis<K - 1, Scalar>();
85
86 for (auto i = 0u; i != K; ++i) {
87 for (auto j = 0u; j != K; ++j) {
88 low[i][j] = coeff_mat_km1[i][j];
89 high[i + 1][j] = coeff_mat_km1[i][j];
90 }
91 }
92
93 for (auto k = 0u; k != K; ++k) {
94 left[k][k + 1] = static_cast<Scalar>(K - (k + 1)) / static_cast<Scalar>(K);
95 left[k][k] = Scalar(1) - left[k][k + 1];
96
97 right[k][k + 1] = Scalar(1) / static_cast<Scalar>(K);
98 right[k][k] = -right[k][k + 1];
99 }
100
101 return low * left + high * right;
102 }
103}
104
109template<std::size_t K, typename Scalar = double>
111{
113 if constexpr (K == 0) {
114 ret[0][0] = 1;
115 return ret;
116 } else {
117 constexpr auto coeff_mat_km1 = bernstein_basis<K - 1, Scalar>();
120
121 for (auto i = 0u; i != K; ++i) {
122 for (auto j = 0u; j != K; ++j) {
123 low[i][j] = coeff_mat_km1[i][j];
124 high[i + 1][j] = coeff_mat_km1[i][j];
125 }
126 }
127
128 for (auto k = 0u; k != K; ++k) {
129 left[k][k] = Scalar(1);
130
131 right[k][k] = Scalar(-1);
132 right[k][k + 1] = Scalar(1);
133 }
134
135 return low * left + high * right;
136 }
137}
138
143template<std::size_t K, typename Scalar = double>
145{
147 ret[0][0] = 1;
148
149 if constexpr (K > 0) { ret[1][1] = 2; }
150
151 if constexpr (K > 1) {
152 for (auto k = 2u; k < K + 1; ++k) {
153 for (auto i = 0u; i < k; ++i) { ret[i + 1][k] += 2 * ret[i][k - 1]; }
154 for (auto i = 0u; i + 1 < k; ++i) { ret[i][k] -= 2 * (k - 1) * ret[i][k - 2]; }
155 }
156 }
157 return ret;
158}
159
164template<std::size_t K, typename Scalar = double>
166{
168 ret[0][0] = 1;
169
170 if constexpr (K > 0) {
171 ret[0][1] = 1.;
172 ret[1][1] = -1;
173 }
174
175 if constexpr (K > 1) {
176 for (auto k = 2u; k < K + 1; ++k) {
177 for (auto i = 0u; i < k; ++i) {
178 ret[i][k] += (2 * k - 1) * ret[i][k - 1] / k;
179 ret[i + 1][k] -= ret[i][k - 1] / k;
180 }
181 for (auto i = 0u; i + 1 < k; ++i) { ret[i][k] -= static_cast<double>(k - 1) * ret[i][k - 2] / k; }
182 }
183 }
184 return ret;
185}
186
198template<std::size_t K, typename Scalar = double>
199constexpr StaticMatrix<Scalar, K + 1, K + 1> jacobi_basis(double alpha, double beta)
200{
202 ret[0][0] = 1;
203
204 if constexpr (K > 0) {
205 ret[0][1] = alpha + 1. - (alpha + beta + 2) / 2;
206 ret[1][1] = (alpha + beta + 2.) / 2;
207 }
208
209 if constexpr (K > 1) {
210 for (auto k = 2u; k < K + 1; ++k) {
211 const auto frac = 1. / ((2 * k) * (k + alpha + beta) * (2 * k + alpha + beta - 2));
212 const auto c1 = (2 * k + alpha + beta - 1) * (alpha * alpha - beta * beta);
213 const auto c2 = (2 * k + alpha + beta - 1) * (2 * k + alpha + beta) * (2 * k + alpha + beta - 2);
214 const auto c3 = 2 * (k + alpha - 1) * (k + beta - 1) * (2 * k + alpha + beta);
215 for (auto i = 0u; i < k; ++i) {
216 ret[i][k] += c1 * ret[i][k - 1] * frac;
217 ret[i + 1][k] += c2 * ret[i][k - 1] * frac;
218 }
219 for (auto i = 0u; i + 1 < k; ++i) { ret[i][k] -= c3 * ret[i][k - 2] * frac; }
220 }
221 }
222
223 return ret;
224}
225
226} // namespace detail
227
229enum class PolynomialBasis {
231 Bernstein,
233 Bspline,
239 Hermite,
241 Laguerre,
243 Legendre,
245 Monomial,
246};
247
263template<PolynomialBasis Basis, std::size_t K, typename Scalar = double>
265{
266 if constexpr (Basis == PolynomialBasis::Monomial) {
268 for (auto k = 0u; k <= K; ++k) { ret[k][k] = Scalar(1); }
269 return ret;
270 }
271 if constexpr (Basis == PolynomialBasis::Bernstein) { return detail::bernstein_basis<K, Scalar>(); }
272 if constexpr (Basis == PolynomialBasis::Laguerre) { return detail::laguerre_basis<K, Scalar>(); }
273 if constexpr (Basis == PolynomialBasis::Hermite) { return detail::hermite_basis<K, Scalar>(); }
274 if constexpr (Basis == PolynomialBasis::Legendre) { return detail::jacobi_basis<K, Scalar>(0, 0); }
275 if constexpr (Basis == PolynomialBasis::Chebyshev1st) {
276 auto ret = detail::jacobi_basis<K, Scalar>(-0.5, -0.5);
277 const auto fac = monomial_derivative<K>(1.) * ret;
278 for (auto k = 0u; k < K + 1; ++k) {
279 for (auto r = 0u; r < K + 1; ++r) { ret[r][k] /= fac[0][k]; }
280 }
281 return ret;
282 }
283 if constexpr (Basis == PolynomialBasis::Chebyshev2nd) {
284 auto ret = detail::jacobi_basis<K, Scalar>(0.5, 0.5);
285 const auto fac = monomial_derivative<K>(1.) * ret;
286 for (auto k = 0u; k < K + 1; ++k) {
287 for (auto r = 0u; r < K + 1; ++r) { ret[r][k] *= static_cast<Scalar>(k + 1) / fac[0][k]; }
288 }
289 return ret;
290 }
291 if constexpr (Basis == PolynomialBasis::Bspline) { return detail::bspline_basis<K, Scalar>(); }
292}
293
312template<std::size_t K, std::ranges::random_access_range R, typename Scalar = std::ranges::range_value_t<R>>
314{
316
317 for (auto row = 0u; row < K + 1; ++row) {
318 ret[row][0] = 1;
319 for (auto col = 0u; col < K + 1; ++col) {
320 if (col != row) {
321 const auto row_copy = ret[row];
322 ret[row].fill(0);
323 for (auto i = 0u; i <= col - (col > row ? 1 : 0); ++i) {
324 ret[row][i + 1] += row_copy[i] / (*(ts.begin() + row) - *(ts.begin() + col));
325 ret[row][i] -= *(ts.begin() + col) * row_copy[i] / (*(ts.begin() + row) - *(ts.begin() + col));
326 }
327 }
328 }
329 }
330
331 return ret.transpose();
332}
333
345template<std::size_t K, std::size_t N, typename Scalar, std::ranges::sized_range R>
348{
349 assert(std::ranges::size(ts) == N);
350
352
353 for (auto j = 0u; const auto t : ts) {
354 const auto U = monomial_derivative<K>(t, 1);
355 const auto U_B = U * B;
356 for (auto i = 0u; i < K + 1; ++i) { ret[i][j] = U_B[0][i]; }
357 ++j;
358 }
359
360 return ret;
361}
362
381template<PolynomialBasis Basis, std::size_t K, typename Scalar = double>
383{
384 auto M = polynomial_basis<Basis, K, Scalar>();
385 for (auto i = 0u; i != K + 1; ++i) {
386 for (auto j = 0u; j != K; ++j) { M[i][K - 1 - j] += M[i][K - j]; }
387 }
388 return M;
389}
390
399template<std::size_t K, std::size_t P, typename Scalar = double>
401{
403 for (auto i = 0u; i <= K; ++i) {
404 for (auto j = i; j <= K; ++j) {
405 if (i >= P && j >= P) {
406 std::size_t c = 1;
407 for (auto _i = i - P + 1; _i <= i; ++_i) { c *= _i; }
408 for (auto _j = j - P + 1; _j <= j; ++_j) { c *= _j; }
409 ret[i][j] = static_cast<Scalar>(c) / static_cast<Scalar>(i + j - 2 * P + 1);
410 } else {
411 ret[i][j] = 0;
412 }
413 ret[j][i] = ret[i][j];
414 }
415 }
416 return ret;
417}
418
427inline constexpr double integrate_absolute_polynomial(double t0, double t1, double A, double B, double C)
428{
429 // location of first zero (if any)
430 double mid1 = std::numeric_limits<double>::infinity();
431 // location of second zero (if any)
432 double mid2 = std::numeric_limits<double>::infinity();
433
434 if (std::abs(A) < 1e-9 && std::abs(B) > 1e-9) {
435 // linear non-constant function
436 mid1 = std::clamp(-C / B, t0, t1);
437 } else if (std::abs(A) > 1e-9) {
438 // quadratic function
439 const double res = B * B / (4 * A * A) - C / A;
440
441 if (res > 0) {
442 mid1 = -B / (2 * A) - std::sqrt(res);
443 mid2 = -B / (2 * A) + std::sqrt(res);
444 }
445 }
446
447 const auto integ = [&](double u) { return A * u * u * u / 3 + B * u * u / 2 + C * u; };
448
449 const double mid1cl = std::clamp(mid1, t0, t1);
450 const double mid2cl = std::clamp(mid2, t0, t1);
451
452 return std::abs(integ(t1) - integ(t0) + 2 * integ(mid1cl) - 2 * integ(mid2cl));
453}
454
455SMOOTH_END_NAMESPACE
constexpr StaticMatrix< Scalar, K+1, K+1 > jacobi_basis(double alpha, double beta)
Jacobi basis coefficient matrix.
Definition basis.hpp:199
constexpr StaticMatrix< Scalar, K+1, K+1 > monomial_integral()
Calculate integral over matrix of squared monomial P-derivatives.
Definition basis.hpp:400
SMOOTH_BEGIN_NAMESPACE constexpr StaticMatrix< Scalar, 1, K+1 > monomial_derivative(Scalar u, std::size_t p=0)
Monomial derivative (compile-time version).
Definition basis.hpp:27
constexpr StaticMatrix< Scalar, P+1, K+1 > monomial_derivatives(Scalar u)
Monomial derivatives up to order.
Definition basis.hpp:61
constexpr StaticMatrix< Scalar, K+1, K+1 > lagrange_basis(const R &ts)
Lagrange polynomial basis coefficients.
Definition basis.hpp:313
constexpr double integrate_absolute_polynomial(double t0, double t1, double A, double B, double C)
Integrate the absolute value of a quadratic 1D polynomial.
Definition basis.hpp:427
constexpr StaticMatrix< Scalar, K+1, K+1 > bernstein_basis()
Bernstein basis coefficient matrix.
Definition basis.hpp:110
constexpr StaticMatrix< Scalar, K+1, N > polynomial_basis_derivatives(const StaticMatrix< Scalar, K+1, K+1 > &B, const R &ts)
Polynomial basis derivative coefficients.
Definition basis.hpp:347
constexpr StaticMatrix< Scalar, K+1, K+1 > bspline_basis()
Bspline basis coefficient matrix.
Definition basis.hpp:75
constexpr StaticMatrix< Scalar, K+1, K+1 > hermite_basis()
Hermite basis coefficient matrix.
Definition basis.hpp:144
constexpr StaticMatrix< Scalar, K+1, K+1 > polynomial_basis()
Compile-time coefficient matrix for given basis.
Definition basis.hpp:264
constexpr StaticMatrix< Scalar, K+1, K+1 > polynomial_cumulative_basis()
Cumulative coefficient matrix for given basis.
Definition basis.hpp:382
PolynomialBasis
Polynomial basis types.
Definition basis.hpp:229
@ Bspline
Basis on [0, 1] with left to right ordering.
@ Bernstein
Basis on [0, 1] with left to right ordering.
@ Hermite
Orthogonal basis on [-inf, inf] w.r.t the weight exp(-x^2)
@ Laguerre
Orthogonal basis on [0, inf] w.r.t the weight exp(-x)
@ Monomial
The standard monomial basis (1, x, x^2, ...)
@ Chebyshev2nd
Orthogonal basis on [-1, 1] w.r.t the weight sqrt(1-x^2)
@ Chebyshev1st
Orthogonal basis on [-1, 1] w.r.t the weight 1 / sqrt(1-x^2)
@ Legendre
Orthogonal basis on [-1, 1].
constexpr StaticMatrix< Scalar, K+1, K+1 > laguerre_basis()
Laguerre basis coefficient matrix.
Definition basis.hpp:165
typename traits::man< M >::Scalar Scalar
Manifold scalar type.
Definition manifold.hpp:88
Utilities for compile-time matrix algebra.
Elementary structure for compile-time matrix algebra.
constexpr StaticMatrix< _Scalar, _Rows, _Cols > transpose() const
Matrix transpose.