test_so2.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include <iostream>
  2. #include <sophus/so2.hpp>
  3. #include "tests.hpp"
  4. // Explicit instantiate all class templates so that all member methods
  5. // get compiled and for code coverage analysis.
  6. namespace Eigen {
  7. template class Map<Sophus::SO2<double>>;
  8. template class Map<Sophus::SO2<double> const>;
  9. } // namespace Eigen
  10. namespace Sophus {
  11. template class SO2<double, Eigen::AutoAlign>;
  12. template class SO2<float, Eigen::DontAlign>;
  13. #if SOPHUS_CERES
  14. template class SO2<ceres::Jet<double, 3>>;
  15. #endif
  16. template <class Scalar>
  17. class Tests {
  18. public:
  19. using SO2Type = SO2<Scalar>;
  20. using Point = typename SO2<Scalar>::Point;
  21. using Tangent = typename SO2<Scalar>::Tangent;
  22. Scalar const kPi = Constants<Scalar>::pi();
  23. Tests() {
  24. so2_vec_.push_back(SO2Type::exp(Scalar(0.0)));
  25. so2_vec_.push_back(SO2Type::exp(Scalar(0.2)));
  26. so2_vec_.push_back(SO2Type::exp(Scalar(10.)));
  27. so2_vec_.push_back(SO2Type::exp(Scalar(0.00001)));
  28. so2_vec_.push_back(SO2Type::exp(kPi));
  29. so2_vec_.push_back(SO2Type::exp(Scalar(0.2)) * SO2Type::exp(kPi) *
  30. SO2Type::exp(Scalar(-0.2)));
  31. so2_vec_.push_back(SO2Type::exp(Scalar(-0.3)) * SO2Type::exp(kPi) *
  32. SO2Type::exp(Scalar(0.3)));
  33. tangent_vec_.push_back(Tangent(Scalar(0)));
  34. tangent_vec_.push_back(Tangent(Scalar(1)));
  35. tangent_vec_.push_back(Tangent(Scalar(kPi / 2.)));
  36. tangent_vec_.push_back(Tangent(Scalar(-1)));
  37. tangent_vec_.push_back(Tangent(Scalar(20)));
  38. tangent_vec_.push_back(Tangent(Scalar(kPi / 2. + 0.0001)));
  39. point_vec_.push_back(Point(Scalar(1), Scalar(2)));
  40. point_vec_.push_back(Point(Scalar(1), Scalar(-3)));
  41. }
  42. void runAll() {
  43. bool passed = testLieProperties();
  44. passed &= testUnity();
  45. passed &= testRawDataAcces();
  46. passed &= testConstructors();
  47. passed &= testFit();
  48. processTestResult(passed);
  49. }
  50. private:
  51. bool testLieProperties() {
  52. LieGroupTests<SO2Type> tests(so2_vec_, tangent_vec_, point_vec_);
  53. return tests.doAllTestsPass();
  54. }
  55. bool testUnity() {
  56. bool passed = true;
  57. // Test that the complex number magnitude stays close to one.
  58. SO2Type current_q;
  59. for (std::size_t i = 0; i < 1000; ++i) {
  60. for (SO2Type const& q : so2_vec_) {
  61. current_q *= q;
  62. }
  63. }
  64. SOPHUS_TEST_APPROX(passed, current_q.unit_complex().norm(), Scalar(1),
  65. Constants<Scalar>::epsilon(), "Magnitude drift");
  66. return passed;
  67. }
  68. bool testRawDataAcces() {
  69. bool passed = true;
  70. Vector2<Scalar> raw = {0, 1};
  71. Eigen::Map<SO2Type const> map_of_const_so2(raw.data());
  72. SOPHUS_TEST_APPROX(passed, map_of_const_so2.unit_complex().eval(), raw,
  73. Constants<Scalar>::epsilon());
  74. SOPHUS_TEST_EQUAL(passed, map_of_const_so2.unit_complex().data(),
  75. raw.data());
  76. Eigen::Map<SO2Type const> const_shallow_copy = map_of_const_so2;
  77. SOPHUS_TEST_EQUAL(passed, const_shallow_copy.unit_complex().eval(),
  78. map_of_const_so2.unit_complex().eval());
  79. Vector2<Scalar> raw2 = {1, 0};
  80. Eigen::Map<SO2Type> map_of_so2(raw.data());
  81. map_of_so2.setComplex(raw2);
  82. SOPHUS_TEST_APPROX(passed, map_of_so2.unit_complex().eval(), raw2,
  83. Constants<Scalar>::epsilon());
  84. SOPHUS_TEST_EQUAL(passed, map_of_so2.unit_complex().data(), raw.data());
  85. SOPHUS_TEST_NEQ(passed, map_of_so2.unit_complex().data(), raw2.data());
  86. Eigen::Map<SO2Type> shallow_copy = map_of_so2;
  87. SOPHUS_TEST_EQUAL(passed, shallow_copy.unit_complex().eval(),
  88. map_of_so2.unit_complex().eval());
  89. SO2Type const const_so2(raw2);
  90. for (int i = 0; i < 2; ++i) {
  91. SOPHUS_TEST_EQUAL(passed, const_so2.data()[i], raw2.data()[i]);
  92. }
  93. SO2Type so2(raw2);
  94. for (int i = 0; i < 2; ++i) {
  95. so2.data()[i] = raw[i];
  96. }
  97. for (int i = 0; i < 2; ++i) {
  98. SOPHUS_TEST_EQUAL(passed, so2.data()[i], raw.data()[i]);
  99. }
  100. Vector2<Scalar> data1 = {1, 0}, data2 = {0, 1};
  101. Eigen::Map<SO2Type> map1(data1.data()), map2(data2.data());
  102. // map -> map assignment
  103. map2 = map1;
  104. SOPHUS_TEST_EQUAL(passed, map1.matrix(), map2.matrix());
  105. // map -> type assignment
  106. SO2Type copy;
  107. copy = map1;
  108. SOPHUS_TEST_EQUAL(passed, map1.matrix(), copy.matrix());
  109. // type -> map assignment
  110. copy = SO2Type(Scalar(0.5));
  111. map1 = copy;
  112. SOPHUS_TEST_EQUAL(passed, map1.matrix(), copy.matrix());
  113. return passed;
  114. }
  115. bool testConstructors() {
  116. bool passed = true;
  117. Matrix2<Scalar> R = so2_vec_.front().matrix();
  118. SO2Type so2(R);
  119. SOPHUS_TEST_APPROX(passed, R, so2.matrix(), Constants<Scalar>::epsilon());
  120. return passed;
  121. }
  122. template <class S = Scalar>
  123. enable_if_t<std::is_floating_point<S>::value, bool> testFit() {
  124. bool passed = true;
  125. for (int i = 0; i < 100; ++i) {
  126. Matrix2<Scalar> R = Matrix2<Scalar>::Random();
  127. SO2Type so2 = SO2Type::fitToSO2(R);
  128. SO2Type so2_2 = SO2Type::fitToSO2(so2.matrix());
  129. SOPHUS_TEST_APPROX(passed, so2.matrix(), so2_2.matrix(),
  130. Constants<Scalar>::epsilon());
  131. }
  132. return passed;
  133. }
  134. template <class S = Scalar>
  135. enable_if_t<!std::is_floating_point<S>::value, bool> testFit() {
  136. return true;
  137. }
  138. std::vector<SO2Type, Eigen::aligned_allocator<SO2Type>> so2_vec_;
  139. std::vector<Tangent, Eigen::aligned_allocator<Tangent>> tangent_vec_;
  140. std::vector<Point, Eigen::aligned_allocator<Point>> point_vec_;
  141. };
  142. int test_so2() {
  143. using std::cerr;
  144. using std::endl;
  145. cerr << "Test SO2" << endl << endl;
  146. cerr << "Double tests: " << endl;
  147. Tests<double>().runAll();
  148. cerr << "Float tests: " << endl;
  149. Tests<float>().runAll();
  150. #if SOPHUS_CERES
  151. cerr << "ceres::Jet<double, 3> tests: " << endl;
  152. Tests<ceres::Jet<double, 3>>().runAll();
  153. #endif
  154. return 0;
  155. }
  156. } // namespace Sophus
  157. int main() { return Sophus::test_so2(); }