Использование пользовательских скалярных типов
По умолчанию, Eigen в настоящее время поддерживает стандартные типы с плавающей точкой (float, double, std::complex<float>, std::complex<double>, long double), а также все встроенные целочисленные типы (например, int, unsigned int, short, и т.д.), и bool. На системах x86-64, long double позволяет локально принудительно использовать регистры x87 с расширенной точностью (по сравнению с SSE).
Для добавления поддержки пользовательского типа T необходимо:
- убедиться, что базовые операторы (+,-,*,/, и т.д.) поддерживаются типом
T - добавить специализацию структуры Eigen::NumTraits<T> (см. NumTraits)
- определить математические функции, имеющие смысл для вашего типа. Это включает стандартные функции, такие как sqrt, pow, sin, tan, conj, real, imag и т.д., а также abs2, которая является специфической для Eigen. (см. файл Eigen/src/Core/MathFunctions.h)
Математические функции должны быть определены в том же пространстве имён, что и T, или в пространстве имён std, хотя второй подход не рекомендуется.
Вот конкретный пример добавления поддержки типа adouble из библиотеки Adolc. Adolc — это библиотека автоматического дифференцирования. Тип adouble представляет собой вещественное значение, отслеживающее значения любого количества частных производных.
#ifndef ADOLCSUPPORT_H #define ADOLCSUPPORT_H #define ADOLC_TAPELESS #include <adolc/adouble.h> #include <Eigen/Core> namespace Eigen { template<> struct NumTraits<adtl::adouble> : NumTraits<double> // permits to get the epsilon, dummy_precision, lowest, highest functions { typedef adtl::adouble Real; typedef adtl::adouble NonInteger; typedef adtl::adouble Nested; enum { IsComplex = 0, IsInteger = 0, IsSigned = 1, RequireInitialization = 1, ReadCost = 1, AddCost = 3, MulCost = 3 }; }; } 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; } } #endif // ADOLCSUPPORT_H
Этот другой пример добавляет поддержку типа mpq_class из GMP. Он демонстрирует, как можно изменить способ, которым Eigen выбирает лучший главный элемент при LU-разложении. Выбирается коэффициент с наивысшим значением оценки, где оценка по умолчанию — абсолютное значение числа, но мы можем определить другую оценку, например, для предпочтения главных элементов с более компактным представлением (это пример, а не рекомендация). Обратите внимание, что оценки должны быть всегда неотрицательными, и только нулю разрешается иметь оценку ноль. Кроме того, это может плохо взаимодействовать с порогами для неточных скалярных типов.
#include <gmpxx.h> #include <Eigen/Core> #include <boost/operators.hpp> namespace Eigen { template<> struct NumTraits<mpq_class> : GenericNumTraits<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; } static inline int digits10() { return 0; } enum { IsInteger = 0, IsSigned = 1, IsComplex = 0, RequireInitialization = 1, ReadCost = 6, AddCost = 150, MulCost = 100 }; }; namespace internal { 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; } }; } }
© Eigen.
Licensed under the MPL2 License.
https://eigen.tuxfamily.org/dox/TopicCustomizing_CustomScalar.html