Объединение библиотеки линейной алгебры с Boost:: Units
Я занимаюсь научным программированием и делаю очень хороший опыт как с Boost.Units, который обеспечивает анализ размеров во время компиляции для количеств (т.е. количество меток с единицами и, следовательно, ломает множество ошибок с классическим анализом физических измерений) и используя Eigen 2 для линейной алгебры.
Однако Eigen не имеет понятия единиц, и, хотя вы можете установить скалярные величины в матрицах для Eigen, он ожидает, что умножение двух величин даст один и тот же тип, что, очевидно, неверно для единиц. Например, код типа:
using boost::units::quantity;
namespace si = boost::units::si;
Eigen::Matrix< quantity< si::length >, 2, 1 > meter_vector;
quantity< si::area > norm = meter_vector.squaredNorm();
не работает, хотя и логически корректен.
Есть ли библиотека матриц, которая поддерживает единицы? Я знаю, что в прошлом это было бы трудно реализовать, и С++ 11 и decltype
сделают это намного проще, но это было возможно с помощью С++ 03 и специализированных шаблонов.
Ответы
Ответ 1
Я считаю, что Blitz ++ поддерживает большую часть функциональных возможностей Boost.Units.
Изменить с помощью OP. Для справки здесь приведен полный тестовый код, с которым я тестировал функциональность умножения матрицы Блица:
#include <blitz/array.h>
#include <boost/units/systems/si/area.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/quantity.hpp>
using boost::units::quantity;
namespace si = boost::units::si;
namespace blitz {
template< typename U1, typename T1, typename U2, typename T2>
struct Multiply< quantity<U1,T1>, quantity<U2,T2> >
{
typedef typename boost::units::multiply_typeof_helper< quantity<U1,T1>, quantity<U2,T2> >::type T_numtype;
static inline T_numtype apply( quantity<U1,T1> a, quantity<U2,T2> b ) { return a*b; }
};
}
using namespace blitz;
int main() {
Array< quantity<si::length>, 1 > matrix;
Array< quantity<si::area>, 1 > area;
area = matrix * matrix;
return 0;
}
Ответ 2
Вы должны проверить эту страницу Wiki:
http://eigen.tuxfamily.org/dox-devel/TopicCustomizingEigen.html
Eigen требует некоторой работы для использования, кроме примитивных типов данных, но это вообще возможно.
Ответ 3
Трудность использования стандартной опции плагина Eigen library заключается в том, что существующие операторы +, -, * и т.д. должны быть заменены для количества единиц усиления Boost, которые будут использоваться.
Например, для пользовательского типа блоков Boost для работы с оператором * multiply для произвольного CUSTOM_TYPE он должен выглядеть следующим образом:
template<class X,class Y>
CUSTOM_TYPE<typename boost::units::multiply_typeof_helper<X,Y>::type>
operator*(const CUSTOM_TYPE<X>& x,const CUSTOM_TYPE<Y>& y)
{
typedef typename boost::units::multiply_typeof_helper<X,Y>::type type;
return CUSTOM_TYPE<type>( ... );
}
Обратите внимание, как тип возврата не совпадает с типами ввода. Здесь вы создаете возвращаемый тип с помощью вспомогательного шаблона multiply_typeof_helper. Это связано с тем, что умножение счетчиков с секундами не даст вам количества единиц. Тем не менее, оператор Eigen * по умолчанию возвращает тот же "тип", что и входы - это проблема.
Другой вариант заключается в том, чтобы встроить собственную матрицу внутри величины, а не встраивать ее внутри матрицы.