From b7fb6056a717cc3c372cfb7115c527ee8bc05ddb Mon Sep 17 00:00:00 2001 From: Sameer Agarwal Date: Wed, 3 Sep 2014 11:19:02 -0700 Subject: [PATCH] Remove NumericDiffFunctor. Its API was broken, and its implementation was an unnecessary layer of abstraction over CostFunctionToFunctor. Change-Id: I18fc261fc6a3620b51a9eeb4dde0af03d753af69 --- docs/source/modeling.rst | 165 ++++----- docs/source/version_history.rst | 4 + include/ceres/numeric_diff_functor.h | 351 -------------------- internal/ceres/CMakeLists.txt | 1 - internal/ceres/numeric_diff_functor_test.cc | 125 ------- 5 files changed, 70 insertions(+), 576 deletions(-) delete mode 100644 include/ceres/numeric_diff_functor.h delete mode 100644 internal/ceres/numeric_diff_functor_test.cc diff --git a/docs/source/modeling.rst b/docs/source/modeling.rst index 5bbd441b4..4b333c4ce 100644 --- a/docs/source/modeling.rst +++ b/docs/source/modeling.rst @@ -567,105 +567,15 @@ the corresponding accessors. This information will be verified by the As a rule of thumb, try using :class:`NumericDiffCostFunction` before you use :class:`DynamicNumericDiffCostFunction`. - -:class:`NumericDiffFunctor` ---------------------------- - -.. class:: NumericDiffFunctor - - Sometimes parts of a cost function can be differentiated - automatically or analytically but others require numeric - differentiation. :class:`NumericDiffFunctor` is a wrapper class - that takes a variadic functor evaluating a function, numerically - differentiates it and makes it available as a templated functor so - that it can be easily used as part of Ceres' automatic - differentiation framework. - - For example, let us assume that - - .. code-block:: c++ - - struct IntrinsicProjection - IntrinsicProjection(const double* observations); - bool operator()(const double* calibration, - const double* point, - double* residuals); - }; - - is a functor that implements the projection of a point in its local - coordinate system onto its image plane and subtracts it from the - observed point projection. - - Now we would like to compose the action of this functor with the - action of camera extrinsics, i.e., rotation and translation, which - is given by the following templated function - - .. code-block:: c++ - - template - void RotateAndTranslatePoint(const T* rotation, - const T* translation, - const T* point, - T* result); - - To compose the extrinsics and intrinsics, we can construct a - ``CameraProjection`` functor as follows. - - .. code-block:: c++ - - struct CameraProjection { - typedef NumericDiffFunctor - IntrinsicProjectionFunctor; - - CameraProjection(double* observation) { - intrinsic_projection_.reset( - new IntrinsicProjectionFunctor(observation)) { - } - - template - bool operator()(const T* rotation, - const T* translation, - const T* intrinsics, - const T* point, - T* residuals) const { - T transformed_point[3]; - RotateAndTranslatePoint(rotation, translation, point, transformed_point); - return (*intrinsic_projection_)(intrinsics, transformed_point, residual); - } - - private: - scoped_ptr intrinsic_projection_; - }; - - Here, we made the choice of using ``CENTRAL`` differences to compute - the jacobian of ``IntrinsicProjection``. - - Now, we are ready to construct an automatically differentiated cost - function as - - .. code-block:: c++ - - CostFunction* cost_function = - new AutoDiffCostFunction( - new CameraProjection(observations)); - - ``cost_function`` now seamlessly integrates automatic - differentiation of ``RotateAndTranslatePoint`` with a numerically - differentiated version of ``IntrinsicProjection``. - - :class:`CostFunctionToFunctor` ------------------------------ .. class:: CostFunctionToFunctor - Just like :class:`NumericDiffFunctor` allows numeric - differentiation to be mixed with automatic differentiation, - :class:`CostFunctionToFunctor` provides an even more general - mechanism. :class:`CostFunctionToFunctor` is an adapter class that - allows users to use :class:`CostFunction` objects in templated - functors which are to be used for automatic differentiation. This - allows the user to seamlessly mix analytic, numeric and automatic + :class:`CostFunctionToFunctor` is an adapter class that allows + users to use :class:`CostFunction` objects in templated functors + which are to be used for automatic differentiation. This allows + the user to seamlessly mix analytic, numeric and automatic differentiation. For example, let us assume that @@ -704,10 +614,10 @@ the corresponding accessors. This information will be verified by the .. code-block:: c++ struct CameraProjection { - CameraProjection(double* observation) { - intrinsic_projection_.reset( - new CostFunctionToFunctor<2, 5, 3>(new IntrinsicProjection(observation_))); + CameraProjection(double* observation) + : intrinsic_projection_(new IntrinsicProjection(observation_)) { } + template bool operator()(const T* rotation, const T* translation, @@ -719,14 +629,71 @@ the corresponding accessors. This information will be verified by the // Note that we call intrinsic_projection_, just like it was // any other templated functor. - return (*intrinsic_projection_)(intrinsics, transformed_point, residual); + return intrinsic_projection_(intrinsics, transformed_point, residual); } private: - scoped_ptr > intrinsic_projection_; + CostFunctionToFunctor<2,5,3> intrinsic_projection_; }; + In the above example, we assumed that ``IntrinsicProjection`` is a + ``CostFunction`` capable of evaluating its value and its + derivatives. Suppose, if that were not the case and + ``IntrinsicProjection`` was defined as follows: + + .. code-block:: c++ + + struct IntrinsicProjection + IntrinsicProjection(const double* observations) { + observations_[0] = observations[0]; + observations_[1] = observations[1]; + } + + bool operator()(const double* calibration, + const double* point, + double* residuals) { + double projection[2]; + ThirdPartyProjectionFunction(calibration, point, projection); + residuals[0] = observations_[0] - projection[0]; + residuals[1] = observations_[1] - projection[1]; + return true; + } + double observations_[2]; + }; + + + Here ``ThirdPartyProjectionFunction`` is some third party library + function that we have no control over. So this function can compute + its value and we would like to use numeric differentiation to + compute its derivatives. In this case we can use a combination of + ``NumericDiffCostFunction`` and ``CostFunctionToFunctor`` to get the + job done. + + .. code-block:: c++ + + struct CameraProjection { + CameraProjection(double* observation) + intrinsic_projection_( + new NumericDiffCostFunction( + new IntrinsicProjection(observations)) { + } + + template + bool operator()(const T* rotation, + const T* translation, + const T* intrinsics, + const T* point, + T* residuals) const { + T transformed_point[3]; + RotateAndTranslatePoint(rotation, translation, point, transformed_point); + return intrinsic_projection_(intrinsics, transformed_point, residual); + } + + private: + CostFunctionToFunctor<2,5,3> intrinsic_projection_; + }; + :class:`ConditionedCostFunction` -------------------------------- diff --git a/docs/source/version_history.rst b/docs/source/version_history.rst index 8853fb747..cbbad6574 100644 --- a/docs/source/version_history.rst +++ b/docs/source/version_history.rst @@ -16,6 +16,10 @@ HEAD Backward Incompatible API Changes --------------------------------- +#. ``NumericDiffFunctor`` has been removed. It's API was broken, and + the implementation was an unnecessary layer of abstraction over + ``CostFunctionToFunctor``. + #. ``Solver::Options::solver_log`` has been removed. If needed this iteration callback can easily be implemented in user code. diff --git a/include/ceres/numeric_diff_functor.h b/include/ceres/numeric_diff_functor.h deleted file mode 100644 index a29eb97fa..000000000 --- a/include/ceres/numeric_diff_functor.h +++ /dev/null @@ -1,351 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2013 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// 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) -// -// A wrapper class that takes a variadic functor evaluating a -// function, numerically differentiates it and makes it available as a -// templated functor so that it can be easily used as part of Ceres' -// automatic differentiation framework. -// -// For example: -// -// For example, let us assume that -// -// struct IntrinsicProjection -// IntrinsicProjection(const double* observations); -// bool operator()(const double* calibration, -// const double* point, -// double* residuals); -// }; -// -// is a functor that implements the projection of a point in its local -// coordinate system onto its image plane and subtracts it from the -// observed point projection. -// -// Now we would like to compose the action of this functor with the -// action of camera extrinsics, i.e., rotation and translation, which -// is given by the following templated function -// -// template -// void RotateAndTranslatePoint(const T* rotation, -// const T* translation, -// const T* point, -// T* result); -// -// To compose the extrinsics and intrinsics, we can construct a -// CameraProjection functor as follows. -// -// struct CameraProjection { -// typedef NumericDiffFunctor -// IntrinsicProjectionFunctor; -// -// CameraProjection(double* observation) { -// intrinsic_projection_.reset( -// new IntrinsicProjectionFunctor(observation)) { -// } -// -// template -// bool operator()(const T* rotation, -// const T* translation, -// const T* intrinsics, -// const T* point, -// T* residuals) const { -// T transformed_point[3]; -// RotateAndTranslatePoint(rotation, translation, point, transformed_point); -// return (*intrinsic_projection_)(intrinsics, transformed_point, residual); -// } -// -// private: -// scoped_ptr intrinsic_projection_; -// }; -// -// Here, we made the choice of using CENTRAL differences to compute -// the jacobian of IntrinsicProjection. -// -// Now, we are ready to construct an automatically differentiated cost -// function as -// -// CostFunction* cost_function = -// new AutoDiffCostFunction( -// new CameraProjection(observations)); -// -// cost_function now seamlessly integrates automatic differentiation -// of RotateAndTranslatePoint with a numerically differentiated -// version of IntrinsicProjection. - -#ifndef CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_ -#define CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_ - -#include "ceres/numeric_diff_cost_function.h" -#include "ceres/types.h" -#include "ceres/cost_function_to_functor.h" - -namespace ceres { - -template -class NumericDiffFunctor { - public: - // relative_step_size controls the step size used by the numeric - // differentiation process. - explicit NumericDiffFunctor(double relative_step_size = 1e-6) - : functor_( - new NumericDiffCostFunction(new Functor, - TAKE_OWNERSHIP, - kNumResiduals, - relative_step_size)) { - } - - NumericDiffFunctor(Functor* functor, double relative_step_size = 1e-6) - : functor_(new NumericDiffCostFunction( - functor, - TAKE_OWNERSHIP, - kNumResiduals, - relative_step_size)) { - } - - bool operator()(const double* x0, double* residuals) const { - return functor_(x0, residuals); - } - - bool operator()(const double* x0, - const double* x1, - double* residuals) const { - return functor_(x0, x1, residuals); - } - - bool operator()(const double* x0, - const double* x1, - const double* x2, - double* residuals) const { - return functor_(x0, x1, x2, residuals); - } - - bool operator()(const double* x0, - const double* x1, - const double* x2, - const double* x3, - double* residuals) const { - return functor_(x0, x1, x2, x3, residuals); - } - - bool operator()(const double* x0, - const double* x1, - const double* x2, - const double* x3, - const double* x4, - double* residuals) const { - return functor_(x0, x1, x2, x3, x4, residuals); - } - - bool operator()(const double* x0, - const double* x1, - const double* x2, - const double* x3, - const double* x4, - const double* x5, - double* residuals) const { - return functor_(x0, x1, x2, x3, x4, x5, residuals); - } - - bool operator()(const double* x0, - const double* x1, - const double* x2, - const double* x3, - const double* x4, - const double* x5, - const double* x6, - double* residuals) const { - return functor_(x0, x1, x2, x3, x4, x5, x6, residuals); - } - - bool operator()(const double* x0, - const double* x1, - const double* x2, - const double* x3, - const double* x4, - const double* x5, - const double* x6, - const double* x7, - double* residuals) const { - return functor_(x0, x1, x2, x3, x4, x5, x6, x7, residuals); - } - - bool operator()(const double* x0, - const double* x1, - const double* x2, - const double* x3, - const double* x4, - const double* x5, - const double* x6, - const double* x7, - const double* x8, - double* residuals) const { - return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, residuals); - } - - bool operator()(const double* x0, - const double* x1, - const double* x2, - const double* x3, - const double* x4, - const double* x5, - const double* x6, - const double* x7, - const double* x8, - const double* x9, - double* residuals) const { - return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, residuals); - } - - template - bool operator()(const T* x0, T* residuals) const { - return functor_(x0, residuals); - } - - template - bool operator()(const T* x0, - const T* x1, - T* residuals) const { - return functor_(x0, x1, residuals); - } - - template - bool operator()(const T* x0, - const T* x1, - const T* x2, - T* residuals) const { - return functor_(x0, x1, x2, residuals); - } - - template - bool operator()(const T* x0, - const T* x1, - const T* x2, - const T* x3, - T* residuals) const { - return functor_(x0, x1, x2, x3, residuals); - } - - template - bool operator()(const T* x0, - const T* x1, - const T* x2, - const T* x3, - const T* x4, - T* residuals) const { - return functor_(x0, x1, x2, x3, x4, residuals); - } - - template - bool operator()(const T* x0, - const T* x1, - const T* x2, - const T* x3, - const T* x4, - const T* x5, - T* residuals) const { - return functor_(x0, x1, x2, x3, x4, x5, residuals); - } - - template - bool operator()(const T* x0, - const T* x1, - const T* x2, - const T* x3, - const T* x4, - const T* x5, - const T* x6, - T* residuals) const { - return functor_(x0, x1, x2, x3, x4, x5, x6, residuals); - } - - template - bool operator()(const T* x0, - const T* x1, - const T* x2, - const T* x3, - const T* x4, - const T* x5, - const T* x6, - const T* x7, - T* residuals) const { - return functor_(x0, x1, x2, x3, x4, x5, x6, x7, residuals); - } - - template - bool operator()(const T* x0, - const T* x1, - const T* x2, - const T* x3, - const T* x4, - const T* x5, - const T* x6, - const T* x7, - const T* x8, - T* residuals) const { - return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, residuals); - } - - template - bool operator()(const T* x0, - const T* x1, - const T* x2, - const T* x3, - const T* x4, - const T* x5, - const T* x6, - const T* x7, - const T* x8, - const T* x9, - T* residuals) const { - return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, residuals); - } - - - private: - CostFunctionToFunctor functor_; -}; - -} // namespace ceres - -#endif // CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_ diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt index 85b49060f..ec9dee365 100644 --- a/internal/ceres/CMakeLists.txt +++ b/internal/ceres/CMakeLists.txt @@ -263,7 +263,6 @@ IF (BUILD_TESTING AND GFLAGS) CERES_TEST(minimizer) CERES_TEST(normal_prior) CERES_TEST(numeric_diff_cost_function) - CERES_TEST(numeric_diff_functor) CERES_TEST(ordered_groups) CERES_TEST(parameter_block) CERES_TEST(parameter_block_ordering) diff --git a/internal/ceres/numeric_diff_functor_test.cc b/internal/ceres/numeric_diff_functor_test.cc deleted file mode 100644 index acd7ff91f..000000000 --- a/internal/ceres/numeric_diff_functor_test.cc +++ /dev/null @@ -1,125 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2013 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// 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) - -#include "ceres/numeric_diff_functor.h" - -#include -#include -#include -#include -#include "ceres/autodiff_cost_function.h" -#include "ceres/internal/scoped_ptr.h" -#include "ceres/numeric_diff_test_utils.h" -#include "ceres/test_util.h" -#include "ceres/types.h" -#include "glog/logging.h" -#include "gtest/gtest.h" - -namespace ceres { -namespace internal { - -TEST(NumericDiffCostFunction, EasyCaseCentralDifferences) { - typedef NumericDiffFunctor - NumericDiffEasyFunctor; - - internal::scoped_ptr cost_function; - EasyFunctor functor; - - cost_function.reset( - new AutoDiffCostFunction( - new NumericDiffEasyFunctor)); - - functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL); - - cost_function.reset( - new AutoDiffCostFunction( - new NumericDiffEasyFunctor(new EasyFunctor))); - functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL); -} - -TEST(NumericDiffCostFunction, EasyCaseForwardDifferences) { - typedef NumericDiffFunctor - NumericDiffEasyFunctor; - - internal::scoped_ptr cost_function; - EasyFunctor functor; - - cost_function.reset( - new AutoDiffCostFunction( - new NumericDiffEasyFunctor)); - - functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD); - - cost_function.reset( - new AutoDiffCostFunction( - new NumericDiffEasyFunctor(new EasyFunctor))); - functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD); -} - -TEST(NumericDiffCostFunction, TranscendentalCaseCentralDifferences) { - typedef NumericDiffFunctor - NumericDiffTranscendentalFunctor; - - internal::scoped_ptr cost_function; - TranscendentalFunctor functor; - - cost_function.reset( - new AutoDiffCostFunction( - new NumericDiffTranscendentalFunctor)); - - functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL); - - cost_function.reset( - new AutoDiffCostFunction( - new NumericDiffTranscendentalFunctor(new TranscendentalFunctor))); - functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL); -} - -TEST(NumericDiffCostFunction, TranscendentalCaseForwardDifferences) { - typedef NumericDiffFunctor - NumericDiffTranscendentalFunctor; - - internal::scoped_ptr cost_function; - TranscendentalFunctor functor; - - cost_function.reset( - new AutoDiffCostFunction( - new NumericDiffTranscendentalFunctor)); - - functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD); - - cost_function.reset( - new AutoDiffCostFunction( - new NumericDiffTranscendentalFunctor(new TranscendentalFunctor))); - functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD); -} - -} // namespace internal -} // namespace ceres