manifold_test.cc 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  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: sameeragarwal@google.com (Sameer Agarwal)
  30. #include "ceres/manifold.h"
  31. #include <cmath>
  32. #include <limits>
  33. #include <memory>
  34. #include <utility>
  35. #include "Eigen/Geometry"
  36. #include "ceres/constants.h"
  37. #include "ceres/dynamic_numeric_diff_cost_function.h"
  38. #include "ceres/internal/eigen.h"
  39. #include "ceres/internal/port.h"
  40. #include "ceres/line_manifold.h"
  41. #include "ceres/manifold_test_utils.h"
  42. #include "ceres/numeric_diff_options.h"
  43. #include "ceres/product_manifold.h"
  44. #include "ceres/rotation.h"
  45. #include "ceres/sphere_manifold.h"
  46. #include "ceres/types.h"
  47. #include "gmock/gmock.h"
  48. #include "gtest/gtest.h"
  49. namespace ceres::internal {
  50. constexpr int kNumTrials = 1000;
  51. constexpr double kTolerance = 1e-9;
  52. TEST(EuclideanManifold, StaticNormalFunctionTest) {
  53. EuclideanManifold<3> manifold;
  54. EXPECT_EQ(manifold.AmbientSize(), 3);
  55. EXPECT_EQ(manifold.TangentSize(), 3);
  56. Vector zero_tangent = Vector::Zero(manifold.TangentSize());
  57. for (int trial = 0; trial < kNumTrials; ++trial) {
  58. const Vector x = Vector::Random(manifold.AmbientSize());
  59. const Vector y = Vector::Random(manifold.AmbientSize());
  60. Vector delta = Vector::Random(manifold.TangentSize());
  61. Vector x_plus_delta = Vector::Zero(manifold.AmbientSize());
  62. manifold.Plus(x.data(), delta.data(), x_plus_delta.data());
  63. EXPECT_NEAR((x_plus_delta - x - delta).norm() / (x + delta).norm(),
  64. 0.0,
  65. kTolerance);
  66. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  67. }
  68. }
  69. TEST(EuclideanManifold, DynamicNormalFunctionTest) {
  70. EuclideanManifold<DYNAMIC> manifold(3);
  71. EXPECT_EQ(manifold.AmbientSize(), 3);
  72. EXPECT_EQ(manifold.TangentSize(), 3);
  73. Vector zero_tangent = Vector::Zero(manifold.TangentSize());
  74. for (int trial = 0; trial < kNumTrials; ++trial) {
  75. const Vector x = Vector::Random(manifold.AmbientSize());
  76. const Vector y = Vector::Random(manifold.AmbientSize());
  77. Vector delta = Vector::Random(manifold.TangentSize());
  78. Vector x_plus_delta = Vector::Zero(manifold.AmbientSize());
  79. manifold.Plus(x.data(), delta.data(), x_plus_delta.data());
  80. EXPECT_NEAR((x_plus_delta - x - delta).norm() / (x + delta).norm(),
  81. 0.0,
  82. kTolerance);
  83. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  84. }
  85. }
  86. TEST(SubsetManifold, EmptyConstantParameters) {
  87. SubsetManifold manifold(3, {});
  88. for (int trial = 0; trial < kNumTrials; ++trial) {
  89. const Vector x = Vector::Random(3);
  90. const Vector y = Vector::Random(3);
  91. Vector delta = Vector::Random(3);
  92. Vector x_plus_delta = Vector::Zero(3);
  93. manifold.Plus(x.data(), delta.data(), x_plus_delta.data());
  94. EXPECT_NEAR((x_plus_delta - x - delta).norm() / (x + delta).norm(),
  95. 0.0,
  96. kTolerance);
  97. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  98. }
  99. }
  100. TEST(SubsetManifold, NegativeParameterIndexDeathTest) {
  101. EXPECT_DEATH_IF_SUPPORTED(SubsetManifold manifold(2, {-1}),
  102. "greater than equal to zero");
  103. }
  104. TEST(SubsetManifold, GreaterThanSizeParameterIndexDeathTest) {
  105. EXPECT_DEATH_IF_SUPPORTED(SubsetManifold manifold(2, {2}),
  106. "less than the size");
  107. }
  108. TEST(SubsetManifold, DuplicateParametersDeathTest) {
  109. EXPECT_DEATH_IF_SUPPORTED(SubsetManifold manifold(2, {1, 1}), "duplicates");
  110. }
  111. TEST(SubsetManifold, NormalFunctionTest) {
  112. const int kAmbientSize = 4;
  113. const int kTangentSize = 3;
  114. for (int i = 0; i < kAmbientSize; ++i) {
  115. SubsetManifold manifold_with_ith_parameter_constant(kAmbientSize, {i});
  116. for (int trial = 0; trial < kNumTrials; ++trial) {
  117. const Vector x = Vector::Random(kAmbientSize);
  118. Vector y = Vector::Random(kAmbientSize);
  119. // x and y must have the same i^th coordinate to be on the manifold.
  120. y[i] = x[i];
  121. Vector delta = Vector::Random(kTangentSize);
  122. Vector x_plus_delta = Vector::Zero(kAmbientSize);
  123. x_plus_delta.setZero();
  124. manifold_with_ith_parameter_constant.Plus(
  125. x.data(), delta.data(), x_plus_delta.data());
  126. int k = 0;
  127. for (int j = 0; j < kAmbientSize; ++j) {
  128. if (j == i) {
  129. EXPECT_EQ(x_plus_delta[j], x[j]);
  130. } else {
  131. EXPECT_EQ(x_plus_delta[j], x[j] + delta[k++]);
  132. }
  133. }
  134. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(
  135. manifold_with_ith_parameter_constant, x, delta, y, kTolerance);
  136. }
  137. }
  138. }
  139. TEST(ProductManifold, Size2) {
  140. SubsetManifold manifold1(5, {2});
  141. SubsetManifold manifold2(3, {0, 1});
  142. ProductManifold<SubsetManifold, SubsetManifold> manifold(manifold1,
  143. manifold2);
  144. EXPECT_EQ(manifold.AmbientSize(),
  145. manifold1.AmbientSize() + manifold2.AmbientSize());
  146. EXPECT_EQ(manifold.TangentSize(),
  147. manifold1.TangentSize() + manifold2.TangentSize());
  148. }
  149. TEST(ProductManifold, Size3) {
  150. SubsetManifold manifold1(5, {2});
  151. SubsetManifold manifold2(3, {0, 1});
  152. SubsetManifold manifold3(4, {1});
  153. ProductManifold<SubsetManifold, SubsetManifold, SubsetManifold> manifold(
  154. manifold1, manifold2, manifold3);
  155. EXPECT_EQ(manifold.AmbientSize(),
  156. manifold1.AmbientSize() + manifold2.AmbientSize() +
  157. manifold3.AmbientSize());
  158. EXPECT_EQ(manifold.TangentSize(),
  159. manifold1.TangentSize() + manifold2.TangentSize() +
  160. manifold3.TangentSize());
  161. }
  162. TEST(ProductManifold, Size4) {
  163. SubsetManifold manifold1(5, {2});
  164. SubsetManifold manifold2(3, {0, 1});
  165. SubsetManifold manifold3(4, {1});
  166. SubsetManifold manifold4(2, {0});
  167. ProductManifold<SubsetManifold,
  168. SubsetManifold,
  169. SubsetManifold,
  170. SubsetManifold>
  171. manifold(manifold1, manifold2, manifold3, manifold4);
  172. EXPECT_EQ(manifold.AmbientSize(),
  173. manifold1.AmbientSize() + manifold2.AmbientSize() +
  174. manifold3.AmbientSize() + manifold4.AmbientSize());
  175. EXPECT_EQ(manifold.TangentSize(),
  176. manifold1.TangentSize() + manifold2.TangentSize() +
  177. manifold3.TangentSize() + manifold4.TangentSize());
  178. }
  179. TEST(ProductManifold, NormalFunctionTest) {
  180. SubsetManifold manifold1(5, {2});
  181. SubsetManifold manifold2(3, {0, 1});
  182. SubsetManifold manifold3(4, {1});
  183. SubsetManifold manifold4(2, {0});
  184. ProductManifold<SubsetManifold,
  185. SubsetManifold,
  186. SubsetManifold,
  187. SubsetManifold>
  188. manifold(manifold1, manifold2, manifold3, manifold4);
  189. for (int trial = 0; trial < kNumTrials; ++trial) {
  190. const Vector x = Vector::Random(manifold.AmbientSize());
  191. Vector delta = Vector::Random(manifold.TangentSize());
  192. Vector x_plus_delta = Vector::Zero(manifold.AmbientSize());
  193. Vector x_plus_delta_expected = Vector::Zero(manifold.AmbientSize());
  194. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), x_plus_delta.data()));
  195. int ambient_cursor = 0;
  196. int tangent_cursor = 0;
  197. EXPECT_TRUE(manifold1.Plus(&x[ambient_cursor],
  198. &delta[tangent_cursor],
  199. &x_plus_delta_expected[ambient_cursor]));
  200. ambient_cursor += manifold1.AmbientSize();
  201. tangent_cursor += manifold1.TangentSize();
  202. EXPECT_TRUE(manifold2.Plus(&x[ambient_cursor],
  203. &delta[tangent_cursor],
  204. &x_plus_delta_expected[ambient_cursor]));
  205. ambient_cursor += manifold2.AmbientSize();
  206. tangent_cursor += manifold2.TangentSize();
  207. EXPECT_TRUE(manifold3.Plus(&x[ambient_cursor],
  208. &delta[tangent_cursor],
  209. &x_plus_delta_expected[ambient_cursor]));
  210. ambient_cursor += manifold3.AmbientSize();
  211. tangent_cursor += manifold3.TangentSize();
  212. EXPECT_TRUE(manifold4.Plus(&x[ambient_cursor],
  213. &delta[tangent_cursor],
  214. &x_plus_delta_expected[ambient_cursor]));
  215. ambient_cursor += manifold4.AmbientSize();
  216. tangent_cursor += manifold4.TangentSize();
  217. for (int i = 0; i < x.size(); ++i) {
  218. EXPECT_EQ(x_plus_delta[i], x_plus_delta_expected[i]);
  219. }
  220. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(
  221. manifold, x, delta, x_plus_delta, kTolerance);
  222. }
  223. }
  224. TEST(ProductManifold, ZeroTangentSizeAndEuclidean) {
  225. SubsetManifold subset_manifold(1, {0});
  226. EuclideanManifold<2> euclidean_manifold;
  227. ProductManifold<SubsetManifold, EuclideanManifold<2>> manifold(
  228. subset_manifold, euclidean_manifold);
  229. EXPECT_EQ(manifold.AmbientSize(), 3);
  230. EXPECT_EQ(manifold.TangentSize(), 2);
  231. for (int trial = 0; trial < kNumTrials; ++trial) {
  232. const Vector x = Vector::Random(3);
  233. Vector y = Vector::Random(3);
  234. y[0] = x[0];
  235. Vector delta = Vector::Random(2);
  236. Vector x_plus_delta = Vector::Zero(3);
  237. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), x_plus_delta.data()));
  238. EXPECT_EQ(x_plus_delta[0], x[0]);
  239. EXPECT_EQ(x_plus_delta[1], x[1] + delta[0]);
  240. EXPECT_EQ(x_plus_delta[2], x[2] + delta[1]);
  241. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  242. }
  243. }
  244. TEST(ProductManifold, EuclideanAndZeroTangentSize) {
  245. SubsetManifold subset_manifold(1, {0});
  246. EuclideanManifold<2> euclidean_manifold;
  247. ProductManifold<EuclideanManifold<2>, SubsetManifold> manifold(
  248. euclidean_manifold, subset_manifold);
  249. EXPECT_EQ(manifold.AmbientSize(), 3);
  250. EXPECT_EQ(manifold.TangentSize(), 2);
  251. for (int trial = 0; trial < kNumTrials; ++trial) {
  252. const Vector x = Vector::Random(3);
  253. Vector y = Vector::Random(3);
  254. y[2] = x[2];
  255. Vector delta = Vector::Random(2);
  256. Vector x_plus_delta = Vector::Zero(3);
  257. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), x_plus_delta.data()));
  258. EXPECT_EQ(x_plus_delta[0], x[0] + delta[0]);
  259. EXPECT_EQ(x_plus_delta[1], x[1] + delta[1]);
  260. EXPECT_EQ(x_plus_delta[2], x[2]);
  261. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  262. }
  263. }
  264. struct CopyableManifold : ceres::Manifold {
  265. CopyableManifold() = default;
  266. CopyableManifold(const CopyableManifold&) = default;
  267. // Do not care about copy-assignment
  268. CopyableManifold& operator=(const CopyableManifold&) = delete;
  269. // Not moveable
  270. CopyableManifold(CopyableManifold&&) = delete;
  271. CopyableManifold& operator=(CopyableManifold&&) = delete;
  272. int AmbientSize() const override { return 3; }
  273. int TangentSize() const override { return 2; }
  274. bool Plus(const double* x,
  275. const double* delta,
  276. double* x_plus_delta) const override {
  277. return true;
  278. }
  279. bool PlusJacobian(const double* x, double* jacobian) const override {
  280. return true;
  281. }
  282. bool RightMultiplyByPlusJacobian(const double* x,
  283. const int num_rows,
  284. const double* ambient_matrix,
  285. double* tangent_matrix) const override {
  286. return true;
  287. }
  288. bool Minus(const double* y,
  289. const double* x,
  290. double* y_minus_x) const override {
  291. return true;
  292. }
  293. bool MinusJacobian(const double* x, double* jacobian) const override {
  294. return true;
  295. }
  296. };
  297. struct MoveableManifold : ceres::Manifold {
  298. MoveableManifold() = default;
  299. MoveableManifold(MoveableManifold&&) = default;
  300. // Do not care about move-assignment
  301. MoveableManifold& operator=(MoveableManifold&&) = delete;
  302. // Not copyable
  303. MoveableManifold(const MoveableManifold&) = delete;
  304. MoveableManifold& operator=(const MoveableManifold&) = delete;
  305. int AmbientSize() const override { return 3; }
  306. int TangentSize() const override { return 2; }
  307. bool Plus(const double* x,
  308. const double* delta,
  309. double* x_plus_delta) const override {
  310. return true;
  311. }
  312. bool PlusJacobian(const double* x, double* jacobian) const override {
  313. return true;
  314. }
  315. bool RightMultiplyByPlusJacobian(const double* x,
  316. const int num_rows,
  317. const double* ambient_matrix,
  318. double* tangent_matrix) const override {
  319. return true;
  320. }
  321. bool Minus(const double* y,
  322. const double* x,
  323. double* y_minus_x) const override {
  324. return true;
  325. }
  326. bool MinusJacobian(const double* x, double* jacobian) const override {
  327. return true;
  328. }
  329. };
  330. TEST(ProductManifold, CopyableOnly) {
  331. ProductManifold<CopyableManifold, EuclideanManifold<3>> manifold1{
  332. CopyableManifold{}, EuclideanManifold<3>{}};
  333. CopyableManifold inner2;
  334. ProductManifold<CopyableManifold, EuclideanManifold<3>> manifold2{
  335. inner2, EuclideanManifold<3>{}};
  336. EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
  337. EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
  338. }
  339. TEST(ProductManifold, MoveableOnly) {
  340. ProductManifold<MoveableManifold, EuclideanManifold<3>> manifold1{
  341. MoveableManifold{}, EuclideanManifold<3>{}};
  342. MoveableManifold inner2;
  343. ProductManifold<MoveableManifold, EuclideanManifold<3>> manifold2{
  344. std::move(inner2), EuclideanManifold<3>{}};
  345. EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
  346. EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
  347. }
  348. TEST(ProductManifold, CopyableOrMoveable) {
  349. const CopyableManifold inner12{};
  350. ProductManifold<MoveableManifold, CopyableManifold> manifold1{
  351. MoveableManifold{}, inner12};
  352. MoveableManifold inner21;
  353. CopyableManifold inner22;
  354. ProductManifold<MoveableManifold, CopyableManifold> manifold2{
  355. std::move(inner21), inner22};
  356. EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
  357. EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
  358. }
  359. struct NonDefaultConstructibleManifold : ceres::Manifold {
  360. NonDefaultConstructibleManifold(int, int) {}
  361. int AmbientSize() const override { return 4; }
  362. int TangentSize() const override { return 3; }
  363. bool Plus(const double* x,
  364. const double* delta,
  365. double* x_plus_delta) const override {
  366. return true;
  367. }
  368. bool PlusJacobian(const double* x, double* jacobian) const override {
  369. return true;
  370. }
  371. bool RightMultiplyByPlusJacobian(const double* x,
  372. const int num_rows,
  373. const double* ambient_matrix,
  374. double* tangent_matrix) const override {
  375. return true;
  376. }
  377. bool Minus(const double* y,
  378. const double* x,
  379. double* y_minus_x) const override {
  380. return true;
  381. }
  382. bool MinusJacobian(const double* x, double* jacobian) const override {
  383. return true;
  384. }
  385. };
  386. TEST(ProductManifold, NonDefaultConstructible) {
  387. ProductManifold<NonDefaultConstructibleManifold, QuaternionManifold>
  388. manifold1{NonDefaultConstructibleManifold{1, 2}, QuaternionManifold{}};
  389. ProductManifold<QuaternionManifold, NonDefaultConstructibleManifold>
  390. manifold2{QuaternionManifold{}, NonDefaultConstructibleManifold{1, 2}};
  391. EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
  392. EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
  393. }
  394. TEST(ProductManifold, DefaultConstructible) {
  395. ProductManifold<EuclideanManifold<3>, SphereManifold<4>> manifold1;
  396. ProductManifold<SphereManifold<4>, EuclideanManifold<3>> manifold2;
  397. EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
  398. EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
  399. }
  400. TEST(ProductManifold, Pointers) {
  401. auto p = std::make_unique<QuaternionManifold>();
  402. auto q = std::make_shared<EuclideanManifold<3>>();
  403. ProductManifold<std::unique_ptr<Manifold>,
  404. EuclideanManifold<3>,
  405. std::shared_ptr<EuclideanManifold<3>>>
  406. manifold1{
  407. std::make_unique<QuaternionManifold>(), EuclideanManifold<3>{}, q};
  408. ProductManifold<QuaternionManifold*,
  409. EuclideanManifold<3>,
  410. std::shared_ptr<EuclideanManifold<3>>>
  411. manifold2{p.get(), EuclideanManifold<3>{}, q};
  412. EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
  413. EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
  414. }
  415. TEST(QuaternionManifold, PlusPiBy2) {
  416. QuaternionManifold manifold;
  417. Vector x = Vector::Zero(4);
  418. x[0] = 1.0;
  419. for (int i = 0; i < 3; ++i) {
  420. Vector delta = Vector::Zero(3);
  421. delta[i] = constants::pi / 2;
  422. Vector x_plus_delta = Vector::Zero(4);
  423. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), x_plus_delta.data()));
  424. // Expect that the element corresponding to pi/2 is +/- 1. All other
  425. // elements should be zero.
  426. for (int j = 0; j < 4; ++j) {
  427. if (i == (j - 1)) {
  428. EXPECT_LT(std::abs(x_plus_delta[j]) - 1,
  429. std::numeric_limits<double>::epsilon())
  430. << "\ndelta = " << delta.transpose()
  431. << "\nx_plus_delta = " << x_plus_delta.transpose()
  432. << "\n expected the " << j
  433. << "th element of x_plus_delta to be +/- 1.";
  434. } else {
  435. EXPECT_LT(std::abs(x_plus_delta[j]),
  436. std::numeric_limits<double>::epsilon())
  437. << "\ndelta = " << delta.transpose()
  438. << "\nx_plus_delta = " << x_plus_delta.transpose()
  439. << "\n expected the " << j << "th element of x_plus_delta to be 0.";
  440. }
  441. }
  442. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(
  443. manifold, x, delta, x_plus_delta, kTolerance);
  444. }
  445. }
  446. // Compute the expected value of QuaternionManifold::Plus via functions in
  447. // rotation.h and compares it to the one computed by QuaternionManifold::Plus.
  448. MATCHER_P2(QuaternionManifoldPlusIsCorrectAt, x, delta, "") {
  449. // This multiplication by 2 is needed because AngleAxisToQuaternion uses
  450. // |delta|/2 as the angle of rotation where as in the implementation of
  451. // QuaternionManifold for historical reasons we use |delta|.
  452. const Vector two_delta = delta * 2;
  453. Vector delta_q(4);
  454. AngleAxisToQuaternion(two_delta.data(), delta_q.data());
  455. Vector expected(4);
  456. QuaternionProduct(delta_q.data(), x.data(), expected.data());
  457. Vector actual(4);
  458. EXPECT_TRUE(arg.Plus(x.data(), delta.data(), actual.data()));
  459. const double n = (actual - expected).norm();
  460. const double d = expected.norm();
  461. const double diffnorm = n / d;
  462. if (diffnorm > kTolerance) {
  463. *result_listener << "\nx: " << x.transpose()
  464. << "\ndelta: " << delta.transpose()
  465. << "\nexpected: " << expected.transpose()
  466. << "\nactual: " << actual.transpose()
  467. << "\ndiff: " << (expected - actual).transpose()
  468. << "\ndiffnorm : " << diffnorm;
  469. return false;
  470. }
  471. return true;
  472. }
  473. static Vector RandomQuaternion() {
  474. Vector x = Vector::Random(4);
  475. x.normalize();
  476. return x;
  477. }
  478. TEST(QuaternionManifold, GenericDelta) {
  479. QuaternionManifold manifold;
  480. for (int trial = 0; trial < kNumTrials; ++trial) {
  481. const Vector x = RandomQuaternion();
  482. const Vector y = RandomQuaternion();
  483. Vector delta = Vector::Random(3);
  484. EXPECT_THAT(manifold, QuaternionManifoldPlusIsCorrectAt(x, delta));
  485. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  486. }
  487. }
  488. TEST(QuaternionManifold, SmallDelta) {
  489. QuaternionManifold manifold;
  490. for (int trial = 0; trial < kNumTrials; ++trial) {
  491. const Vector x = RandomQuaternion();
  492. const Vector y = RandomQuaternion();
  493. Vector delta = Vector::Random(3);
  494. delta.normalize();
  495. delta *= 1e-6;
  496. EXPECT_THAT(manifold, QuaternionManifoldPlusIsCorrectAt(x, delta));
  497. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  498. }
  499. }
  500. TEST(QuaternionManifold, DeltaJustBelowPi) {
  501. QuaternionManifold manifold;
  502. for (int trial = 0; trial < kNumTrials; ++trial) {
  503. const Vector x = RandomQuaternion();
  504. const Vector y = RandomQuaternion();
  505. Vector delta = Vector::Random(3);
  506. delta.normalize();
  507. delta *= (constants::pi - 1e-6);
  508. EXPECT_THAT(manifold, QuaternionManifoldPlusIsCorrectAt(x, delta));
  509. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  510. }
  511. }
  512. // Compute the expected value of EigenQuaternionManifold::Plus using Eigen and
  513. // compares it to the one computed by QuaternionManifold::Plus.
  514. MATCHER_P2(EigenQuaternionManifoldPlusIsCorrectAt, x, delta, "") {
  515. // This multiplication by 2 is needed because AngleAxisToQuaternion uses
  516. // |delta|/2 as the angle of rotation where as in the implementation of
  517. // Quaternion for historical reasons we use |delta|.
  518. const Vector two_delta = delta * 2;
  519. Vector delta_q(4);
  520. AngleAxisToQuaternion(two_delta.data(), delta_q.data());
  521. Eigen::Quaterniond delta_eigen_q(
  522. delta_q[0], delta_q[1], delta_q[2], delta_q[3]);
  523. Eigen::Map<const Eigen::Quaterniond> x_eigen_q(x.data());
  524. Eigen::Quaterniond expected = delta_eigen_q * x_eigen_q;
  525. double actual[4];
  526. EXPECT_TRUE(arg.Plus(x.data(), delta.data(), actual));
  527. Eigen::Map<Eigen::Quaterniond> actual_eigen_q(actual);
  528. const double n = (actual_eigen_q.coeffs() - expected.coeffs()).norm();
  529. const double d = expected.norm();
  530. const double diffnorm = n / d;
  531. if (diffnorm > kTolerance) {
  532. *result_listener
  533. << "\nx: " << x.transpose() << "\ndelta: " << delta.transpose()
  534. << "\nexpected: " << expected.coeffs().transpose()
  535. << "\nactual: " << actual_eigen_q.coeffs().transpose() << "\ndiff: "
  536. << (expected.coeffs() - actual_eigen_q.coeffs()).transpose()
  537. << "\ndiffnorm : " << diffnorm;
  538. return false;
  539. }
  540. return true;
  541. }
  542. TEST(EigenQuaternionManifold, GenericDelta) {
  543. EigenQuaternionManifold manifold;
  544. for (int trial = 0; trial < kNumTrials; ++trial) {
  545. const Vector x = RandomQuaternion();
  546. const Vector y = RandomQuaternion();
  547. Vector delta = Vector::Random(3);
  548. EXPECT_THAT(manifold, EigenQuaternionManifoldPlusIsCorrectAt(x, delta));
  549. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  550. }
  551. }
  552. TEST(EigenQuaternionManifold, SmallDelta) {
  553. EigenQuaternionManifold manifold;
  554. for (int trial = 0; trial < kNumTrials; ++trial) {
  555. const Vector x = RandomQuaternion();
  556. const Vector y = RandomQuaternion();
  557. Vector delta = Vector::Random(3);
  558. delta.normalize();
  559. delta *= 1e-6;
  560. EXPECT_THAT(manifold, EigenQuaternionManifoldPlusIsCorrectAt(x, delta));
  561. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  562. }
  563. }
  564. TEST(EigenQuaternionManifold, DeltaJustBelowPi) {
  565. EigenQuaternionManifold manifold;
  566. for (int trial = 0; trial < kNumTrials; ++trial) {
  567. const Vector x = RandomQuaternion();
  568. const Vector y = RandomQuaternion();
  569. Vector delta = Vector::Random(3);
  570. delta.normalize();
  571. delta *= (constants::pi - 1e-6);
  572. EXPECT_THAT(manifold, EigenQuaternionManifoldPlusIsCorrectAt(x, delta));
  573. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  574. }
  575. }
  576. using Eigen::Vector2d;
  577. using Eigen::Vector3d;
  578. using Vector6d = Eigen::Matrix<double, 6, 1>;
  579. using Eigen::Vector4d;
  580. using Vector8d = Eigen::Matrix<double, 8, 1>;
  581. TEST(SphereManifold, ZeroTest) {
  582. Vector4d x{0.0, 0.0, 0.0, 1.0};
  583. Vector3d delta = Vector3d::Zero();
  584. Vector4d y = Vector4d::Zero();
  585. SphereManifold<4> manifold;
  586. manifold.Plus(x.data(), delta.data(), y.data());
  587. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  588. }
  589. TEST(SphereManifold, NearZeroTest1) {
  590. Vector4d x{1e-5, 1e-5, 1e-5, 1.0};
  591. x.normalize();
  592. Vector3d delta{0.0, 1.0, 0.0};
  593. Vector4d y = Vector4d::Zero();
  594. SphereManifold<4> manifold;
  595. manifold.Plus(x.data(), delta.data(), y.data());
  596. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  597. }
  598. TEST(SphereManifold, NearZeroTest2) {
  599. Vector4d x{0.01, 0.0, 0.0, 0.0};
  600. Vector3d delta{0.0, 1.0, 0.0};
  601. Vector4d y = Vector4d::Zero();
  602. SphereManifold<4> manifold;
  603. manifold.Plus(x.data(), delta.data(), y.data());
  604. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  605. }
  606. TEST(SphereManifold, Plus2DTest) {
  607. Eigen::Vector2d x{0.0, 1.0};
  608. SphereManifold<2> manifold;
  609. {
  610. double delta[1]{constants::pi / 4};
  611. Eigen::Vector2d y = Eigen::Vector2d::Zero();
  612. EXPECT_TRUE(manifold.Plus(x.data(), delta, y.data()));
  613. const Eigen::Vector2d gtY(std::sqrt(2.0) / 2.0, std::sqrt(2.0) / 2.0);
  614. EXPECT_LT((y - gtY).norm(), kTolerance);
  615. }
  616. {
  617. double delta[1]{constants::pi / 2};
  618. Eigen::Vector2d y = Eigen::Vector2d::Zero();
  619. EXPECT_TRUE(manifold.Plus(x.data(), delta, y.data()));
  620. const Eigen::Vector2d gtY = Eigen::Vector2d::UnitX();
  621. EXPECT_LT((y - gtY).norm(), kTolerance);
  622. }
  623. {
  624. double delta[1]{constants::pi};
  625. Eigen::Vector2d y = Eigen::Vector2d::Zero();
  626. EXPECT_TRUE(manifold.Plus(x.data(), delta, y.data()));
  627. const Eigen::Vector2d gtY = -Eigen::Vector2d::UnitY();
  628. EXPECT_LT((y - gtY).norm(), kTolerance);
  629. }
  630. {
  631. double delta[1]{2.0 * constants::pi};
  632. Eigen::Vector2d y = Eigen::Vector2d::Zero();
  633. EXPECT_TRUE(manifold.Plus(x.data(), delta, y.data()));
  634. const Eigen::Vector2d gtY = Eigen::Vector2d::UnitY();
  635. EXPECT_LT((y - gtY).norm(), kTolerance);
  636. }
  637. }
  638. TEST(SphereManifold, Plus3DTest) {
  639. Eigen::Vector3d x{0.0, 0.0, 1.0};
  640. SphereManifold<3> manifold;
  641. {
  642. Eigen::Vector2d delta{constants::pi / 2, 0.0};
  643. Eigen::Vector3d y = Eigen::Vector3d::Zero();
  644. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  645. const Eigen::Vector3d gtY = Eigen::Vector3d::UnitX();
  646. EXPECT_LT((y - gtY).norm(), kTolerance);
  647. }
  648. {
  649. Eigen::Vector2d delta{constants::pi, 0.0};
  650. Eigen::Vector3d y = Eigen::Vector3d::Zero();
  651. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  652. const Eigen::Vector3d gtY = -Eigen::Vector3d::UnitZ();
  653. EXPECT_LT((y - gtY).norm(), kTolerance);
  654. }
  655. {
  656. Eigen::Vector2d delta{2.0 * constants::pi, 0.0};
  657. Eigen::Vector3d y = Eigen::Vector3d::Zero();
  658. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  659. const Eigen::Vector3d gtY = Eigen::Vector3d::UnitZ();
  660. EXPECT_LT((y - gtY).norm(), kTolerance);
  661. }
  662. {
  663. Eigen::Vector2d delta{0.0, constants::pi / 2};
  664. Eigen::Vector3d y = Eigen::Vector3d::Zero();
  665. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  666. const Eigen::Vector3d gtY = Eigen::Vector3d::UnitY();
  667. EXPECT_LT((y - gtY).norm(), kTolerance);
  668. }
  669. {
  670. Eigen::Vector2d delta{0.0, constants::pi};
  671. Eigen::Vector3d y = Eigen::Vector3d::Zero();
  672. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  673. const Eigen::Vector3d gtY = -Eigen::Vector3d::UnitZ();
  674. EXPECT_LT((y - gtY).norm(), kTolerance);
  675. }
  676. {
  677. Eigen::Vector2d delta{0.0, 2.0 * constants::pi};
  678. Eigen::Vector3d y = Eigen::Vector3d::Zero();
  679. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  680. const Eigen::Vector3d gtY = Eigen::Vector3d::UnitZ();
  681. EXPECT_LT((y - gtY).norm(), kTolerance);
  682. }
  683. {
  684. Eigen::Vector2d delta =
  685. Eigen::Vector2d(1, 1).normalized() * constants::pi / 2;
  686. Eigen::Vector3d y = Eigen::Vector3d::Zero();
  687. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  688. const Eigen::Vector3d gtY(std::sqrt(2.0) / 2.0, std::sqrt(2.0) / 2.0, 0.0);
  689. EXPECT_LT((y - gtY).norm(), kTolerance);
  690. }
  691. {
  692. Eigen::Vector2d delta = Eigen::Vector2d(1, 1).normalized() * constants::pi;
  693. Eigen::Vector3d y = Eigen::Vector3d::Zero();
  694. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  695. const Eigen::Vector3d gtY = -Eigen::Vector3d::UnitZ();
  696. EXPECT_LT((y - gtY).norm(), kTolerance);
  697. }
  698. }
  699. TEST(SphereManifold, Minus2DTest) {
  700. Eigen::Vector2d x{1.0, 0.0};
  701. SphereManifold<2> manifold;
  702. {
  703. double delta[1];
  704. const Eigen::Vector2d y(std::sqrt(2.0) / 2.0, std::sqrt(2.0) / 2.0);
  705. const double gtDelta{constants::pi / 4};
  706. EXPECT_TRUE(manifold.Minus(y.data(), x.data(), delta));
  707. EXPECT_LT(std::abs(delta[0] - gtDelta), kTolerance);
  708. }
  709. {
  710. double delta[1];
  711. const Eigen::Vector2d y(-1, 0);
  712. const double gtDelta{constants::pi};
  713. EXPECT_TRUE(manifold.Minus(y.data(), x.data(), delta));
  714. EXPECT_LT(std::abs(delta[0] - gtDelta), kTolerance);
  715. }
  716. }
  717. TEST(SphereManifold, Minus3DTest) {
  718. Eigen::Vector3d x{1.0, 0.0, 0.0};
  719. SphereManifold<3> manifold;
  720. {
  721. Eigen::Vector2d delta;
  722. const Eigen::Vector3d y(std::sqrt(2.0) / 2.0, 0.0, std::sqrt(2.0) / 2.0);
  723. const Eigen::Vector2d gtDelta(constants::pi / 4, 0.0);
  724. EXPECT_TRUE(manifold.Minus(y.data(), x.data(), delta.data()));
  725. EXPECT_LT((delta - gtDelta).norm(), kTolerance);
  726. }
  727. {
  728. Eigen::Vector2d delta;
  729. const Eigen::Vector3d y(-1, 0, 0);
  730. const Eigen::Vector2d gtDelta(0.0, constants::pi);
  731. EXPECT_TRUE(manifold.Minus(y.data(), x.data(), delta.data()));
  732. EXPECT_LT((delta - gtDelta).norm(), kTolerance);
  733. }
  734. }
  735. TEST(SphereManifold, DeathTests) {
  736. EXPECT_DEATH_IF_SUPPORTED(SphereManifold<Eigen::Dynamic> x(1), "size");
  737. }
  738. TEST(SphereManifold, NormalFunctionTest) {
  739. SphereManifold<4> manifold;
  740. EXPECT_EQ(manifold.AmbientSize(), 4);
  741. EXPECT_EQ(manifold.TangentSize(), 3);
  742. Vector zero_tangent = Vector::Zero(manifold.TangentSize());
  743. for (int trial = 0; trial < kNumTrials; ++trial) {
  744. const Vector x = Vector::Random(manifold.AmbientSize());
  745. Vector y = Vector::Random(manifold.AmbientSize());
  746. Vector delta = Vector::Random(manifold.TangentSize());
  747. if (x.norm() == 0.0 || y.norm() == 0.0) {
  748. continue;
  749. }
  750. // X and y need to have the same length.
  751. y *= x.norm() / y.norm();
  752. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  753. }
  754. }
  755. TEST(SphereManifold, NormalFunctionTestDynamic) {
  756. SphereManifold<ceres::DYNAMIC> manifold(5);
  757. EXPECT_EQ(manifold.AmbientSize(), 5);
  758. EXPECT_EQ(manifold.TangentSize(), 4);
  759. Vector zero_tangent = Vector::Zero(manifold.TangentSize());
  760. for (int trial = 0; trial < kNumTrials; ++trial) {
  761. const Vector x = Vector::Random(manifold.AmbientSize());
  762. Vector y = Vector::Random(manifold.AmbientSize());
  763. Vector delta = Vector::Random(manifold.TangentSize());
  764. if (x.norm() == 0.0 || y.norm() == 0.0) {
  765. continue;
  766. }
  767. // X and y need to have the same length.
  768. y *= x.norm() / y.norm();
  769. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  770. }
  771. }
  772. TEST(LineManifold, ZeroTest3D) {
  773. const Vector6d x = Vector6d::Unit(5);
  774. const Vector4d delta = Vector4d::Zero();
  775. Vector6d y = Vector6d::Zero();
  776. LineManifold<3> manifold;
  777. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  778. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  779. }
  780. TEST(LineManifold, ZeroTest4D) {
  781. const Vector8d x = Vector8d::Unit(7);
  782. const Vector6d delta = Vector6d::Zero();
  783. Vector8d y = Vector8d::Zero();
  784. LineManifold<4> manifold;
  785. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  786. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  787. }
  788. TEST(LineManifold, ZeroOriginPointTest3D) {
  789. const Vector6d x = Vector6d::Unit(5);
  790. Vector4d delta;
  791. delta << 0.0, 0.0, 1.0, 2.0;
  792. Vector6d y = Vector6d::Zero();
  793. LineManifold<3> manifold;
  794. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  795. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  796. }
  797. TEST(LineManifold, ZeroOriginPointTest4D) {
  798. const Vector8d x = Vector8d::Unit(7);
  799. Vector6d delta;
  800. delta << 0.0, 0.0, 0.0, 0.5, 1.0, 1.5;
  801. Vector8d y = Vector8d::Zero();
  802. LineManifold<4> manifold;
  803. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  804. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  805. }
  806. TEST(LineManifold, ZeroDirTest3D) {
  807. Vector6d x = Vector6d::Unit(5);
  808. Vector4d delta;
  809. delta << 3.0, 2.0, 0.0, 0.0;
  810. Vector6d y = Vector6d::Zero();
  811. LineManifold<3> manifold;
  812. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  813. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  814. }
  815. TEST(LineManifold, ZeroDirTest4D) {
  816. Vector8d x = Vector8d::Unit(7);
  817. Vector6d delta;
  818. delta << 3.0, 2.0, 1.0, 0.0, 0.0, 0.0;
  819. Vector8d y = Vector8d::Zero();
  820. LineManifold<4> manifold;
  821. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  822. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  823. }
  824. TEST(LineManifold, Plus) {
  825. Vector6d x = Vector6d::Unit(5);
  826. LineManifold<3> manifold;
  827. {
  828. Vector4d delta{0.0, 2.0, constants::pi / 2, 0.0};
  829. Vector6d y = Vector6d::Random();
  830. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  831. Vector6d gtY;
  832. gtY << 2.0 * Vector3d::UnitY(), Vector3d::UnitX();
  833. EXPECT_LT((y - gtY).norm(), kTolerance);
  834. }
  835. {
  836. Vector4d delta{3.0, 0.0, 0.0, constants::pi / 2};
  837. Vector6d y = Vector6d::Zero();
  838. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  839. Vector6d gtY;
  840. gtY << 3.0 * Vector3d::UnitX(), Vector3d::UnitY();
  841. EXPECT_LT((y - gtY).norm(), kTolerance);
  842. }
  843. {
  844. Vector4d delta;
  845. delta << Vector2d(1.0, 2.0),
  846. Vector2d(1, 1).normalized() * constants::pi / 2;
  847. Vector6d y = Vector6d::Zero();
  848. EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
  849. Vector6d gtY;
  850. gtY << Vector3d(1.0, 2.0, 0.0),
  851. Vector3d(std::sqrt(2.0) / 2.0, std::sqrt(2.0) / 2.0, 0.0);
  852. EXPECT_LT((y - gtY).norm(), kTolerance);
  853. }
  854. }
  855. TEST(LineManifold, NormalFunctionTest) {
  856. LineManifold<3> manifold;
  857. EXPECT_EQ(manifold.AmbientSize(), 6);
  858. EXPECT_EQ(manifold.TangentSize(), 4);
  859. Vector zero_tangent = Vector::Zero(manifold.TangentSize());
  860. for (int trial = 0; trial < kNumTrials; ++trial) {
  861. Vector x = Vector::Random(manifold.AmbientSize());
  862. Vector y = Vector::Random(manifold.AmbientSize());
  863. Vector delta = Vector::Random(manifold.TangentSize());
  864. if (x.tail<3>().norm() == 0.0) {
  865. continue;
  866. }
  867. x.tail<3>().normalize();
  868. manifold.Plus(x.data(), delta.data(), y.data());
  869. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  870. }
  871. }
  872. TEST(LineManifold, NormalFunctionTestDynamic) {
  873. LineManifold<ceres::DYNAMIC> manifold(3);
  874. EXPECT_EQ(manifold.AmbientSize(), 6);
  875. EXPECT_EQ(manifold.TangentSize(), 4);
  876. Vector zero_tangent = Vector::Zero(manifold.TangentSize());
  877. for (int trial = 0; trial < kNumTrials; ++trial) {
  878. Vector x = Vector::Random(manifold.AmbientSize());
  879. Vector y = Vector::Random(manifold.AmbientSize());
  880. Vector delta = Vector::Random(manifold.TangentSize());
  881. if (x.tail<3>().norm() == 0.0) {
  882. continue;
  883. }
  884. x.tail<3>().normalize();
  885. manifold.Plus(x.data(), delta.data(), y.data());
  886. EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
  887. }
  888. }
  889. } // namespace ceres::internal