invert_psd_matrix_test.cc 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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/invert_psd_matrix.h"
  31. #include "ceres/internal/eigen.h"
  32. #include "gtest/gtest.h"
  33. namespace ceres::internal {
  34. static constexpr bool kFullRank = true;
  35. static constexpr bool kRankDeficient = false;
  36. template <int kSize>
  37. typename EigenTypes<kSize, kSize>::Matrix RandomPSDMatrixWithEigenValues(
  38. const typename EigenTypes<kSize>::Vector& eigenvalues) {
  39. typename EigenTypes<kSize, kSize>::Matrix m(eigenvalues.rows(),
  40. eigenvalues.rows());
  41. m.setRandom();
  42. Eigen::SelfAdjointEigenSolver<typename EigenTypes<kSize, kSize>::Matrix> es(
  43. m);
  44. return es.eigenvectors() * eigenvalues.asDiagonal() *
  45. es.eigenvectors().transpose();
  46. }
  47. TEST(InvertPSDMatrix, Identity3x3) {
  48. const Matrix m = Matrix::Identity(3, 3);
  49. const Matrix inverse_m = InvertPSDMatrix<3>(kFullRank, m);
  50. EXPECT_NEAR((inverse_m - m).norm() / m.norm(),
  51. 0.0,
  52. std::numeric_limits<double>::epsilon());
  53. }
  54. TEST(InvertPSDMatrix, FullRank5x5) {
  55. EigenTypes<5>::Vector eigenvalues;
  56. eigenvalues.setRandom();
  57. eigenvalues = eigenvalues.array().abs().matrix();
  58. const Matrix m = RandomPSDMatrixWithEigenValues<5>(eigenvalues);
  59. const Matrix inverse_m = InvertPSDMatrix<5>(kFullRank, m);
  60. EXPECT_NEAR((m * inverse_m - Matrix::Identity(5, 5)).norm() / 5.0,
  61. 0.0,
  62. 10 * std::numeric_limits<double>::epsilon());
  63. }
  64. TEST(InvertPSDMatrix, RankDeficient5x5) {
  65. EigenTypes<5>::Vector eigenvalues;
  66. eigenvalues.setRandom();
  67. eigenvalues = eigenvalues.array().abs().matrix();
  68. eigenvalues(3) = 0.0;
  69. const Matrix m = RandomPSDMatrixWithEigenValues<5>(eigenvalues);
  70. const Matrix inverse_m = InvertPSDMatrix<5>(kRankDeficient, m);
  71. Matrix pseudo_identity = Matrix::Identity(5, 5);
  72. pseudo_identity(3, 3) = 0.0;
  73. EXPECT_NEAR((m * inverse_m * m - m).norm() / m.norm(),
  74. 0.0,
  75. 10 * std::numeric_limits<double>::epsilon());
  76. }
  77. TEST(InvertPSDMatrix, DynamicFullRank5x5) {
  78. EigenTypes<Eigen::Dynamic>::Vector eigenvalues(5);
  79. eigenvalues.setRandom();
  80. eigenvalues = eigenvalues.array().abs().matrix();
  81. const Matrix m = RandomPSDMatrixWithEigenValues<Eigen::Dynamic>(eigenvalues);
  82. const Matrix inverse_m = InvertPSDMatrix<Eigen::Dynamic>(kFullRank, m);
  83. EXPECT_NEAR((m * inverse_m - Matrix::Identity(5, 5)).norm() / 5.0,
  84. 0.0,
  85. 10 * std::numeric_limits<double>::epsilon());
  86. }
  87. TEST(InvertPSDMatrix, DynamicRankDeficient5x5) {
  88. EigenTypes<Eigen::Dynamic>::Vector eigenvalues(5);
  89. eigenvalues.setRandom();
  90. eigenvalues = eigenvalues.array().abs().matrix();
  91. eigenvalues(3) = 0.0;
  92. const Matrix m = RandomPSDMatrixWithEigenValues<Eigen::Dynamic>(eigenvalues);
  93. const Matrix inverse_m = InvertPSDMatrix<Eigen::Dynamic>(kRankDeficient, m);
  94. Matrix pseudo_identity = Matrix::Identity(5, 5);
  95. pseudo_identity(3, 3) = 0.0;
  96. EXPECT_NEAR((m * inverse_m * m - m).norm() / m.norm(),
  97. 0.0,
  98. 10 * std::numeric_limits<double>::epsilon());
  99. }
  100. } // namespace ceres::internal