| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 | 
							- // Ceres Solver - A fast non-linear least squares minimizer
 
- // Copyright 2015 Google Inc. All rights reserved.
 
- // http://ceres-solver.org/
 
- //
 
- // Redistribution and use in source and binary forms, with or without
 
- // modification, are permitted provided that the following conditions are met:
 
- //
 
- // * Redistributions of source code must retain the above copyright notice,
 
- //   this list of conditions and the following disclaimer.
 
- // * Redistributions in binary form must reproduce the above copyright notice,
 
- //   this list of conditions and the following disclaimer in the documentation
 
- //   and/or other materials provided with the distribution.
 
- // * Neither the name of Google Inc. nor the names of its contributors may be
 
- //   used to endorse or promote products derived from this software without
 
- //   specific prior written permission.
 
- //
 
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
- // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
- // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 
- // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
- // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
- // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
- // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
- // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
- // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
- // POSSIBILITY OF SUCH DAMAGE.
 
- //
 
- // Author: sameeragarwal@google.com (Sameer Agarwal)
 
- //         mierle@gmail.com (Keir Mierle)
 
- //         tbennun@gmail.com (Tal Ben-Nun)
 
- //
 
- // Finite differencing routines used by NumericDiffCostFunction.
 
- #ifndef CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
 
- #define CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
 
- #include <cstring>
 
- #include "Eigen/Dense"
 
- #include "Eigen/StdVector"
 
- #include "ceres/cost_function.h"
 
- #include "ceres/internal/fixed_array.h"
 
- #include "ceres/internal/variadic_evaluate.h"
 
- #include "ceres/numeric_diff_options.h"
 
- #include "ceres/types.h"
 
- #include "glog/logging.h"
 
- namespace ceres {
 
- namespace internal {
 
- // This is split from the main class because C++ doesn't allow partial template
 
- // specializations for member functions. The alternative is to repeat the main
 
- // class for differing numbers of parameters, which is also unfortunate.
 
- template <typename CostFunctor, NumericDiffMethodType kMethod,
 
-           int kNumResiduals, typename ParameterDims, int kParameterBlock,
 
-           int kParameterBlockSize>
 
- struct NumericDiff {
 
-   // Mutates parameters but must restore them before return.
 
-   static bool EvaluateJacobianForParameterBlock(
 
-       const CostFunctor* functor,
 
-       const double* residuals_at_eval_point,
 
-       const NumericDiffOptions& options,
 
-       int num_residuals,
 
-       int parameter_block_index,
 
-       int parameter_block_size,
 
-       double **parameters,
 
-       double *jacobian) {
 
-     using Eigen::Map;
 
-     using Eigen::Matrix;
 
-     using Eigen::RowMajor;
 
-     using Eigen::ColMajor;
 
-     const int num_residuals_internal =
 
-         (kNumResiduals != ceres::DYNAMIC ? kNumResiduals : num_residuals);
 
-     const int parameter_block_index_internal =
 
-         (kParameterBlock != ceres::DYNAMIC ? kParameterBlock :
 
-                                              parameter_block_index);
 
-     const int parameter_block_size_internal =
 
-         (kParameterBlockSize != ceres::DYNAMIC ? kParameterBlockSize :
 
-                                                  parameter_block_size);
 
-     typedef Matrix<double, kNumResiduals, 1> ResidualVector;
 
-     typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
 
-     // The convoluted reasoning for choosing the Row/Column major
 
-     // ordering of the matrix is an artifact of the restrictions in
 
-     // Eigen that prevent it from creating RowMajor matrices with a
 
-     // single column. In these cases, we ask for a ColMajor matrix.
 
-     typedef Matrix<double,
 
-                    kNumResiduals,
 
-                    kParameterBlockSize,
 
-                    (kParameterBlockSize == 1) ? ColMajor : RowMajor>
 
-         JacobianMatrix;
 
-     Map<JacobianMatrix> parameter_jacobian(jacobian,
 
-                                            num_residuals_internal,
 
-                                            parameter_block_size_internal);
 
-     Map<ParameterVector> x_plus_delta(
 
-         parameters[parameter_block_index_internal],
 
-         parameter_block_size_internal);
 
-     ParameterVector x(x_plus_delta);
 
-     ParameterVector step_size = x.array().abs() *
 
-         ((kMethod == RIDDERS) ? options.ridders_relative_initial_step_size :
 
-         options.relative_step_size);
 
-     // It is not a good idea to make the step size arbitrarily
 
-     // small. This will lead to problems with round off and numerical
 
-     // instability when dividing by the step size. The general
 
-     // recommendation is to not go down below sqrt(epsilon).
 
-     double min_step_size = std::sqrt(std::numeric_limits<double>::epsilon());
 
-     // For Ridders' method, the initial step size is required to be large,
 
-     // thus ridders_relative_initial_step_size is used.
 
-     if (kMethod == RIDDERS) {
 
-       min_step_size = std::max(min_step_size,
 
-                                options.ridders_relative_initial_step_size);
 
-     }
 
-     // For each parameter in the parameter block, use finite differences to
 
-     // compute the derivative for that parameter.
 
-     FixedArray<double> temp_residual_array(num_residuals_internal);
 
-     FixedArray<double> residual_array(num_residuals_internal);
 
-     Map<ResidualVector> residuals(residual_array.get(),
 
-                                   num_residuals_internal);
 
-     for (int j = 0; j < parameter_block_size_internal; ++j) {
 
-       const double delta = std::max(min_step_size, step_size(j));
 
-       if (kMethod == RIDDERS) {
 
-         if (!EvaluateRiddersJacobianColumn(functor, j, delta,
 
-                                            options,
 
-                                            num_residuals_internal,
 
-                                            parameter_block_size_internal,
 
-                                            x.data(),
 
-                                            residuals_at_eval_point,
 
-                                            parameters,
 
-                                            x_plus_delta.data(),
 
-                                            temp_residual_array.get(),
 
-                                            residual_array.get())) {
 
-           return false;
 
-         }
 
-       } else {
 
-         if (!EvaluateJacobianColumn(functor, j, delta,
 
-                                     num_residuals_internal,
 
-                                     parameter_block_size_internal,
 
-                                     x.data(),
 
-                                     residuals_at_eval_point,
 
-                                     parameters,
 
-                                     x_plus_delta.data(),
 
-                                     temp_residual_array.get(),
 
-                                     residual_array.get())) {
 
-           return false;
 
-         }
 
-       }
 
-       parameter_jacobian.col(j).matrix() = residuals;
 
-     }
 
-     return true;
 
-   }
 
-   static bool EvaluateJacobianColumn(const CostFunctor* functor,
 
-                                      int parameter_index,
 
-                                      double delta,
 
-                                      int num_residuals,
 
-                                      int parameter_block_size,
 
-                                      const double* x_ptr,
 
-                                      const double* residuals_at_eval_point,
 
-                                      double** parameters,
 
-                                      double* x_plus_delta_ptr,
 
-                                      double* temp_residuals_ptr,
 
-                                      double* residuals_ptr) {
 
-     using Eigen::Map;
 
-     using Eigen::Matrix;
 
-     typedef Matrix<double, kNumResiduals, 1> ResidualVector;
 
-     typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
 
-     Map<const ParameterVector> x(x_ptr, parameter_block_size);
 
-     Map<ParameterVector> x_plus_delta(x_plus_delta_ptr,
 
-                                       parameter_block_size);
 
-     Map<ResidualVector> residuals(residuals_ptr, num_residuals);
 
-     Map<ResidualVector> temp_residuals(temp_residuals_ptr, num_residuals);
 
-     // Mutate 1 element at a time and then restore.
 
-     x_plus_delta(parameter_index) = x(parameter_index) + delta;
 
-     if (!VariadicEvaluate<ParameterDims>(*functor,
 
-                                          parameters,
 
-                                          residuals.data())) {
 
-       return false;
 
-     }
 
-     // Compute this column of the jacobian in 3 steps:
 
-     // 1. Store residuals for the forward part.
 
-     // 2. Subtract residuals for the backward (or 0) part.
 
-     // 3. Divide out the run.
 
-     double one_over_delta = 1.0 / delta;
 
-     if (kMethod == CENTRAL || kMethod == RIDDERS) {
 
-       // Compute the function on the other side of x(parameter_index).
 
-       x_plus_delta(parameter_index) = x(parameter_index) - delta;
 
-       if (!VariadicEvaluate<ParameterDims>(*functor,
 
-                                            parameters,
 
-                                            temp_residuals.data())) {
 
-         return false;
 
-       }
 
-       residuals -= temp_residuals;
 
-       one_over_delta /= 2;
 
-     } else {
 
-       // Forward difference only; reuse existing residuals evaluation.
 
-       residuals -=
 
-           Map<const ResidualVector>(residuals_at_eval_point,
 
-                                     num_residuals);
 
-     }
 
-     // Restore x_plus_delta.
 
-     x_plus_delta(parameter_index) = x(parameter_index);
 
-     // Divide out the run to get slope.
 
-     residuals *= one_over_delta;
 
-     return true;
 
-   }
 
-   // This numeric difference implementation uses adaptive differentiation
 
-   // on the parameters to obtain the Jacobian matrix. The adaptive algorithm
 
-   // is based on Ridders' method for adaptive differentiation, which creates
 
-   // a Romberg tableau from varying step sizes and extrapolates the
 
-   // intermediate results to obtain the current computational error.
 
-   //
 
-   // References:
 
-   // C.J.F. Ridders, Accurate computation of F'(x) and F'(x) F"(x), Advances
 
-   // in Engineering Software (1978), Volume 4, Issue 2, April 1982,
 
-   // Pages 75-76, ISSN 0141-1195,
 
-   // http://dx.doi.org/10.1016/S0141-1195(82)80057-0.
 
-   static bool EvaluateRiddersJacobianColumn(
 
-       const CostFunctor* functor,
 
-       int parameter_index,
 
-       double delta,
 
-       const NumericDiffOptions& options,
 
-       int num_residuals,
 
-       int parameter_block_size,
 
-       const double* x_ptr,
 
-       const double* residuals_at_eval_point,
 
-       double** parameters,
 
-       double* x_plus_delta_ptr,
 
-       double* temp_residuals_ptr,
 
-       double* residuals_ptr) {
 
-     using Eigen::Map;
 
-     using Eigen::Matrix;
 
-     using Eigen::aligned_allocator;
 
-     typedef Matrix<double, kNumResiduals, 1> ResidualVector;
 
-     typedef Matrix<double, kNumResiduals, Eigen::Dynamic> ResidualCandidateMatrix;
 
-     typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
 
-     Map<const ParameterVector> x(x_ptr, parameter_block_size);
 
-     Map<ParameterVector> x_plus_delta(x_plus_delta_ptr,
 
-                                       parameter_block_size);
 
-     Map<ResidualVector> residuals(residuals_ptr, num_residuals);
 
-     Map<ResidualVector> temp_residuals(temp_residuals_ptr, num_residuals);
 
-     // In order for the algorithm to converge, the step size should be
 
-     // initialized to a value that is large enough to produce a significant
 
-     // change in the function.
 
-     // As the derivative is estimated, the step size decreases.
 
-     // By default, the step sizes are chosen so that the middle column
 
-     // of the Romberg tableau uses the input delta.
 
-     double current_step_size = delta *
 
-         pow(options.ridders_step_shrink_factor,
 
-             options.max_num_ridders_extrapolations / 2);
 
-     // Double-buffering temporary differential candidate vectors
 
-     // from previous step size.
 
-     ResidualCandidateMatrix stepsize_candidates_a(
 
-         num_residuals,
 
-         options.max_num_ridders_extrapolations);
 
-     ResidualCandidateMatrix stepsize_candidates_b(
 
-         num_residuals,
 
-         options.max_num_ridders_extrapolations);
 
-     ResidualCandidateMatrix* current_candidates = &stepsize_candidates_a;
 
-     ResidualCandidateMatrix* previous_candidates = &stepsize_candidates_b;
 
-     // Represents the computational error of the derivative. This variable is
 
-     // initially set to a large value, and is set to the difference between
 
-     // current and previous finite difference extrapolations.
 
-     // norm_error is supposed to decrease as the finite difference tableau
 
-     // generation progresses, serving both as an estimate for differentiation
 
-     // error and as a measure of differentiation numerical stability.
 
-     double norm_error = std::numeric_limits<double>::max();
 
-     // Loop over decreasing step sizes until:
 
-     //  1. Error is smaller than a given value (ridders_epsilon),
 
-     //  2. Maximal order of extrapolation reached, or
 
-     //  3. Extrapolation becomes numerically unstable.
 
-     for (int i = 0; i < options.max_num_ridders_extrapolations; ++i) {
 
-       // Compute the numerical derivative at this step size.
 
-       if (!EvaluateJacobianColumn(functor, parameter_index, current_step_size,
 
-                                   num_residuals,
 
-                                   parameter_block_size,
 
-                                   x.data(),
 
-                                   residuals_at_eval_point,
 
-                                   parameters,
 
-                                   x_plus_delta.data(),
 
-                                   temp_residuals.data(),
 
-                                   current_candidates->col(0).data())) {
 
-         // Something went wrong; bail.
 
-         return false;
 
-       }
 
-       // Store initial results.
 
-       if (i == 0) {
 
-         residuals = current_candidates->col(0);
 
-       }
 
-       // Shrink differentiation step size.
 
-       current_step_size /= options.ridders_step_shrink_factor;
 
-       // Extrapolation factor for Richardson acceleration method (see below).
 
-       double richardson_factor = options.ridders_step_shrink_factor *
 
-           options.ridders_step_shrink_factor;
 
-       for (int k = 1; k <= i; ++k) {
 
-         // Extrapolate the various orders of finite differences using
 
-         // the Richardson acceleration method.
 
-         current_candidates->col(k) =
 
-             (richardson_factor * current_candidates->col(k - 1) -
 
-              previous_candidates->col(k - 1)) / (richardson_factor - 1.0);
 
-         richardson_factor *= options.ridders_step_shrink_factor *
 
-             options.ridders_step_shrink_factor;
 
-         // Compute the difference between the previous value and the current.
 
-         double candidate_error = std::max(
 
-             (current_candidates->col(k) -
 
-              current_candidates->col(k - 1)).norm(),
 
-             (current_candidates->col(k) -
 
-              previous_candidates->col(k - 1)).norm());
 
-         // If the error has decreased, update results.
 
-         if (candidate_error <= norm_error) {
 
-           norm_error = candidate_error;
 
-           residuals = current_candidates->col(k);
 
-           // If the error is small enough, stop.
 
-           if (norm_error < options.ridders_epsilon) {
 
-             break;
 
-           }
 
-         }
 
-       }
 
-       // After breaking out of the inner loop, declare convergence.
 
-       if (norm_error < options.ridders_epsilon) {
 
-         break;
 
-       }
 
-       // Check to see if the current gradient estimate is numerically unstable.
 
-       // If so, bail out and return the last stable result.
 
-       if (i > 0) {
 
-         double tableau_error = (current_candidates->col(i) -
 
-             previous_candidates->col(i - 1)).norm();
 
-         // Compare current error to the chosen candidate's error.
 
-         if (tableau_error >= 2 * norm_error) {
 
-           break;
 
-         }
 
-       }
 
-       std::swap(current_candidates, previous_candidates);
 
-     }
 
-     return true;
 
-   }
 
- };
 
- // This function calls NumericDiff<...>::EvaluateJacobianForParameterBlock for
 
- // each parameter block.
 
- //
 
- // Example:
 
- // A call to 
 
- // EvaluateJacobianForParameterBlocks<StaticParameterDims<2, 3>>(
 
- //        functor,
 
- //        residuals_at_eval_point,
 
- //        options,
 
- //        num_residuals,
 
- //        parameters,
 
- //        jacobians);
 
- // will result in the following calls to
 
- // NumericDiff<...>::EvaluateJacobianForParameterBlock:
 
- //
 
- // if (!NumericDiff<
 
- //          CostFunctor, method, kNumResiduals, ParameterDims, 0,
 
- //          2>::EvaluateJacobianForParameterBlock(functor,
 
- //                                                residuals_at_eval_point,
 
- //                                                options,
 
- //                                                num_residuals,
 
- //                                                0,
 
- //                                                2,
 
- //                                                parameters,
 
- //                                                jacobians[0])) {
 
- //   return false;
 
- // }
 
- // if (!NumericDiff<
 
- //          CostFunctor, method, kNumResiduals, ParameterDims, 1,
 
- //          3>::EvaluateJacobianForParameterBlock(functor,
 
- //                                                residuals_at_eval_point,
 
- //                                                options,
 
- //                                                num_residuals,
 
- //                                                1,
 
- //                                                3,
 
- //                                                parameters,
 
- //                                                jacobians[1])) {
 
- //   return false;
 
- // }
 
- template <typename ParameterDims,
 
-           typename Parameters = typename ParameterDims::Parameters,
 
-           int ParameterIdx = 0>
 
- struct EvaluateJacobianForParameterBlocks;
 
- template <typename ParameterDims, int N, int... Ns, int ParameterIdx>
 
- struct EvaluateJacobianForParameterBlocks<
 
-     ParameterDims, integer_sequence<int, N, Ns...>, ParameterIdx> {
 
-   template <NumericDiffMethodType method, int kNumResiduals,
 
-             typename CostFunctor>
 
-   static bool Apply(const CostFunctor* functor,
 
-                     const double* residuals_at_eval_point,
 
-                     const NumericDiffOptions& options, int num_residuals,
 
-                     double** parameters, double** jacobians) {
 
-     if (!NumericDiff<
 
-             CostFunctor, method, kNumResiduals, ParameterDims, ParameterIdx,
 
-             N>::EvaluateJacobianForParameterBlock(functor,
 
-                                                   residuals_at_eval_point,
 
-                                                   options,
 
-                                                   num_residuals,
 
-                                                   ParameterIdx,
 
-                                                   N,
 
-                                                   parameters,
 
-                                                   jacobians[ParameterIdx])) {
 
-       return false;
 
-     }
 
-     return EvaluateJacobianForParameterBlocks<
 
-         ParameterDims, integer_sequence<int, Ns...>, ParameterIdx + 1>::
 
-         template Apply<method, kNumResiduals>(functor,
 
-                                               residuals_at_eval_point,
 
-                                               options,
 
-                                               num_residuals,
 
-                                               parameters, jacobians);
 
-   }
 
- };
 
- // End of 'recursion'. Nothing more to do.
 
- template <typename ParameterDims, int ParameterIdx>
 
- struct EvaluateJacobianForParameterBlocks<ParameterDims, integer_sequence<int>,
 
-                                           ParameterIdx> {
 
-   template <NumericDiffMethodType method, int kNumResiduals,
 
-             typename CostFunctor>
 
-   static bool Apply(const CostFunctor* /* NOT USED*/,
 
-                     const double* /* NOT USED*/,
 
-                     const NumericDiffOptions& /* NOT USED*/, int /* NOT USED*/,
 
-                     double** /* NOT USED*/, double** /* NOT USED*/) {
 
-     return true;
 
-   }
 
- };
 
- }  // namespace internal
 
- }  // namespace ceres
 
- #endif  // CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
 
 
  |