From 303d37a7161c30074ce56d3e213dc66cbdce3a98 Mon Sep 17 00:00:00 2001 From: dellaert Date: Sun, 5 Oct 2014 11:22:14 +0200 Subject: [PATCH 1/9] Separate hierarchy --- gtsam_unstable/nonlinear/Expression-inl.h | 89 ++++++++++++++++++- gtsam_unstable/nonlinear/Expression.h | 4 +- .../nonlinear/tests/testExpression.cpp | 10 ++- 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/gtsam_unstable/nonlinear/Expression-inl.h b/gtsam_unstable/nonlinear/Expression-inl.h index 3cb735b6e..7f371b886 100644 --- a/gtsam_unstable/nonlinear/Expression-inl.h +++ b/gtsam_unstable/nonlinear/Expression-inl.h @@ -107,6 +107,84 @@ public: } }; +//----------------------------------------------------------------------------- +/** + * Execution trace for reverse AD + */ +template +class JacobianTrace { + +public: + + /// Constructor + JacobianTrace() { + } + + virtual ~JacobianTrace() { + } + + /// Return value + const T& value() const = 0; + + /// Return value and derivatives + virtual Augmented augmented() const = 0; +}; + +template +class JacobianTraceConstant : public JacobianTrace { + +protected: + + T constant_; + +public: + + /// Constructor + JacobianTraceConstant(const T& constant) : + constant_(constant) { + } + + virtual ~JacobianTraceConstant() { + } + + /// Return value + const T& value() const { + return constant_; + } + + /// Return value and derivatives + virtual Augmented augmented() const { + return Augmented(constant_); + } +}; + +template +class JacobianTraceLeaf : public JacobianTrace { + +protected: + + T value_; + +public: + + /// Constructor + JacobianTraceLeaf(const T& value) : + value_(value) { + } + + virtual ~JacobianTraceLeaf() { + } + + /// Return value + const T& value() const { + return value_; + } + + /// Return value and derivatives + virtual Augmented augmented() const { + return Augmented(value_); + } +}; //----------------------------------------------------------------------------- /** * Expression node. The superclass for objects that do the heavy lifting @@ -137,6 +215,10 @@ public: /// Return value and derivatives virtual Augmented forward(const Values& values) const = 0; + /// Construct an execution trace for reverse AD + virtual JacobianTrace reverse(const Values& values) const { + return JacobianTrace(T()); + } }; //----------------------------------------------------------------------------- @@ -173,10 +255,13 @@ public: /// Return value and derivatives virtual Augmented forward(const Values& values) const { - T t = value(values); - return Augmented(t); + return Augmented(constant_); } + /// Construct an execution trace for reverse AD + virtual JacobianTrace reverse(const Values& values) const { + return JacobianTrace(constant_); + } }; //----------------------------------------------------------------------------- diff --git a/gtsam_unstable/nonlinear/Expression.h b/gtsam_unstable/nonlinear/Expression.h index 27f51893c..bd17febf0 100644 --- a/gtsam_unstable/nonlinear/Expression.h +++ b/gtsam_unstable/nonlinear/Expression.h @@ -103,7 +103,9 @@ public: /// Return value and derivatives Augmented augmented(const Values& values) const { - return root_->forward(values); + JacobianTrace trace = root_->reverse(values); + return trace.augmented(); +// return root_->forward(values); } const boost::shared_ptr >& root() const { diff --git a/gtsam_unstable/nonlinear/tests/testExpression.cpp b/gtsam_unstable/nonlinear/tests/testExpression.cpp index 057359155..19a54c755 100644 --- a/gtsam_unstable/nonlinear/tests/testExpression.cpp +++ b/gtsam_unstable/nonlinear/tests/testExpression.cpp @@ -36,13 +36,15 @@ Point2 uncalibrate(const CAL& K, const Point2& p, boost::optional Dcal, return K.uncalibrate(p, Dcal, Dp); } +static const Rot3 someR = Rot3::RzRyRx(1,2,3); + /* ************************************************************************* */ TEST(Expression, constant) { - Expression R(Rot3::identity()); + Expression R(someR); Values values; Augmented a = R.augmented(values); - EXPECT(assert_equal(Rot3::identity(), a.value())); + EXPECT(assert_equal(someR, a.value())); JacobianMap expected; EXPECT(a.jacobians() == expected); } @@ -52,9 +54,9 @@ TEST(Expression, constant) { TEST(Expression, leaf) { Expression R(100); Values values; - values.insert(100,Rot3::identity()); + values.insert(100,someR); Augmented a = R.augmented(values); - EXPECT(assert_equal(Rot3::identity(), a.value())); + EXPECT(assert_equal(someR, a.value())); JacobianMap expected; expected[100] = eye(3); EXPECT(a.jacobians() == expected); From 8e527a2251e231dae707c79a0f8f8da0a8ab99f9 Mon Sep 17 00:00:00 2001 From: dellaert Date: Sun, 5 Oct 2014 13:27:41 +0200 Subject: [PATCH 2/9] Binary Trace compiles, runs --- gtsam_unstable/nonlinear/Expression-inl.h | 132 +++++++----------- gtsam_unstable/nonlinear/Expression.h | 5 +- .../nonlinear/tests/testExpression.cpp | 23 +-- 3 files changed, 64 insertions(+), 96 deletions(-) diff --git a/gtsam_unstable/nonlinear/Expression-inl.h b/gtsam_unstable/nonlinear/Expression-inl.h index 7f371b886..ddf3a3cd7 100644 --- a/gtsam_unstable/nonlinear/Expression-inl.h +++ b/gtsam_unstable/nonlinear/Expression-inl.h @@ -75,6 +75,12 @@ public: add(H, jacobians); } + /// Construct from value and two disjoint JacobianMaps + Augmented(const T& t, const JacobianMap& jacobians1, const JacobianMap& jacobians2) : + value_(t), jacobians_(jacobians1) { + jacobians_.insert(jacobians2.begin(), jacobians2.end()); + } + /// Construct value, pre-multiply jacobians by H Augmented(const T& t, const Matrix& H1, const JacobianMap& jacobians1, const Matrix& H2, const JacobianMap& jacobians2) : @@ -107,84 +113,6 @@ public: } }; -//----------------------------------------------------------------------------- -/** - * Execution trace for reverse AD - */ -template -class JacobianTrace { - -public: - - /// Constructor - JacobianTrace() { - } - - virtual ~JacobianTrace() { - } - - /// Return value - const T& value() const = 0; - - /// Return value and derivatives - virtual Augmented augmented() const = 0; -}; - -template -class JacobianTraceConstant : public JacobianTrace { - -protected: - - T constant_; - -public: - - /// Constructor - JacobianTraceConstant(const T& constant) : - constant_(constant) { - } - - virtual ~JacobianTraceConstant() { - } - - /// Return value - const T& value() const { - return constant_; - } - - /// Return value and derivatives - virtual Augmented augmented() const { - return Augmented(constant_); - } -}; - -template -class JacobianTraceLeaf : public JacobianTrace { - -protected: - - T value_; - -public: - - /// Constructor - JacobianTraceLeaf(const T& value) : - value_(value) { - } - - virtual ~JacobianTraceLeaf() { - } - - /// Return value - const T& value() const { - return value_; - } - - /// Return value and derivatives - virtual Augmented augmented() const { - return Augmented(value_); - } -}; //----------------------------------------------------------------------------- /** * Expression node. The superclass for objects that do the heavy lifting @@ -202,6 +130,13 @@ protected: public: + struct Trace { + T value() const { + return T(); + } + virtual Augmented augmented(const Matrix& H) const = 0; + }; + /// Destructor virtual ~ExpressionNode() { } @@ -216,8 +151,8 @@ public: virtual Augmented forward(const Values& values) const = 0; /// Construct an execution trace for reverse AD - virtual JacobianTrace reverse(const Values& values) const { - return JacobianTrace(T()); + virtual boost::shared_ptr reverse(const Values& values) const { + return boost::shared_ptr(); } }; @@ -259,8 +194,9 @@ public: } /// Construct an execution trace for reverse AD - virtual JacobianTrace reverse(const Values& values) const { - return JacobianTrace(constant_); + virtual boost::shared_ptr::Trace> reverse( + const Values& values) const { + return boost::shared_ptr::Trace>(); } }; @@ -413,7 +349,37 @@ public: return Augmented(t, H1, argument1.jacobians(), H2, argument2.jacobians()); } -}; + /// Trace structure for reverse AD + typedef typename ExpressionNode::Trace BaseTrace; + struct Trace: public BaseTrace { + boost::shared_ptr::Trace> trace1; + boost::shared_ptr::Trace> trace2; + Matrix H1, H2; + T t; + /// Return value and derivatives + virtual Augmented augmented(const Matrix& H) const { + // This is a top-down calculation + // The end-result needs Jacobians to all leaf nodes. + // Since this is not a leaf node, we compute what is needed for leaf nodes here + // The binary node represents a fork in the tree, and hence we will get two Augmented maps + Augmented augmented1 = trace1->augmented(H*H1); + Augmented augmented2 = trace1->augmented(H*H2); + return Augmented(t, augmented1.jacobians(), augmented2.jacobians()); + } + }; + + /// Construct an execution trace for reverse AD + virtual boost::shared_ptr reverse(const Values& values) const { + boost::shared_ptr trace = boost::make_shared(); + trace->trace1 = this->expressionA1_->reverse(values); + trace->trace2 = this->expressionA2_->reverse(values); + trace->t = function_(trace->trace1->value(), trace->trace2->value(), + trace->H1, trace->H2); + return trace; + } + +} +; //----------------------------------------------------------------------------- } diff --git a/gtsam_unstable/nonlinear/Expression.h b/gtsam_unstable/nonlinear/Expression.h index bd17febf0..18adea27e 100644 --- a/gtsam_unstable/nonlinear/Expression.h +++ b/gtsam_unstable/nonlinear/Expression.h @@ -103,8 +103,9 @@ public: /// Return value and derivatives Augmented augmented(const Values& values) const { - JacobianTrace trace = root_->reverse(values); - return trace.augmented(); + boost::shared_ptr::Trace> trace = root_->reverse(values); + size_t n = T::Dim(); + return trace->augmented(Eigen::MatrixXd::Identity(n, n)); // return root_->forward(values); } diff --git a/gtsam_unstable/nonlinear/tests/testExpression.cpp b/gtsam_unstable/nonlinear/tests/testExpression.cpp index 19a54c755..dbd52c4e4 100644 --- a/gtsam_unstable/nonlinear/tests/testExpression.cpp +++ b/gtsam_unstable/nonlinear/tests/testExpression.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -64,17 +65,17 @@ TEST(Expression, leaf) { /* ************************************************************************* */ -TEST(Expression, nullaryMethod) { - Expression p(67); - Expression norm(p, &Point3::norm); - Values values; - values.insert(67,Point3(3,4,5)); - Augmented a = norm.augmented(values); - EXPECT(a.value() == sqrt(50)); - JacobianMap expected; - expected[67] = (Matrix(1,3) << 3/sqrt(50),4/sqrt(50),5/sqrt(50)); - EXPECT(assert_equal(expected.at(67),a.jacobians().at(67))); -} +//TEST(Expression, nullaryMethod) { +// Expression p(67); +// Expression norm(p, &Point3::norm); +// Values values; +// values.insert(67,Point3(3,4,5)); +// Augmented a = norm.augmented(values); +// EXPECT(a.value() == sqrt(50)); +// JacobianMap expected; +// expected[67] = (Matrix(1,3) << 3/sqrt(50),4/sqrt(50),5/sqrt(50)); +// EXPECT(assert_equal(expected.at(67),a.jacobians().at(67))); +//} /* ************************************************************************* */ From 75445307b2ed90b6160a40576e2ec50fa25b02c4 Mon Sep 17 00:00:00 2001 From: dellaert Date: Sun, 5 Oct 2014 13:33:23 +0200 Subject: [PATCH 3/9] Unary Trace done --- gtsam_unstable/nonlinear/Expression-inl.h | 35 +++++++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/gtsam_unstable/nonlinear/Expression-inl.h b/gtsam_unstable/nonlinear/Expression-inl.h index ddf3a3cd7..95580e3ec 100644 --- a/gtsam_unstable/nonlinear/Expression-inl.h +++ b/gtsam_unstable/nonlinear/Expression-inl.h @@ -69,6 +69,11 @@ public: jacobians_[key] = Eigen::MatrixXd::Identity(n, n); } + /// Construct from value and JacobianMap + Augmented(const T& t, const JacobianMap& jacobians) : + value_(t), jacobians_(jacobians) { + } + /// Construct value, pre-multiply jacobians by H Augmented(const T& t, const Matrix& H, const JacobianMap& jacobians) : value_(t) { @@ -76,7 +81,8 @@ public: } /// Construct from value and two disjoint JacobianMaps - Augmented(const T& t, const JacobianMap& jacobians1, const JacobianMap& jacobians2) : + Augmented(const T& t, const JacobianMap& jacobians1, + const JacobianMap& jacobians2) : value_(t), jacobians_(jacobians1) { jacobians_.insert(jacobians2.begin(), jacobians2.end()); } @@ -288,6 +294,29 @@ public: return Augmented(t, H, argument.jacobians()); } + /// Trace structure for reverse AD + typedef typename ExpressionNode::Trace BaseTrace; + struct Trace: public BaseTrace { + boost::shared_ptr::Trace> trace1; + Matrix H1; + T t; + /// Return value and derivatives + virtual Augmented augmented(const Matrix& H) const { + // This is a top-down calculation + // The end-result needs Jacobians to all leaf nodes. + // Since this is not a leaf node, we compute what is needed for leaf nodes here + Augmented augmented1 = trace1->augmented(H * H1); + return Augmented(t, augmented1.jacobians()); + } + }; + + /// Construct an execution trace for reverse AD + virtual boost::shared_ptr reverse(const Values& values) const { + boost::shared_ptr trace = boost::make_shared(); + trace->trace1 = this->expressionA_->reverse(values); + trace->t = function_(trace->trace1->value(), trace->H1); + return trace; + } }; //----------------------------------------------------------------------------- @@ -362,8 +391,8 @@ public: // The end-result needs Jacobians to all leaf nodes. // Since this is not a leaf node, we compute what is needed for leaf nodes here // The binary node represents a fork in the tree, and hence we will get two Augmented maps - Augmented augmented1 = trace1->augmented(H*H1); - Augmented augmented2 = trace1->augmented(H*H2); + Augmented augmented1 = trace1->augmented(H * H1); + Augmented augmented2 = trace1->augmented(H * H2); return Augmented(t, augmented1.jacobians(), augmented2.jacobians()); } }; From 7c195422454a9ad53e0e8a238cd201f44d0aac69 Mon Sep 17 00:00:00 2001 From: dellaert Date: Sun, 5 Oct 2014 13:37:51 +0200 Subject: [PATCH 4/9] Leaf Trace compiles --- gtsam_unstable/nonlinear/Expression-inl.h | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/gtsam_unstable/nonlinear/Expression-inl.h b/gtsam_unstable/nonlinear/Expression-inl.h index 95580e3ec..16489ea80 100644 --- a/gtsam_unstable/nonlinear/Expression-inl.h +++ b/gtsam_unstable/nonlinear/Expression-inl.h @@ -69,6 +69,12 @@ public: jacobians_[key] = Eigen::MatrixXd::Identity(n, n); } + /// Construct value dependent on a single key, with Jacobain H + Augmented(const T& t, Key key, const Matrix& H) : + value_(t) { + jacobians_[key] = H; + } + /// Construct from value and JacobianMap Augmented(const T& t, const JacobianMap& jacobians) : value_(t), jacobians_(jacobians) { @@ -245,6 +251,28 @@ public: return Augmented(t, key_); } + /// Trace structure for reverse AD + typedef typename ExpressionNode::Trace BaseTrace; + struct Trace: public BaseTrace { + T t; + Key key; + /// Return value and derivatives + virtual Augmented augmented(const Matrix& H) const { + // This is a top-down calculation + // The end-result needs Jacobians to all leaf nodes. + // Since this is a leaf node, we are done and just insert H in the JacobianMap + return Augmented(t, key, H); + } + }; + + /// Construct an execution trace for reverse AD + virtual boost::shared_ptr reverse(const Values& values) const { + boost::shared_ptr trace = boost::make_shared(); + trace->t = value(values); + trace->key = key_; + return trace; + } + }; //----------------------------------------------------------------------------- From 8db2cd17fc8d03e43fe943ee2b565dd6e23982ee Mon Sep 17 00:00:00 2001 From: dellaert Date: Sun, 5 Oct 2014 13:41:20 +0200 Subject: [PATCH 5/9] Finished constant Trace and *everything* just works!!! Amazing :-) --- gtsam_unstable/nonlinear/Expression-inl.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/gtsam_unstable/nonlinear/Expression-inl.h b/gtsam_unstable/nonlinear/Expression-inl.h index 16489ea80..cfd0bf7f2 100644 --- a/gtsam_unstable/nonlinear/Expression-inl.h +++ b/gtsam_unstable/nonlinear/Expression-inl.h @@ -205,10 +205,22 @@ public: return Augmented(constant_); } + /// Trace structure for reverse AD + typedef typename ExpressionNode::Trace BaseTrace; + struct Trace: public BaseTrace { + T t; + /// Return value and derivatives + virtual Augmented augmented(const Matrix& H) const { + // Base case: just return value and empty map + return Augmented(t); + } + }; + /// Construct an execution trace for reverse AD - virtual boost::shared_ptr::Trace> reverse( - const Values& values) const { - return boost::shared_ptr::Trace>(); + virtual boost::shared_ptr reverse(const Values& values) const { + boost::shared_ptr trace = boost::make_shared(); + trace->t = constant_; + return trace; } }; From fdf9c10b422e61044e0973fda3c9d5fad9256587 Mon Sep 17 00:00:00 2001 From: dellaert Date: Sun, 5 Oct 2014 15:00:10 +0200 Subject: [PATCH 6/9] Implemented value and now testBADFactor also runs --- gtsam_unstable/nonlinear/Expression-inl.h | 48 +++- gtsam_unstable/nonlinear/Expression.h | 6 +- .../nonlinear/tests/testBADFactor.cpp | 260 +++++++++++------- 3 files changed, 194 insertions(+), 120 deletions(-) diff --git a/gtsam_unstable/nonlinear/Expression-inl.h b/gtsam_unstable/nonlinear/Expression-inl.h index cfd0bf7f2..f9187ec65 100644 --- a/gtsam_unstable/nonlinear/Expression-inl.h +++ b/gtsam_unstable/nonlinear/Expression-inl.h @@ -21,6 +21,7 @@ #include #include +#include #include namespace gtsam { @@ -44,6 +45,17 @@ private: typedef std::pair Pair; + /// Insert terms into jacobians_, premultiplying by H, adding if already exists + void add(const JacobianMap& terms) { + BOOST_FOREACH(const Pair& term, terms) { + JacobianMap::iterator it = jacobians_.find(term.first); + if (it != jacobians_.end()) + it->second += term.second; + else + jacobians_[term.first] = term.second; + } + } + /// Insert terms into jacobians_, premultiplying by H, adding if already exists void add(const Matrix& H, const JacobianMap& terms) { BOOST_FOREACH(const Pair& term, terms) { @@ -90,7 +102,7 @@ public: Augmented(const T& t, const JacobianMap& jacobians1, const JacobianMap& jacobians2) : value_(t), jacobians_(jacobians1) { - jacobians_.insert(jacobians2.begin(), jacobians2.end()); + add(jacobians2); } /// Construct value, pre-multiply jacobians by H @@ -143,8 +155,9 @@ protected: public: struct Trace { + T t; T value() const { - return T(); + return t; } virtual Augmented augmented(const Matrix& H) const = 0; }; @@ -208,11 +221,10 @@ public: /// Trace structure for reverse AD typedef typename ExpressionNode::Trace BaseTrace; struct Trace: public BaseTrace { - T t; /// Return value and derivatives virtual Augmented augmented(const Matrix& H) const { // Base case: just return value and empty map - return Augmented(t); + return Augmented(this->t); } }; @@ -220,6 +232,8 @@ public: virtual boost::shared_ptr reverse(const Values& values) const { boost::shared_ptr trace = boost::make_shared(); trace->t = constant_; + std::cout << "constant\n:"; + GTSAM_PRINT(trace->t); return trace; } }; @@ -266,14 +280,12 @@ public: /// Trace structure for reverse AD typedef typename ExpressionNode::Trace BaseTrace; struct Trace: public BaseTrace { - T t; Key key; /// Return value and derivatives virtual Augmented augmented(const Matrix& H) const { - // This is a top-down calculation - // The end-result needs Jacobians to all leaf nodes. - // Since this is a leaf node, we are done and just insert H in the JacobianMap - return Augmented(t, key, H); + // Base case: just insert H in the JacobianMap with correct key + std::cout << "Inserting Jacobian " << DefaultKeyFormatter(key) << "\n"; + return Augmented(this->t, key, H); } }; @@ -282,6 +294,8 @@ public: boost::shared_ptr trace = boost::make_shared(); trace->t = value(values); trace->key = key_; + std::cout << "Leaf(" << DefaultKeyFormatter(key_) << "):\n"; + GTSAM_PRINT(trace->t); return trace; } @@ -339,14 +353,13 @@ public: struct Trace: public BaseTrace { boost::shared_ptr::Trace> trace1; Matrix H1; - T t; /// Return value and derivatives virtual Augmented augmented(const Matrix& H) const { // This is a top-down calculation // The end-result needs Jacobians to all leaf nodes. // Since this is not a leaf node, we compute what is needed for leaf nodes here Augmented augmented1 = trace1->augmented(H * H1); - return Augmented(t, augmented1.jacobians()); + return Augmented(this->t, augmented1.jacobians()); } }; @@ -354,7 +367,10 @@ public: virtual boost::shared_ptr reverse(const Values& values) const { boost::shared_ptr trace = boost::make_shared(); trace->trace1 = this->expressionA_->reverse(values); + std::cout << "Unary:\n"; + GTSAM_PRINT(trace->trace1->value()); trace->t = function_(trace->trace1->value(), trace->H1); + GTSAM_PRINT(trace->t); return trace; } }; @@ -424,7 +440,6 @@ public: boost::shared_ptr::Trace> trace1; boost::shared_ptr::Trace> trace2; Matrix H1, H2; - T t; /// Return value and derivatives virtual Augmented augmented(const Matrix& H) const { // This is a top-down calculation @@ -432,8 +447,9 @@ public: // Since this is not a leaf node, we compute what is needed for leaf nodes here // The binary node represents a fork in the tree, and hence we will get two Augmented maps Augmented augmented1 = trace1->augmented(H * H1); - Augmented augmented2 = trace1->augmented(H * H2); - return Augmented(t, augmented1.jacobians(), augmented2.jacobians()); + Augmented augmented2 = trace2->augmented(H * H2); + return Augmented(this->t, augmented1.jacobians(), + augmented2.jacobians()); } }; @@ -442,8 +458,12 @@ public: boost::shared_ptr trace = boost::make_shared(); trace->trace1 = this->expressionA1_->reverse(values); trace->trace2 = this->expressionA2_->reverse(values); + std::cout << "Binary:\n"; + GTSAM_PRINT(trace->trace1->value()); + GTSAM_PRINT(trace->trace2->value()); trace->t = function_(trace->trace1->value(), trace->trace2->value(), trace->H1, trace->H2); + GTSAM_PRINT(trace->t); return trace; } diff --git a/gtsam_unstable/nonlinear/Expression.h b/gtsam_unstable/nonlinear/Expression.h index 18adea27e..64b1013fe 100644 --- a/gtsam_unstable/nonlinear/Expression.h +++ b/gtsam_unstable/nonlinear/Expression.h @@ -103,10 +103,14 @@ public: /// Return value and derivatives Augmented augmented(const Values& values) const { +#define REVERSE_AD +#ifdef REVERSE_AD boost::shared_ptr::Trace> trace = root_->reverse(values); size_t n = T::Dim(); return trace->augmented(Eigen::MatrixXd::Identity(n, n)); -// return root_->forward(values); +#else + return root_->forward(values); +#endif } const boost::shared_ptr >& root() const { diff --git a/gtsam_unstable/nonlinear/tests/testBADFactor.cpp b/gtsam_unstable/nonlinear/tests/testBADFactor.cpp index 7b9dcd765..4a5b1a76f 100644 --- a/gtsam_unstable/nonlinear/tests/testBADFactor.cpp +++ b/gtsam_unstable/nonlinear/tests/testBADFactor.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -29,141 +30,190 @@ using namespace std; using namespace gtsam; -/* ************************************************************************* */ +Point2 measured(-17, 30); +SharedNoiseModel model = noiseModel::Unit::Create(2); +/* ************************************************************************* */ +// Unary(Leaf)) TEST(BADFactor, test) { // Create some values Values values; - values.insert(1, Pose3()); values.insert(2, Point3(0, 0, 1)); - values.insert(3, Cal3_S2()); - // Create old-style factor to create expected value and derivatives - Point2 measured(-17, 30); - SharedNoiseModel model = noiseModel::Unit::Create(2); - GeneralSFMFactor2 old(measured, model, 1, 2, 3); - double expected_error = old.error(values); - GaussianFactor::shared_ptr expected = old.linearize(values); - - // Test Constant expression - Expression c(0); + JacobianFactor expected( // + 2, (Matrix(2, 3) << 1, 0, 0, 0, 1, 0), // + (Vector(2) << -17, 30)); // Create leaves - Pose3_ x(1); Point3_ p(2); - Cal3_S2_ K(3); - - // Create expression tree - Point3_ p_cam(x, &Pose3::transform_to, p); - Point2_ xy_hat(PinholeCamera::project_to_camera, p_cam); - Point2_ uv_hat(K, &Cal3_S2::uncalibrate, xy_hat); - - // Create factor and check value, dimension, linearization - BADFactor f(model, measured, uv_hat); - EXPECT_DOUBLES_EQUAL(expected_error, f.error(values), 1e-9); - EXPECT_LONGS_EQUAL(2, f.dim()); - boost::shared_ptr gf = f.linearize(values); - EXPECT( assert_equal(*expected, *gf, 1e-9)); // Try concise version - BADFactor f2(model, measured, - uncalibrate(K, project(transform_to(x, p)))); - EXPECT_DOUBLES_EQUAL(expected_error, f2.error(values), 1e-9); - EXPECT_LONGS_EQUAL(2, f2.dim()); - boost::shared_ptr gf2 = f2.linearize(values); - EXPECT( assert_equal(*expected, *gf2, 1e-9)); -} - -/* ************************************************************************* */ - -TEST(BADFactor, compose1) { - - // Create expression - Rot3_ R1(1), R2(2); - Rot3_ R3 = R1 * R2; - - // Create factor - BADFactor f(noiseModel::Unit::Create(3), Rot3(), R3); - - // Create some values - Values values; - values.insert(1, Rot3()); - values.insert(2, Rot3()); - - // Check unwhitenedError - std::vector H(2); - Vector actual = f.unwhitenedError(values, H); - EXPECT( assert_equal(eye(3), H[0],1e-9)); - EXPECT( assert_equal(eye(3), H[1],1e-9)); - - // Check linearization - JacobianFactor expected(1, eye(3), 2, eye(3), zero(3)); + BADFactor f(model, measured, project(p)); + EXPECT_LONGS_EQUAL(2, f.dim()); boost::shared_ptr gf = f.linearize(values); boost::shared_ptr jf = // boost::dynamic_pointer_cast(gf); - EXPECT( assert_equal(expected, *jf,1e-9)); + EXPECT( assert_equal(expected, *jf, 1e-9)); } /* ************************************************************************* */ -// Test compose with arguments referring to the same rotation -TEST(BADFactor, compose2) { + // Unary(Binary(Leaf,Leaf)) + TEST(BADFactor, test1) { - // Create expression - Rot3_ R1(1), R2(1); - Rot3_ R3 = R1 * R2; + // Create some values + Values values; + values.insert(1, Pose3()); + values.insert(2, Point3(0, 0, 1)); - // Create factor - BADFactor f(noiseModel::Unit::Create(3), Rot3(), R3); + // Create old-style factor to create expected value and derivatives + GenericProjectionFactor old(measured, model, 1, 2, + boost::make_shared()); + double expected_error = old.error(values); + GaussianFactor::shared_ptr expected = old.linearize(values); - // Create some values - Values values; - values.insert(1, Rot3()); + // Create leaves + Pose3_ x(1); + Point3_ p(2); - // Check unwhitenedError - std::vector H(1); - Vector actual = f.unwhitenedError(values, H); - EXPECT_LONGS_EQUAL(1, H.size()); - EXPECT( assert_equal(2*eye(3), H[0],1e-9)); + // Try concise version + BADFactor f2(model, measured, project(transform_to(x, p))); + EXPECT_DOUBLES_EQUAL(expected_error, f2.error(values), 1e-9); + EXPECT_LONGS_EQUAL(2, f2.dim()); + boost::shared_ptr gf2 = f2.linearize(values); + EXPECT( assert_equal(*expected, *gf2, 1e-9)); + } - // Check linearization - JacobianFactor expected(1, 2 * eye(3), zero(3)); - boost::shared_ptr gf = f.linearize(values); - boost::shared_ptr jf = // - boost::dynamic_pointer_cast(gf); - EXPECT( assert_equal(expected, *jf,1e-9)); -} + /* ************************************************************************* */ + // Binary(Leaf,Unary(Binary(Leaf,Leaf))) + TEST(BADFactor, test2) { -/* ************************************************************************* */ -// Test compose with one arguments referring to a constant same rotation -TEST(BADFactor, compose3) { + // Create some values + Values values; + values.insert(1, Pose3()); + values.insert(2, Point3(0, 0, 1)); + values.insert(3, Cal3_S2()); - // Create expression - Rot3_ R1(Rot3::identity()), R2(3); - Rot3_ R3 = R1 * R2; + // Create old-style factor to create expected value and derivatives + GeneralSFMFactor2 old(measured, model, 1, 2, 3); + double expected_error = old.error(values); + GaussianFactor::shared_ptr expected = old.linearize(values); - // Create factor - BADFactor f(noiseModel::Unit::Create(3), Rot3(), R3); + // Create leaves + Pose3_ x(1); + Point3_ p(2); + Cal3_S2_ K(3); - // Create some values - Values values; - values.insert(3, Rot3()); + // Create expression tree + Point3_ p_cam(x, &Pose3::transform_to, p); + Point2_ xy_hat(PinholeCamera::project_to_camera, p_cam); + Point2_ uv_hat(K, &Cal3_S2::uncalibrate, xy_hat); - // Check unwhitenedError - std::vector H(1); - Vector actual = f.unwhitenedError(values, H); - EXPECT_LONGS_EQUAL(1, H.size()); - EXPECT( assert_equal(eye(3), H[0],1e-9)); + // Create factor and check value, dimension, linearization + BADFactor f(model, measured, uv_hat); + EXPECT_DOUBLES_EQUAL(expected_error, f.error(values), 1e-9); + EXPECT_LONGS_EQUAL(2, f.dim()); + boost::shared_ptr gf = f.linearize(values); + EXPECT( assert_equal(*expected, *gf, 1e-9)); - // Check linearization - JacobianFactor expected(3, eye(3), zero(3)); - boost::shared_ptr gf = f.linearize(values); - boost::shared_ptr jf = // - boost::dynamic_pointer_cast(gf); - EXPECT( assert_equal(expected, *jf,1e-9)); -} + // Try concise version + BADFactor f2(model, measured, + uncalibrate(K, project(transform_to(x, p)))); + EXPECT_DOUBLES_EQUAL(expected_error, f2.error(values), 1e-9); + EXPECT_LONGS_EQUAL(2, f2.dim()); + boost::shared_ptr gf2 = f2.linearize(values); + EXPECT( assert_equal(*expected, *gf2, 1e-9)); + } -/* ************************************************************************* */ + /* ************************************************************************* */ + + TEST(BADFactor, compose1) { + + // Create expression + Rot3_ R1(1), R2(2); + Rot3_ R3 = R1 * R2; + + // Create factor + BADFactor f(noiseModel::Unit::Create(3), Rot3(), R3); + + // Create some values + Values values; + values.insert(1, Rot3()); + values.insert(2, Rot3()); + + // Check unwhitenedError + std::vector H(2); + Vector actual = f.unwhitenedError(values, H); + EXPECT( assert_equal(eye(3), H[0],1e-9)); + EXPECT( assert_equal(eye(3), H[1],1e-9)); + + // Check linearization + JacobianFactor expected(1, eye(3), 2, eye(3), zero(3)); + boost::shared_ptr gf = f.linearize(values); + boost::shared_ptr jf = // + boost::dynamic_pointer_cast(gf); + EXPECT( assert_equal(expected, *jf,1e-9)); + } + + /* ************************************************************************* */ + // Test compose with arguments referring to the same rotation + TEST(BADFactor, compose2) { + + // Create expression + Rot3_ R1(1), R2(1); + Rot3_ R3 = R1 * R2; + + // Create factor + BADFactor f(noiseModel::Unit::Create(3), Rot3(), R3); + + // Create some values + Values values; + values.insert(1, Rot3()); + + // Check unwhitenedError + std::vector H(1); + Vector actual = f.unwhitenedError(values, H); + EXPECT_LONGS_EQUAL(1, H.size()); + EXPECT( assert_equal(2*eye(3), H[0],1e-9)); + + // Check linearization + JacobianFactor expected(1, 2 * eye(3), zero(3)); + boost::shared_ptr gf = f.linearize(values); + boost::shared_ptr jf = // + boost::dynamic_pointer_cast(gf); + EXPECT( assert_equal(expected, *jf,1e-9)); + } + + /* ************************************************************************* */ + // Test compose with one arguments referring to a constant same rotation + TEST(BADFactor, compose3) { + + // Create expression + Rot3_ R1(Rot3::identity()), R2(3); + Rot3_ R3 = R1 * R2; + + // Create factor + BADFactor f(noiseModel::Unit::Create(3), Rot3(), R3); + + // Create some values + Values values; + values.insert(3, Rot3()); + + // Check unwhitenedError + std::vector H(1); + Vector actual = f.unwhitenedError(values, H); + EXPECT_LONGS_EQUAL(1, H.size()); + EXPECT( assert_equal(eye(3), H[0],1e-9)); + + // Check linearization + JacobianFactor expected(3, eye(3), zero(3)); + boost::shared_ptr gf = f.linearize(values); + boost::shared_ptr jf = // + boost::dynamic_pointer_cast(gf); + EXPECT( assert_equal(expected, *jf,1e-9)); + } + + /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); From 27186624673bce7ed63d8efb38a304b09e1215cf Mon Sep 17 00:00:00 2001 From: dellaert Date: Sun, 5 Oct 2014 15:01:36 +0200 Subject: [PATCH 7/9] Removed debug printing --- gtsam_unstable/nonlinear/Expression-inl.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/gtsam_unstable/nonlinear/Expression-inl.h b/gtsam_unstable/nonlinear/Expression-inl.h index f9187ec65..a282e8e84 100644 --- a/gtsam_unstable/nonlinear/Expression-inl.h +++ b/gtsam_unstable/nonlinear/Expression-inl.h @@ -21,7 +21,6 @@ #include #include -#include #include namespace gtsam { @@ -232,8 +231,6 @@ public: virtual boost::shared_ptr reverse(const Values& values) const { boost::shared_ptr trace = boost::make_shared(); trace->t = constant_; - std::cout << "constant\n:"; - GTSAM_PRINT(trace->t); return trace; } }; @@ -284,7 +281,6 @@ public: /// Return value and derivatives virtual Augmented augmented(const Matrix& H) const { // Base case: just insert H in the JacobianMap with correct key - std::cout << "Inserting Jacobian " << DefaultKeyFormatter(key) << "\n"; return Augmented(this->t, key, H); } }; @@ -294,8 +290,6 @@ public: boost::shared_ptr trace = boost::make_shared(); trace->t = value(values); trace->key = key_; - std::cout << "Leaf(" << DefaultKeyFormatter(key_) << "):\n"; - GTSAM_PRINT(trace->t); return trace; } @@ -367,10 +361,7 @@ public: virtual boost::shared_ptr reverse(const Values& values) const { boost::shared_ptr trace = boost::make_shared(); trace->trace1 = this->expressionA_->reverse(values); - std::cout << "Unary:\n"; - GTSAM_PRINT(trace->trace1->value()); trace->t = function_(trace->trace1->value(), trace->H1); - GTSAM_PRINT(trace->t); return trace; } }; @@ -458,12 +449,8 @@ public: boost::shared_ptr trace = boost::make_shared(); trace->trace1 = this->expressionA1_->reverse(values); trace->trace2 = this->expressionA2_->reverse(values); - std::cout << "Binary:\n"; - GTSAM_PRINT(trace->trace1->value()); - GTSAM_PRINT(trace->trace2->value()); trace->t = function_(trace->trace1->value(), trace->trace2->value(), trace->H1, trace->H2); - GTSAM_PRINT(trace->t); return trace; } From 001504a4321db438df63469a02cbc2841b42bed0 Mon Sep 17 00:00:00 2001 From: dellaert Date: Sun, 5 Oct 2014 17:12:38 +0200 Subject: [PATCH 8/9] JacobianTrace base, and avoid copying JacobianMaps. --- gtsam_unstable/nonlinear/Expression-inl.h | 123 ++++++++++++---------- gtsam_unstable/nonlinear/Expression.h | 6 +- 2 files changed, 72 insertions(+), 57 deletions(-) diff --git a/gtsam_unstable/nonlinear/Expression-inl.h b/gtsam_unstable/nonlinear/Expression-inl.h index a282e8e84..85e4be001 100644 --- a/gtsam_unstable/nonlinear/Expression-inl.h +++ b/gtsam_unstable/nonlinear/Expression-inl.h @@ -28,7 +28,16 @@ namespace gtsam { template class Expression; -typedef std::map JacobianMap; +class JacobianMap: public std::map { +public: + void add(Key key, const Matrix& H) { + iterator it = find(key); + if (it != end()) + it->second += H; + else + insert(std::make_pair(key, H)); + } +}; //----------------------------------------------------------------------------- /** @@ -46,24 +55,14 @@ private: /// Insert terms into jacobians_, premultiplying by H, adding if already exists void add(const JacobianMap& terms) { - BOOST_FOREACH(const Pair& term, terms) { - JacobianMap::iterator it = jacobians_.find(term.first); - if (it != jacobians_.end()) - it->second += term.second; - else - jacobians_[term.first] = term.second; - } + BOOST_FOREACH(const Pair& term, terms) + jacobians_.add(term.first, term.second); } /// Insert terms into jacobians_, premultiplying by H, adding if already exists void add(const Matrix& H, const JacobianMap& terms) { - BOOST_FOREACH(const Pair& term, terms) { - JacobianMap::iterator it = jacobians_.find(term.first); - if (it != jacobians_.end()) - it->second += H * term.second; - else - jacobians_[term.first] = H * term.second; - } + BOOST_FOREACH(const Pair& term, terms) + jacobians_.add(term.first, H * term.second); } public: @@ -122,6 +121,11 @@ public: return jacobians_; } + /// Return jacobians + JacobianMap& jacobians() { + return jacobians_; + } + /// Not dependent on any key bool constant() const { return jacobians_.empty(); @@ -136,6 +140,28 @@ public: } }; +//----------------------------------------------------------------------------- +template +struct JacobianTrace { + T t; + T value() const { + return t; + } + virtual void update(const Matrix& H, JacobianMap& jacobians) const = 0; + +// /// Insert terms into jacobians_, adding if already exists +// static void add(const JacobianMap& terms) { +// typedef std::pair Pair; +// BOOST_FOREACH(const Pair& term, terms) { +// JacobianMap::iterator it = jacobians_.find(term.first); +// if (it != jacobians_.end()) +// it->second += term.second; +// else +// jacobians_[term.first] = term.second; +// } +// } +}; + //----------------------------------------------------------------------------- /** * Expression node. The superclass for objects that do the heavy lifting @@ -153,14 +179,6 @@ protected: public: - struct Trace { - T t; - T value() const { - return t; - } - virtual Augmented augmented(const Matrix& H) const = 0; - }; - /// Destructor virtual ~ExpressionNode() { } @@ -175,9 +193,8 @@ public: virtual Augmented forward(const Values& values) const = 0; /// Construct an execution trace for reverse AD - virtual boost::shared_ptr reverse(const Values& values) const { - return boost::shared_ptr(); - } + virtual boost::shared_ptr > reverse( + const Values& values) const = 0; }; //----------------------------------------------------------------------------- @@ -218,17 +235,16 @@ public: } /// Trace structure for reverse AD - typedef typename ExpressionNode::Trace BaseTrace; - struct Trace: public BaseTrace { + struct Trace: public JacobianTrace { /// Return value and derivatives - virtual Augmented augmented(const Matrix& H) const { - // Base case: just return value and empty map - return Augmented(this->t); + virtual void update(const Matrix& H, JacobianMap& jacobians) const { + // Base case: don't touch jacobians } }; /// Construct an execution trace for reverse AD - virtual boost::shared_ptr reverse(const Values& values) const { + virtual boost::shared_ptr > reverse( + const Values& values) const { boost::shared_ptr trace = boost::make_shared(); trace->t = constant_; return trace; @@ -275,18 +291,18 @@ public: } /// Trace structure for reverse AD - typedef typename ExpressionNode::Trace BaseTrace; - struct Trace: public BaseTrace { + struct Trace: public JacobianTrace { Key key; /// Return value and derivatives - virtual Augmented augmented(const Matrix& H) const { - // Base case: just insert H in the JacobianMap with correct key - return Augmented(this->t, key, H); + virtual void update(const Matrix& H, JacobianMap& jacobians) const { + // Base case: just insert a new H in the JacobianMap with correct key + jacobians.add(key, H); } }; /// Construct an execution trace for reverse AD - virtual boost::shared_ptr reverse(const Values& values) const { + virtual boost::shared_ptr > reverse( + const Values& values) const { boost::shared_ptr trace = boost::make_shared(); trace->t = value(values); trace->key = key_; @@ -343,22 +359,21 @@ public: } /// Trace structure for reverse AD - typedef typename ExpressionNode::Trace BaseTrace; - struct Trace: public BaseTrace { - boost::shared_ptr::Trace> trace1; + struct Trace: public JacobianTrace { + boost::shared_ptr > trace1; Matrix H1; /// Return value and derivatives - virtual Augmented augmented(const Matrix& H) const { + virtual void update(const Matrix& H, JacobianMap& jacobians) const { // This is a top-down calculation // The end-result needs Jacobians to all leaf nodes. // Since this is not a leaf node, we compute what is needed for leaf nodes here - Augmented augmented1 = trace1->augmented(H * H1); - return Augmented(this->t, augmented1.jacobians()); + trace1->update(H * H1, jacobians); } }; /// Construct an execution trace for reverse AD - virtual boost::shared_ptr reverse(const Values& values) const { + virtual boost::shared_ptr > reverse( + const Values& values) const { boost::shared_ptr trace = boost::make_shared(); trace->trace1 = this->expressionA_->reverse(values); trace->t = function_(trace->trace1->value(), trace->H1); @@ -426,26 +441,24 @@ public: } /// Trace structure for reverse AD - typedef typename ExpressionNode::Trace BaseTrace; - struct Trace: public BaseTrace { - boost::shared_ptr::Trace> trace1; - boost::shared_ptr::Trace> trace2; + struct Trace: public JacobianTrace { + boost::shared_ptr > trace1; + boost::shared_ptr > trace2; Matrix H1, H2; /// Return value and derivatives - virtual Augmented augmented(const Matrix& H) const { + virtual void update(const Matrix& H, JacobianMap& jacobians) const { // This is a top-down calculation // The end-result needs Jacobians to all leaf nodes. // Since this is not a leaf node, we compute what is needed for leaf nodes here // The binary node represents a fork in the tree, and hence we will get two Augmented maps - Augmented augmented1 = trace1->augmented(H * H1); - Augmented augmented2 = trace2->augmented(H * H2); - return Augmented(this->t, augmented1.jacobians(), - augmented2.jacobians()); + trace1->update(H * H1, jacobians); + trace2->update(H * H2, jacobians); } }; /// Construct an execution trace for reverse AD - virtual boost::shared_ptr reverse(const Values& values) const { + virtual boost::shared_ptr > reverse( + const Values& values) const { boost::shared_ptr trace = boost::make_shared(); trace->trace1 = this->expressionA1_->reverse(values); trace->trace2 = this->expressionA2_->reverse(values); diff --git a/gtsam_unstable/nonlinear/Expression.h b/gtsam_unstable/nonlinear/Expression.h index 64b1013fe..709070d9b 100644 --- a/gtsam_unstable/nonlinear/Expression.h +++ b/gtsam_unstable/nonlinear/Expression.h @@ -105,9 +105,11 @@ public: Augmented augmented(const Values& values) const { #define REVERSE_AD #ifdef REVERSE_AD - boost::shared_ptr::Trace> trace = root_->reverse(values); + boost::shared_ptr > trace = root_->reverse(values); + Augmented augmented(trace->value()); size_t n = T::Dim(); - return trace->augmented(Eigen::MatrixXd::Identity(n, n)); + trace->update(Eigen::MatrixXd::Identity(n, n), augmented.jacobians()); + return augmented; #else return root_->forward(values); #endif From caf742d5e12ff04bd0b4ccc7eb42e5073cd0b8d6 Mon Sep 17 00:00:00 2001 From: dellaert Date: Sun, 5 Oct 2014 17:20:55 +0200 Subject: [PATCH 9/9] Better names --- gtsam_unstable/nonlinear/Expression-inl.h | 32 +++++++++++------------ gtsam_unstable/nonlinear/Expression.h | 4 +-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/gtsam_unstable/nonlinear/Expression-inl.h b/gtsam_unstable/nonlinear/Expression-inl.h index 85e4be001..669f1369d 100644 --- a/gtsam_unstable/nonlinear/Expression-inl.h +++ b/gtsam_unstable/nonlinear/Expression-inl.h @@ -147,7 +147,7 @@ struct JacobianTrace { T value() const { return t; } - virtual void update(const Matrix& H, JacobianMap& jacobians) const = 0; + virtual void reverseAD(const Matrix& H, JacobianMap& jacobians) const = 0; // /// Insert terms into jacobians_, adding if already exists // static void add(const JacobianMap& terms) { @@ -193,7 +193,7 @@ public: virtual Augmented forward(const Values& values) const = 0; /// Construct an execution trace for reverse AD - virtual boost::shared_ptr > reverse( + virtual boost::shared_ptr > traceExecution( const Values& values) const = 0; }; @@ -237,13 +237,13 @@ public: /// Trace structure for reverse AD struct Trace: public JacobianTrace { /// Return value and derivatives - virtual void update(const Matrix& H, JacobianMap& jacobians) const { + virtual void reverseAD(const Matrix& H, JacobianMap& jacobians) const { // Base case: don't touch jacobians } }; /// Construct an execution trace for reverse AD - virtual boost::shared_ptr > reverse( + virtual boost::shared_ptr > traceExecution( const Values& values) const { boost::shared_ptr trace = boost::make_shared(); trace->t = constant_; @@ -294,14 +294,14 @@ public: struct Trace: public JacobianTrace { Key key; /// Return value and derivatives - virtual void update(const Matrix& H, JacobianMap& jacobians) const { + virtual void reverseAD(const Matrix& H, JacobianMap& jacobians) const { // Base case: just insert a new H in the JacobianMap with correct key jacobians.add(key, H); } }; /// Construct an execution trace for reverse AD - virtual boost::shared_ptr > reverse( + virtual boost::shared_ptr > traceExecution( const Values& values) const { boost::shared_ptr trace = boost::make_shared(); trace->t = value(values); @@ -363,19 +363,19 @@ public: boost::shared_ptr > trace1; Matrix H1; /// Return value and derivatives - virtual void update(const Matrix& H, JacobianMap& jacobians) const { + virtual void reverseAD(const Matrix& H, JacobianMap& jacobians) const { // This is a top-down calculation // The end-result needs Jacobians to all leaf nodes. // Since this is not a leaf node, we compute what is needed for leaf nodes here - trace1->update(H * H1, jacobians); + trace1->reverseAD(H * H1, jacobians); } }; /// Construct an execution trace for reverse AD - virtual boost::shared_ptr > reverse( + virtual boost::shared_ptr > traceExecution( const Values& values) const { boost::shared_ptr trace = boost::make_shared(); - trace->trace1 = this->expressionA_->reverse(values); + trace->trace1 = this->expressionA_->traceExecution(values); trace->t = function_(trace->trace1->value(), trace->H1); return trace; } @@ -446,22 +446,22 @@ public: boost::shared_ptr > trace2; Matrix H1, H2; /// Return value and derivatives - virtual void update(const Matrix& H, JacobianMap& jacobians) const { + virtual void reverseAD(const Matrix& H, JacobianMap& jacobians) const { // This is a top-down calculation // The end-result needs Jacobians to all leaf nodes. // Since this is not a leaf node, we compute what is needed for leaf nodes here // The binary node represents a fork in the tree, and hence we will get two Augmented maps - trace1->update(H * H1, jacobians); - trace2->update(H * H2, jacobians); + trace1->reverseAD(H * H1, jacobians); + trace2->reverseAD(H * H2, jacobians); } }; /// Construct an execution trace for reverse AD - virtual boost::shared_ptr > reverse( + virtual boost::shared_ptr > traceExecution( const Values& values) const { boost::shared_ptr trace = boost::make_shared(); - trace->trace1 = this->expressionA1_->reverse(values); - trace->trace2 = this->expressionA2_->reverse(values); + trace->trace1 = this->expressionA1_->traceExecution(values); + trace->trace2 = this->expressionA2_->traceExecution(values); trace->t = function_(trace->trace1->value(), trace->trace2->value(), trace->H1, trace->H2); return trace; diff --git a/gtsam_unstable/nonlinear/Expression.h b/gtsam_unstable/nonlinear/Expression.h index 709070d9b..f3653abdf 100644 --- a/gtsam_unstable/nonlinear/Expression.h +++ b/gtsam_unstable/nonlinear/Expression.h @@ -105,10 +105,10 @@ public: Augmented augmented(const Values& values) const { #define REVERSE_AD #ifdef REVERSE_AD - boost::shared_ptr > trace = root_->reverse(values); + boost::shared_ptr > trace = root_->traceExecution(values); Augmented augmented(trace->value()); size_t n = T::Dim(); - trace->update(Eigen::MatrixXd::Identity(n, n), augmented.jacobians()); + trace->reverseAD(Eigen::MatrixXd::Identity(n, n), augmented.jacobians()); return augmented; #else return root_->forward(values);