2008-08-24 23:15:32 +08:00
namespace Eigen {
2010-07-04 16:14:47 +08:00
/** \page TopicCustomizingEigen Customizing/Extending Eigen
2008-08-24 23:15:32 +08:00
2009-11-20 01:09:04 +08:00
Eigen can be extended in several ways, for instance, by defining global methods, \ref ExtendingMatrixBase "by adding custom methods to MatrixBase", adding support to \ref CustomScalarType "custom types" etc.
2008-08-24 23:15:32 +08:00
Big changes in Eigen documentation:
- Organize the documentation into "chapters".
- Each chapter include many documentation pages, reference pages organized as modules, and a quick reference page.
- The "Chapters" tree is created using the defgroup/ingroup mechanism, even for the documentation pages (i.e., .dox files for which I added an \eigenManualPage macro that we can switch between \page or \defgroup ).
- Add a "General topics" entry for all pages that do not fit well in the previous "chapters".
- The highlevel struture is managed by a new eigendoxy_layout.xml file.
- remove the "index" and quite useless pages (namespace list, class hierarchy, member list, file list, etc.)
- add the javascript search-engine.
- add the "treeview" panel.
- remove \tableofcontents (replace them by a custom \eigenAutoToc macro to be able to easily re-enable if needed).
- add javascript to automatically generate a TOC from the h1/h2 tags of the current page, and put the TOC in the left side panel.
- overload various javascript function generated by doxygen to:
- remove the root of the treeview
- remove links to section/subsection from the treeview
- automatically expand the "Chapters" section
- automatically expand the current section
- adjust the height of the treeview to take into account the TOC
- always use the default .css file, eigendoxy.css now only includes our modifications
- use Doxyfile to specify our logo
- remove cross references to unsupported modules (temporarily)
2013-01-05 23:37:11 +08:00
\eigenAutoToc
2008-08-24 23:15:32 +08:00
2011-02-14 06:50:57 +08:00
\section ExtendingMatrixBase Extending MatrixBase (and other classes)
2008-08-24 23:15:32 +08:00
In this section we will see how to add custom methods to MatrixBase. Since all expressions and matrix types inherit MatrixBase, adding a method to MatrixBase make it immediately available to all expressions ! A typical use case is, for instance, to make Eigen compatible with another API.
2010-04-29 20:04:42 +08:00
You certainly know that in C++ it is not possible to add methods to an existing class. So how that's possible ? Here the trick is to include in the declaration of MatrixBase a file defined by the preprocessor token \c EIGEN_MATRIXBASE_PLUGIN:
2008-08-24 23:15:32 +08:00
\code
class MatrixBase {
// ...
#ifdef EIGEN_MATRIXBASE_PLUGIN
#include EIGEN_MATRIXBASE_PLUGIN
#endif
};
\endcode
2011-02-14 06:50:57 +08:00
Therefore to extend MatrixBase with your own methods you just have to create a file with your method declaration and define EIGEN_MATRIXBASE_PLUGIN before you include any Eigen's header file.
2008-08-24 23:15:32 +08:00
2011-02-14 06:50:57 +08:00
You can extend many of the other classes used in Eigen by defining similarly named preprocessor symbols. For instance, define \c EIGEN_ARRAYBASE_PLUGIN if you want to extend the ArrayBase class. A full list of classes that can be extended in this way and the corresponding preprocessor symbols can be found on our page \ref TopicPreprocessorDirectives.
Here is an example of an extension file for adding methods to MatrixBase: \n
2008-08-24 23:15:32 +08:00
\b MatrixBaseAddons.h
\code
inline Scalar at(uint i, uint j) const { return this->operator()(i,j); }
inline Scalar& at(uint i, uint j) { return this->operator()(i,j); }
inline Scalar at(uint i) const { return this->operator[](i); }
inline Scalar& at(uint i) { return this->operator[](i); }
2008-11-04 03:14:17 +08:00
inline RealScalar squaredLength() const { return squaredNorm(); }
2008-08-24 23:15:32 +08:00
inline RealScalar length() const { return norm(); }
2008-11-04 03:14:17 +08:00
inline RealScalar invLength(void) const { return fast_inv_sqrt(squaredNorm()); }
2008-08-24 23:15:32 +08:00
template<typename OtherDerived>
inline Scalar squaredDistanceTo(const MatrixBase<OtherDerived>& other) const
2008-11-04 03:14:17 +08:00
{ return (derived() - other.derived()).squaredNorm(); }
2008-08-24 23:15:32 +08:00
template<typename OtherDerived>
inline RealScalar distanceTo(const MatrixBase<OtherDerived>& other) const
2010-10-25 22:15:22 +08:00
{ return internal::sqrt(derived().squaredDistanceTo(other)); }
2008-08-24 23:15:32 +08:00
inline void scaleTo(RealScalar l) { RealScalar vl = norm(); if (vl>1e-9) derived() *= (l/vl); }
2010-01-18 03:04:49 +08:00
inline Transpose<Derived> transposed() {return this->transpose();}
inline const Transpose<Derived> transposed() const {return this->transpose();}
2008-08-24 23:15:32 +08:00
2010-01-18 03:04:49 +08:00
inline uint minComponentId(void) const { int i; this->minCoeff(&i); return i; }
inline uint maxComponentId(void) const { int i; this->maxCoeff(&i); return i; }
2008-08-24 23:15:32 +08:00
template<typename OtherDerived>
2010-01-18 03:04:49 +08:00
void makeFloor(const MatrixBase<OtherDerived>& other) { derived() = derived().cwiseMin(other.derived()); }
2008-08-24 23:15:32 +08:00
template<typename OtherDerived>
2010-01-18 03:04:49 +08:00
void makeCeil(const MatrixBase<OtherDerived>& other) { derived() = derived().cwiseMax(other.derived()); }
2008-08-24 23:15:32 +08:00
2010-10-25 22:15:22 +08:00
const CwiseUnaryOp<internal::scalar_add_op<Scalar>, Derived>
2010-01-18 03:04:49 +08:00
operator+(const Scalar& scalar) const
2010-10-25 22:15:22 +08:00
{ return CwiseUnaryOp<internal::scalar_add_op<Scalar>, Derived>(derived(), internal::scalar_add_op<Scalar>(scalar)); }
2008-08-24 23:15:32 +08:00
2010-10-25 22:15:22 +08:00
friend const CwiseUnaryOp<internal::scalar_add_op<Scalar>, Derived>
2010-01-18 03:04:49 +08:00
operator+(const Scalar& scalar, const MatrixBase<Derived>& mat)
2010-10-25 22:15:22 +08:00
{ return CwiseUnaryOp<internal::scalar_add_op<Scalar>, Derived>(mat.derived(), internal::scalar_add_op<Scalar>(scalar)); }
2008-08-24 23:15:32 +08:00
\endcode
Then one can the following declaration in the config.h or whatever prerequisites header file of his project:
\code
#define EIGEN_MATRIXBASE_PLUGIN "MatrixBaseAddons.h"
\endcode
2009-02-09 06:36:28 +08:00
\section InheritingFromMatrix Inheriting from Matrix
2008-09-14 19:59:10 +08:00
2013-08-03 05:33:12 +08:00
Before inheriting from Matrix, be really, I mean REALLY, sure that using
2009-02-09 06:36:28 +08:00
EIGEN_MATRIX_PLUGIN is not what you really want (see previous section).
If you just need to add few members to Matrix, this is the way to go.
2013-08-03 05:33:12 +08:00
An example of when you actually need to inherit Matrix, is when you
have several layers of heritage such as
MyVerySpecificVector1, MyVerySpecificVector2 -> MyVector1 -> Matrix and
MyVerySpecificVector3, MyVerySpecificVector4 -> MyVector2 -> Matrix.
2009-02-09 06:36:28 +08:00
2012-07-05 20:36:02 +08:00
In order for your object to work within the %Eigen framework, you need to
2009-02-09 06:36:28 +08:00
define a few members in your inherited class.
2013-08-03 05:33:12 +08:00
Here is a minimalistic example:
\include CustomizingEigen_Inheritance.cpp
Output: \verbinclude CustomizingEigen_Inheritance.out
2009-02-09 06:36:28 +08:00
This is the kind of error you can get if you don't provide those methods
2013-08-03 05:33:12 +08:00
\verbatim
error: no match for ‘ operator=’ in ‘ v = Eigen::operator*(
const Eigen::MatrixBase<Eigen::Matrix<double, -0x000000001, 1, 0, -0x000000001, 1> >::Scalar&,
const Eigen::MatrixBase<Eigen::Matrix<double, -0x000000001, 1> >::StorageBaseType&)
(((const Eigen::MatrixBase<Eigen::Matrix<double, -0x000000001, 1> >::StorageBaseType&)
((const Eigen::MatrixBase<Eigen::Matrix<double, -0x000000001, 1> >::StorageBaseType*)(& v))))’
\endverbatim
2008-09-14 19:59:10 +08:00
2010-01-15 22:45:07 +08:00
\anchor user_defined_scalars \section CustomScalarType Using custom scalar types
2008-09-14 19:59:10 +08:00
2013-01-10 00:44:25 +08:00
By default, Eigen currently supports standard floating-point types (\c float, \c double, \c std::complex<float>, \c std::complex<double>, \c long \c double), as well as all native integer types (e.g., \c int, \c unsigned \c int, \c short, etc.), and \c bool.
2012-06-19 03:49:55 +08:00
On x86-64 systems, \c long \c double permits to locally enforces the use of x87 registers with extended accuracy (in comparison to SSE).
2008-09-14 19:59:10 +08:00
In order to add support for a custom type \c T you need:
2012-06-17 03:35:59 +08:00
-# make sure the common operator (+,-,*,/,etc.) are supported by the type \c T
-# add a specialization of struct Eigen::NumTraits<T> (see \ref NumTraits)
2012-06-19 03:49:55 +08:00
-# define the math functions that makes sense for your type. This includes standard ones like sqrt, pow, sin, tan, conj, real, imag, etc, as well as abs2 which is Eigen specific.
2008-09-14 19:59:10 +08:00
(see the file Eigen/src/Core/MathFunctions.h)
2013-01-10 00:44:25 +08:00
The math function should be defined in the same namespace than \c T, or in the \c std namespace though that second approach is not recommended.
2012-06-19 03:49:55 +08:00
2009-09-27 07:56:50 +08:00
Here is a concrete example adding support for the Adolc's \c adouble type. <a href="https://projects.coin-or.org/ADOL-C">Adolc</a> is an automatic differentiation library. The type \c adouble is basically a real value tracking the values of any number of partial derivatives.
2008-09-14 19:59:10 +08:00
\code
2012-06-17 03:35:59 +08:00
#ifndef ADOLCSUPPORT_H
#define ADOLCSUPPORT_H
2008-09-14 19:59:10 +08:00
#define ADOLC_TAPELESS
#include <adolc/adouble.h>
#include <Eigen/Core>
namespace Eigen {
template<> struct NumTraits<adtl::adouble>
2012-06-19 03:49:55 +08:00
: NumTraits<double> // permits to get the epsilon, dummy_precision, lowest, highest functions
2008-09-14 19:59:10 +08:00
{
typedef adtl::adouble Real;
2010-04-29 06:51:38 +08:00
typedef adtl::adouble NonInteger;
typedef adtl::adouble Nested;
2008-09-14 19:59:10 +08:00
enum {
IsComplex = 0,
2010-04-29 06:51:38 +08:00
IsInteger = 0,
2012-06-17 03:35:59 +08:00
IsSigned = 1,
RequireInitialization = 1,
2008-09-14 19:59:10 +08:00
ReadCost = 1,
2012-06-19 03:49:55 +08:00
AddCost = 3,
MulCost = 3
2008-09-14 19:59:10 +08:00
};
};
}
2012-06-19 03:49:55 +08:00
namespace adtl {
inline const adouble& conj(const adouble& x) { return x; }
inline const adouble& real(const adouble& x) { return x; }
inline adouble imag(const adouble&) { return 0.; }
inline adouble abs(const adouble& x) { return fabs(x); }
inline adouble abs2(const adouble& x) { return x*x; }
2008-09-14 19:59:10 +08:00
}
2012-06-17 03:35:59 +08:00
#endif // ADOLCSUPPORT_H
2008-09-14 19:59:10 +08:00
\endcode
2015-03-04 00:08:28 +08:00
This other example adds support for the \c mpq_class type from <a href="https://gmplib.org/">GMP</a>. It shows in particular how to change the way Eigen picks the best pivot during LU factorization. It selects the coefficient with the highest score, where the score is by default the absolute value of a number, but we can define a different score, for instance to prefer pivots with a more compact representation (this is an example, not a recommendation). Note that the scores should always be non-negative and only zero is allowed to have a score of zero. Also, this can interact badly with thresholds for inexact scalar types.
\code
#include <gmpxx.h>
#include <Eigen/Core>
#include <boost/operators.hpp>
namespace Eigen {
template<class> struct NumTraits;
template<> struct NumTraits<mpq_class>
{
typedef mpq_class Real;
typedef mpq_class NonInteger;
typedef mpq_class Nested;
static inline Real epsilon() { return 0; }
static inline Real dummy_precision() { return 0; }
enum {
IsInteger = 0,
IsSigned = 1,
IsComplex = 0,
RequireInitialization = 1,
ReadCost = 6,
AddCost = 150,
MulCost = 100
};
};
namespace internal {
template<>
struct significant_decimals_impl<mpq_class>
{
// Infinite precision when printing
static inline int run() { return 0; }
};
template<> struct scalar_score_coeff_op<mpq_class> {
struct result_type : boost::totally_ordered1<result_type> {
std::size_t len;
result_type(int i = 0) : len(i) {} // Eigen uses Score(0) and Score()
result_type(mpq_class const& q) :
len(mpz_size(q.get_num_mpz_t())+
mpz_size(q.get_den_mpz_t())-1) {}
friend bool operator<(result_type x, result_type y) {
// 0 is the worst possible pivot
if (x.len == 0) return y.len > 0;
if (y.len == 0) return false;
// Prefer a pivot with a small representation
return x.len > y.len;
}
friend bool operator==(result_type x, result_type y) {
// Only used to test if the score is 0
return x.len == y.len;
}
};
result_type operator()(mpq_class const& x) const { return x; }
};
}
}
\endcode
2008-09-14 19:59:10 +08:00
2010-12-27 23:07:07 +08:00
\sa \ref TopicPreprocessorDirectives
2008-08-24 23:15:32 +08:00
*/
}