/* ---------------------------------------------------------------------------- * GTSAM Copyright 2010, Georgia Tech Research Corporation, * Atlanta, Georgia 30332-0415 * All Rights Reserved * Authors: Frank Dellaert, et al. (see THANKS for the full author list) * See LICENSE for the license information * -------------------------------1------------------------------------------- */ /** * @file testCustomChartExpression.cpp * @date September 18, 2014 * @author Frank Dellaert * @author Paul Furgale * @brief unit tests for Block Automatic Differentiation */ #include #include using namespace gtsam; // A simple prototype custom chart that does two things: // 1. it reduces the dimension of the variable being estimated // 2. it scales the input to retract. // // The Jacobian of this chart is: // [ 2 0 ] // [ 0 3 ] // [ 0 0 ] struct ProjectionChart { typedef Eigen::Vector3d type; typedef Eigen::Vector2d vector; static vector local(const type& origin, const type& other) { return (other - origin).head<2>(); } static type retract(const type& origin, const vector& d) { return origin + Eigen::Vector3d(2.0 * d[0], 3.0 * d[1], 0.0); } static int getDimension(const type& origin) { return 2; } }; namespace gtsam { namespace traits { template<> struct is_chart : public boost::true_type {}; template<> struct dimension : public boost::integral_constant {}; } // namespace traits } // namespace gtsam TEST(ExpressionCustomChart, projection) { // Create expression Expression point(1); Eigen::Vector3d pval(1.0, 2.0, 3.0); Values standard; standard.insert(1, pval); Values custom; custom.insert(1, pval, ProjectionChart()); Eigen::Vector3d pstandard = point.value(standard); Eigen::Vector3d pcustom = point.value(custom); // The values should be the same. EXPECT(assert_equal(Matrix(pstandard), Matrix(pcustom), 1e-10)); EXPECT_LONGS_EQUAL(3, standard.at(1).dim()); VectorValues vstandard = standard.zeroVectors(); EXPECT_LONGS_EQUAL(3, vstandard.at(1).size()); EXPECT_LONGS_EQUAL(2, custom.at(1).dim()); VectorValues vcustom = custom.zeroVectors(); EXPECT_LONGS_EQUAL(2, vcustom.at(1).size()); ExpressionFactor f(noiseModel::Unit::Create(pval.size()), pval, point); std::shared_ptr gfstandard = f.linearize(standard); std::shared_ptr jfstandard = // std::dynamic_pointer_cast(gfstandard); typedef std::pair Jacobian; Jacobian Jstandard = jfstandard->jacobianUnweighted(); EXPECT(assert_equal(Eigen::Matrix3d::Identity(), Jstandard.first, 1e-10)); std::shared_ptr gfcustom = f.linearize(custom); std::shared_ptr jfcustom = // std::dynamic_pointer_cast(gfcustom); Eigen::MatrixXd expectedJacobian = Eigen::MatrixXd::Zero(3,2); expectedJacobian(0,0) = 2.0; expectedJacobian(1,1) = 3.0; Jacobian Jcustom = jfcustom->jacobianUnweighted(); EXPECT(assert_equal(expectedJacobian, Jcustom.first, 1e-10)); // Amazingly, the finite differences get the expected Jacobian right. const double fd_step = 1e-5; const double tolerance = 1e-5; EXPECT_CORRECT_EXPRESSION_JACOBIANS(point, custom, fd_step, tolerance); } /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */