residual_block_utils_test.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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/residual_block_utils.h"
  31. #include <cmath>
  32. #include <limits>
  33. #include <memory>
  34. #include "ceres/cost_function.h"
  35. #include "ceres/parameter_block.h"
  36. #include "ceres/residual_block.h"
  37. #include "ceres/sized_cost_function.h"
  38. #include "gtest/gtest.h"
  39. namespace ceres {
  40. namespace internal {
  41. // Routine to check if ResidualBlock::Evaluate for unary CostFunction
  42. // with one residual succeeds with true or dies.
  43. static void CheckEvaluation(const CostFunction& cost_function, bool is_good) {
  44. double x = 1.0;
  45. ParameterBlock parameter_block(&x, 1, -1);
  46. std::vector<ParameterBlock*> parameter_blocks;
  47. parameter_blocks.push_back(&parameter_block);
  48. ResidualBlock residual_block(&cost_function, nullptr, parameter_blocks, -1);
  49. std::unique_ptr<double[]> scratch(
  50. new double[residual_block.NumScratchDoublesForEvaluate()]);
  51. double cost;
  52. double residuals;
  53. double jacobian;
  54. double* jacobians[] = {&jacobian};
  55. EXPECT_EQ(residual_block.Evaluate(
  56. true, &cost, &residuals, jacobians, scratch.get()),
  57. is_good);
  58. }
  59. // A CostFunction that behaves normally, i.e., it computes numerically
  60. // valid residuals and jacobians.
  61. class GoodCostFunction : public SizedCostFunction<1, 1> {
  62. public:
  63. bool Evaluate(double const* const* parameters,
  64. double* residuals,
  65. double** jacobians) const final {
  66. residuals[0] = 1;
  67. if (jacobians != nullptr && jacobians[0] != nullptr) {
  68. jacobians[0][0] = 0.0;
  69. }
  70. return true;
  71. }
  72. };
  73. // The following four CostFunctions simulate the different ways in
  74. // which user code can cause ResidualBlock::Evaluate to fail.
  75. class NoResidualUpdateCostFunction : public SizedCostFunction<1, 1> {
  76. public:
  77. bool Evaluate(double const* const* parameters,
  78. double* residuals,
  79. double** jacobians) const final {
  80. // Forget to update the residuals.
  81. // residuals[0] = 1;
  82. if (jacobians != nullptr && jacobians[0] != nullptr) {
  83. jacobians[0][0] = 0.0;
  84. }
  85. return true;
  86. }
  87. };
  88. class NoJacobianUpdateCostFunction : public SizedCostFunction<1, 1> {
  89. public:
  90. bool Evaluate(double const* const* parameters,
  91. double* residuals,
  92. double** jacobians) const final {
  93. residuals[0] = 1;
  94. if (jacobians != nullptr && jacobians[0] != nullptr) {
  95. // Forget to update the jacobians.
  96. // jacobians[0][0] = 0.0;
  97. }
  98. return true;
  99. }
  100. };
  101. class BadResidualCostFunction : public SizedCostFunction<1, 1> {
  102. public:
  103. bool Evaluate(double const* const* parameters,
  104. double* residuals,
  105. double** jacobians) const final {
  106. residuals[0] = std::numeric_limits<double>::infinity();
  107. if (jacobians != nullptr && jacobians[0] != nullptr) {
  108. jacobians[0][0] = 0.0;
  109. }
  110. return true;
  111. }
  112. };
  113. class BadJacobianCostFunction : public SizedCostFunction<1, 1> {
  114. public:
  115. bool Evaluate(double const* const* parameters,
  116. double* residuals,
  117. double** jacobians) const final {
  118. residuals[0] = 1.0;
  119. if (jacobians != nullptr && jacobians[0] != nullptr) {
  120. jacobians[0][0] = std::numeric_limits<double>::quiet_NaN();
  121. }
  122. return true;
  123. }
  124. };
  125. // Note: It is preferable to write the below test as:
  126. //
  127. // CheckEvaluation(GoodCostFunction(), true);
  128. // CheckEvaluation(NoResidualUpdateCostFunction(), false);
  129. // CheckEvaluation(NoJacobianUpdateCostFunction(), false);
  130. // ...
  131. //
  132. // however, there is a bug in the version of GCC on Mac OS X we tested, which
  133. // requires the objects get put into local variables instead of getting
  134. // instantiated on the stack.
  135. TEST(ResidualBlockUtils, CheckAllCombinationsOfBadness) {
  136. GoodCostFunction good_fun;
  137. CheckEvaluation(good_fun, true);
  138. NoResidualUpdateCostFunction no_residual;
  139. CheckEvaluation(no_residual, false);
  140. NoJacobianUpdateCostFunction no_jacobian;
  141. CheckEvaluation(no_jacobian, false);
  142. BadResidualCostFunction bad_residual;
  143. CheckEvaluation(bad_residual, false);
  144. BadJacobianCostFunction bad_jacobian;
  145. CheckEvaluation(bad_jacobian, false);
  146. }
  147. } // namespace internal
  148. } // namespace ceres