123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- #ifndef CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
- #define CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
- #include <cstring>
- #include <utility>
- #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::internal {
- template <typename CostFunctor,
- NumericDiffMethodType kMethod,
- int kNumResiduals,
- typename ParameterDims,
- int kParameterBlock,
- int kParameterBlockSize>
- struct NumericDiff {
-
- 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::ColMajor;
- using Eigen::Map;
- using Eigen::Matrix;
- using Eigen::RowMajor;
- DCHECK(jacobian);
- 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);
- using ResidualVector = Matrix<double, kNumResiduals, 1>;
- using ParameterVector = Matrix<double, kParameterBlockSize, 1>;
-
-
-
-
- using JacobianMatrix =
- Matrix<double,
- kNumResiduals,
- kParameterBlockSize,
- (kParameterBlockSize == 1) ? ColMajor : RowMajor>;
- 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);
-
-
-
-
- double min_step_size = std::sqrt(std::numeric_limits<double>::epsilon());
-
-
- if (kMethod == RIDDERS) {
- min_step_size =
- (std::max)(min_step_size, options.ridders_relative_initial_step_size);
- }
-
-
- FixedArray<double> temp_residual_array(num_residuals_internal);
- FixedArray<double> residual_array(num_residuals_internal);
- Map<ResidualVector> residuals(residual_array.data(),
- 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.data(),
- residual_array.data())) {
- 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.data(),
- residual_array.data())) {
- 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;
- using ResidualVector = Matrix<double, kNumResiduals, 1>;
- using ParameterVector = Matrix<double, kParameterBlockSize, 1>;
- 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);
-
- x_plus_delta(parameter_index) = x(parameter_index) + delta;
- if (!VariadicEvaluate<ParameterDims>(
- *functor, parameters, residuals.data())) {
- return false;
- }
-
-
-
-
- double one_over_delta = 1.0 / delta;
- if (kMethod == CENTRAL || kMethod == RIDDERS) {
-
- 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 {
-
- residuals -=
- Map<const ResidualVector>(residuals_at_eval_point, num_residuals);
- }
-
- x_plus_delta(parameter_index) = x(parameter_index);
-
- residuals *= one_over_delta;
- return true;
- }
-
-
-
-
-
-
-
-
-
-
-
- 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::aligned_allocator;
- using Eigen::Map;
- using Eigen::Matrix;
- using ResidualVector = Matrix<double, kNumResiduals, 1>;
- using ResidualCandidateMatrix =
- Matrix<double, kNumResiduals, Eigen::Dynamic>;
- using ParameterVector = Matrix<double, kParameterBlockSize, 1>;
- 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);
-
-
-
-
-
-
- double current_step_size =
- delta * pow(options.ridders_step_shrink_factor,
- options.max_num_ridders_extrapolations / 2);
-
-
- 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;
-
-
-
-
-
-
- double norm_error = (std::numeric_limits<double>::max)();
-
-
-
-
- for (int i = 0; i < options.max_num_ridders_extrapolations; ++i) {
-
- 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())) {
-
- return false;
- }
-
- if (i == 0) {
- residuals = current_candidates->col(0);
- }
-
- current_step_size /= options.ridders_step_shrink_factor;
-
- double richardson_factor = options.ridders_step_shrink_factor *
- options.ridders_step_shrink_factor;
- for (int k = 1; k <= i; ++k) {
-
-
- 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;
-
- 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 (candidate_error <= norm_error) {
- norm_error = candidate_error;
- residuals = current_candidates->col(k);
-
- if (norm_error < options.ridders_epsilon) {
- break;
- }
- }
- }
-
- if (norm_error < options.ridders_epsilon) {
- break;
- }
-
-
- if (i > 0) {
- double tableau_error =
- (current_candidates->col(i) - previous_candidates->col(i - 1))
- .norm();
-
- if (tableau_error >= 2 * norm_error) {
- break;
- }
- }
- std::swap(current_candidates, previous_candidates);
- }
- return true;
- }
- };
- 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,
- std::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 (jacobians[ParameterIdx] != nullptr) {
- 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,
- std::integer_sequence<int, Ns...>,
- ParameterIdx + 1>::
- template Apply<method, kNumResiduals>(functor,
- residuals_at_eval_point,
- options,
- num_residuals,
- parameters,
- jacobians);
- }
- };
- template <typename ParameterDims, int ParameterIdx>
- struct EvaluateJacobianForParameterBlocks<ParameterDims,
- std::integer_sequence<int>,
- ParameterIdx> {
- template <NumericDiffMethodType method,
- int kNumResiduals,
- typename CostFunctor>
- static bool Apply(const CostFunctor* ,
- const double* ,
- const NumericDiffOptions& ,
- int ,
- double** ,
- double** ) {
- return true;
- }
- };
- }
- #endif
|