blob: 2d564000e65f5bf6ac1561e375897ddb35c90f2d [file] [log] [blame]
Austin Schuh70cc9552019-01-21 19:46:48 -08001// Ceres Solver - A fast non-linear least squares minimizer
2// Copyright 2015 Google Inc. All rights reserved.
3// http://ceres-solver.org/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7//
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.
16//
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.
28//
29// Author: keir@google.com (Keir Mierle)
30
31#include "ceres/internal/autodiff.h"
32
Austin Schuh70cc9552019-01-21 19:46:48 -080033#include "ceres/random.h"
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080034#include "gtest/gtest.h"
Austin Schuh70cc9552019-01-21 19:46:48 -080035
36namespace ceres {
37namespace internal {
38
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080039template <typename T>
40inline T& RowMajorAccess(T* base, int rows, int cols, int i, int j) {
Austin Schuh70cc9552019-01-21 19:46:48 -080041 return base[cols * i + j];
42}
43
44// Do (symmetric) finite differencing using the given function object 'b' of
45// type 'B' and scalar type 'T' with step size 'del'.
46//
47// The type B should have a signature
48//
49// bool operator()(T const *, T *) const;
50//
51// which maps a vector of parameters to a vector of outputs.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080052template <typename B, typename T, int M, int N>
53inline bool SymmetricDiff(const B& b,
54 const T par[N],
55 T del, // step size.
56 T fun[M],
57 T jac[M * N]) { // row-major.
Austin Schuh70cc9552019-01-21 19:46:48 -080058 if (!b(par, fun)) {
59 return false;
60 }
61
62 // Temporary parameter vector.
63 T tmp_par[N];
64 for (int j = 0; j < N; ++j) {
65 tmp_par[j] = par[j];
66 }
67
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.
70 T fwd_fun[M];
71 T bwd_fun[M];
72
73 for (int j = 0; j < N; ++j) {
74 // Forward step.
75 tmp_par[j] = par[j] + del;
76 if (!b(tmp_par, fwd_fun)) {
77 return false;
78 }
79
80 // Backward step.
81 tmp_par[j] = par[j] - del;
82 if (!b(tmp_par, bwd_fun)) {
83 return false;
84 }
85
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);
91 }
92
93 // Restore our temporary vector.
94 tmp_par[j] = par[j];
95 }
96
97 return true;
98}
99
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800100template <typename A>
101inline void QuaternionToScaledRotation(A const q[4], A R[3 * 3]) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800102 // Make convenient names for elements of q.
103 A a = q[0];
104 A b = q[1];
105 A c = q[2];
106 A d = q[3];
107 // This is not to eliminate common sub-expression, but to
108 // make the lines shorter so that they fit in 80 columns!
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800109 A aa = a * a;
110 A ab = a * b;
111 A ac = a * c;
112 A ad = a * d;
113 A bb = b * b;
114 A bc = b * c;
115 A bd = b * d;
116 A cc = c * c;
117 A cd = c * d;
118 A dd = d * d;
Austin Schuh70cc9552019-01-21 19:46:48 -0800119#define R(i, j) RowMajorAccess(R, 3, 3, (i), (j))
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800120 R(0, 0) = aa + bb - cc - dd;
121 R(0, 1) = A(2) * (bc - ad);
122 R(0, 2) = A(2) * (ac + bd); // NOLINT
123 R(1, 0) = A(2) * (ad + bc);
124 R(1, 1) = aa - bb + cc - dd;
125 R(1, 2) = A(2) * (cd - ab); // NOLINT
126 R(2, 0) = A(2) * (bd - ac);
127 R(2, 1) = A(2) * (ab + cd);
128 R(2, 2) = aa - bb - cc + dd; // NOLINT
Austin Schuh70cc9552019-01-21 19:46:48 -0800129#undef R
130}
131
132// A structure for projecting a 3x4 camera matrix and a
133// homogeneous 3D point, to a 2D inhomogeneous point.
134struct Projective {
135 // Function that takes P and X as separate vectors:
136 // P, X -> x
137 template <typename A>
138 bool operator()(A const P[12], A const X[4], A x[2]) const {
139 A PX[3];
140 for (int i = 0; i < 3; ++i) {
141 PX[i] = RowMajorAccess(P, 3, 4, i, 0) * X[0] +
142 RowMajorAccess(P, 3, 4, i, 1) * X[1] +
143 RowMajorAccess(P, 3, 4, i, 2) * X[2] +
144 RowMajorAccess(P, 3, 4, i, 3) * X[3];
145 }
146 if (PX[2] != 0.0) {
147 x[0] = PX[0] / PX[2];
148 x[1] = PX[1] / PX[2];
149 return true;
150 }
151 return false;
152 }
153
154 // Version that takes P and X packed in one vector:
155 //
156 // (P, X) -> x
157 //
158 template <typename A>
159 bool operator()(A const P_X[12 + 4], A x[2]) const {
160 return operator()(P_X + 0, P_X + 12, x);
161 }
162};
163
164// Test projective camera model projector.
165TEST(AutoDiff, ProjectiveCameraModel) {
166 srand(5);
167 double const tol = 1e-10; // floating-point tolerance.
168 double const del = 1e-4; // finite-difference step.
169 double const err = 1e-6; // finite-difference tolerance.
170
171 Projective b;
172
173 // Make random P and X, in a single vector.
174 double PX[12 + 4];
175 for (int i = 0; i < 12 + 4; ++i) {
176 PX[i] = RandDouble();
177 }
178
179 // Handy names for the P and X parts.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800180 double* P = PX + 0;
181 double* X = PX + 12;
Austin Schuh70cc9552019-01-21 19:46:48 -0800182
183 // Apply the mapping, to get image point b_x.
184 double b_x[2];
185 b(P, X, b_x);
186
187 // Use finite differencing to estimate the Jacobian.
188 double fd_x[2];
189 double fd_J[2 * (12 + 4)];
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800190 ASSERT_TRUE(
191 (SymmetricDiff<Projective, double, 2, 12 + 4>(b, PX, del, fd_x, fd_J)));
Austin Schuh70cc9552019-01-21 19:46:48 -0800192
193 for (int i = 0; i < 2; ++i) {
194 ASSERT_NEAR(fd_x[i], b_x[i], tol);
195 }
196
197 // Use automatic differentiation to compute the Jacobian.
198 double ad_x1[2];
199 double J_PX[2 * (12 + 4)];
200 {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800201 double* parameters[] = {PX};
202 double* jacobians[] = {J_PX};
203 ASSERT_TRUE((AutoDifferentiate<2, StaticParameterDims<12 + 4>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800204 b, parameters, 2, ad_x1, jacobians)));
205
206 for (int i = 0; i < 2; ++i) {
207 ASSERT_NEAR(ad_x1[i], b_x[i], tol);
208 }
209 }
210
211 // Use automatic differentiation (again), with two arguments.
212 {
213 double ad_x2[2];
214 double J_P[2 * 12];
215 double J_X[2 * 4];
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800216 double* parameters[] = {P, X};
217 double* jacobians[] = {J_P, J_X};
218 ASSERT_TRUE((AutoDifferentiate<2, StaticParameterDims<12, 4>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800219 b, parameters, 2, ad_x2, jacobians)));
220
221 for (int i = 0; i < 2; ++i) {
222 ASSERT_NEAR(ad_x2[i], b_x[i], tol);
223 }
224
225 // Now compare the jacobians we got.
226 for (int i = 0; i < 2; ++i) {
227 for (int j = 0; j < 12 + 4; ++j) {
228 ASSERT_NEAR(J_PX[(12 + 4) * i + j], fd_J[(12 + 4) * i + j], err);
229 }
230
231 for (int j = 0; j < 12; ++j) {
232 ASSERT_NEAR(J_PX[(12 + 4) * i + j], J_P[12 * i + j], tol);
233 }
234 for (int j = 0; j < 4; ++j) {
235 ASSERT_NEAR(J_PX[(12 + 4) * i + 12 + j], J_X[4 * i + j], tol);
236 }
237 }
238 }
239}
240
241// Object to implement the projection by a calibrated camera.
242struct Metric {
243 // The mapping is
244 //
245 // q, c, X -> x = dehomg(R(q) (X - c))
246 //
247 // where q is a quaternion and c is the center of projection.
248 //
249 // This function takes three input vectors.
250 template <typename A>
251 bool operator()(A const q[4], A const c[3], A const X[3], A x[2]) const {
252 A R[3 * 3];
253 QuaternionToScaledRotation(q, R);
254
255 // Convert the quaternion mapping all the way to projective matrix.
256 A P[3 * 4];
257
258 // Set P(:, 1:3) = R
259 for (int i = 0; i < 3; ++i) {
260 for (int j = 0; j < 3; ++j) {
261 RowMajorAccess(P, 3, 4, i, j) = RowMajorAccess(R, 3, 3, i, j);
262 }
263 }
264
265 // Set P(:, 4) = - R c
266 for (int i = 0; i < 3; ++i) {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800267 RowMajorAccess(P, 3, 4, i, 3) = -(RowMajorAccess(R, 3, 3, i, 0) * c[0] +
268 RowMajorAccess(R, 3, 3, i, 1) * c[1] +
269 RowMajorAccess(R, 3, 3, i, 2) * c[2]);
Austin Schuh70cc9552019-01-21 19:46:48 -0800270 }
271
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800272 A X1[4] = {X[0], X[1], X[2], A(1)};
Austin Schuh70cc9552019-01-21 19:46:48 -0800273 Projective p;
274 return p(P, X1, x);
275 }
276
277 // A version that takes a single vector.
278 template <typename A>
279 bool operator()(A const q_c_X[4 + 3 + 3], A x[2]) const {
280 return operator()(q_c_X, q_c_X + 4, q_c_X + 4 + 3, x);
281 }
282};
283
284// This test is similar in structure to the previous one.
285TEST(AutoDiff, Metric) {
286 srand(5);
287 double const tol = 1e-10; // floating-point tolerance.
288 double const del = 1e-4; // finite-difference step.
289 double const err = 1e-5; // finite-difference tolerance.
290
291 Metric b;
292
293 // Make random parameter vector.
294 double qcX[4 + 3 + 3];
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800295 for (int i = 0; i < 4 + 3 + 3; ++i) qcX[i] = RandDouble();
Austin Schuh70cc9552019-01-21 19:46:48 -0800296
297 // Handy names.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800298 double* q = qcX;
299 double* c = qcX + 4;
300 double* X = qcX + 4 + 3;
Austin Schuh70cc9552019-01-21 19:46:48 -0800301
302 // Compute projection, b_x.
303 double b_x[2];
304 ASSERT_TRUE(b(q, c, X, b_x));
305
306 // Finite differencing estimate of Jacobian.
307 double fd_x[2];
308 double fd_J[2 * (4 + 3 + 3)];
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800309 ASSERT_TRUE(
310 (SymmetricDiff<Metric, double, 2, 4 + 3 + 3>(b, qcX, del, fd_x, fd_J)));
Austin Schuh70cc9552019-01-21 19:46:48 -0800311
312 for (int i = 0; i < 2; ++i) {
313 ASSERT_NEAR(fd_x[i], b_x[i], tol);
314 }
315
316 // Automatic differentiation.
317 double ad_x[2];
318 double J_q[2 * 4];
319 double J_c[2 * 3];
320 double J_X[2 * 3];
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800321 double* parameters[] = {q, c, X};
322 double* jacobians[] = {J_q, J_c, J_X};
323 ASSERT_TRUE((AutoDifferentiate<2, StaticParameterDims<4, 3, 3>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800324 b, parameters, 2, ad_x, jacobians)));
325
326 for (int i = 0; i < 2; ++i) {
327 ASSERT_NEAR(ad_x[i], b_x[i], tol);
328 }
329
330 // Compare the pieces.
331 for (int i = 0; i < 2; ++i) {
332 for (int j = 0; j < 4; ++j) {
333 ASSERT_NEAR(J_q[4 * i + j], fd_J[(4 + 3 + 3) * i + j], err);
334 }
335 for (int j = 0; j < 3; ++j) {
336 ASSERT_NEAR(J_c[3 * i + j], fd_J[(4 + 3 + 3) * i + j + 4], err);
337 }
338 for (int j = 0; j < 3; ++j) {
339 ASSERT_NEAR(J_X[3 * i + j], fd_J[(4 + 3 + 3) * i + j + 4 + 3], err);
340 }
341 }
342}
343
344struct VaryingResidualFunctor {
345 template <typename T>
346 bool operator()(const T x[2], T* y) const {
347 for (int i = 0; i < num_residuals; ++i) {
348 y[i] = T(i) * x[0] * x[1] * x[1];
349 }
350 return true;
351 }
352
353 int num_residuals;
354};
355
356TEST(AutoDiff, VaryingNumberOfResidualsForOneCostFunctorType) {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800357 double x[2] = {1.0, 5.5};
358 double* parameters[] = {x};
Austin Schuh70cc9552019-01-21 19:46:48 -0800359 const int kMaxResiduals = 10;
360 double J_x[2 * kMaxResiduals];
361 double residuals[kMaxResiduals];
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800362 double* jacobians[] = {J_x};
Austin Schuh70cc9552019-01-21 19:46:48 -0800363
364 // Use a single functor, but tweak it to produce different numbers of
365 // residuals.
366 VaryingResidualFunctor functor;
367
368 for (int num_residuals = 1; num_residuals < kMaxResiduals; ++num_residuals) {
369 // Tweak the number of residuals to produce.
370 functor.num_residuals = num_residuals;
371
372 // Run autodiff with the new number of residuals.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800373 ASSERT_TRUE((AutoDifferentiate<DYNAMIC, StaticParameterDims<2>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800374 functor, parameters, num_residuals, residuals, jacobians)));
375
376 const double kTolerance = 1e-14;
377 for (int i = 0; i < num_residuals; ++i) {
378 EXPECT_NEAR(J_x[2 * i + 0], i * x[1] * x[1], kTolerance) << "i: " << i;
379 EXPECT_NEAR(J_x[2 * i + 1], 2 * i * x[0] * x[1], kTolerance)
380 << "i: " << i;
381 }
382 }
383}
384
385struct Residual1Param {
386 template <typename T>
387 bool operator()(const T* x0, T* y) const {
388 y[0] = *x0;
389 return true;
390 }
391};
392
393struct Residual2Param {
394 template <typename T>
395 bool operator()(const T* x0, const T* x1, T* y) const {
396 y[0] = *x0 + pow(*x1, 2);
397 return true;
398 }
399};
400
401struct Residual3Param {
402 template <typename T>
403 bool operator()(const T* x0, const T* x1, const T* x2, T* y) const {
404 y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3);
405 return true;
406 }
407};
408
409struct Residual4Param {
410 template <typename T>
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800411 bool operator()(
412 const T* x0, const T* x1, const T* x2, const T* x3, T* y) const {
Austin Schuh70cc9552019-01-21 19:46:48 -0800413 y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4);
414 return true;
415 }
416};
417
418struct Residual5Param {
419 template <typename T>
420 bool operator()(const T* x0,
421 const T* x1,
422 const T* x2,
423 const T* x3,
424 const T* x4,
425 T* y) const {
426 y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5);
427 return true;
428 }
429};
430
431struct Residual6Param {
432 template <typename T>
433 bool operator()(const T* x0,
434 const T* x1,
435 const T* x2,
436 const T* x3,
437 const T* x4,
438 const T* x5,
439 T* y) const {
440 y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5) +
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800441 pow(*x5, 6);
Austin Schuh70cc9552019-01-21 19:46:48 -0800442 return true;
443 }
444};
445
446struct Residual7Param {
447 template <typename T>
448 bool operator()(const T* x0,
449 const T* x1,
450 const T* x2,
451 const T* x3,
452 const T* x4,
453 const T* x5,
454 const T* x6,
455 T* y) const {
456 y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5) +
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800457 pow(*x5, 6) + pow(*x6, 7);
Austin Schuh70cc9552019-01-21 19:46:48 -0800458 return true;
459 }
460};
461
462struct Residual8Param {
463 template <typename T>
464 bool operator()(const T* x0,
465 const T* x1,
466 const T* x2,
467 const T* x3,
468 const T* x4,
469 const T* x5,
470 const T* x6,
471 const T* x7,
472 T* y) const {
473 y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5) +
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800474 pow(*x5, 6) + pow(*x6, 7) + pow(*x7, 8);
Austin Schuh70cc9552019-01-21 19:46:48 -0800475 return true;
476 }
477};
478
479struct Residual9Param {
480 template <typename T>
481 bool operator()(const T* x0,
482 const T* x1,
483 const T* x2,
484 const T* x3,
485 const T* x4,
486 const T* x5,
487 const T* x6,
488 const T* x7,
489 const T* x8,
490 T* y) const {
491 y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5) +
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800492 pow(*x5, 6) + pow(*x6, 7) + pow(*x7, 8) + pow(*x8, 9);
Austin Schuh70cc9552019-01-21 19:46:48 -0800493 return true;
494 }
495};
496
497struct Residual10Param {
498 template <typename T>
499 bool operator()(const T* x0,
500 const T* x1,
501 const T* x2,
502 const T* x3,
503 const T* x4,
504 const T* x5,
505 const T* x6,
506 const T* x7,
507 const T* x8,
508 const T* x9,
509 T* y) const {
510 y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5) +
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800511 pow(*x5, 6) + pow(*x6, 7) + pow(*x7, 8) + pow(*x8, 9) + pow(*x9, 10);
Austin Schuh70cc9552019-01-21 19:46:48 -0800512 return true;
513 }
514};
515
516TEST(AutoDiff, VariadicAutoDiff) {
517 double x[10];
518 double residual = 0;
519 double* parameters[10];
520 double jacobian_values[10];
521 double* jacobians[10];
522
523 for (int i = 0; i < 10; ++i) {
524 x[i] = 2.0;
525 parameters[i] = x + i;
526 jacobians[i] = jacobian_values + i;
527 }
528
529 {
530 Residual1Param functor;
531 int num_variables = 1;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800532 EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800533 functor, parameters, 1, &residual, jacobians)));
534 EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
535 for (int i = 0; i < num_variables; ++i) {
536 EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
537 }
538 }
539
540 {
541 Residual2Param functor;
542 int num_variables = 2;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800543 EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800544 functor, parameters, 1, &residual, jacobians)));
545 EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
546 for (int i = 0; i < num_variables; ++i) {
547 EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
548 }
549 }
550
551 {
552 Residual3Param functor;
553 int num_variables = 3;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800554 EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1, 1>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800555 functor, parameters, 1, &residual, jacobians)));
556 EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
557 for (int i = 0; i < num_variables; ++i) {
558 EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
559 }
560 }
561
562 {
563 Residual4Param functor;
564 int num_variables = 4;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800565 EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800566 functor, parameters, 1, &residual, jacobians)));
567 EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
568 for (int i = 0; i < num_variables; ++i) {
569 EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
570 }
571 }
572
573 {
574 Residual5Param functor;
575 int num_variables = 5;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800576 EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800577 functor, parameters, 1, &residual, jacobians)));
578 EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
579 for (int i = 0; i < num_variables; ++i) {
580 EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
581 }
582 }
583
584 {
585 Residual6Param functor;
586 int num_variables = 6;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800587 EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1, 1>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800588 functor, parameters, 1, &residual, jacobians)));
589 EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
590 for (int i = 0; i < num_variables; ++i) {
591 EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
592 }
593 }
594
595 {
596 Residual7Param functor;
597 int num_variables = 7;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800598 EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1, 1, 1>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800599 functor, parameters, 1, &residual, jacobians)));
600 EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
601 for (int i = 0; i < num_variables; ++i) {
602 EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
603 }
604 }
605
606 {
607 Residual8Param functor;
608 int num_variables = 8;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800609 EXPECT_TRUE(
610 (AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1, 1, 1, 1>>(
611 functor, parameters, 1, &residual, jacobians)));
Austin Schuh70cc9552019-01-21 19:46:48 -0800612 EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
613 for (int i = 0; i < num_variables; ++i) {
614 EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
615 }
616 }
617
618 {
619 Residual9Param functor;
620 int num_variables = 9;
621 EXPECT_TRUE(
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800622 (AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1, 1, 1, 1, 1>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800623 functor, parameters, 1, &residual, jacobians)));
624 EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
625 for (int i = 0; i < num_variables; ++i) {
626 EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
627 }
628 }
629
630 {
631 Residual10Param functor;
632 int num_variables = 10;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800633 EXPECT_TRUE((
634 AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1, 1, 1, 1, 1, 1>>(
Austin Schuh70cc9552019-01-21 19:46:48 -0800635 functor, parameters, 1, &residual, jacobians)));
636 EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
637 for (int i = 0; i < num_variables; ++i) {
638 EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
639 }
640 }
641}
642
643// This is fragile test that triggers the alignment bug on
644// i686-apple-darwin10-llvm-g++-4.2 (GCC) 4.2.1. It is quite possible,
645// that other combinations of operating system + compiler will
646// re-arrange the operations in this test.
647//
648// But this is the best (and only) way we know of to trigger this
649// problem for now. A more robust solution that guarantees the
650// alignment of Eigen types used for automatic differentiation would
651// be nice.
652TEST(AutoDiff, AlignedAllocationTest) {
653 // This int is needed to allocate 16 bits on the stack, so that the
654 // next allocation is not aligned by default.
655 char y = 0;
656
657 // This is needed to prevent the compiler from optimizing y out of
658 // this function.
659 y += 1;
660
661 typedef Jet<double, 2> JetT;
662 FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(3);
663
664 // Need this to makes sure that x does not get optimized out.
665 x[0] = x[0] + JetT(1.0);
666}
667
668} // namespace internal
669} // namespace ceres