residual_block.cc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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. // sameeragarwal@google.com (Sameer Agarwal)
  31. #include "ceres/residual_block.h"
  32. #include <algorithm>
  33. #include <cstddef>
  34. #include <vector>
  35. #include "ceres/corrector.h"
  36. #include "ceres/cost_function.h"
  37. #include "ceres/internal/eigen.h"
  38. #include "ceres/internal/fixed_array.h"
  39. #include "ceres/loss_function.h"
  40. #include "ceres/manifold.h"
  41. #include "ceres/parameter_block.h"
  42. #include "ceres/residual_block_utils.h"
  43. #include "ceres/small_blas.h"
  44. using Eigen::Dynamic;
  45. namespace ceres::internal {
  46. ResidualBlock::ResidualBlock(
  47. const CostFunction* cost_function,
  48. const LossFunction* loss_function,
  49. const std::vector<ParameterBlock*>& parameter_blocks,
  50. int index)
  51. : cost_function_(cost_function),
  52. loss_function_(loss_function),
  53. parameter_blocks_(
  54. new ParameterBlock*[cost_function->parameter_block_sizes().size()]),
  55. index_(index) {
  56. CHECK(cost_function_ != nullptr);
  57. std::copy(parameter_blocks.begin(),
  58. parameter_blocks.end(),
  59. parameter_blocks_.get());
  60. }
  61. bool ResidualBlock::Evaluate(const bool apply_loss_function,
  62. double* cost,
  63. double* residuals,
  64. double** jacobians,
  65. double* scratch) const {
  66. const int num_parameter_blocks = NumParameterBlocks();
  67. const int num_residuals = cost_function_->num_residuals();
  68. // Collect the parameters from their blocks. This will rarely allocate, since
  69. // residuals taking more than 8 parameter block arguments are rare.
  70. FixedArray<const double*, 8> parameters(num_parameter_blocks);
  71. for (int i = 0; i < num_parameter_blocks; ++i) {
  72. parameters[i] = parameter_blocks_[i]->state();
  73. }
  74. // Put pointers into the scratch space into global_jacobians as appropriate.
  75. FixedArray<double*, 8> global_jacobians(num_parameter_blocks);
  76. if (jacobians != nullptr) {
  77. for (int i = 0; i < num_parameter_blocks; ++i) {
  78. const ParameterBlock* parameter_block = parameter_blocks_[i];
  79. if (jacobians[i] != nullptr &&
  80. parameter_block->PlusJacobian() != nullptr) {
  81. global_jacobians[i] = scratch;
  82. scratch += num_residuals * parameter_block->Size();
  83. } else {
  84. global_jacobians[i] = jacobians[i];
  85. }
  86. }
  87. }
  88. // If the caller didn't request residuals, use the scratch space for them.
  89. bool outputting_residuals = (residuals != nullptr);
  90. if (!outputting_residuals) {
  91. residuals = scratch;
  92. }
  93. // Invalidate the evaluation buffers so that we can check them after
  94. // the CostFunction::Evaluate call, to see if all the return values
  95. // that were required were written to and that they are finite.
  96. double** eval_jacobians =
  97. (jacobians != nullptr) ? global_jacobians.data() : nullptr;
  98. InvalidateEvaluation(*this, cost, residuals, eval_jacobians);
  99. if (!cost_function_->Evaluate(parameters.data(), residuals, eval_jacobians)) {
  100. return false;
  101. }
  102. if (!IsEvaluationValid(*this, parameters.data(), residuals, eval_jacobians)) {
  103. // clang-format off
  104. std::string message =
  105. "\n\n"
  106. "Error in evaluating the ResidualBlock.\n\n"
  107. "There are two possible reasons. Either the CostFunction did not evaluate and fill all \n" // NOLINT
  108. "residual and jacobians that were requested or there was a non-finite value (nan/infinite)\n" // NOLINT
  109. "generated during the or jacobian computation. \n\n" +
  110. EvaluationToString(
  111. *this, parameters.data(), cost, residuals, eval_jacobians);
  112. // clang-format on
  113. LOG(WARNING) << message;
  114. return false;
  115. }
  116. double squared_norm = VectorRef(residuals, num_residuals).squaredNorm();
  117. // Update the plus_jacobian for the manifolds.
  118. if (jacobians != nullptr) {
  119. for (int i = 0; i < num_parameter_blocks; ++i) {
  120. if (jacobians[i] != nullptr) {
  121. const ParameterBlock* parameter_block = parameter_blocks_[i];
  122. // Apply the Manifold::PlusJacobian to the ambient jacobians.
  123. if (parameter_block->PlusJacobian() != nullptr) {
  124. // jacobians[i] = global_jacobians[i] * global_to_local_jacobian.
  125. MatrixMatrixMultiply<Dynamic, Dynamic, Dynamic, Dynamic, 0>(
  126. global_jacobians[i],
  127. num_residuals,
  128. parameter_block->Size(),
  129. parameter_block->PlusJacobian(),
  130. parameter_block->Size(),
  131. parameter_block->TangentSize(),
  132. jacobians[i],
  133. 0,
  134. 0,
  135. num_residuals,
  136. parameter_block->TangentSize());
  137. }
  138. }
  139. }
  140. }
  141. if (loss_function_ == nullptr || !apply_loss_function) {
  142. *cost = 0.5 * squared_norm;
  143. return true;
  144. }
  145. double rho[3];
  146. loss_function_->Evaluate(squared_norm, rho);
  147. *cost = 0.5 * rho[0];
  148. // No jacobians and not outputting residuals? All done. Doing an early exit
  149. // here avoids constructing the "Corrector" object below in a common case.
  150. if (jacobians == nullptr && !outputting_residuals) {
  151. return true;
  152. }
  153. // Correct for the effects of the loss function. The jacobians need to be
  154. // corrected before the residuals, since they use the uncorrected residuals.
  155. Corrector correct(squared_norm, rho);
  156. if (jacobians != nullptr) {
  157. for (int i = 0; i < num_parameter_blocks; ++i) {
  158. if (jacobians[i] != nullptr) {
  159. const ParameterBlock* parameter_block = parameter_blocks_[i];
  160. // Correct the jacobians for the loss function.
  161. correct.CorrectJacobian(num_residuals,
  162. parameter_block->TangentSize(),
  163. residuals,
  164. jacobians[i]);
  165. }
  166. }
  167. }
  168. // Correct the residuals with the loss function.
  169. if (outputting_residuals) {
  170. correct.CorrectResiduals(num_residuals, residuals);
  171. }
  172. return true;
  173. }
  174. int ResidualBlock::NumScratchDoublesForEvaluate() const {
  175. // Compute the amount of scratch space needed to store the full-sized
  176. // jacobians. For parameters that have no manifold no storage is needed and
  177. // the passed-in jacobian array is used directly. Also include space to store
  178. // the residuals, which is needed for cost-only evaluations. This is slightly
  179. // pessimistic, since both won't be needed all the time, but the amount of
  180. // excess should not cause problems for the caller.
  181. int num_parameters = NumParameterBlocks();
  182. int scratch_doubles = 1;
  183. for (int i = 0; i < num_parameters; ++i) {
  184. const ParameterBlock* parameter_block = parameter_blocks_[i];
  185. if (parameter_block->PlusJacobian() != nullptr) {
  186. scratch_doubles += parameter_block->Size();
  187. }
  188. }
  189. scratch_doubles *= NumResiduals();
  190. return scratch_doubles;
  191. }
  192. } // namespace ceres::internal