1
// Ceres Solver - A fast non-linear least squares minimizer
2
// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
3
// http://code.google.com/p/ceres-solver/
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are met:
8
// * Redistributions of source code must retain the above copyright notice,
9
// this list of conditions and the following disclaimer.
10
// * Redistributions in binary form must reproduce the above copyright notice,
11
// this list of conditions and the following disclaimer in the documentation
12
// and/or other materials provided with the distribution.
13
// * Neither the name of Google Inc. nor the names of its contributors may be
14
// used to endorse or promote products derived from this software without
15
// specific prior written permission.
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
// POSSIBILITY OF SUCH DAMAGE.
29
// Author: keir@google.com (Keir Mierle)
31
#include "ceres/internal/autodiff.h"
33
#include "gtest/gtest.h"
34
#include "ceres/random.h"
39
template <typename T> inline
40
T &RowMajorAccess(T *base, int rows, int cols, int i, int j) {
41
return base[cols * i + j];
44
// Do (symmetric) finite differencing using the given function object 'b' of
45
// type 'B' and scalar type 'T' with step size 'del'.
47
// The type B should have a signature
49
// bool operator()(T const *, T *) const;
51
// which maps a vector of parameters to a vector of outputs.
52
template <typename B, typename T, int M, int N> inline
53
bool SymmetricDiff(const B& b,
57
T jac[M * N]) { // row-major.
62
// Temporary parameter vector.
64
for (int j = 0; j < N; ++j) {
68
// For each dimension, we do one forward step and one backward step in
69
// parameter space, and store the output vector vectors in these vectors.
73
for (int j = 0; j < N; ++j) {
75
tmp_par[j] = par[j] + del;
76
if (!b(tmp_par, fwd_fun)) {
81
tmp_par[j] = par[j] - del;
82
if (!b(tmp_par, bwd_fun)) {
86
// Symmetric differencing:
87
// f'(a) = (f(a + h) - f(a - h)) / (2 h)
88
for (int i = 0; i < M; ++i) {
89
RowMajorAccess(jac, M, N, i, j) =
90
(fwd_fun[i] - bwd_fun[i]) / (T(2) * del);
93
// Restore our temporary vector.
100
template <typename A> inline
101
void QuaternionToScaledRotation(A const q[4], A R[3 * 3]) {
102
// Make convenient names for elements of q.
107
// This is not to eliminate common sub-expression, but to
108
// make the lines shorter so that they fit in 80 columns!
119
#define R(i, j) RowMajorAccess(R, 3, 3, (i), (j))
120
R(0, 0) = aa+bb-cc-dd; R(0, 1) = A(2)*(bc-ad); R(0, 2) = A(2)*(ac+bd); // NOLINT
121
R(1, 0) = A(2)*(ad+bc); R(1, 1) = aa-bb+cc-dd; R(1, 2) = A(2)*(cd-ab); // NOLINT
122
R(2, 0) = A(2)*(bd-ac); R(2, 1) = A(2)*(ab+cd); R(2, 2) = aa-bb-cc+dd; // NOLINT
126
// A structure for projecting a 3x4 camera matrix and a
127
// homogeneous 3D point, to a 2D inhomogeneous point.
129
// Function that takes P and X as separate vectors:
131
template <typename A>
132
bool operator()(A const P[12], A const X[4], A x[2]) const {
134
for (int i = 0; i < 3; ++i) {
135
PX[i] = RowMajorAccess(P, 3, 4, i, 0) * X[0] +
136
RowMajorAccess(P, 3, 4, i, 1) * X[1] +
137
RowMajorAccess(P, 3, 4, i, 2) * X[2] +
138
RowMajorAccess(P, 3, 4, i, 3) * X[3];
141
x[0] = PX[0] / PX[2];
142
x[1] = PX[1] / PX[2];
148
// Version that takes P and X packed in one vector:
152
template <typename A>
153
bool operator()(A const P_X[12 + 4], A x[2]) const {
154
return operator()(P_X + 0, P_X + 12, x);
158
// Test projective camera model projector.
159
TEST(AutoDiff, ProjectiveCameraModel) {
161
double const tol = 1e-10; // floating-point tolerance.
162
double const del = 1e-4; // finite-difference step.
163
double const err = 1e-6; // finite-difference tolerance.
167
// Make random P and X, in a single vector.
169
for (int i = 0; i < 12 + 4; ++i) {
170
PX[i] = RandDouble();
173
// Handy names for the P and X parts.
177
// Apply the mapping, to get image point b_x.
181
// Use finite differencing to estimate the Jacobian.
183
double fd_J[2 * (12 + 4)];
184
ASSERT_TRUE((SymmetricDiff<Projective, double, 2, 12 + 4>(b, PX, del,
187
for (int i = 0; i < 2; ++i) {
188
ASSERT_EQ(fd_x[i], b_x[i]);
191
// Use automatic differentiation to compute the Jacobian.
193
double J_PX[2 * (12 + 4)];
195
double *parameters[] = { PX };
196
double *jacobians[] = { J_PX };
197
ASSERT_TRUE((AutoDiff<Projective, double, 12 + 4>::Differentiate(
198
b, parameters, 2, ad_x1, jacobians)));
200
for (int i = 0; i < 2; ++i) {
201
ASSERT_NEAR(ad_x1[i], b_x[i], tol);
205
// Use automatic differentiation (again), with two arguments.
210
double *parameters[] = { P, X };
211
double *jacobians[] = { J_P, J_X };
212
ASSERT_TRUE((AutoDiff<Projective, double, 12, 4>::Differentiate(
213
b, parameters, 2, ad_x2, jacobians)));
215
for (int i = 0; i < 2; ++i) {
216
ASSERT_NEAR(ad_x2[i], b_x[i], tol);
219
// Now compare the jacobians we got.
220
for (int i = 0; i < 2; ++i) {
221
for (int j = 0; j < 12 + 4; ++j) {
222
ASSERT_NEAR(J_PX[(12 + 4) * i + j], fd_J[(12 + 4) * i + j], err);
225
for (int j = 0; j < 12; ++j) {
226
ASSERT_NEAR(J_PX[(12 + 4) * i + j], J_P[12 * i + j], tol);
228
for (int j = 0; j < 4; ++j) {
229
ASSERT_NEAR(J_PX[(12 + 4) * i + 12 + j], J_X[4 * i + j], tol);
235
// Object to implement the projection by a calibrated camera.
239
// q, c, X -> x = dehomg(R(q) (X - c))
241
// where q is a quaternion and c is the center of projection.
243
// This function takes three input vectors.
244
template <typename A>
245
bool operator()(A const q[4], A const c[3], A const X[3], A x[2]) const {
247
QuaternionToScaledRotation(q, R);
249
// Convert the quaternion mapping all the way to projective matrix.
253
for (int i = 0; i < 3; ++i) {
254
for (int j = 0; j < 3; ++j) {
255
RowMajorAccess(P, 3, 4, i, j) = RowMajorAccess(R, 3, 3, i, j);
259
// Set P(:, 4) = - R c
260
for (int i = 0; i < 3; ++i) {
261
RowMajorAccess(P, 3, 4, i, 3) =
262
- (RowMajorAccess(R, 3, 3, i, 0) * c[0] +
263
RowMajorAccess(R, 3, 3, i, 1) * c[1] +
264
RowMajorAccess(R, 3, 3, i, 2) * c[2]);
267
A X1[4] = { X[0], X[1], X[2], A(1) };
272
// A version that takes a single vector.
273
template <typename A>
274
bool operator()(A const q_c_X[4 + 3 + 3], A x[2]) const {
275
return operator()(q_c_X, q_c_X + 4, q_c_X + 4 + 3, x);
279
// This test is similar in structure to the previous one.
280
TEST(AutoDiff, Metric) {
282
double const tol = 1e-10; // floating-point tolerance.
283
double const del = 1e-4; // finite-difference step.
284
double const err = 1e-5; // finite-difference tolerance.
288
// Make random parameter vector.
289
double qcX[4 + 3 + 3];
290
for (int i = 0; i < 4 + 3 + 3; ++i)
291
qcX[i] = RandDouble();
296
double *X = qcX + 4 + 3;
298
// Compute projection, b_x.
300
ASSERT_TRUE(b(q, c, X, b_x));
302
// Finite differencing estimate of Jacobian.
304
double fd_J[2 * (4 + 3 + 3)];
305
ASSERT_TRUE((SymmetricDiff<Metric, double, 2, 4 + 3 + 3>(b, qcX, del,
308
for (int i = 0; i < 2; ++i) {
309
ASSERT_NEAR(fd_x[i], b_x[i], tol);
312
// Automatic differentiation.
317
double *parameters[] = { q, c, X };
318
double *jacobians[] = { J_q, J_c, J_X };
319
ASSERT_TRUE((AutoDiff<Metric, double, 4, 3, 3>::Differentiate(
320
b, parameters, 2, ad_x, jacobians)));
322
for (int i = 0; i < 2; ++i) {
323
ASSERT_NEAR(ad_x[i], b_x[i], tol);
326
// Compare the pieces.
327
for (int i = 0; i < 2; ++i) {
328
for (int j = 0; j < 4; ++j) {
329
ASSERT_NEAR(J_q[4 * i + j], fd_J[(4 + 3 + 3) * i + j], err);
331
for (int j = 0; j < 3; ++j) {
332
ASSERT_NEAR(J_c[3 * i + j], fd_J[(4 + 3 + 3) * i + j + 4], err);
334
for (int j = 0; j < 3; ++j) {
335
ASSERT_NEAR(J_X[3 * i + j], fd_J[(4 + 3 + 3) * i + j + 4 + 3], err);
340
struct VaryingResidualFunctor {
341
template <typename T>
342
bool operator()(const T x[2], T* y) const {
343
for (int i = 0; i < num_residuals; ++i) {
344
y[i] = T(i) * x[0] * x[1] * x[1];
352
TEST(AutoDiff, VaryingNumberOfResidualsForOneCostFunctorType) {
353
double x[2] = { 1.0, 5.5 };
354
double *parameters[] = { x };
355
const int kMaxResiduals = 10;
356
double J_x[2 * kMaxResiduals];
357
double residuals[kMaxResiduals];
358
double *jacobians[] = { J_x };
360
// Use a single functor, but tweak it to produce different numbers of
362
VaryingResidualFunctor functor;
364
for (int num_residuals = 1; num_residuals < kMaxResiduals; ++num_residuals) {
365
// Tweak the number of residuals to produce.
366
functor.num_residuals = num_residuals;
368
// Run autodiff with the new number of residuals.
369
ASSERT_TRUE((AutoDiff<VaryingResidualFunctor, double, 2>::Differentiate(
370
functor, parameters, num_residuals, residuals, jacobians)));
372
const double kTolerance = 1e-14;
373
for (int i = 0; i < num_residuals; ++i) {
374
EXPECT_NEAR(J_x[2 * i + 0], i * x[1] * x[1], kTolerance) << "i: " << i;
375
EXPECT_NEAR(J_x[2 * i + 1], 2 * i * x[0] * x[1], kTolerance) << "i: " << i;
380
} // namespace internal