numeric_diff_first_order_function.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Ceres Solver - A fast non-linear least squares minimizer
  2. // Copyright 2019 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. #ifndef CERES_PUBLIC_NUMERIC_DIFF_FIRST_ORDER_FUNCTION_H_
  31. #define CERES_PUBLIC_NUMERIC_DIFF_FIRST_ORDER_FUNCTION_H_
  32. #include <algorithm>
  33. #include <memory>
  34. #include "ceres/first_order_function.h"
  35. #include "ceres/internal/eigen.h"
  36. #include "ceres/internal/fixed_array.h"
  37. #include "ceres/internal/numeric_diff.h"
  38. #include "ceres/internal/parameter_dims.h"
  39. #include "ceres/internal/variadic_evaluate.h"
  40. #include "ceres/numeric_diff_options.h"
  41. #include "ceres/types.h"
  42. #include "glog/logging.h"
  43. namespace ceres {
  44. // Creates FirstOrderFunctions as needed by the GradientProblem
  45. // framework, with gradients computed via numeric differentiation. For
  46. // more information on numeric differentiation, see the wikipedia
  47. // article at https://en.wikipedia.org/wiki/Numerical_differentiation
  48. //
  49. // To get an numerically differentiated cost function, you must define
  50. // a class with an operator() (a functor) that computes the cost.
  51. //
  52. // The function must write the computed value in the last argument
  53. // (the only non-const one) and return true to indicate success.
  54. //
  55. // For example, consider a scalar error e = x'y - a, where both x and y are
  56. // two-dimensional column vector parameters, the prime sign indicates
  57. // transposition, and a is a constant.
  58. //
  59. // To write an numerically-differentiable cost function for the above model,
  60. // first define the object
  61. //
  62. // class QuadraticCostFunctor {
  63. // public:
  64. // explicit QuadraticCostFunctor(double a) : a_(a) {}
  65. // bool operator()(const double* const xy, double* cost) const {
  66. // constexpr int kInputVectorLength = 2;
  67. // const double* const x = xy;
  68. // const double* const y = xy + kInputVectorLength;
  69. // *cost = x[0] * y[0] + x[1] * y[1] - a_;
  70. // return true;
  71. // }
  72. //
  73. // private:
  74. // double a_;
  75. // };
  76. //
  77. //
  78. // Note that in the declaration of operator() the input parameters xy
  79. // come first, and are passed as const pointers to array of
  80. // doubles. The output cost is the last parameter.
  81. //
  82. // Then given this class definition, the numerically differentiated
  83. // first order function with central differences used for computing the
  84. // derivative can be constructed as follows.
  85. //
  86. // FirstOrderFunction* function
  87. // = new NumericDiffFirstOrderFunction<MyScalarCostFunctor, CENTRAL, 4>(
  88. // new QuadraticCostFunctor(1.0)); ^ ^ ^
  89. // | | |
  90. // Finite Differencing Scheme -+ | |
  91. // Dimension of xy ------------------------+
  92. //
  93. //
  94. // In the instantiation above, the template parameters following
  95. // "QuadraticCostFunctor", "CENTRAL, 4", describe the finite
  96. // differencing scheme as "central differencing" and the functor as
  97. // computing its cost from a 4 dimensional input.
  98. //
  99. // If the size of the parameter vector is not known at compile time, then an
  100. // alternate construction syntax can be used:
  101. //
  102. // FirstOrderFunction* function
  103. // = new NumericDiffFirstOrderFunction<MyScalarCostFunctor, CENTRAL>(
  104. // new QuadraticCostFunctor(1.0), 4);
  105. //
  106. // Note that instead of passing 4 as a template argument, it is now passed as
  107. // the second argument to the constructor.
  108. template <typename FirstOrderFunctor,
  109. NumericDiffMethodType kMethod,
  110. int kNumParameters = DYNAMIC>
  111. class NumericDiffFirstOrderFunction final : public FirstOrderFunction {
  112. public:
  113. // Constructor for the case where the parameter size is known at compile time.
  114. explicit NumericDiffFirstOrderFunction(
  115. FirstOrderFunctor* functor,
  116. Ownership ownership = TAKE_OWNERSHIP,
  117. const NumericDiffOptions& options = NumericDiffOptions())
  118. : functor_(functor),
  119. num_parameters_(kNumParameters),
  120. ownership_(ownership),
  121. options_(options) {
  122. static_assert(kNumParameters != DYNAMIC,
  123. "Number of parameters must be static when defined via the "
  124. "template parameter. Use the other constructor for "
  125. "dynamically sized functions.");
  126. static_assert(kNumParameters > 0, "kNumParameters must be positive");
  127. }
  128. // Constructor for the case where the parameter size is specified at run time.
  129. explicit NumericDiffFirstOrderFunction(
  130. FirstOrderFunctor* functor,
  131. int num_parameters,
  132. Ownership ownership = TAKE_OWNERSHIP,
  133. const NumericDiffOptions& options = NumericDiffOptions())
  134. : functor_(functor),
  135. num_parameters_(num_parameters),
  136. ownership_(ownership),
  137. options_(options) {
  138. static_assert(
  139. kNumParameters == DYNAMIC,
  140. "Template parameter must be DYNAMIC when using this constructor. If "
  141. "you want to provide the number of parameters statically use the other "
  142. "constructor.");
  143. CHECK_GT(num_parameters, 0);
  144. }
  145. ~NumericDiffFirstOrderFunction() override {
  146. if (ownership_ != TAKE_OWNERSHIP) {
  147. functor_.release();
  148. }
  149. }
  150. bool Evaluate(const double* const parameters,
  151. double* cost,
  152. double* gradient) const override {
  153. // Get the function value (cost) at the the point to evaluate.
  154. if (!(*functor_)(parameters, cost)) {
  155. return false;
  156. }
  157. if (gradient == nullptr) {
  158. return true;
  159. }
  160. // Create a copy of the parameters which will get mutated.
  161. internal::FixedArray<double, 32> parameters_copy(num_parameters_);
  162. std::copy_n(parameters, num_parameters_, parameters_copy.data());
  163. double* parameters_ptr = parameters_copy.data();
  164. constexpr int kNumResiduals = 1;
  165. if constexpr (kNumParameters == DYNAMIC) {
  166. internal::FirstOrderFunctorAdapter<FirstOrderFunctor> fofa(*functor_);
  167. return internal::NumericDiff<
  168. internal::FirstOrderFunctorAdapter<FirstOrderFunctor>,
  169. kMethod,
  170. kNumResiduals,
  171. internal::DynamicParameterDims,
  172. 0,
  173. DYNAMIC>::EvaluateJacobianForParameterBlock(&fofa,
  174. cost,
  175. options_,
  176. kNumResiduals,
  177. 0,
  178. num_parameters_,
  179. &parameters_ptr,
  180. gradient);
  181. } else {
  182. return internal::EvaluateJacobianForParameterBlocks<
  183. internal::StaticParameterDims<kNumParameters>>::
  184. template Apply<kMethod, 1>(functor_.get(),
  185. cost,
  186. options_,
  187. kNumResiduals,
  188. &parameters_ptr,
  189. &gradient);
  190. }
  191. }
  192. int NumParameters() const override { return num_parameters_; }
  193. const FirstOrderFunctor& functor() const { return *functor_; }
  194. private:
  195. std::unique_ptr<FirstOrderFunctor> functor_;
  196. const int num_parameters_;
  197. const Ownership ownership_;
  198. const NumericDiffOptions options_;
  199. };
  200. } // namespace ceres
  201. #endif // CERES_PUBLIC_NUMERIC_DIFF_FIRST_ORDER_FUNCTION_H_