/* ---------------------------------------------------------------------------- * 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 Expression.h * @date September 18, 2014 * @author Frank Dellaert * @author Paul Furgale * @brief Expressions for Block Automatic Differentiation */ #pragma once #include "Expression-inl.h" #include #include namespace gtsam { /** * Expression class that supports automatic differentiation */ template class Expression { private: // Paul's trick shared pointer, polymorphic root of entire expression tree boost::shared_ptr > root_; public: // Construct a constant expression Expression(const T& value) : root_(new ConstantExpression(value)) { } // Construct a leaf expression, with Key Expression(const Key& key) : root_(new LeafExpression(key)) { } // Construct a leaf expression, with Symbol Expression(const Symbol& symbol) : root_(new LeafExpression(symbol)) { } // Construct a leaf expression, creating Symbol Expression(unsigned char c, size_t j) : root_(new LeafExpression(Symbol(c, j))) { } /// Construct a nullary method expression template Expression(const Expression& expression, T (A::*method)(typename OptionalJacobian::type) const) : root_(new UnaryExpression(boost::bind(method, _1, _2), expression)) { } /// Construct a unary function expression template Expression(typename UnaryExpression::Function function, const Expression& expression) : root_(new UnaryExpression(function, expression)) { } /// Construct a unary method expression template Expression(const Expression& expression1, T (A1::*method)(const A2&, typename OptionalJacobian::type, typename OptionalJacobian::type) const, const Expression& expression2) : root_( new BinaryExpression(boost::bind(method, _1, _2, _3, _4), expression1, expression2)) { } /// Construct a binary function expression template Expression(typename BinaryExpression::Function function, const Expression& expression1, const Expression& expression2) : root_( new BinaryExpression(function, expression1, expression2)) { } /// Construct a ternary function expression template Expression(typename TernaryExpression::Function function, const Expression& expression1, const Expression& expression2, const Expression& expression3) : root_( new TernaryExpression(function, expression1, expression2, expression3)) { } /// Return keys that play in this expression std::set keys() const { return root_->keys(); } /// Return dimensions for each argument, as a map void dims(std::map& map) const { root_->dims(map); } // Return size needed for memory buffer in traceExecution size_t traceSize() const { return root_->traceSize(); } /// trace execution, very unsafe, for testing purposes only //TODO this is not only used for testing, but in value() below! T traceExecution(const Values& values, ExecutionTrace& trace, char* raw) const { return root_->traceExecution(values, trace, raw); } /// Return value and derivatives, reverse AD version T value(const Values& values, JacobianMap& jacobians) const { // The following piece of code is absolutely crucial for performance. // We allocate a block of memory on the stack, which can be done at runtime // with modern C++ compilers. The traceExecution then fills this memory // with an execution trace, made up entirely of "Record" structs, see // the FunctionalNode class in expression-inl.h size_t size = traceSize(); char raw[size]; ExecutionTrace trace; T value(traceExecution(values, trace, raw)); trace.startReverseAD(jacobians); return value; } /// Return value T value(const Values& values) const { return root_->value(values); } const boost::shared_ptr >& root() const { return root_; } /// Define type so we can apply it as a meta-function typedef Expression type; }; // http://stackoverflow.com/questions/16260445/boost-bind-to-operator template struct apply_compose { typedef T result_type; static const int Dim = traits::dimension::value; typedef Eigen::Matrix Jacobian; T operator()(const T& x, const T& y, boost::optional H1, boost::optional H2) const { return x.compose(y, H1, H2); } }; /// Construct a product expression, assumes T::compose(T) -> T template Expression operator*(const Expression& expression1, const Expression& expression2) { return Expression(boost::bind(apply_compose(), _1, _2, _3, _4), expression1, expression2); } /// Construct an array of leaves template std::vector > createUnknowns(size_t n, char c, size_t start = 0) { std::vector > unknowns; unknowns.reserve(n); for (size_t i = start; i < start + n; i++) unknowns.push_back(Expression(c, i)); return unknowns; } }