Skip to content

Commit 5ef8c0a

Browse files
committed
IntegrationMatrix and DoubleIntegrationWeights
1 parent e32ccdf commit 5ef8c0a

File tree

3 files changed

+210
-101
lines changed

3 files changed

+210
-101
lines changed

gtsam/basis/Chebyshev2.cpp

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
*/
1818

1919
#include <gtsam/basis/Chebyshev2.h>
20+
21+
#include <Eigen/Dense>
22+
2023
#include <cassert>
2124

2225
namespace gtsam {
@@ -93,24 +96,20 @@ namespace {
9396
// Helper function to calculate a row of the differentiation matrix, [-1,1] interval
9497
Vector differentiationMatrixRow(size_t N, const Vector& points, size_t i) {
9598
Vector row(N);
99+
const size_t K = N - 1;
96100
double xi = points(i);
97-
double ci = (i == 0 || i == N - 1) ? 2. : 1.;
98101
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));
110108
}
111109
else {
112110
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.;
114113
double t = ((i + j) % 2) == 0 ? 1 : -1;
115114
row(j) = (ci / cj) * t / (xi - xj);
116115
}
@@ -225,6 +224,43 @@ Chebyshev2::DiffMatrix Chebyshev2::DifferentiationMatrix(size_t N, double a, dou
225224
return DifferentiationMatrix(N) / ((b - a) / 2.0);
226225
}
227226

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+
*/
228264
Weights Chebyshev2::IntegrationWeights(size_t N) {
229265
Weights weights(N);
230266
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) {
254290
return IntegrationWeights(N) * (b - a) / 2.0;
255291
}
256292

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+
}
265298

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);
268301
}
269302

270303
/**

gtsam/basis/Chebyshev2.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,32 @@ class GTSAM_EXPORT Chebyshev2 : public Basis<Chebyshev2> {
102102
/// Compute D = differentiation matrix, for interval [a,b]
103103
static DiffMatrix DifferentiationMatrix(size_t N, double a, double b);
104104

105+
/// IntegrationMatrix returns the (N+1)×(N+1) matrix P such that for any f,
106+
/// F = P * f recovers F (the antiderivative) satisfying f = D * F and F(0)=0.
107+
static Matrix IntegrationMatrix(size_t N);
108+
109+
/// IntegrationMatrix returns the (N+1)×(N+1) matrix P for interval [a,b]
110+
static Matrix IntegrationMatrix(size_t N, double a, double b);
111+
105112
/**
106-
* Evaluate Clenshaw-Curtis integration weights.
113+
* Calculate Clenshaw-Curtis integration weights.
107114
* Trefethen00book, pg 128, clencurt.m
108115
* Note that N in clencurt.m is 1 less than our N
109116
*/
110117
static Weights IntegrationWeights(size_t N);
111118

112-
/// Evaluate Clenshaw-Curtis integration weights, for interval [a,b]
119+
/// Calculate Clenshaw-Curtis integration weights, for interval [a,b]
113120
static Weights IntegrationWeights(size_t N, double a, double b);
114121

115-
/// IntegrationMatrix returns the (N+1)×(N+1) matrix P such that for any f,
116-
/// F = P * f recovers F (the antiderivative) satisfying f = D * F and F(0)=0.
117-
static Matrix IntegrationMatrix(size_t N);
122+
/**
123+
* Calculate Double Clenshaw-Curtis integration weights
124+
* We compute them as W * P, where W are the Clenshaw-Curtis weights and P is
125+
* the integration matrix.
126+
*/
127+
static Weights DoubleIntegrationWeights(size_t N);
128+
129+
/// Calculate Double Clenshaw-Curtis integration weights, for interval [a,b]
130+
static Weights DoubleIntegrationWeights(size_t N, double a, double b);
118131

119132
/// Create matrix of values at Chebyshev points given vector-valued function.
120133
static Vector vector(std::function<double(double)> f,

0 commit comments

Comments
 (0)