cppad_eigen.hpp

View page source

Enable Use of Eigen Linear Algebra Package with CppAD

Syntax

# include <cppad/example/cppad_eigen.hpp>

Purpose

Enables the use of the eigen linear algebra package with the type AD < Base > ; see custom scalar types.

Example

The files eigen_array.cpp and eigen_det.cpp contain an example and test of this include file. They return true if they succeed and false otherwise.

CppAD Declarations

First declare some items that are defined by cppad.hpp:

namespace CppAD {
   // AD<Base>
   template <class Base> class AD;
   // numeric_limits<Float>
   template <class Float>  class numeric_limits;
}

std Declarations

Next declare some template specializations in std namespace:

namespace std {
   template <class Base> bool isinf(const CppAD::AD<Base> &x);
   template <class Base> bool isfinite(const CppAD::AD<Base> &x);
   template <class Base> bool isnan(const CppAD::AD<Base> &x);
}

Include Eigen/Core

Next define the eigen plugin and then include Eigen/Core:

# define EIGEN_MATRIXBASE_PLUGIN <cppad/example/eigen_plugin.hpp>
# include <Eigen/Core>

Eigen NumTraits

Eigen needs the following definitions, in the Eigen namespace, to work properly with AD < Base > scalars:

namespace Eigen {
   template <class Base> struct NumTraits< CppAD::AD<Base> >
   {  // type that corresponds to the real part of an AD<Base> value
      typedef CppAD::AD<Base>   Real;
      // type for AD<Base> operations that result in non-integer values
      typedef CppAD::AD<Base>   NonInteger;
      //  type to use for numeric literals such as "2" or "0.5".
      typedef CppAD::AD<Base>   Literal;
      // type for nested value inside an AD<Base> expression tree
      typedef CppAD::AD<Base>   Nested;

      enum {
         // does not support complex Base types
         IsComplex             = 0 ,
         // does not support integer Base types
         IsInteger             = 0 ,
         // only support signed Base types
         IsSigned              = 1 ,
         // must initialize an AD<Base> object
         RequireInitialization = 1 ,
         // computational cost of the corresponding operations
         ReadCost              = 1 ,
         AddCost               = 2 ,
         MulCost               = 2
      };

      // machine epsilon with type of real part of x
      // (use assumption that Base is not complex)
      static CppAD::AD<Base> epsilon(void)
      {  return CppAD::numeric_limits< CppAD::AD<Base> >::epsilon(); }

      // relaxed version of machine epsilon for comparison of different
      // operations that should result in the same value
      static CppAD::AD<Base> dummy_precision(void)
      {  return 100. *
            CppAD::numeric_limits< CppAD::AD<Base> >::epsilon();
      }

      // minimum normalized positive value
      static CppAD::AD<Base> lowest(void)
      {  return CppAD::numeric_limits< CppAD::AD<Base> >::min(); }

      // maximum finite value
      static CppAD::AD<Base> highest(void)
      {  return CppAD::numeric_limits< CppAD::AD<Base> >::max(); }

      // number of decimal digits that can be represented without change.
      static int digits10(void)
      {  return CppAD::numeric_limits< CppAD::AD<Base> >::digits10; }

      // number of decimal digits necessary to uniquely represent values.
      static int max_digits10(void)
      {  return CppAD::numeric_limits< CppAD::AD<Base> >::max_digits10; }

      // not a number
      static CppAD::AD<Base> quiet_NaN(void)
      {  return CppAD::numeric_limits< CppAD::AD<Base> >::quiet_NaN(); }

      // positive infinite value
      static CppAD::AD<Base> infinity(void)
      {  return CppAD::numeric_limits< CppAD::AD<Base> >::infinity(); }
   };
}

Eigen ScalarBinaryOpTraits

namespace Eigen {
   // Inform Eigen that a binary operations between Base and AD<Base>
   // are allowed and thate the return type is AD<Base>
   template<typename Base, typename BinOp>
   struct ScalarBinaryOpTraits<CppAD::AD<Base>, Base, BinOp>{
      typedef CppAD::AD<Base> ReturnType;
   };
   template<typename Base, typename BinOp>
   struct ScalarBinaryOpTraits<Base, CppAD::AD<Base>, BinOp>
   {
      typedef CppAD::AD<Base> ReturnType;
   };
}

CppAD Namespace

Eigen needs the following definitions, in the CppAD namespace, to work properly with AD < Base > scalars:

namespace CppAD {
      // functions that return references
      template <class Base> const AD<Base>& conj(const AD<Base>& x)
      {  return x; }
      template <class Base> const AD<Base>& real(const AD<Base>& x)
      {  return x; }

      // functions that return values (note abs is defined by cppad.hpp)
      template <class Base> AD<Base> imag(const AD<Base>& x)
      {  return CppAD::AD<Base>(0.); }
      template <class Base> AD<Base> abs2(const AD<Base>& x)
      {  return x * x; }
}

eigen_vector

The class CppAD::eigen_vector is a wrapper for Eigen column vectors so that they are simple vectors . To be specific, it converts Eigen::Index arguments and return values to size_t .

namespace CppAD {
   template <class Scalar>
   class eigen_vector : public Eigen::Matrix<Scalar, Eigen::Dynamic, 1> {
   private:
      // base_class
      typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> base_class;
   public:
      // constructor
      eigen_vector(size_t n) : base_class( Eigen::Index(n) )
      { }
      eigen_vector(void) : base_class()
      { }
      // operator[]
      Scalar& operator[](size_t i)
      {  return base_class::operator[]( Eigen::Index(i) ); }
      const Scalar& operator[](size_t i) const
      {  return base_class::operator[]( Eigen::Index(i) ); }
      // size
      size_t size(void) const
      {  return size_t( base_class::size() ); }
      // resize
      void resize(size_t n)
      {  base_class::resize( Eigen::Index(n) ); }
   };
}

Include cppad.hpp

# include <cppad/cppad.hpp>

std Definitions

The definitions below use cppad.hpp. Note that Value function can only be used with a constant parameter argument.

namespace std {
   template <class Base> bool isinf(const CppAD::AD<Base> &x)
   {  return isinf(CppAD::Value( CppAD::Var2Par(x) ) ); }

   template <class Base> bool isfinite(const CppAD::AD<Base> &x)
   {  return isfinite(CppAD::Value( CppAD::Var2Par(x) ) ); }

   template <class Base> bool isnan(const CppAD::AD<Base> &x)
   {  return isnan(CppAD::Value( CppAD::Var2Par(x) ) ); }
}