Объединение библиотеки линейной алгебры с 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 * по умолчанию возвращает тот же "тип", что и входы - это проблема.

Другой вариант заключается в том, чтобы встроить собственную матрицу внутри величины, а не встраивать ее внутри матрицы.