198 lines
6.3 KiB
C++
198 lines
6.3 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
|
|
|
|
* -------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
* @file CallRecord.h
|
|
* @date November 21, 2014
|
|
* @author Frank Dellaert
|
|
* @author Paul Furgale
|
|
* @author Hannes Sommer
|
|
* @brief Internals for Expression.h, not for general consumption
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <gtsam/base/VerticalBlockMatrix.h>
|
|
#include <gtsam/base/FastVector.h>
|
|
#include <gtsam/base/Matrix.h>
|
|
|
|
#include <boost/mpl/transform.hpp>
|
|
|
|
namespace gtsam {
|
|
|
|
class JacobianMap;
|
|
// forward declaration
|
|
|
|
//-----------------------------------------------------------------------------
|
|
namespace internal {
|
|
|
|
/**
|
|
* ConvertToDynamicIf converts to a dense matrix with dynamic rows iff
|
|
* ConvertToDynamicRows (colums stay as they are) otherwise
|
|
* it just passes dense Eigen matrices through.
|
|
*/
|
|
template<bool ConvertToDynamicRows>
|
|
struct ConvertToVirtualFunctionSupportedMatrixType {
|
|
template<typename Derived>
|
|
static Eigen::Matrix<double, Eigen::Dynamic, Derived::ColsAtCompileTime> convert(
|
|
const Eigen::MatrixBase<Derived> & x) {
|
|
return x;
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct ConvertToVirtualFunctionSupportedMatrixType<false> {
|
|
template<typename Derived>
|
|
static const Eigen::Matrix<double, Derived::RowsAtCompileTime,
|
|
Derived::ColsAtCompileTime> convert(
|
|
const Eigen::MatrixBase<Derived> & x) {
|
|
return x;
|
|
}
|
|
// special treatment of matrices that don't need conversion
|
|
template<int Rows, int Cols>
|
|
static const Eigen::Matrix<double, Rows, Cols> & convert(
|
|
const Eigen::Matrix<double, Rows, Cols> & x) {
|
|
return x;
|
|
}
|
|
};
|
|
|
|
} // namespace internal
|
|
|
|
/**
|
|
* The CallRecord is an abstract base class for the any class that stores
|
|
* the Jacobians of applying a function with respect to each of its arguments,
|
|
* as well as an execution trace for each of its arguments.
|
|
*/
|
|
template<int Cols>
|
|
struct CallRecord {
|
|
|
|
// Print entire record, recursively
|
|
inline void print(const std::string& indent) const {
|
|
_print(indent);
|
|
}
|
|
|
|
// Main entry point for the reverse AD process of a functional expression.
|
|
// Called *once* by the main AD entry point, ExecutionTrace::startReverseAD1
|
|
// This function then calls ExecutionTrace::reverseAD for every argument
|
|
// which will in turn call the reverseAD method below.
|
|
// This non-virtual function _startReverseAD3, implemented in derived
|
|
inline void startReverseAD2(JacobianMap& jacobians) const {
|
|
_startReverseAD3(jacobians);
|
|
}
|
|
|
|
// Dispatch the reverseAD2 calls issued by ExecutionTrace::reverseAD1
|
|
// Here we convert to dynamic if the
|
|
template<typename Derived>
|
|
inline void reverseAD2(const Eigen::MatrixBase<Derived> & dFdT,
|
|
JacobianMap& jacobians) const {
|
|
_reverseAD3(
|
|
internal::ConvertToVirtualFunctionSupportedMatrixType<
|
|
(Derived::RowsAtCompileTime > 5)>::convert(dFdT),
|
|
jacobians);
|
|
}
|
|
|
|
// This overload supports matrices with both rows and columns dynamically sized.
|
|
// The template version above would be slower by introducing an extra conversion
|
|
// to statically sized columns.
|
|
inline void reverseAD2(const Matrix & dFdT, JacobianMap& jacobians) const {
|
|
_reverseAD3(dFdT, jacobians);
|
|
}
|
|
|
|
virtual ~CallRecord() {
|
|
}
|
|
|
|
private:
|
|
|
|
virtual void _print(const std::string& indent) const = 0;
|
|
virtual void _startReverseAD3(JacobianMap& jacobians) const = 0;
|
|
|
|
virtual void _reverseAD3(const Matrix & dFdT,
|
|
JacobianMap& jacobians) const = 0;
|
|
|
|
virtual void _reverseAD3(
|
|
const Eigen::Matrix<double, Eigen::Dynamic, Cols> & dFdT,
|
|
JacobianMap& jacobians) const = 0;
|
|
|
|
virtual void _reverseAD3(const Eigen::Matrix<double, 1, Cols> & dFdT,
|
|
JacobianMap& jacobians) const = 0;
|
|
virtual void _reverseAD3(const Eigen::Matrix<double, 2, Cols> & dFdT,
|
|
JacobianMap& jacobians) const = 0;
|
|
virtual void _reverseAD3(const Eigen::Matrix<double, 3, Cols> & dFdT,
|
|
JacobianMap& jacobians) const = 0;
|
|
virtual void _reverseAD3(const Eigen::Matrix<double, 4, Cols> & dFdT,
|
|
JacobianMap& jacobians) const = 0;
|
|
virtual void _reverseAD3(const Eigen::Matrix<double, 5, Cols> & dFdT,
|
|
JacobianMap& jacobians) const = 0;
|
|
};
|
|
|
|
/**
|
|
* CallRecordMaxVirtualStaticRows tells which separate virtual reverseAD with specific
|
|
* static rows (1..CallRecordMaxVirtualStaticRows) methods are part of the CallRecord
|
|
* interface. It is used to keep the testCallRecord unit test in sync.
|
|
*/
|
|
const int CallRecordMaxVirtualStaticRows = 5;
|
|
|
|
namespace internal {
|
|
/**
|
|
* The CallRecordImplementor implements the CallRecord interface for a Derived class by
|
|
* delegating to its corresponding (templated) non-virtual methods.
|
|
*/
|
|
template<typename Derived, int Cols>
|
|
struct CallRecordImplementor: public CallRecord<Cols> {
|
|
private:
|
|
|
|
const Derived & derived() const {
|
|
return static_cast<const Derived&>(*this);
|
|
}
|
|
|
|
virtual void _print(const std::string& indent) const {
|
|
derived().print(indent);
|
|
}
|
|
|
|
virtual void _startReverseAD3(JacobianMap& jacobians) const {
|
|
derived().startReverseAD4(jacobians);
|
|
}
|
|
|
|
virtual void _reverseAD3(const Matrix & dFdT, JacobianMap& jacobians) const {
|
|
derived().reverseAD4(dFdT, jacobians);
|
|
}
|
|
|
|
virtual void _reverseAD3(
|
|
const Eigen::Matrix<double, Eigen::Dynamic, Cols> & dFdT,
|
|
JacobianMap& jacobians) const {
|
|
derived().reverseAD4(dFdT, jacobians);
|
|
}
|
|
virtual void _reverseAD3(const Eigen::Matrix<double, 1, Cols> & dFdT,
|
|
JacobianMap& jacobians) const {
|
|
derived().reverseAD4(dFdT, jacobians);
|
|
}
|
|
virtual void _reverseAD3(const Eigen::Matrix<double, 2, Cols> & dFdT,
|
|
JacobianMap& jacobians) const {
|
|
derived().reverseAD4(dFdT, jacobians);
|
|
}
|
|
virtual void _reverseAD3(const Eigen::Matrix<double, 3, Cols> & dFdT,
|
|
JacobianMap& jacobians) const {
|
|
derived().reverseAD4(dFdT, jacobians);
|
|
}
|
|
virtual void _reverseAD3(const Eigen::Matrix<double, 4, Cols> & dFdT,
|
|
JacobianMap& jacobians) const {
|
|
derived().reverseAD4(dFdT, jacobians);
|
|
}
|
|
virtual void _reverseAD3(const Eigen::Matrix<double, 5, Cols> & dFdT,
|
|
JacobianMap& jacobians) const {
|
|
derived().reverseAD4(dFdT, jacobians);
|
|
}
|
|
};
|
|
|
|
} // namespace internal
|
|
|
|
} // gtsam
|