autodiff_test.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. // Ceres Solver - A fast non-linear least squares minimizer
  2. // Copyright 2023 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. #include "ceres/internal/autodiff.h"
  31. #include <algorithm>
  32. #include <iterator>
  33. #include <random>
  34. #include "gtest/gtest.h"
  35. namespace ceres::internal {
  36. template <typename T>
  37. inline T& RowMajorAccess(T* base, int rows, int cols, int i, int j) {
  38. return base[cols * i + j];
  39. }
  40. // Do (symmetric) finite differencing using the given function object 'b' of
  41. // type 'B' and scalar type 'T' with step size 'del'.
  42. //
  43. // The type B should have a signature
  44. //
  45. // bool operator()(T const *, T *) const;
  46. //
  47. // which maps a vector of parameters to a vector of outputs.
  48. template <typename B, typename T, int M, int N>
  49. inline bool SymmetricDiff(const B& b,
  50. const T par[N],
  51. T del, // step size.
  52. T fun[M],
  53. T jac[M * N]) { // row-major.
  54. if (!b(par, fun)) {
  55. return false;
  56. }
  57. // Temporary parameter vector.
  58. T tmp_par[N];
  59. for (int j = 0; j < N; ++j) {
  60. tmp_par[j] = par[j];
  61. }
  62. // For each dimension, we do one forward step and one backward step in
  63. // parameter space, and store the output vector vectors in these vectors.
  64. T fwd_fun[M];
  65. T bwd_fun[M];
  66. for (int j = 0; j < N; ++j) {
  67. // Forward step.
  68. tmp_par[j] = par[j] + del;
  69. if (!b(tmp_par, fwd_fun)) {
  70. return false;
  71. }
  72. // Backward step.
  73. tmp_par[j] = par[j] - del;
  74. if (!b(tmp_par, bwd_fun)) {
  75. return false;
  76. }
  77. // Symmetric differencing:
  78. // f'(a) = (f(a + h) - f(a - h)) / (2 h)
  79. for (int i = 0; i < M; ++i) {
  80. RowMajorAccess(jac, M, N, i, j) =
  81. (fwd_fun[i] - bwd_fun[i]) / (T(2) * del);
  82. }
  83. // Restore our temporary vector.
  84. tmp_par[j] = par[j];
  85. }
  86. return true;
  87. }
  88. template <typename A>
  89. inline void QuaternionToScaledRotation(A const q[4], A R[3 * 3]) {
  90. // Make convenient names for elements of q.
  91. A a = q[0];
  92. A b = q[1];
  93. A c = q[2];
  94. A d = q[3];
  95. // This is not to eliminate common sub-expression, but to
  96. // make the lines shorter so that they fit in 80 columns!
  97. A aa = a * a;
  98. A ab = a * b;
  99. A ac = a * c;
  100. A ad = a * d;
  101. A bb = b * b;
  102. A bc = b * c;
  103. A bd = b * d;
  104. A cc = c * c;
  105. A cd = c * d;
  106. A dd = d * d;
  107. #define R(i, j) RowMajorAccess(R, 3, 3, (i), (j))
  108. R(0, 0) = aa + bb - cc - dd;
  109. R(0, 1) = A(2) * (bc - ad);
  110. R(0, 2) = A(2) * (ac + bd); // NOLINT
  111. R(1, 0) = A(2) * (ad + bc);
  112. R(1, 1) = aa - bb + cc - dd;
  113. R(1, 2) = A(2) * (cd - ab); // NOLINT
  114. R(2, 0) = A(2) * (bd - ac);
  115. R(2, 1) = A(2) * (ab + cd);
  116. R(2, 2) = aa - bb - cc + dd; // NOLINT
  117. #undef R
  118. }
  119. // A structure for projecting a 3x4 camera matrix and a
  120. // homogeneous 3D point, to a 2D inhomogeneous point.
  121. struct Projective {
  122. // Function that takes P and X as separate vectors:
  123. // P, X -> x
  124. template <typename A>
  125. bool operator()(A const P[12], A const X[4], A x[2]) const {
  126. A PX[3];
  127. for (int i = 0; i < 3; ++i) {
  128. PX[i] = RowMajorAccess(P, 3, 4, i, 0) * X[0] +
  129. RowMajorAccess(P, 3, 4, i, 1) * X[1] +
  130. RowMajorAccess(P, 3, 4, i, 2) * X[2] +
  131. RowMajorAccess(P, 3, 4, i, 3) * X[3];
  132. }
  133. if (PX[2] != 0.0) {
  134. x[0] = PX[0] / PX[2];
  135. x[1] = PX[1] / PX[2];
  136. return true;
  137. }
  138. return false;
  139. }
  140. // Version that takes P and X packed in one vector:
  141. //
  142. // (P, X) -> x
  143. //
  144. template <typename A>
  145. bool operator()(A const P_X[12 + 4], A x[2]) const {
  146. return operator()(P_X + 0, P_X + 12, x);
  147. }
  148. };
  149. // Test projective camera model projector.
  150. TEST(AutoDiff, ProjectiveCameraModel) {
  151. double const tol = 1e-10; // floating-point tolerance.
  152. double const del = 1e-4; // finite-difference step.
  153. double const err = 1e-6; // finite-difference tolerance.
  154. Projective b;
  155. std::mt19937 prng;
  156. std::uniform_real_distribution<double> uniform01(0.0, 1.0);
  157. // Make random P and X, in a single vector.
  158. double PX[12 + 4];
  159. std::generate(std::begin(PX), std::end(PX), [&prng, &uniform01] {
  160. return uniform01(prng);
  161. });
  162. // Handy names for the P and X parts.
  163. double* P = PX + 0;
  164. double* X = PX + 12;
  165. // Apply the mapping, to get image point b_x.
  166. double b_x[2];
  167. b(P, X, b_x);
  168. // Use finite differencing to estimate the Jacobian.
  169. double fd_x[2];
  170. double fd_J[2 * (12 + 4)];
  171. ASSERT_TRUE(
  172. (SymmetricDiff<Projective, double, 2, 12 + 4>(b, PX, del, fd_x, fd_J)));
  173. for (int i = 0; i < 2; ++i) {
  174. ASSERT_NEAR(fd_x[i], b_x[i], tol);
  175. }
  176. // Use automatic differentiation to compute the Jacobian.
  177. double ad_x1[2];
  178. double J_PX[2 * (12 + 4)];
  179. {
  180. double* parameters[] = {PX};
  181. double* jacobians[] = {J_PX};
  182. ASSERT_TRUE((AutoDifferentiate<2, StaticParameterDims<12 + 4>>(
  183. b, parameters, 2, ad_x1, jacobians)));
  184. for (int i = 0; i < 2; ++i) {
  185. ASSERT_NEAR(ad_x1[i], b_x[i], tol);
  186. }
  187. }
  188. // Use automatic differentiation (again), with two arguments.
  189. {
  190. double ad_x2[2];
  191. double J_P[2 * 12];
  192. double J_X[2 * 4];
  193. double* parameters[] = {P, X};
  194. double* jacobians[] = {J_P, J_X};
  195. ASSERT_TRUE((AutoDifferentiate<2, StaticParameterDims<12, 4>>(
  196. b, parameters, 2, ad_x2, jacobians)));
  197. for (int i = 0; i < 2; ++i) {
  198. ASSERT_NEAR(ad_x2[i], b_x[i], tol);
  199. }
  200. // Now compare the jacobians we got.
  201. for (int i = 0; i < 2; ++i) {
  202. for (int j = 0; j < 12 + 4; ++j) {
  203. ASSERT_NEAR(J_PX[(12 + 4) * i + j], fd_J[(12 + 4) * i + j], err);
  204. }
  205. for (int j = 0; j < 12; ++j) {
  206. ASSERT_NEAR(J_PX[(12 + 4) * i + j], J_P[12 * i + j], tol);
  207. }
  208. for (int j = 0; j < 4; ++j) {
  209. ASSERT_NEAR(J_PX[(12 + 4) * i + 12 + j], J_X[4 * i + j], tol);
  210. }
  211. }
  212. }
  213. }
  214. // Object to implement the projection by a calibrated camera.
  215. struct Metric {
  216. // The mapping is
  217. //
  218. // q, c, X -> x = dehomg(R(q) (X - c))
  219. //
  220. // where q is a quaternion and c is the center of projection.
  221. //
  222. // This function takes three input vectors.
  223. template <typename A>
  224. bool operator()(A const q[4], A const c[3], A const X[3], A x[2]) const {
  225. A R[3 * 3];
  226. QuaternionToScaledRotation(q, R);
  227. // Convert the quaternion mapping all the way to projective matrix.
  228. A P[3 * 4];
  229. // Set P(:, 1:3) = R
  230. for (int i = 0; i < 3; ++i) {
  231. for (int j = 0; j < 3; ++j) {
  232. RowMajorAccess(P, 3, 4, i, j) = RowMajorAccess(R, 3, 3, i, j);
  233. }
  234. }
  235. // Set P(:, 4) = - R c
  236. for (int i = 0; i < 3; ++i) {
  237. RowMajorAccess(P, 3, 4, i, 3) = -(RowMajorAccess(R, 3, 3, i, 0) * c[0] +
  238. RowMajorAccess(R, 3, 3, i, 1) * c[1] +
  239. RowMajorAccess(R, 3, 3, i, 2) * c[2]);
  240. }
  241. A X1[4] = {X[0], X[1], X[2], A(1)};
  242. Projective p;
  243. return p(P, X1, x);
  244. }
  245. // A version that takes a single vector.
  246. template <typename A>
  247. bool operator()(A const q_c_X[4 + 3 + 3], A x[2]) const {
  248. return operator()(q_c_X, q_c_X + 4, q_c_X + 4 + 3, x);
  249. }
  250. };
  251. // This test is similar in structure to the previous one.
  252. TEST(AutoDiff, Metric) {
  253. double const tol = 1e-10; // floating-point tolerance.
  254. double const del = 1e-4; // finite-difference step.
  255. double const err = 2e-5; // finite-difference tolerance.
  256. Metric b;
  257. // Make random parameter vector.
  258. double qcX[4 + 3 + 3];
  259. std::mt19937 prng;
  260. std::uniform_real_distribution<double> uniform01(0.0, 1.0);
  261. std::generate(std::begin(qcX), std::end(qcX), [&prng, &uniform01] {
  262. return uniform01(prng);
  263. });
  264. // Handy names.
  265. double* q = qcX;
  266. double* c = qcX + 4;
  267. double* X = qcX + 4 + 3;
  268. // Compute projection, b_x.
  269. double b_x[2];
  270. ASSERT_TRUE(b(q, c, X, b_x));
  271. // Finite differencing estimate of Jacobian.
  272. double fd_x[2];
  273. double fd_J[2 * (4 + 3 + 3)];
  274. ASSERT_TRUE(
  275. (SymmetricDiff<Metric, double, 2, 4 + 3 + 3>(b, qcX, del, fd_x, fd_J)));
  276. for (int i = 0; i < 2; ++i) {
  277. ASSERT_NEAR(fd_x[i], b_x[i], tol);
  278. }
  279. // Automatic differentiation.
  280. double ad_x[2];
  281. double J_q[2 * 4];
  282. double J_c[2 * 3];
  283. double J_X[2 * 3];
  284. double* parameters[] = {q, c, X};
  285. double* jacobians[] = {J_q, J_c, J_X};
  286. ASSERT_TRUE((AutoDifferentiate<2, StaticParameterDims<4, 3, 3>>(
  287. b, parameters, 2, ad_x, jacobians)));
  288. for (int i = 0; i < 2; ++i) {
  289. ASSERT_NEAR(ad_x[i], b_x[i], tol);
  290. }
  291. // Compare the pieces.
  292. for (int i = 0; i < 2; ++i) {
  293. for (int j = 0; j < 4; ++j) {
  294. ASSERT_NEAR(J_q[4 * i + j], fd_J[(4 + 3 + 3) * i + j], err);
  295. }
  296. for (int j = 0; j < 3; ++j) {
  297. ASSERT_NEAR(J_c[3 * i + j], fd_J[(4 + 3 + 3) * i + j + 4], err);
  298. }
  299. for (int j = 0; j < 3; ++j) {
  300. ASSERT_NEAR(J_X[3 * i + j], fd_J[(4 + 3 + 3) * i + j + 4 + 3], err);
  301. }
  302. }
  303. }
  304. struct VaryingResidualFunctor {
  305. template <typename T>
  306. bool operator()(const T x[2], T* y) const {
  307. for (int i = 0; i < num_residuals; ++i) {
  308. y[i] = T(i) * x[0] * x[1] * x[1];
  309. }
  310. return true;
  311. }
  312. int num_residuals;
  313. };
  314. TEST(AutoDiff, VaryingNumberOfResidualsForOneCostFunctorType) {
  315. double x[2] = {1.0, 5.5};
  316. double* parameters[] = {x};
  317. const int kMaxResiduals = 10;
  318. double J_x[2 * kMaxResiduals];
  319. double residuals[kMaxResiduals];
  320. double* jacobians[] = {J_x};
  321. // Use a single functor, but tweak it to produce different numbers of
  322. // residuals.
  323. VaryingResidualFunctor functor;
  324. for (int num_residuals = 1; num_residuals < kMaxResiduals; ++num_residuals) {
  325. // Tweak the number of residuals to produce.
  326. functor.num_residuals = num_residuals;
  327. // Run autodiff with the new number of residuals.
  328. ASSERT_TRUE((AutoDifferentiate<DYNAMIC, StaticParameterDims<2>>(
  329. functor, parameters, num_residuals, residuals, jacobians)));
  330. const double kTolerance = 1e-14;
  331. for (int i = 0; i < num_residuals; ++i) {
  332. EXPECT_NEAR(J_x[2 * i + 0], i * x[1] * x[1], kTolerance) << "i: " << i;
  333. EXPECT_NEAR(J_x[2 * i + 1], 2 * i * x[0] * x[1], kTolerance)
  334. << "i: " << i;
  335. }
  336. }
  337. }
  338. struct Residual1Param {
  339. template <typename T>
  340. bool operator()(const T* x0, T* y) const {
  341. y[0] = *x0;
  342. return true;
  343. }
  344. };
  345. struct Residual2Param {
  346. template <typename T>
  347. bool operator()(const T* x0, const T* x1, T* y) const {
  348. y[0] = *x0 + pow(*x1, 2);
  349. return true;
  350. }
  351. };
  352. struct Residual3Param {
  353. template <typename T>
  354. bool operator()(const T* x0, const T* x1, const T* x2, T* y) const {
  355. y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3);
  356. return true;
  357. }
  358. };
  359. struct Residual4Param {
  360. template <typename T>
  361. bool operator()(
  362. const T* x0, const T* x1, const T* x2, const T* x3, T* y) const {
  363. y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4);
  364. return true;
  365. }
  366. };
  367. struct Residual5Param {
  368. template <typename T>
  369. bool operator()(const T* x0,
  370. const T* x1,
  371. const T* x2,
  372. const T* x3,
  373. const T* x4,
  374. T* y) const {
  375. y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5);
  376. return true;
  377. }
  378. };
  379. struct Residual6Param {
  380. template <typename T>
  381. bool operator()(const T* x0,
  382. const T* x1,
  383. const T* x2,
  384. const T* x3,
  385. const T* x4,
  386. const T* x5,
  387. T* y) const {
  388. y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5) +
  389. pow(*x5, 6);
  390. return true;
  391. }
  392. };
  393. struct Residual7Param {
  394. template <typename T>
  395. bool operator()(const T* x0,
  396. const T* x1,
  397. const T* x2,
  398. const T* x3,
  399. const T* x4,
  400. const T* x5,
  401. const T* x6,
  402. T* y) const {
  403. y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5) +
  404. pow(*x5, 6) + pow(*x6, 7);
  405. return true;
  406. }
  407. };
  408. struct Residual8Param {
  409. template <typename T>
  410. bool operator()(const T* x0,
  411. const T* x1,
  412. const T* x2,
  413. const T* x3,
  414. const T* x4,
  415. const T* x5,
  416. const T* x6,
  417. const T* x7,
  418. T* y) const {
  419. y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5) +
  420. pow(*x5, 6) + pow(*x6, 7) + pow(*x7, 8);
  421. return true;
  422. }
  423. };
  424. struct Residual9Param {
  425. template <typename T>
  426. bool operator()(const T* x0,
  427. const T* x1,
  428. const T* x2,
  429. const T* x3,
  430. const T* x4,
  431. const T* x5,
  432. const T* x6,
  433. const T* x7,
  434. const T* x8,
  435. T* y) const {
  436. y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5) +
  437. pow(*x5, 6) + pow(*x6, 7) + pow(*x7, 8) + pow(*x8, 9);
  438. return true;
  439. }
  440. };
  441. struct Residual10Param {
  442. template <typename T>
  443. bool operator()(const T* x0,
  444. const T* x1,
  445. const T* x2,
  446. const T* x3,
  447. const T* x4,
  448. const T* x5,
  449. const T* x6,
  450. const T* x7,
  451. const T* x8,
  452. const T* x9,
  453. T* y) const {
  454. y[0] = *x0 + pow(*x1, 2) + pow(*x2, 3) + pow(*x3, 4) + pow(*x4, 5) +
  455. pow(*x5, 6) + pow(*x6, 7) + pow(*x7, 8) + pow(*x8, 9) + pow(*x9, 10);
  456. return true;
  457. }
  458. };
  459. TEST(AutoDiff, VariadicAutoDiff) {
  460. double x[10];
  461. double residual = 0;
  462. double* parameters[10];
  463. double jacobian_values[10];
  464. double* jacobians[10];
  465. for (int i = 0; i < 10; ++i) {
  466. x[i] = 2.0;
  467. parameters[i] = x + i;
  468. jacobians[i] = jacobian_values + i;
  469. }
  470. {
  471. Residual1Param functor;
  472. int num_variables = 1;
  473. EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1>>(
  474. functor, parameters, 1, &residual, jacobians)));
  475. EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
  476. for (int i = 0; i < num_variables; ++i) {
  477. EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
  478. }
  479. }
  480. {
  481. Residual2Param functor;
  482. int num_variables = 2;
  483. EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1>>(
  484. functor, parameters, 1, &residual, jacobians)));
  485. EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
  486. for (int i = 0; i < num_variables; ++i) {
  487. EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
  488. }
  489. }
  490. {
  491. Residual3Param functor;
  492. int num_variables = 3;
  493. EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1, 1>>(
  494. functor, parameters, 1, &residual, jacobians)));
  495. EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
  496. for (int i = 0; i < num_variables; ++i) {
  497. EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
  498. }
  499. }
  500. {
  501. Residual4Param functor;
  502. int num_variables = 4;
  503. EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1>>(
  504. functor, parameters, 1, &residual, jacobians)));
  505. EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
  506. for (int i = 0; i < num_variables; ++i) {
  507. EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
  508. }
  509. }
  510. {
  511. Residual5Param functor;
  512. int num_variables = 5;
  513. EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1>>(
  514. functor, parameters, 1, &residual, jacobians)));
  515. EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
  516. for (int i = 0; i < num_variables; ++i) {
  517. EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
  518. }
  519. }
  520. {
  521. Residual6Param functor;
  522. int num_variables = 6;
  523. EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1, 1>>(
  524. functor, parameters, 1, &residual, jacobians)));
  525. EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
  526. for (int i = 0; i < num_variables; ++i) {
  527. EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
  528. }
  529. }
  530. {
  531. Residual7Param functor;
  532. int num_variables = 7;
  533. EXPECT_TRUE((AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1, 1, 1>>(
  534. functor, parameters, 1, &residual, jacobians)));
  535. EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
  536. for (int i = 0; i < num_variables; ++i) {
  537. EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
  538. }
  539. }
  540. {
  541. Residual8Param functor;
  542. int num_variables = 8;
  543. EXPECT_TRUE(
  544. (AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1, 1, 1, 1>>(
  545. functor, parameters, 1, &residual, jacobians)));
  546. EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
  547. for (int i = 0; i < num_variables; ++i) {
  548. EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
  549. }
  550. }
  551. {
  552. Residual9Param functor;
  553. int num_variables = 9;
  554. EXPECT_TRUE(
  555. (AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1, 1, 1, 1, 1>>(
  556. functor, parameters, 1, &residual, jacobians)));
  557. EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
  558. for (int i = 0; i < num_variables; ++i) {
  559. EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
  560. }
  561. }
  562. {
  563. Residual10Param functor;
  564. int num_variables = 10;
  565. EXPECT_TRUE((
  566. AutoDifferentiate<1, StaticParameterDims<1, 1, 1, 1, 1, 1, 1, 1, 1, 1>>(
  567. functor, parameters, 1, &residual, jacobians)));
  568. EXPECT_EQ(residual, pow(2, num_variables + 1) - 2);
  569. for (int i = 0; i < num_variables; ++i) {
  570. EXPECT_EQ(jacobian_values[i], (i + 1) * pow(2, i));
  571. }
  572. }
  573. }
  574. // This is fragile test that triggers the alignment bug on
  575. // i686-apple-darwin10-llvm-g++-4.2 (GCC) 4.2.1. It is quite possible,
  576. // that other combinations of operating system + compiler will
  577. // re-arrange the operations in this test.
  578. //
  579. // But this is the best (and only) way we know of to trigger this
  580. // problem for now. A more robust solution that guarantees the
  581. // alignment of Eigen types used for automatic differentiation would
  582. // be nice.
  583. TEST(AutoDiff, AlignedAllocationTest) {
  584. // This int is needed to allocate 16 bits on the stack, so that the
  585. // next allocation is not aligned by default.
  586. char y = 0;
  587. // This is needed to prevent the compiler from optimizing y out of
  588. // this function.
  589. y += 1;
  590. using JetT = Jet<double, 2>;
  591. FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(3);
  592. // Need this to makes sure that x does not get optimized out.
  593. x[0] = x[0] + JetT(1.0);
  594. }
  595. } // namespace ceres::internal