114 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
| /* ----------------------------------------------------------------------------
 | |
| 
 | |
|  * 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 <gtsam_unstable/nonlinear/expressionTesting.h>
 | |
| #include <CppUnitLite/TestHarness.h>
 | |
| 
 | |
| 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<ProjectionChart> : public boost::true_type {};
 | |
| template<> struct dimension<ProjectionChart> : public boost::integral_constant<int, 2> {};
 | |
| }  // namespace traits
 | |
| }  // namespace gtsam
 | |
| 
 | |
| TEST(ExpressionCustomChart, projection) {
 | |
|   // Create expression
 | |
|   Expression<Eigen::Vector3d> 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<Eigen::Vector3d> f(noiseModel::Unit::Create(pval.size()), pval, point);
 | |
| 
 | |
|   boost::shared_ptr<GaussianFactor> gfstandard = f.linearize(standard);
 | |
|   boost::shared_ptr<JacobianFactor> jfstandard = //
 | |
|       boost::dynamic_pointer_cast<JacobianFactor>(gfstandard);
 | |
| 
 | |
|   typedef std::pair<Eigen::MatrixXd, Eigen::VectorXd> Jacobian;
 | |
|   Jacobian Jstandard = jfstandard->jacobianUnweighted();
 | |
|   EXPECT(assert_equal(Eigen::Matrix3d::Identity(), Jstandard.first, 1e-10));
 | |
| 
 | |
|   boost::shared_ptr<GaussianFactor> gfcustom = f.linearize(custom);
 | |
|   boost::shared_ptr<JacobianFactor> jfcustom = //
 | |
|       boost::dynamic_pointer_cast<JacobianFactor>(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);
 | |
| }
 | |
| /* ************************************************************************* */
 | |
| 
 |