|
17 | 17 | */ |
18 | 18 |
|
19 | 19 | #include <gtsam/basis/Chebyshev2.h> |
| 20 | + |
| 21 | +#include <Eigen/Dense> |
| 22 | + |
20 | 23 | #include <cassert> |
21 | 24 |
|
22 | 25 | namespace gtsam { |
@@ -93,24 +96,20 @@ namespace { |
93 | 96 | // Helper function to calculate a row of the differentiation matrix, [-1,1] interval |
94 | 97 | Vector differentiationMatrixRow(size_t N, const Vector& points, size_t i) { |
95 | 98 | Vector row(N); |
| 99 | + const size_t K = N - 1; |
96 | 100 | double xi = points(i); |
97 | | - double ci = (i == 0 || i == N - 1) ? 2. : 1.; |
98 | 101 | for (size_t j = 0; j < N; j++) { |
99 | | - if (i == 0 && j == 0) { |
100 | | - // we reverse the sign since we order the cheb points from -1 to 1 |
101 | | - row(j) = -(ci * (N - 1) * (N - 1) + 1) / 6.0; |
102 | | - } |
103 | | - else if (i == N - 1 && j == N - 1) { |
104 | | - // we reverse the sign since we order the cheb points from -1 to 1 |
105 | | - row(j) = (ci * (N - 1) * (N - 1) + 1) / 6.0; |
106 | | - } |
107 | | - else if (i == j) { |
108 | | - double xi2 = xi * xi; |
109 | | - row(j) = -xi / (2 * (1 - xi2)); |
| 102 | + if (i == j) { |
| 103 | + // Diagonal elements |
| 104 | + if (i == 0 || i == K) |
| 105 | + row(j) = (i == 0 ? -1 : 1) * (2.0 * K * K + 1) / 6.0; |
| 106 | + else |
| 107 | + row(j) = -xi / (2.0 * (1.0 - xi * xi)); |
110 | 108 | } |
111 | 109 | else { |
112 | 110 | double xj = points(j); |
113 | | - double cj = (j == 0 || j == N - 1) ? 2. : 1.; |
| 111 | + double ci = (i == 0 || i == K) ? 2. : 1.; |
| 112 | + double cj = (j == 0 || j == K) ? 2. : 1.; |
114 | 113 | double t = ((i + j) % 2) == 0 ? 1 : -1; |
115 | 114 | row(j) = (ci / cj) * t / (xi - xj); |
116 | 115 | } |
@@ -225,6 +224,43 @@ Chebyshev2::DiffMatrix Chebyshev2::DifferentiationMatrix(size_t N, double a, dou |
225 | 224 | return DifferentiationMatrix(N) / ((b - a) / 2.0); |
226 | 225 | } |
227 | 226 |
|
| 227 | +Matrix Chebyshev2::IntegrationMatrix(size_t N) { |
| 228 | + // Obtain the differentiation matrix. |
| 229 | + const Matrix D = DifferentiationMatrix(N); |
| 230 | + |
| 231 | + // Compute the pseudo-inverse of the differentiation matrix. |
| 232 | + Eigen::JacobiSVD<Matrix> svd(D, Eigen::ComputeThinU | Eigen::ComputeThinV); |
| 233 | + const auto& S = svd.singularValues(); |
| 234 | + Matrix invS = Matrix::Zero(N, N); |
| 235 | + for (int i = 0; i < N - 1; ++i) invS(i, i) = 1.0 / S(i); |
| 236 | + Matrix P = svd.matrixV() * invS * svd.matrixU().transpose(); |
| 237 | + |
| 238 | + // Return a version of P that makes sure (P*f)(0) = 0. |
| 239 | + const Weights row0 = P.row(0); |
| 240 | + P.rowwise() -= row0; |
| 241 | + return P; |
| 242 | +} |
| 243 | + |
| 244 | +Matrix Chebyshev2::IntegrationMatrix(size_t N, double a, double b) { |
| 245 | + return IntegrationMatrix(N) * (b - a) / 2.0; |
| 246 | +} |
| 247 | + |
| 248 | +/* |
| 249 | + Trefethen00book, pg 128, clencurt.m |
| 250 | + Note that N in clencurt.m is 1 less than our N, we call it K below. |
| 251 | + K = N-1; |
| 252 | + theta = pi*(0:K)'/K; |
| 253 | + w = zeros(1,N); ii = 2:K; v = ones(K-1, 1); |
| 254 | + if mod(K,2) == 0 |
| 255 | + w(1) = 1/(K^2-1); w(N) = w(1); |
| 256 | + for k=1:K/2-1, v = v-2*cos(2*k*theta(ii))/(4*k^2-1); end |
| 257 | + v = v - cos(K*theta(ii))/(K^2-1); |
| 258 | + else |
| 259 | + w(1) = 1/K^2; w(N) = w(1); |
| 260 | + for k=1:K/2, v = v-2*cos(2*k*theta(ii))/(4*k^2-1); end |
| 261 | + end |
| 262 | + w(ii) = 2*v/K; |
| 263 | +*/ |
228 | 264 | Weights Chebyshev2::IntegrationWeights(size_t N) { |
229 | 265 | Weights weights(N); |
230 | 266 | const size_t K = N - 1, // number of intervals between N points |
@@ -254,17 +290,14 @@ Weights Chebyshev2::IntegrationWeights(size_t N, double a, double b) { |
254 | 290 | return IntegrationWeights(N) * (b - a) / 2.0; |
255 | 291 | } |
256 | 292 |
|
257 | | -Matrix Chebyshev2::IntegrationMatrix(size_t N) { |
258 | | - // Obtain the differentiation matrix. |
259 | | - Matrix D = DifferentiationMatrix(N); |
260 | | - |
261 | | - // We want f = D * F, where F is the anti-derivative of f. |
262 | | - // However, D is singular, so we enforce F(0) = f(0) by modifying its first row. |
263 | | - D.row(0).setZero(); |
264 | | - D(0, 0) = 1.0; |
| 293 | +Weights Chebyshev2::DoubleIntegrationWeights(size_t N) { |
| 294 | + // we have w * P, where w are the Clenshaw-Curtis weights and P is the integration matrix |
| 295 | + // But P does not by default return a function starting at zero. |
| 296 | + return Chebyshev2::IntegrationWeights(N) * Chebyshev2::IntegrationMatrix(N); |
| 297 | +} |
265 | 298 |
|
266 | | - // Now D is invertible; its inverse is the integration operator. |
267 | | - return D.inverse(); |
| 299 | +Weights Chebyshev2::DoubleIntegrationWeights(size_t N, double a, double b) { |
| 300 | + return Chebyshev2::IntegrationWeights(N, a, b) * Chebyshev2::IntegrationMatrix(N, a, b); |
268 | 301 | } |
269 | 302 |
|
270 | 303 | /** |
|
0 commit comments