|  | // 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) | 
|  |  | 
|  | #include "ceres/cost_function_to_functor.h" | 
|  |  | 
|  | #include <cstdint> | 
|  | #include <memory> | 
|  |  | 
|  | #include "ceres/autodiff_cost_function.h" | 
|  | #include "ceres/dynamic_autodiff_cost_function.h" | 
|  | #include "ceres/dynamic_cost_function_to_functor.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | namespace ceres::internal { | 
|  |  | 
|  | using std::vector; | 
|  | const double kTolerance = 1e-18; | 
|  |  | 
|  | static void ExpectCostFunctionsAreEqual( | 
|  | const CostFunction& cost_function, | 
|  | const CostFunction& actual_cost_function) { | 
|  | EXPECT_EQ(cost_function.num_residuals(), | 
|  | actual_cost_function.num_residuals()); | 
|  | const int num_residuals = cost_function.num_residuals(); | 
|  | const vector<int32_t>& parameter_block_sizes = | 
|  | cost_function.parameter_block_sizes(); | 
|  | const vector<int32_t>& actual_parameter_block_sizes = | 
|  | actual_cost_function.parameter_block_sizes(); | 
|  | EXPECT_EQ(parameter_block_sizes.size(), actual_parameter_block_sizes.size()); | 
|  |  | 
|  | int num_parameters = 0; | 
|  | for (int i = 0; i < parameter_block_sizes.size(); ++i) { | 
|  | EXPECT_EQ(parameter_block_sizes[i], actual_parameter_block_sizes[i]); | 
|  | num_parameters += parameter_block_sizes[i]; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<double[]> parameters(new double[num_parameters]); | 
|  | for (int i = 0; i < num_parameters; ++i) { | 
|  | parameters[i] = static_cast<double>(i) + 1.0; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<double[]> residuals(new double[num_residuals]); | 
|  | std::unique_ptr<double[]> jacobians( | 
|  | new double[num_parameters * num_residuals]); | 
|  |  | 
|  | std::unique_ptr<double[]> actual_residuals(new double[num_residuals]); | 
|  | std::unique_ptr<double[]> actual_jacobians( | 
|  | new double[num_parameters * num_residuals]); | 
|  |  | 
|  | std::unique_ptr<double*[]> parameter_blocks( | 
|  | new double*[parameter_block_sizes.size()]); | 
|  | std::unique_ptr<double*[]> jacobian_blocks( | 
|  | new double*[parameter_block_sizes.size()]); | 
|  | std::unique_ptr<double*[]> actual_jacobian_blocks( | 
|  | new double*[parameter_block_sizes.size()]); | 
|  |  | 
|  | num_parameters = 0; | 
|  | for (int i = 0; i < parameter_block_sizes.size(); ++i) { | 
|  | parameter_blocks[i] = parameters.get() + num_parameters; | 
|  | jacobian_blocks[i] = jacobians.get() + num_parameters * num_residuals; | 
|  | actual_jacobian_blocks[i] = | 
|  | actual_jacobians.get() + num_parameters * num_residuals; | 
|  | num_parameters += parameter_block_sizes[i]; | 
|  | } | 
|  |  | 
|  | EXPECT_TRUE( | 
|  | cost_function.Evaluate(parameter_blocks.get(), residuals.get(), nullptr)); | 
|  | EXPECT_TRUE(actual_cost_function.Evaluate( | 
|  | parameter_blocks.get(), actual_residuals.get(), nullptr)); | 
|  | for (int i = 0; i < num_residuals; ++i) { | 
|  | EXPECT_NEAR(residuals[i], actual_residuals[i], kTolerance) | 
|  | << "residual id: " << i; | 
|  | } | 
|  |  | 
|  | EXPECT_TRUE(cost_function.Evaluate( | 
|  | parameter_blocks.get(), residuals.get(), jacobian_blocks.get())); | 
|  | EXPECT_TRUE(actual_cost_function.Evaluate(parameter_blocks.get(), | 
|  | actual_residuals.get(), | 
|  | actual_jacobian_blocks.get())); | 
|  | for (int i = 0; i < num_residuals; ++i) { | 
|  | EXPECT_NEAR(residuals[i], actual_residuals[i], kTolerance) | 
|  | << "residual : " << i; | 
|  | } | 
|  |  | 
|  | for (int i = 0; i < num_residuals * num_parameters; ++i) { | 
|  | EXPECT_NEAR(jacobians[i], actual_jacobians[i], kTolerance) | 
|  | << "jacobian : " << i << " " << jacobians[i] << " " | 
|  | << actual_jacobians[i]; | 
|  | } | 
|  | } | 
|  |  | 
|  | struct OneParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()(const T* x1, T* residuals) const { | 
|  | residuals[0] = x1[0] * x1[0]; | 
|  | residuals[1] = x1[1] * x1[1]; | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct TwoParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()(const T* x1, const T* x2, T* residuals) const { | 
|  | residuals[0] = x1[0] * x1[0] + x2[0] * x2[0]; | 
|  | residuals[1] = x1[1] * x1[1] + x2[1] * x2[1]; | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct ThreeParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()(const T* x1, const T* x2, const T* x3, T* residuals) const { | 
|  | residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0]; | 
|  | residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1]; | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct FourParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()( | 
|  | const T* x1, const T* x2, const T* x3, const T* x4, T* residuals) const { | 
|  | residuals[0] = | 
|  | x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] + x4[0] * x4[0]; | 
|  | residuals[1] = | 
|  | x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] + x4[1] * x4[1]; | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct FiveParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()(const T* x1, | 
|  | const T* x2, | 
|  | const T* x3, | 
|  | const T* x4, | 
|  | const T* x5, | 
|  | T* residuals) const { | 
|  | residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] + | 
|  | x4[0] * x4[0] + x5[0] * x5[0]; | 
|  | residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] + | 
|  | x4[1] * x4[1] + x5[1] * x5[1]; | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct SixParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()(const T* x1, | 
|  | const T* x2, | 
|  | const T* x3, | 
|  | const T* x4, | 
|  | const T* x5, | 
|  | const T* x6, | 
|  | T* residuals) const { | 
|  | residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] + | 
|  | x4[0] * x4[0] + x5[0] * x5[0] + x6[0] * x6[0]; | 
|  | residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] + | 
|  | x4[1] * x4[1] + x5[1] * x5[1] + x6[1] * x6[1]; | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct SevenParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()(const T* x1, | 
|  | const T* x2, | 
|  | const T* x3, | 
|  | const T* x4, | 
|  | const T* x5, | 
|  | const T* x6, | 
|  | const T* x7, | 
|  | T* residuals) const { | 
|  | residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] + | 
|  | x4[0] * x4[0] + x5[0] * x5[0] + x6[0] * x6[0] + | 
|  | x7[0] * x7[0]; | 
|  | residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] + | 
|  | x4[1] * x4[1] + x5[1] * x5[1] + x6[1] * x6[1] + | 
|  | x7[1] * x7[1]; | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct EightParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()(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 { | 
|  | residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] + | 
|  | x4[0] * x4[0] + x5[0] * x5[0] + x6[0] * x6[0] + | 
|  | x7[0] * x7[0] + x8[0] * x8[0]; | 
|  | residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] + | 
|  | x4[1] * x4[1] + x5[1] * x5[1] + x6[1] * x6[1] + | 
|  | x7[1] * x7[1] + x8[1] * x8[1]; | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct NineParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()(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 { | 
|  | residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] + | 
|  | x4[0] * x4[0] + x5[0] * x5[0] + x6[0] * x6[0] + | 
|  | x7[0] * x7[0] + x8[0] * x8[0] + x9[0] * x9[0]; | 
|  | residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] + | 
|  | x4[1] * x4[1] + x5[1] * x5[1] + x6[1] * x6[1] + | 
|  | x7[1] * x7[1] + x8[1] * x8[1] + x9[1] * x9[1]; | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct TenParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()(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, | 
|  | const T* x10, | 
|  | T* residuals) const { | 
|  | residuals[0] = x1[0] * x1[0] + x2[0] * x2[0] + x3[0] * x3[0] + | 
|  | x4[0] * x4[0] + x5[0] * x5[0] + x6[0] * x6[0] + | 
|  | x7[0] * x7[0] + x8[0] * x8[0] + x9[0] * x9[0] + | 
|  | x10[0] * x10[0]; | 
|  | residuals[1] = x1[1] * x1[1] + x2[1] * x2[1] + x3[1] * x3[1] + | 
|  | x4[1] * x4[1] + x5[1] * x5[1] + x6[1] * x6[1] + | 
|  | x7[1] * x7[1] + x8[1] * x8[1] + x9[1] * x9[1] + | 
|  | x10[1] * x10[1]; | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class DynamicTwoParameterBlockFunctor { | 
|  | public: | 
|  | template <typename T> | 
|  | bool operator()(T const* const* parameters, T* residuals) const { | 
|  | for (int i = 0; i < 2; ++i) { | 
|  | residuals[0] = parameters[i][0] * parameters[i][0]; | 
|  | residuals[1] = parameters[i][1] * parameters[i][1]; | 
|  | } | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Check that AutoDiff(Functor1) == AutoDiff(CostToFunctor(AutoDiff(Functor1))) | 
|  | #define TEST_BODY(Functor1)                                                    \ | 
|  | TEST(CostFunctionToFunctor, Functor1) {                                      \ | 
|  | typedef AutoDiffCostFunction<Functor1, 2, PARAMETER_BLOCK_SIZES>           \ | 
|  | CostFunction1;                                                         \ | 
|  | typedef CostFunctionToFunctor<2, PARAMETER_BLOCK_SIZES> FunctionToFunctor; \ | 
|  | typedef AutoDiffCostFunction<FunctionToFunctor, 2, PARAMETER_BLOCK_SIZES>  \ | 
|  | CostFunction2;                                                         \ | 
|  | \ | 
|  | std::unique_ptr<CostFunction> cost_function(new CostFunction2(             \ | 
|  | new FunctionToFunctor(new CostFunction1(new Functor1))));              \ | 
|  | \ | 
|  | std::unique_ptr<CostFunction> actual_cost_function(                        \ | 
|  | new CostFunction1(new Functor1));                                      \ | 
|  | ExpectCostFunctionsAreEqual(*cost_function, *actual_cost_function);        \ | 
|  | } | 
|  |  | 
|  | #define PARAMETER_BLOCK_SIZES 2 | 
|  | TEST_BODY(OneParameterBlockFunctor) | 
|  | #undef PARAMETER_BLOCK_SIZES | 
|  |  | 
|  | #define PARAMETER_BLOCK_SIZES 2, 2 | 
|  | TEST_BODY(TwoParameterBlockFunctor) | 
|  | #undef PARAMETER_BLOCK_SIZES | 
|  |  | 
|  | #define PARAMETER_BLOCK_SIZES 2, 2, 2 | 
|  | TEST_BODY(ThreeParameterBlockFunctor) | 
|  | #undef PARAMETER_BLOCK_SIZES | 
|  |  | 
|  | #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2 | 
|  | TEST_BODY(FourParameterBlockFunctor) | 
|  | #undef PARAMETER_BLOCK_SIZES | 
|  |  | 
|  | #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2 | 
|  | TEST_BODY(FiveParameterBlockFunctor) | 
|  | #undef PARAMETER_BLOCK_SIZES | 
|  |  | 
|  | #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2, 2 | 
|  | TEST_BODY(SixParameterBlockFunctor) | 
|  | #undef PARAMETER_BLOCK_SIZES | 
|  |  | 
|  | #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2, 2, 2 | 
|  | TEST_BODY(SevenParameterBlockFunctor) | 
|  | #undef PARAMETER_BLOCK_SIZES | 
|  |  | 
|  | #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2, 2, 2, 2 | 
|  | TEST_BODY(EightParameterBlockFunctor) | 
|  | #undef PARAMETER_BLOCK_SIZES | 
|  |  | 
|  | #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2, 2, 2, 2, 2 | 
|  | TEST_BODY(NineParameterBlockFunctor) | 
|  | #undef PARAMETER_BLOCK_SIZES | 
|  |  | 
|  | #define PARAMETER_BLOCK_SIZES 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 | 
|  | TEST_BODY(TenParameterBlockFunctor) | 
|  | #undef PARAMETER_BLOCK_SIZES | 
|  |  | 
|  | #undef TEST_BODY | 
|  |  | 
|  | TEST(CostFunctionToFunctor, DynamicNumberOfResiduals) { | 
|  | std::unique_ptr<CostFunction> cost_function( | 
|  | new AutoDiffCostFunction<CostFunctionToFunctor<ceres::DYNAMIC, 2, 2>, | 
|  | ceres::DYNAMIC, | 
|  | 2, | 
|  | 2>( | 
|  | new CostFunctionToFunctor<ceres::DYNAMIC, 2, 2>( | 
|  | new AutoDiffCostFunction<TwoParameterBlockFunctor, 2, 2, 2>( | 
|  | new TwoParameterBlockFunctor)), | 
|  | 2)); | 
|  |  | 
|  | std::unique_ptr<CostFunction> actual_cost_function( | 
|  | new AutoDiffCostFunction<TwoParameterBlockFunctor, 2, 2, 2>( | 
|  | new TwoParameterBlockFunctor)); | 
|  | ExpectCostFunctionsAreEqual(*cost_function, *actual_cost_function); | 
|  | } | 
|  |  | 
|  | TEST(CostFunctionToFunctor, DynamicCostFunctionToFunctor) { | 
|  | auto* actual_cost_function( | 
|  | new DynamicAutoDiffCostFunction<DynamicTwoParameterBlockFunctor>( | 
|  | new DynamicTwoParameterBlockFunctor)); | 
|  | actual_cost_function->AddParameterBlock(2); | 
|  | actual_cost_function->AddParameterBlock(2); | 
|  | actual_cost_function->SetNumResiduals(2); | 
|  |  | 
|  | DynamicAutoDiffCostFunction<DynamicCostFunctionToFunctor> cost_function( | 
|  | new DynamicCostFunctionToFunctor(actual_cost_function)); | 
|  | cost_function.AddParameterBlock(2); | 
|  | cost_function.AddParameterBlock(2); | 
|  | cost_function.SetNumResiduals(2); | 
|  |  | 
|  | ExpectCostFunctionsAreEqual(cost_function, *actual_cost_function); | 
|  | } | 
|  |  | 
|  | }  // namespace ceres::internal |