/* ---------------------------------------------------------------------------- * 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 * -------------------------------------------------------------------------- */ /** * @file testExpressionMeta.cpp * @date October 14, 2014 * @author Frank Dellaert * @brief Test meta-programming constructs for Expressions */ #include #include #include #include #include #include using namespace std; using namespace gtsam; /* ************************************************************************* */ namespace mpl = boost::mpl; #include #include template struct Incomplete; // Check generation of FunctionalNode typedef mpl::vector MyTypes; typedef FunctionalNode::type Generated; //Incomplete incomplete; BOOST_MPL_ASSERT((boost::is_same< Matrix2, Generated::Record::Jacobian2T >)); // Try generating vectors of ExecutionTrace typedef mpl::vector, ExecutionTrace > ExpectedTraces; typedef mpl::transform >::type MyTraces; BOOST_MPL_ASSERT((mpl::equal< ExpectedTraces, MyTraces >)); template struct MakeTrace { typedef ExecutionTrace type; }; typedef mpl::transform >::type MyTraces1; BOOST_MPL_ASSERT((mpl::equal< ExpectedTraces, MyTraces1 >)); // Try generating vectors of Expression types typedef mpl::vector, Expression > ExpectedExpressions; typedef mpl::transform >::type Expressions; BOOST_MPL_ASSERT((mpl::equal< ExpectedExpressions, Expressions >)); // Try generating vectors of Jacobian types typedef mpl::vector ExpectedJacobians; typedef mpl::transform >::type Jacobians; BOOST_MPL_ASSERT((mpl::equal< ExpectedJacobians, Jacobians >)); // Try accessing a Jacobian typedef mpl::at_c::type Jacobian23; // base zero ! BOOST_MPL_ASSERT((boost::is_same< Matrix23, Jacobian23>)); /* ************************************************************************* */ // Boost Fusion includes allow us to create/access values from MPL vectors #include #include // Create a value and access it TEST(ExpressionFactor, JacobiansValue) { using boost::fusion::at_c; Matrix23 expected; Jacobians jacobians; at_c<1>(jacobians) << 1, 2, 3, 4, 5, 6; Matrix23 actual = at_c<1>(jacobians); CHECK(actual.cols() == expected.cols()); CHECK(actual.rows() == expected.rows()); } /* ************************************************************************* */ // Test out polymorphic transform #include #include #include struct triple { template struct result; // says we will provide result template struct result { typedef double type; // result for int argument }; template struct result { typedef double type; // result for int argument }; template struct result { typedef double type; // result for double argument }; template struct result { typedef double type; // result for double argument }; // actual function template typename result::type operator()(const T& x) const { return (double) x; } }; // Test out polymorphic transform TEST(ExpressionFactor, Triple) { typedef boost::fusion::vector IntDouble; IntDouble H = boost::fusion::make_vector(1, 2.0); // Only works if I use Double2 typedef boost::fusion::result_of::transform::type Result; typedef boost::fusion::vector Double2; Double2 D = boost::fusion::transform(H, triple()); using boost::fusion::at_c; DOUBLES_EQUAL(1.0, at_c<0>(D), 1e-9); DOUBLES_EQUAL(2.0, at_c<1>(D), 1e-9); } /* ************************************************************************* */ #include #include #include #include // Test out invoke TEST(ExpressionFactor, Invoke) { EXPECT_LONGS_EQUAL(2, invoke(plus(),boost::fusion::make_vector(1,1))); // Creating a Pose3 (is there another way?) boost::fusion::vector pair; Pose3 pose = boost::fusion::invoke(boost::value_factory(), pair); } /* ************************************************************************* */ // debug const issue (how to make read/write arguments for invoke) struct test { typedef void result_type; void operator()(int& a, int& b) const { a = 6; b = 7; } }; TEST(ExpressionFactor, ConstIssue) { int a, b; boost::fusion::invoke(test(), boost::fusion::make_vector(boost::ref(a), boost::ref(b))); LONGS_EQUAL(6, a); LONGS_EQUAL(7, b); } /* ************************************************************************* */ // Test out invoke on a given GTSAM function // then construct prototype for it's derivatives TEST(ExpressionFactor, InvokeDerivatives) { // This is the method in Pose3: // Point3 transform_to(const Point3& p) const; // Point3 transform_to(const Point3& p, // boost::optional Dpose, boost::optional Dpoint) const; // Let's assign it it to a boost function object // cast is needed because Pose3::transform_to is overloaded typedef boost::function F; F f = static_cast(&Pose3::transform_to); // Create arguments Pose3 pose; Point3 point; typedef boost::fusion::vector Arguments; Arguments args = boost::fusion::make_vector(pose, point); // Create fused function (takes fusion vector) and call it boost::fusion::fused g(f); Point3 actual = g(args); CHECK(assert_equal(point,actual)); // We can *immediately* do this using invoke Point3 actual2 = boost::fusion::invoke(f, args); CHECK(assert_equal(point,actual2)); // Now, let's create the optional Jacobian arguments typedef Point3 T; typedef boost::mpl::vector TYPES; typedef boost::mpl::transform >::type Optionals; // Unfortunately this is moot: we need a pointer to a function with the // optional derivatives; I don't see a way of calling a function that we // did not get access to by the caller passing us a pointer. // Let's test below whether we can have a proxy object } struct proxy { typedef Point3 result_type; Point3 operator()(const Pose3& pose, const Point3& point) const { return pose.transform_to(point); } Point3 operator()(const Pose3& pose, const Point3& point, boost::optional Dpose, boost::optional Dpoint) const { return pose.transform_to(point, Dpose, Dpoint); } }; TEST(ExpressionFactor, InvokeDerivatives2) { // without derivatives Pose3 pose; Point3 point; Point3 actual = boost::fusion::invoke(proxy(), boost::fusion::make_vector(pose, point)); CHECK(assert_equal(point,actual)); // with derivatives, does not work, const issue again Matrix36 Dpose; Matrix3 Dpoint; Point3 actual2 = boost::fusion::invoke(proxy(), boost::fusion::make_vector(pose, point, boost::ref(Dpose), boost::ref(Dpoint))); CHECK(assert_equal(point,actual2)); } /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */