00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "cartographer/mapping/internal/optimization/cost_functions/spa_cost_function_2d.h"
00018
00019 #include <memory>
00020
00021 #include "cartographer/transform/rigid_transform.h"
00022 #include "gmock/gmock.h"
00023 #include "gtest/gtest.h"
00024
00025 namespace cartographer {
00026 namespace mapping {
00027 namespace optimization {
00028 namespace {
00029
00030 using ::testing::ElementsAre;
00031
00032 constexpr int kPoseDimension = 3;
00033 constexpr int kResidualsCount = 3;
00034 constexpr int kParameterBlocksCount = 2;
00035 constexpr int kJacobianColDimension = kResidualsCount * kPoseDimension;
00036
00037 using ResidualType = std::array<double, kResidualsCount>;
00038 using JacobianType = std::array<std::array<double, kJacobianColDimension>,
00039 kParameterBlocksCount>;
00040
00041 ::testing::Matcher<double> Near(double expected, double precision = 1e-05) {
00042 return testing::DoubleNear(expected, precision);
00043 }
00044
00045 class SpaCostFunction2DTest : public ::testing::Test {
00046 public:
00047 SpaCostFunction2DTest()
00048 : constraint_(PoseGraphInterface::Constraint::Pose{
00049 transform::Rigid3d(Eigen::Vector3d(1., 1., 1.),
00050 Eigen::Quaterniond(1., 1., -1., -1.)),
00051 1, 10}),
00052 auto_diff_cost_(CreateAutoDiffSpaCostFunction(constraint_)),
00053 analytical_cost_(CreateAnalyticalSpaCostFunction(constraint_)) {
00054 for (int i = 0; i < kParameterBlocksCount; ++i) {
00055 jacobian_ptrs_[i] = jacobian_[i].data();
00056 }
00057 }
00058
00059 std::pair<const ResidualType&, const JacobianType&> EvaluateAnalyticalCost(
00060 const std::array<const double*, 2>& parameter_blocks) {
00061 return Evaluate(parameter_blocks, analytical_cost_);
00062 }
00063
00064 std::pair<const ResidualType&, const JacobianType&> EvaluateAutoDiffCost(
00065 const std::array<const double*, 2>& parameter_blocks) {
00066 return Evaluate(parameter_blocks, auto_diff_cost_);
00067 }
00068
00069 private:
00070 std::pair<const ResidualType&, const JacobianType&> Evaluate(
00071 const std::array<const double*, 2>& parameter_blocks,
00072 const std::unique_ptr<ceres::CostFunction>& cost_function) {
00073 cost_function->Evaluate(parameter_blocks.data(), residuals_.data(),
00074 jacobian_ptrs_.data());
00075 return std::make_pair(std::cref(residuals_), std::cref(jacobian_));
00076 }
00077
00078 ResidualType residuals_;
00079 JacobianType jacobian_;
00080 std::array<double*, kParameterBlocksCount> jacobian_ptrs_;
00081 PoseGraphInterface::Constraint::Pose constraint_;
00082 std::unique_ptr<ceres::CostFunction> auto_diff_cost_;
00083 std::unique_ptr<ceres::CostFunction> analytical_cost_;
00084 };
00085
00086 TEST_F(SpaCostFunction2DTest, CompareAutoDiffAndAnalytical) {
00087 std::array<double, 3> start_pose{{1., 1., 1.}};
00088 std::array<double, 3> end_pose{{10., 1., 100.}};
00089 std::array<const double*, 2> parameter_blocks{
00090 {start_pose.data(), end_pose.data()}};
00091
00092 ResidualType auto_diff_residual, analytical_residual;
00093 JacobianType auto_diff_jacobian, analytical_jacobian;
00094 std::tie(auto_diff_residual, auto_diff_jacobian) =
00095 EvaluateAutoDiffCost(parameter_blocks);
00096 std::tie(analytical_residual, analytical_jacobian) =
00097 EvaluateAnalyticalCost(parameter_blocks);
00098
00099 for (int i = 0; i < kResidualsCount; ++i) {
00100 EXPECT_THAT(auto_diff_residual[i], Near(analytical_residual[i]));
00101 }
00102 for (int i = 0; i < kParameterBlocksCount; ++i) {
00103 for (int j = 0; j < kJacobianColDimension; ++j) {
00104 EXPECT_THAT(auto_diff_jacobian[i][j], Near(analytical_jacobian[i][j]));
00105 }
00106 }
00107 }
00108
00109 TEST_F(SpaCostFunction2DTest, EvaluateAnalyticalCost) {
00110 std::array<double, 3> start_pose{{1., 1., 1.}};
00111 std::array<double, 3> end_pose{{10., 1., 100.}};
00112 std::array<const double*, 2> parameter_blocks{
00113 {start_pose.data(), end_pose.data()}};
00114
00115 auto residuals_and_jacobian = EvaluateAnalyticalCost(parameter_blocks);
00116 EXPECT_THAT(residuals_and_jacobian.first,
00117 ElementsAre(Near(-3.86272), Near(8.57324), Near(-6.83333)));
00118 EXPECT_THAT(
00119 residuals_and_jacobian.second,
00120 ElementsAre(
00121 ElementsAre(Near(0.540302), Near(0.841471), Near(7.57324),
00122 Near(-0.841471), Near(0.540302), Near(4.86272), Near(0),
00123 Near(0), Near(10)),
00124 ElementsAre(Near(-0.540302), Near(-0.841471), Near(0), Near(0.841471),
00125 Near(-0.540302), Near(0), Near(0), Near(0), Near(-10))));
00126 }
00127
00128 TEST_F(SpaCostFunction2DTest, EvaluateAutoDiffCost) {
00129 std::array<double, 3> start_pose{{1., 1., 1.}};
00130 std::array<double, 3> end_pose{{10., 1., 100.}};
00131 std::array<const double*, 2> parameter_blocks{
00132 {start_pose.data(), end_pose.data()}};
00133
00134 auto residuals_and_jacobian = EvaluateAutoDiffCost(parameter_blocks);
00135 EXPECT_THAT(residuals_and_jacobian.first,
00136 ElementsAre(Near(-3.86272), Near(8.57324), Near(-6.83333)));
00137 EXPECT_THAT(
00138 residuals_and_jacobian.second,
00139 ElementsAre(
00140 ElementsAre(Near(0.540302), Near(0.841471), Near(7.57324),
00141 Near(-0.841471), Near(0.540302), Near(4.86272), Near(0),
00142 Near(0), Near(10)),
00143 ElementsAre(Near(-0.540302), Near(-0.841471), Near(0), Near(0.841471),
00144 Near(-0.540302), Near(0), Near(0), Near(0), Near(-10))));
00145 }
00146
00147 }
00148 }
00149 }
00150 }