numeric_diff_cost_function.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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: keir@google.com (Keir Mierle)
  30. // sameeragarwal@google.com (Sameer Agarwal)
  31. //
  32. // Create CostFunctions as needed by the least squares framework with jacobians
  33. // computed via numeric (a.k.a. finite) differentiation. For more details see
  34. // http://en.wikipedia.org/wiki/Numerical_differentiation.
  35. //
  36. // To get an numerically differentiated cost function, you must define
  37. // a class with a operator() (a functor) that computes the residuals.
  38. //
  39. // The function must write the computed value in the last argument
  40. // (the only non-const one) and return true to indicate success.
  41. // Please see cost_function.h for details on how the return value
  42. // maybe used to impose simple constraints on the parameter block.
  43. //
  44. // For example, consider a scalar error e = k - x'y, where both x and y are
  45. // two-dimensional column vector parameters, the prime sign indicates
  46. // transposition, and k is a constant. The form of this error, which is the
  47. // difference between a constant and an expression, is a common pattern in least
  48. // squares problems. For example, the value x'y might be the model expectation
  49. // for a series of measurements, where there is an instance of the cost function
  50. // for each measurement k.
  51. //
  52. // The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
  53. // the squaring is implicitly done by the optimization framework.
  54. //
  55. // To write an numerically-differentiable cost function for the above model,
  56. // first define the object
  57. //
  58. // class MyScalarCostFunctor {
  59. // explicit MyScalarCostFunctor(double k): k_(k) {}
  60. //
  61. // bool operator()(const double* const x,
  62. // const double* const y,
  63. // double* residuals) const {
  64. // residuals[0] = k_ - x[0] * y[0] - x[1] * y[1];
  65. // return true;
  66. // }
  67. //
  68. // private:
  69. // double k_;
  70. // };
  71. //
  72. // Note that in the declaration of operator() the input parameters x
  73. // and y come first, and are passed as const pointers to arrays of
  74. // doubles. If there were three input parameters, then the third input
  75. // parameter would come after y. The output is always the last
  76. // parameter, and is also a pointer to an array. In the example above,
  77. // the residual is a scalar, so only residuals[0] is set.
  78. //
  79. // Then given this class definition, the numerically differentiated
  80. // cost function with central differences used for computing the
  81. // derivative can be constructed as follows.
  82. //
  83. // CostFunction* cost_function
  84. // = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, 1, 2, 2>(
  85. // new MyScalarCostFunctor(1.0)); ^ ^ ^ ^
  86. // | | | |
  87. // Finite Differencing Scheme -+ | | |
  88. // Dimension of residual ------------+ | |
  89. // Dimension of x ----------------------+ |
  90. // Dimension of y -------------------------+
  91. //
  92. // In this example, there is usually an instance for each measurement of k.
  93. //
  94. // In the instantiation above, the template parameters following
  95. // "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing
  96. // a 1-dimensional output from two arguments, both 2-dimensional.
  97. //
  98. // NumericDiffCostFunction also supports cost functions with a
  99. // runtime-determined number of residuals. For example:
  100. //
  101. // clang-format off
  102. //
  103. // CostFunction* cost_function
  104. // = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, DYNAMIC, 2, 2>(
  105. // new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
  106. // TAKE_OWNERSHIP, | | |
  107. // runtime_number_of_residuals); <----+ | | |
  108. // | | | |
  109. // | | | |
  110. // Actual number of residuals ------+ | | |
  111. // Indicate dynamic number of residuals --------------------+ | |
  112. // Dimension of x ------------------------------------------------+ |
  113. // Dimension of y ---------------------------------------------------+
  114. // clang-format on
  115. //
  116. //
  117. // The central difference method is considerably more accurate at the cost of
  118. // twice as many function evaluations than forward difference. Consider using
  119. // central differences begin with, and only after that works, trying forward
  120. // difference to improve performance.
  121. //
  122. // WARNING #1: A common beginner's error when first using
  123. // NumericDiffCostFunction is to get the sizing wrong. In particular,
  124. // there is a tendency to set the template parameters to (dimension of
  125. // residual, number of parameters) instead of passing a dimension
  126. // parameter for *every parameter*. In the example above, that would
  127. // be <MyScalarCostFunctor, 1, 2>, which is missing the last '2'
  128. // argument. Please be careful when setting the size parameters.
  129. //
  130. ////////////////////////////////////////////////////////////////////////////
  131. ////////////////////////////////////////////////////////////////////////////
  132. //
  133. // ALTERNATE INTERFACE
  134. //
  135. // For a variety of reasons, including compatibility with legacy code,
  136. // NumericDiffCostFunction can also take CostFunction objects as
  137. // input. The following describes how.
  138. //
  139. // To get a numerically differentiated cost function, define a
  140. // subclass of CostFunction such that the Evaluate() function ignores
  141. // the jacobian parameter. The numeric differentiation wrapper will
  142. // fill in the jacobian parameter if necessary by repeatedly calling
  143. // the Evaluate() function with small changes to the appropriate
  144. // parameters, and computing the slope. For performance, the numeric
  145. // differentiation wrapper class is templated on the concrete cost
  146. // function, even though it could be implemented only in terms of the
  147. // virtual CostFunction interface.
  148. //
  149. // The numerically differentiated version of a cost function for a cost function
  150. // can be constructed as follows:
  151. //
  152. // CostFunction* cost_function
  153. // = new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>(
  154. // new MyCostFunction(...), TAKE_OWNERSHIP);
  155. //
  156. // where MyCostFunction has 1 residual and 2 parameter blocks with sizes 4 and 8
  157. // respectively. Look at the tests for a more detailed example.
  158. //
  159. // TODO(keir): Characterize accuracy; mention pitfalls; provide alternatives.
  160. #ifndef CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
  161. #define CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
  162. #include <array>
  163. #include <memory>
  164. #include "Eigen/Dense"
  165. #include "ceres/cost_function.h"
  166. #include "ceres/internal/numeric_diff.h"
  167. #include "ceres/internal/parameter_dims.h"
  168. #include "ceres/numeric_diff_options.h"
  169. #include "ceres/sized_cost_function.h"
  170. #include "ceres/types.h"
  171. #include "glog/logging.h"
  172. namespace ceres {
  173. template <typename CostFunctor,
  174. NumericDiffMethodType kMethod = CENTRAL,
  175. int kNumResiduals = 0, // Number of residuals, or ceres::DYNAMIC
  176. int... Ns> // Parameters dimensions for each block.
  177. class NumericDiffCostFunction final
  178. : public SizedCostFunction<kNumResiduals, Ns...> {
  179. public:
  180. explicit NumericDiffCostFunction(
  181. CostFunctor* functor,
  182. Ownership ownership = TAKE_OWNERSHIP,
  183. int num_residuals = kNumResiduals,
  184. const NumericDiffOptions& options = NumericDiffOptions())
  185. : functor_(functor), ownership_(ownership), options_(options) {
  186. if (kNumResiduals == DYNAMIC) {
  187. SizedCostFunction<kNumResiduals, Ns...>::set_num_residuals(num_residuals);
  188. }
  189. }
  190. NumericDiffCostFunction(NumericDiffCostFunction&& other)
  191. : functor_(std::move(other.functor_)), ownership_(other.ownership_) {}
  192. virtual ~NumericDiffCostFunction() {
  193. if (ownership_ != TAKE_OWNERSHIP) {
  194. functor_.release();
  195. }
  196. }
  197. bool Evaluate(double const* const* parameters,
  198. double* residuals,
  199. double** jacobians) const override {
  200. using internal::FixedArray;
  201. using internal::NumericDiff;
  202. using ParameterDims =
  203. typename SizedCostFunction<kNumResiduals, Ns...>::ParameterDims;
  204. constexpr int kNumParameters = ParameterDims::kNumParameters;
  205. constexpr int kNumParameterBlocks = ParameterDims::kNumParameterBlocks;
  206. // Get the function value (residuals) at the the point to evaluate.
  207. if (!internal::VariadicEvaluate<ParameterDims>(
  208. *functor_, parameters, residuals)) {
  209. return false;
  210. }
  211. if (jacobians == nullptr) {
  212. return true;
  213. }
  214. // Create a copy of the parameters which will get mutated.
  215. FixedArray<double> parameters_copy(kNumParameters);
  216. std::array<double*, kNumParameterBlocks> parameters_reference_copy =
  217. ParameterDims::GetUnpackedParameters(parameters_copy.data());
  218. for (int block = 0; block < kNumParameterBlocks; ++block) {
  219. memcpy(parameters_reference_copy[block],
  220. parameters[block],
  221. sizeof(double) * ParameterDims::GetDim(block));
  222. }
  223. internal::EvaluateJacobianForParameterBlocks<ParameterDims>::
  224. template Apply<kMethod, kNumResiduals>(
  225. functor_.get(),
  226. residuals,
  227. options_,
  228. SizedCostFunction<kNumResiduals, Ns...>::num_residuals(),
  229. parameters_reference_copy.data(),
  230. jacobians);
  231. return true;
  232. }
  233. const CostFunctor& functor() const { return *functor_; }
  234. private:
  235. std::unique_ptr<CostFunctor> functor_;
  236. Ownership ownership_;
  237. NumericDiffOptions options_;
  238. };
  239. } // namespace ceres
  240. #endif // CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_