| 
									
										
										
										
											2014-10-21 16:42:30 +08:00
										 |  |  | /* ----------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-22 17:23:35 +08:00
										 |  |  |  * -------------------------------------------------------------------------- */ | 
					
						
							| 
									
										
										
										
											2014-10-21 16:42:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * @file testExpression.cpp | 
					
						
							|  |  |  |  * @date September 18, 2014 | 
					
						
							|  |  |  |  * @author Frank Dellaert | 
					
						
							|  |  |  |  * @author Paul Furgale | 
					
						
							|  |  |  |  * @brief unit tests for Block Automatic Differentiation | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-22 17:41:04 +08:00
										 |  |  | #include <gtsam_unstable/nonlinear/AdaptAutoDiff.h>
 | 
					
						
							|  |  |  | #include <gtsam_unstable/nonlinear/Expression.h>
 | 
					
						
							| 
									
										
										
										
											2014-10-21 16:42:30 +08:00
										 |  |  | #include <gtsam/geometry/PinholeCamera.h>
 | 
					
						
							|  |  |  | #include <gtsam/geometry/Pose3.h>
 | 
					
						
							|  |  |  | #include <gtsam/geometry/Cal3_S2.h>
 | 
					
						
							|  |  |  | #include <gtsam/geometry/Cal3Bundler.h>
 | 
					
						
							| 
									
										
										
										
											2014-10-22 00:50:52 +08:00
										 |  |  | #include <gtsam/base/numericalDerivative.h>
 | 
					
						
							| 
									
										
										
										
											2014-10-21 16:42:30 +08:00
										 |  |  | #include <gtsam/base/Testable.h>
 | 
					
						
							|  |  |  | #include <gtsam/base/LieScalar.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-22 17:23:35 +08:00
										 |  |  | #include <gtsam_unstable/nonlinear/ceres_example.h>
 | 
					
						
							| 
									
										
										
										
											2014-10-21 16:42:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #undef CHECK
 | 
					
						
							|  |  |  | #include <CppUnitLite/TestHarness.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <boost/assign/list_of.hpp>
 | 
					
						
							|  |  |  | using boost::assign::list_of; | 
					
						
							|  |  |  | using boost::assign::map_list_of; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace std; | 
					
						
							|  |  |  | using namespace gtsam; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // The DefaultChart of Camera below is laid out like Snavely's 9-dim vector
 | 
					
						
							|  |  |  | typedef PinholeCamera<Cal3Bundler> Camera; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | // Some Ceres Snippets copied for testing
 | 
					
						
							|  |  |  | // Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
 | 
					
						
							|  |  |  | template<typename T> inline T &RowMajorAccess(T *base, int rows, int cols, | 
					
						
							|  |  |  |     int i, int j) { | 
					
						
							|  |  |  |   return base[cols * i + j]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline double RandDouble() { | 
					
						
							|  |  |  |   double r = static_cast<double>(rand()); | 
					
						
							|  |  |  |   return r / RAND_MAX; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A structure for projecting a 3x4 camera matrix and a
 | 
					
						
							|  |  |  | // homogeneous 3D point, to a 2D inhomogeneous point.
 | 
					
						
							|  |  |  | struct Projective { | 
					
						
							|  |  |  |   // Function that takes P and X as separate vectors:
 | 
					
						
							|  |  |  |   //   P, X -> x
 | 
					
						
							|  |  |  |   template<typename A> | 
					
						
							|  |  |  |   bool operator()(A const P[12], A const X[4], A x[2]) const { | 
					
						
							|  |  |  |     A PX[3]; | 
					
						
							|  |  |  |     for (int i = 0; i < 3; ++i) { | 
					
						
							|  |  |  |       PX[i] = RowMajorAccess(P, 3, 4, i, 0) * X[0] | 
					
						
							|  |  |  |           + RowMajorAccess(P, 3, 4, i, 1) * X[1] | 
					
						
							|  |  |  |           + RowMajorAccess(P, 3, 4, i, 2) * X[2] | 
					
						
							|  |  |  |           + RowMajorAccess(P, 3, 4, i, 3) * X[3]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (PX[2] != 0.0) { | 
					
						
							|  |  |  |       x[0] = PX[0] / PX[2]; | 
					
						
							|  |  |  |       x[1] = PX[1] / PX[2]; | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Adapt to eigen types
 | 
					
						
							|  |  |  |   Vector2 operator()(const MatrixRowMajor& P, const Vector4& X) const { | 
					
						
							|  |  |  |     Vector2 x; | 
					
						
							|  |  |  |     if (operator()(P.data(), X.data(), x.data())) | 
					
						
							|  |  |  |       return x; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       throw std::runtime_error("Projective fail"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | // Test Ceres AutoDiff
 | 
					
						
							|  |  |  | TEST(Expression, AutoDiff) { | 
					
						
							|  |  |  |   using ceres::internal::AutoDiff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Instantiate function
 | 
					
						
							|  |  |  |   Projective projective; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Make arguments
 | 
					
						
							|  |  |  |   typedef Eigen::Matrix<double, 3, 4, Eigen::RowMajor> M; | 
					
						
							|  |  |  |   M P; | 
					
						
							|  |  |  |   P << 1, 0, 0, 0, 0, 1, 0, 5, 0, 0, 1, 0; | 
					
						
							|  |  |  |   Vector4 X(10, 0, 5, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Apply the mapping, to get image point b_x.
 | 
					
						
							|  |  |  |   Vector expected = Vector2(2, 1); | 
					
						
							|  |  |  |   Vector2 actual = projective(P, X); | 
					
						
							|  |  |  |   EXPECT(assert_equal(expected,actual,1e-9)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Get expected derivatives
 | 
					
						
							|  |  |  |   Matrix E1 = numericalDerivative21<Vector2, M, Vector4>(Projective(), P, X); | 
					
						
							|  |  |  |   Matrix E2 = numericalDerivative22<Vector2, M, Vector4>(Projective(), P, X); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Get derivatives with AutoDiff
 | 
					
						
							|  |  |  |   Vector2 actual2; | 
					
						
							|  |  |  |   MatrixRowMajor H1(2, 12), H2(2, 4); | 
					
						
							|  |  |  |   double *parameters[] = { P.data(), X.data() }; | 
					
						
							|  |  |  |   double *jacobians[] = { H1.data(), H2.data() }; | 
					
						
							|  |  |  |   CHECK( | 
					
						
							|  |  |  |       (AutoDiff<Projective, double, 12, 4>::Differentiate( projective, parameters, 2, actual2.data(), jacobians))); | 
					
						
							|  |  |  |   EXPECT(assert_equal(E1,H1,1e-8)); | 
					
						
							|  |  |  |   EXPECT(assert_equal(E2,H2,1e-8)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2014-10-22 17:23:35 +08:00
										 |  |  | // Test Ceres AutoDiff on Snavely, defined in ceres_example.h
 | 
					
						
							|  |  |  | // Adapt to GTSAM types
 | 
					
						
							|  |  |  | Vector2 adapted(const Vector9& P, const Vector3& X) { | 
					
						
							|  |  |  |   SnavelyProjection snavely; | 
					
						
							|  |  |  |   Vector2 x; | 
					
						
							|  |  |  |   if (snavely(P.data(), X.data(), x.data())) | 
					
						
							|  |  |  |     return x; | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     throw std::runtime_error("Snavely fail"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-21 16:42:30 +08:00
										 |  |  | TEST(Expression, AutoDiff2) { | 
					
						
							|  |  |  |   using ceres::internal::AutoDiff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Instantiate function
 | 
					
						
							|  |  |  |   SnavelyProjection snavely; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Make arguments
 | 
					
						
							|  |  |  |   Vector9 P; // zero rotation, (0,5,0) translation, focal length 1
 | 
					
						
							|  |  |  |   P << 0, 0, 0, 0, 5, 0, 1, 0, 0; | 
					
						
							|  |  |  |   Vector3 X(10, 0, -5); // negative Z-axis convention of Snavely!
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Apply the mapping, to get image point b_x.
 | 
					
						
							|  |  |  |   Vector expected = Vector2(2, 1); | 
					
						
							| 
									
										
										
										
											2014-10-22 17:23:35 +08:00
										 |  |  |   Vector2 actual = adapted(P, X); | 
					
						
							| 
									
										
										
										
											2014-10-21 16:42:30 +08:00
										 |  |  |   EXPECT(assert_equal(expected,actual,1e-9)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Get expected derivatives
 | 
					
						
							| 
									
										
										
										
											2014-10-22 17:23:35 +08:00
										 |  |  |   Matrix E1 = numericalDerivative21<Vector2, Vector9, Vector3>(adapted, P, X); | 
					
						
							|  |  |  |   Matrix E2 = numericalDerivative22<Vector2, Vector9, Vector3>(adapted, P, X); | 
					
						
							| 
									
										
										
										
											2014-10-21 16:42:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Get derivatives with AutoDiff
 | 
					
						
							|  |  |  |   Vector2 actual2; | 
					
						
							|  |  |  |   MatrixRowMajor H1(2, 9), H2(2, 3); | 
					
						
							|  |  |  |   double *parameters[] = { P.data(), X.data() }; | 
					
						
							|  |  |  |   double *jacobians[] = { H1.data(), H2.data() }; | 
					
						
							|  |  |  |   CHECK( | 
					
						
							|  |  |  |       (AutoDiff<SnavelyProjection, double, 9, 3>::Differentiate( snavely, parameters, 2, actual2.data(), jacobians))); | 
					
						
							|  |  |  |   EXPECT(assert_equal(E1,H1,1e-8)); | 
					
						
							|  |  |  |   EXPECT(assert_equal(E2,H2,1e-8)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | // Test AutoDiff wrapper Snavely
 | 
					
						
							|  |  |  | TEST(Expression, AutoDiff3) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Make arguments
 | 
					
						
							|  |  |  |   Camera P(Pose3(Rot3(), Point3(0, 5, 0)), Cal3Bundler(1, 0, 0)); | 
					
						
							|  |  |  |   Point3 X(10, 0, -5); // negative Z-axis convention of Snavely!
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   typedef AdaptAutoDiff<SnavelyProjection, Point2, Camera, Point3> Adaptor; | 
					
						
							|  |  |  |   Adaptor snavely; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Apply the mapping, to get image point b_x.
 | 
					
						
							|  |  |  |   Point2 expected(2, 1); | 
					
						
							|  |  |  |   Point2 actual = snavely(P, X); | 
					
						
							|  |  |  |   EXPECT(assert_equal(expected,actual,1e-9)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //  // Get expected derivatives
 | 
					
						
							|  |  |  |   Matrix E1 = numericalDerivative21<Point2, Camera, Point3>(Adaptor(), P, X); | 
					
						
							|  |  |  |   Matrix E2 = numericalDerivative22<Point2, Camera, Point3>(Adaptor(), P, X); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Get derivatives with AutoDiff, not gives RowMajor results!
 | 
					
						
							|  |  |  |   Matrix29 H1; | 
					
						
							|  |  |  |   Matrix23 H2; | 
					
						
							|  |  |  |   Point2 actual2 = snavely(P, X, H1, H2); | 
					
						
							| 
									
										
										
										
											2014-11-03 07:59:19 +08:00
										 |  |  |   EXPECT(assert_equal(expected,actual2,1e-9)); | 
					
						
							| 
									
										
										
										
											2014-10-21 16:42:30 +08:00
										 |  |  |   EXPECT(assert_equal(E1,H1,1e-8)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | // Test AutoDiff wrapper in an expression
 | 
					
						
							|  |  |  | TEST(Expression, Snavely) { | 
					
						
							|  |  |  |   Expression<Camera> P(1); | 
					
						
							|  |  |  |   Expression<Point3> X(2); | 
					
						
							|  |  |  |   typedef AdaptAutoDiff<SnavelyProjection, Point2, Camera, Point3> Adaptor; | 
					
						
							|  |  |  |   Expression<Point2> expression(Adaptor(), P, X); | 
					
						
							| 
									
										
										
										
											2014-10-23 07:44:04 +08:00
										 |  |  | #ifdef GTSAM_USE_QUATERNIONS
 | 
					
						
							| 
									
										
										
										
											2014-11-03 07:59:19 +08:00
										 |  |  |   EXPECT_LONGS_EQUAL(400,expression.traceSize()); // Todo, should be zero
 | 
					
						
							| 
									
										
										
										
											2014-10-23 07:44:04 +08:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2014-10-25 05:47:02 +08:00
										 |  |  |   EXPECT_LONGS_EQUAL(432,expression.traceSize()); // Todo, should be zero
 | 
					
						
							| 
									
										
										
										
											2014-10-23 04:51:02 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-10-21 16:42:30 +08:00
										 |  |  |   set<Key> expected = list_of(1)(2); | 
					
						
							|  |  |  |   EXPECT(expected == expression.keys()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | int main() { | 
					
						
							|  |  |  |   TestResult tr; | 
					
						
							|  |  |  |   return TestRegistry::runAllTests(tr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | 
 |