/Src/Dependencies/Boost/boost/units/detail/linear_algebra.hpp
http://hadesmem.googlecode.com/ · C++ Header · 1060 lines · 806 code · 121 blank · 133 comment · 10 complexity · 2772f65b7179ddd485294897a54e6a99 MD5 · raw file
- // Boost.Units - A C++ library for zero-overhead dimensional analysis and
- // unit/quantity manipulation and conversion
- //
- // Copyright (C) 2003-2008 Matthias Christian Schabel
- // Copyright (C) 2008 Steven Watanabe
- //
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_UNITS_DETAIL_LINEAR_ALGEBRA_HPP
- #define BOOST_UNITS_DETAIL_LINEAR_ALGEBRA_HPP
- #include <boost/units/static_rational.hpp>
- #include <boost/mpl/next.hpp>
- #include <boost/mpl/arithmetic.hpp>
- #include <boost/mpl/and.hpp>
- #include <boost/mpl/assert.hpp>
- #include <boost/units/dim.hpp>
- #include <boost/units/dimensionless_type.hpp>
- #include <boost/units/static_rational.hpp>
- #include <boost/units/detail/dimension_list.hpp>
- #include <boost/units/detail/sort.hpp>
- namespace boost {
- namespace units {
- namespace detail {
- // typedef list<rational> equation;
- template<int N>
- struct eliminate_from_pair_of_equations_impl;
- template<class E1, class E2>
- struct eliminate_from_pair_of_equations;
- template<int N>
- struct elimination_impl;
- template<bool is_zero, bool element_is_last>
- struct elimination_skip_leading_zeros_impl;
- template<class Equation, class Vars>
- struct substitute;
- template<int N>
- struct substitute_impl;
- template<bool is_end>
- struct solve_impl;
- template<class T>
- struct solve;
- template<int N>
- struct check_extra_equations_impl;
- template<int N>
- struct normalize_units_impl;
- struct inconsistent {};
- // generally useful utilies.
- template<int N>
- struct divide_equation {
- template<class Begin, class Divisor>
- struct apply {
- typedef list<typename mpl::divides<typename Begin::item, Divisor>::type, typename divide_equation<N - 1>::template apply<typename Begin::next, Divisor>::type> type;
- };
- };
- template<>
- struct divide_equation<0> {
- template<class Begin, class Divisor>
- struct apply {
- typedef dimensionless_type type;
- };
- };
- // eliminate_from_pair_of_equations takes a pair of
- // equations and eliminates the first variable.
- //
- // equation eliminate_from_pair_of_equations(equation l1, equation l2) {
- // rational x1 = l1.front();
- // rational x2 = l2.front();
- // return(transform(pop_front(l1), pop_front(l2), _1 * x2 - _2 * x1));
- // }
- template<int N>
- struct eliminate_from_pair_of_equations_impl {
- template<class Begin1, class Begin2, class X1, class X2>
- struct apply {
- typedef list<
- typename mpl::minus<
- typename mpl::times<typename Begin1::item, X2>::type,
- typename mpl::times<typename Begin2::item, X1>::type
- >::type,
- typename eliminate_from_pair_of_equations_impl<N - 1>::template apply<
- typename Begin1::next,
- typename Begin2::next,
- X1,
- X2
- >::type
- > type;
- };
- };
- template<>
- struct eliminate_from_pair_of_equations_impl<0> {
- template<class Begin1, class Begin2, class X1, class X2>
- struct apply {
- typedef dimensionless_type type;
- };
- };
- template<class E1, class E2>
- struct eliminate_from_pair_of_equations {
- typedef E1 begin1;
- typedef E2 begin2;
- typedef typename eliminate_from_pair_of_equations_impl<(E1::size::value - 1)>::template apply<
- typename begin1::next,
- typename begin2::next,
- typename begin1::item,
- typename begin2::item
- >::type type;
- };
- // Stage 1. Determine which dimensions should
- // have dummy base units. For this purpose
- // row reduce the matrix.
- template<int N>
- struct make_zero_vector {
- typedef list<static_rational<0>, typename make_zero_vector<N - 1>::type> type;
- };
- template<>
- struct make_zero_vector<0> {
- typedef dimensionless_type type;
- };
- template<int Column, int TotalColumns>
- struct create_row_of_identity {
- typedef list<static_rational<0>, typename create_row_of_identity<Column - 1, TotalColumns - 1>::type> type;
- };
- template<int TotalColumns>
- struct create_row_of_identity<0, TotalColumns> {
- typedef list<static_rational<1>, typename make_zero_vector<TotalColumns - 1>::type> type;
- };
- template<int Column>
- struct create_row_of_identity<Column, 0> {
- // error
- };
- template<int RemainingRows>
- struct determine_extra_equations_impl;
- template<bool first_is_zero, bool is_last>
- struct determine_extra_equations_skip_zeros_impl;
- // not the last row and not zero.
- template<>
- struct determine_extra_equations_skip_zeros_impl<false, false> {
- template<class RowsBegin, int RemainingRows, int CurrentColumn, int TotalColumns, class Result>
- struct apply {
- // remove the equation being eliminated against from the set of equations.
- typedef typename determine_extra_equations_impl<RemainingRows - 1>::template apply<typename RowsBegin::next, typename RowsBegin::item>::type next_equations;
- // since this column was present, strip it out.
- typedef Result type;
- };
- };
- // the last row but not zero.
- template<>
- struct determine_extra_equations_skip_zeros_impl<false, true> {
- template<class RowsBegin, int RemainingRows, int CurrentColumn, int TotalColumns, class Result>
- struct apply {
- // remove this equation.
- typedef dimensionless_type next_equations;
- // since this column was present, strip it out.
- typedef Result type;
- };
- };
- // the first columns is zero but it is not the last column.
- // continue with the same loop.
- template<>
- struct determine_extra_equations_skip_zeros_impl<true, false> {
- template<class RowsBegin, int RemainingRows, int CurrentColumn, int TotalColumns, class Result>
- struct apply {
- typedef typename RowsBegin::next::item next_row;
- typedef typename determine_extra_equations_skip_zeros_impl<
- next_row::item::Numerator == 0,
- RemainingRows == 2 // the next one will be the last.
- >::template apply<
- typename RowsBegin::next,
- RemainingRows - 1,
- CurrentColumn,
- TotalColumns,
- Result
- > next;
- typedef list<typename RowsBegin::item::next, typename next::next_equations> next_equations;
- typedef typename next::type type;
- };
- };
- // all the elements in this column are zero.
- template<>
- struct determine_extra_equations_skip_zeros_impl<true, true> {
- template<class RowsBegin, int RemainingRows, int CurrentColumn, int TotalColumns, class Result>
- struct apply {
- typedef list<typename RowsBegin::item::next, dimensionless_type> next_equations;
- typedef list<typename create_row_of_identity<CurrentColumn, TotalColumns>::type, Result> type;
- };
- };
- template<int RemainingRows>
- struct determine_extra_equations_impl {
- template<class RowsBegin, class EliminateAgainst>
- struct apply {
- typedef list<
- typename eliminate_from_pair_of_equations<typename RowsBegin::item, EliminateAgainst>::type,
- typename determine_extra_equations_impl<RemainingRows-1>::template apply<typename RowsBegin::next, EliminateAgainst>::type
- > type;
- };
- };
- template<>
- struct determine_extra_equations_impl<0> {
- template<class RowsBegin, class EliminateAgainst>
- struct apply {
- typedef dimensionless_type type;
- };
- };
- template<int RemainingColumns, bool is_done>
- struct determine_extra_equations {
- template<class RowsBegin, int TotalColumns, class Result>
- struct apply {
- typedef typename RowsBegin::item top_row;
- typedef typename determine_extra_equations_skip_zeros_impl<
- top_row::item::Numerator == 0,
- RowsBegin::item::size::value == 1
- >::template apply<
- RowsBegin,
- RowsBegin::size::value,
- TotalColumns - RemainingColumns,
- TotalColumns,
- Result
- > column_info;
- typedef typename determine_extra_equations<
- RemainingColumns - 1,
- column_info::next_equations::size::value == 0
- >::template apply<
- typename column_info::next_equations,
- TotalColumns,
- typename column_info::type
- >::type type;
- };
- };
- template<int RemainingColumns>
- struct determine_extra_equations<RemainingColumns, true> {
- template<class RowsBegin, int TotalColumns, class Result>
- struct apply {
- typedef typename determine_extra_equations<RemainingColumns - 1, true>::template apply<
- RowsBegin,
- TotalColumns,
- list<typename create_row_of_identity<TotalColumns - RemainingColumns, TotalColumns>::type, Result>
- >::type type;
- };
- };
- template<>
- struct determine_extra_equations<0, true> {
- template<class RowsBegin, int TotalColumns, class Result>
- struct apply {
- typedef Result type;
- };
- };
- // Stage 2
- // invert the matrix using Gauss-Jordan elimination
- template<bool is_zero, bool is_last>
- struct invert_strip_leading_zeroes;
- template<int N>
- struct invert_handle_after_pivot_row;
- // When processing column N, none of the first N rows
- // can be the pivot column.
- template<int N>
- struct invert_handle_inital_rows {
- template<class RowsBegin, class IdentityBegin>
- struct apply {
- typedef typename invert_handle_inital_rows<N - 1>::template apply<
- typename RowsBegin::next,
- typename IdentityBegin::next
- > next;
- typedef typename RowsBegin::item current_row;
- typedef typename IdentityBegin::item current_identity_row;
- typedef typename next::pivot_row pivot_row;
- typedef typename next::identity_pivot_row identity_pivot_row;
- typedef list<
- typename eliminate_from_pair_of_equations_impl<(current_row::size::value) - 1>::template apply<
- typename current_row::next,
- pivot_row,
- typename current_row::item,
- static_rational<1>
- >::type,
- typename next::new_matrix
- > new_matrix;
- typedef list<
- typename eliminate_from_pair_of_equations_impl<(current_identity_row::size::value)>::template apply<
- current_identity_row,
- identity_pivot_row,
- typename current_row::item,
- static_rational<1>
- >::type,
- typename next::identity_result
- > identity_result;
- };
- };
- // This handles the switch to searching for a pivot column.
- // The pivot row will be propagated up in the typedefs
- // pivot_row and identity_pivot_row. It is inserted here.
- template<>
- struct invert_handle_inital_rows<0> {
- template<class RowsBegin, class IdentityBegin>
- struct apply {
- typedef typename RowsBegin::item current_row;
- typedef typename invert_strip_leading_zeroes<
- (current_row::item::Numerator == 0),
- (RowsBegin::size::value == 1)
- >::template apply<
- RowsBegin,
- IdentityBegin
- > next;
- // results
- typedef list<typename next::pivot_row, typename next::new_matrix> new_matrix;
- typedef list<typename next::identity_pivot_row, typename next::identity_result> identity_result;
- typedef typename next::pivot_row pivot_row;
- typedef typename next::identity_pivot_row identity_pivot_row;
- };
- };
- // The first internal element which is not zero.
- template<>
- struct invert_strip_leading_zeroes<false, false> {
- template<class RowsBegin, class IdentityBegin>
- struct apply {
- typedef typename RowsBegin::item current_row;
- typedef typename current_row::item current_value;
- typedef typename divide_equation<(current_row::size::value - 1)>::template apply<typename current_row::next, current_value>::type new_equation;
- typedef typename divide_equation<(IdentityBegin::item::size::value)>::template apply<typename IdentityBegin::item, current_value>::type transformed_identity_equation;
- typedef typename invert_handle_after_pivot_row<(RowsBegin::size::value - 1)>::template apply<
- typename RowsBegin::next,
- typename IdentityBegin::next,
- new_equation,
- transformed_identity_equation
- > next;
- // results
- // Note that we don't add the pivot row to the
- // results here, because it needs to propagated up
- // to the diagonal.
- typedef typename next::new_matrix new_matrix;
- typedef typename next::identity_result identity_result;
- typedef new_equation pivot_row;
- typedef transformed_identity_equation identity_pivot_row;
- };
- };
- // The one and only non-zero element--at the end
- template<>
- struct invert_strip_leading_zeroes<false, true> {
- template<class RowsBegin, class IdentityBegin>
- struct apply {
- typedef typename RowsBegin::item current_row;
- typedef typename current_row::item current_value;
- typedef typename divide_equation<(current_row::size::value - 1)>::template apply<typename current_row::next, current_value>::type new_equation;
- typedef typename divide_equation<(IdentityBegin::item::size::value)>::template apply<typename IdentityBegin::item, current_value>::type transformed_identity_equation;
- // results
- // Note that we don't add the pivot row to the
- // results here, because it needs to propagated up
- // to the diagonal.
- typedef dimensionless_type identity_result;
- typedef dimensionless_type new_matrix;
- typedef new_equation pivot_row;
- typedef transformed_identity_equation identity_pivot_row;
- };
- };
- // One of the initial zeroes
- template<>
- struct invert_strip_leading_zeroes<true, false> {
- template<class RowsBegin, class IdentityBegin>
- struct apply {
- typedef typename RowsBegin::item current_row;
- typedef typename RowsBegin::next::item next_row;
- typedef typename invert_strip_leading_zeroes<
- next_row::item::Numerator == 0,
- RowsBegin::size::value == 2
- >::template apply<
- typename RowsBegin::next,
- typename IdentityBegin::next
- > next;
- typedef typename IdentityBegin::item current_identity_row;
- // these are propagated up.
- typedef typename next::pivot_row pivot_row;
- typedef typename next::identity_pivot_row identity_pivot_row;
- typedef list<
- typename eliminate_from_pair_of_equations_impl<(current_row::size::value - 1)>::template apply<
- typename current_row::next,
- pivot_row,
- typename current_row::item,
- static_rational<1>
- >::type,
- typename next::new_matrix
- > new_matrix;
- typedef list<
- typename eliminate_from_pair_of_equations_impl<(current_identity_row::size::value)>::template apply<
- current_identity_row,
- identity_pivot_row,
- typename current_row::item,
- static_rational<1>
- >::type,
- typename next::identity_result
- > identity_result;
- };
- };
- // the last element, and is zero.
- // Should never happen.
- template<>
- struct invert_strip_leading_zeroes<true, true> {
- };
- template<int N>
- struct invert_handle_after_pivot_row {
- template<class RowsBegin, class IdentityBegin, class MatrixPivot, class IdentityPivot>
- struct apply {
- typedef typename invert_handle_after_pivot_row<N - 1>::template apply<
- typename RowsBegin::next,
- typename IdentityBegin::next,
- MatrixPivot,
- IdentityPivot
- > next;
- typedef typename RowsBegin::item current_row;
- typedef typename IdentityBegin::item current_identity_row;
- typedef MatrixPivot pivot_row;
- typedef IdentityPivot identity_pivot_row;
- // results
- typedef list<
- typename eliminate_from_pair_of_equations_impl<(current_row::size::value - 1)>::template apply<
- typename current_row::next,
- pivot_row,
- typename current_row::item,
- static_rational<1>
- >::type,
- typename next::new_matrix
- > new_matrix;
- typedef list<
- typename eliminate_from_pair_of_equations_impl<(current_identity_row::size::value)>::template apply<
- current_identity_row,
- identity_pivot_row,
- typename current_row::item,
- static_rational<1>
- >::type,
- typename next::identity_result
- > identity_result;
- };
- };
- template<>
- struct invert_handle_after_pivot_row<0> {
- template<class RowsBegin, class IdentityBegin, class MatrixPivot, class IdentityPivot>
- struct apply {
- typedef dimensionless_type new_matrix;
- typedef dimensionless_type identity_result;
- };
- };
- template<int N>
- struct invert_impl {
- template<class RowsBegin, class IdentityBegin>
- struct apply {
- typedef typename invert_handle_inital_rows<RowsBegin::size::value - N>::template apply<RowsBegin, IdentityBegin> process_column;
- typedef typename invert_impl<N - 1>::template apply<
- typename process_column::new_matrix,
- typename process_column::identity_result
- >::type type;
- };
- };
- template<>
- struct invert_impl<0> {
- template<class RowsBegin, class IdentityBegin>
- struct apply {
- typedef IdentityBegin type;
- };
- };
- template<int N>
- struct make_identity {
- template<int Size>
- struct apply {
- typedef list<typename create_row_of_identity<Size - N, Size>::type, typename make_identity<N - 1>::template apply<Size>::type> type;
- };
- };
- template<>
- struct make_identity<0> {
- template<int Size>
- struct apply {
- typedef dimensionless_type type;
- };
- };
- template<class Matrix>
- struct make_square_and_invert {
- typedef typename Matrix::item top_row;
- typedef typename determine_extra_equations<(top_row::size::value), false>::template apply<
- Matrix, // RowsBegin
- top_row::size::value, // TotalColumns
- Matrix // Result
- >::type invertible;
- typedef typename invert_impl<invertible::size::value>::template apply<
- invertible,
- typename make_identity<invertible::size::value>::template apply<invertible::size::value>::type
- >::type type;
- };
- // find_base_dimensions takes a list of
- // base_units and returns a sorted list
- // of all the base_dimensions they use.
- //
- // list<base_dimension> find_base_dimensions(list<base_unit> l) {
- // set<base_dimension> dimensions;
- // for_each(base_unit unit : l) {
- // for_each(dim d : unit.dimension_type) {
- // dimensions = insert(dimensions, d.tag_type);
- // }
- // }
- // return(sort(dimensions, _1 > _2, front_inserter(list<base_dimension>())));
- // }
- typedef char set_no;
- struct set_yes { set_no dummy[2]; };
- template<class T>
- struct wrap {};
- struct set_end {
- static set_no lookup(...);
- typedef mpl::long_<0> size;
- };
- template<class T, class Next>
- struct set : Next {
- using Next::lookup;
- static set_yes lookup(wrap<T>*);
- typedef T item;
- typedef Next next;
- typedef typename mpl::next<typename Next::size>::type size;
- };
- template<bool has_key>
- struct set_insert;
- template<>
- struct set_insert<true> {
- template<class Set, class T>
- struct apply {
- typedef Set type;
- };
- };
- template<>
- struct set_insert<false> {
- template<class Set, class T>
- struct apply {
- typedef set<T, Set> type;
- };
- };
- template<class Set, class T>
- struct has_key {
- static const long size = sizeof(Set::lookup((wrap<T>*)0));
- static const bool value = (size == sizeof(set_yes));
- };
- template<int N>
- struct find_base_dimensions_impl_impl {
- template<class Begin, class S>
- struct apply {
- typedef typename find_base_dimensions_impl_impl<N-1>::template apply<
- typename Begin::next,
- S
- >::type next;
- typedef typename set_insert<
- (has_key<next, typename Begin::item::tag_type>::value)
- >::template apply<
- next,
- typename Begin::item::tag_type
- >::type type;
- };
- };
- template<>
- struct find_base_dimensions_impl_impl<0> {
- template<class Begin, class S>
- struct apply {
- typedef S type;
- };
- };
- template<int N>
- struct find_base_dimensions_impl {
- template<class Begin>
- struct apply {
- typedef typename find_base_dimensions_impl_impl<(Begin::item::dimension_type::size::value)>::template apply<
- typename Begin::item::dimension_type,
- typename find_base_dimensions_impl<N-1>::template apply<typename Begin::next>::type
- >::type type;
- };
- };
- template<>
- struct find_base_dimensions_impl<0> {
- template<class Begin>
- struct apply {
- typedef set_end type;
- };
- };
- template<class T>
- struct find_base_dimensions {
- typedef typename insertion_sort<
- typename find_base_dimensions_impl<
- (T::size::value)
- >::template apply<T>::type
- >::type type;
- };
- // calculate_base_dimension_coefficients finds
- // the coefficients corresponding to the first
- // base_dimension in each of the dimension_lists.
- // It returns two values. The first result
- // is a list of the coefficients. The second
- // is a list with all the incremented iterators.
- // When we encounter a base_dimension that is
- // missing from a dimension_list, we do not
- // increment the iterator and we set the
- // coefficient to zero.
- template<bool has_dimension>
- struct calculate_base_dimension_coefficients_func;
- template<>
- struct calculate_base_dimension_coefficients_func<true> {
- template<class T>
- struct apply {
- typedef typename T::item::value_type type;
- typedef typename T::next next;
- };
- };
- template<>
- struct calculate_base_dimension_coefficients_func<false> {
- template<class T>
- struct apply {
- typedef static_rational<0> type;
- typedef T next;
- };
- };
- // begins_with_dimension returns true iff its first
- // parameter is a valid iterator which yields its
- // second parameter when dereferenced.
- template<class Iterator>
- struct begins_with_dimension {
- template<class Dim>
- struct apply :
- boost::is_same<
- Dim,
- typename Iterator::item::tag_type
- > {};
- };
- template<>
- struct begins_with_dimension<dimensionless_type> {
- template<class Dim>
- struct apply : mpl::false_ {};
- };
- template<int N>
- struct calculate_base_dimension_coefficients_impl {
- template<class BaseUnitDimensions,class Dim,class T>
- struct apply {
- typedef typename calculate_base_dimension_coefficients_func<
- begins_with_dimension<typename BaseUnitDimensions::item>::template apply<
- Dim
- >::value
- >::template apply<
- typename BaseUnitDimensions::item
- > result;
- typedef typename calculate_base_dimension_coefficients_impl<N-1>::template apply<
- typename BaseUnitDimensions::next,
- Dim,
- list<typename result::type, T>
- > next_;
- typedef typename next_::type type;
- typedef list<typename result::next, typename next_::next> next;
- };
- };
- template<>
- struct calculate_base_dimension_coefficients_impl<0> {
- template<class Begin, class BaseUnitDimensions, class T>
- struct apply {
- typedef T type;
- typedef dimensionless_type next;
- };
- };
- // add_zeroes pushs N zeroes onto the
- // front of a list.
- //
- // list<rational> add_zeroes(list<rational> l, int N) {
- // if(N == 0) {
- // return(l);
- // } else {
- // return(push_front(add_zeroes(l, N-1), 0));
- // }
- // }
- template<int N>
- struct add_zeroes_impl {
- // If you get an error here and your base units are
- // in fact linearly independent, please report it.
- BOOST_MPL_ASSERT_MSG((N > 0), base_units_are_probably_not_linearly_independent, (void));
- template<class T>
- struct apply {
- typedef list<
- static_rational<0>,
- typename add_zeroes_impl<N-1>::template apply<T>::type
- > type;
- };
- };
- template<>
- struct add_zeroes_impl<0> {
- template<class T>
- struct apply {
- typedef T type;
- };
- };
- // expand_dimensions finds the exponents of
- // a set of dimensions in a dimension_list.
- // the second parameter is assumed to be
- // a superset of the base_dimensions of
- // the first parameter.
- //
- // list<rational> expand_dimensions(dimension_list, list<base_dimension>);
- template<int N>
- struct expand_dimensions {
- template<class Begin, class DimensionIterator>
- struct apply {
- typedef typename calculate_base_dimension_coefficients_func<
- begins_with_dimension<DimensionIterator>::template apply<typename Begin::item>::value
- >::template apply<DimensionIterator> result;
- typedef list<
- typename result::type,
- typename expand_dimensions<N-1>::template apply<typename Begin::next, typename result::next>::type
- > type;
- };
- };
- template<>
- struct expand_dimensions<0> {
- template<class Begin, class DimensionIterator>
- struct apply {
- typedef dimensionless_type type;
- };
- };
- template<int N>
- struct create_unit_matrix {
- template<class Begin, class Dimensions>
- struct apply {
- typedef typename create_unit_matrix<N - 1>::template apply<typename Begin::next, Dimensions>::type next;
- typedef list<typename expand_dimensions<Dimensions::size::value>::template apply<Dimensions, typename Begin::item::dimension_type>::type, next> type;
- };
- };
- template<>
- struct create_unit_matrix<0> {
- template<class Begin, class Dimensions>
- struct apply {
- typedef dimensionless_type type;
- };
- };
- template<class T>
- struct normalize_units {
- typedef typename find_base_dimensions<T>::type dimensions;
- typedef typename create_unit_matrix<(T::size::value)>::template apply<
- T,
- dimensions
- >::type matrix;
- typedef typename make_square_and_invert<matrix>::type type;
- static const long extra = (type::size::value) - (T::size::value);
- };
- // multiply_add_units computes M x V
- // where M is a matrix and V is a horizontal
- // vector
- //
- // list<rational> multiply_add_units(list<list<rational> >, list<rational>);
- template<int N>
- struct multiply_add_units_impl {
- template<class Begin1, class Begin2 ,class X>
- struct apply {
- typedef list<
- typename mpl::plus<
- typename mpl::times<
- typename Begin2::item,
- X
- >::type,
- typename Begin1::item
- >::type,
- typename multiply_add_units_impl<N-1>::template apply<
- typename Begin1::next,
- typename Begin2::next,
- X
- >::type
- > type;
- };
- };
- template<>
- struct multiply_add_units_impl<0> {
- template<class Begin1, class Begin2 ,class X>
- struct apply {
- typedef dimensionless_type type;
- };
- };
- template<int N>
- struct multiply_add_units {
- template<class Begin1, class Begin2>
- struct apply {
- typedef typename multiply_add_units_impl<
- (Begin2::item::size::value)
- >::template apply<
- typename multiply_add_units<N-1>::template apply<
- typename Begin1::next,
- typename Begin2::next
- >::type,
- typename Begin2::item,
- typename Begin1::item
- >::type type;
- };
- };
- template<>
- struct multiply_add_units<1> {
- template<class Begin1, class Begin2>
- struct apply {
- typedef typename add_zeroes_impl<
- (Begin2::item::size::value)
- >::template apply<dimensionless_type>::type type1;
- typedef typename multiply_add_units_impl<
- (Begin2::item::size::value)
- >::template apply<
- type1,
- typename Begin2::item,
- typename Begin1::item
- >::type type;
- };
- };
- // strip_zeroes erases the first N elements of a list if
- // they are all zero, otherwise returns inconsistent
- //
- // list strip_zeroes(list l, int N) {
- // if(N == 0) {
- // return(l);
- // } else if(l.front == 0) {
- // return(strip_zeroes(pop_front(l), N-1));
- // } else {
- // return(inconsistent);
- // }
- // }
- template<int N>
- struct strip_zeroes_impl;
- template<class T>
- struct strip_zeroes_func {
- template<class L, int N>
- struct apply {
- typedef inconsistent type;
- };
- };
- template<>
- struct strip_zeroes_func<static_rational<0> > {
- template<class L, int N>
- struct apply {
- typedef typename strip_zeroes_impl<N-1>::template apply<typename L::next>::type type;
- };
- };
- template<int N>
- struct strip_zeroes_impl {
- template<class T>
- struct apply {
- typedef typename strip_zeroes_func<typename T::item>::template apply<T, N>::type type;
- };
- };
- template<>
- struct strip_zeroes_impl<0> {
- template<class T>
- struct apply {
- typedef T type;
- };
- };
- // Given a list of base_units, computes the
- // exponents of each base unit for a given
- // dimension.
- //
- // list<rational> calculate_base_unit_exponents(list<base_unit> units, dimension_list dimensions);
- template<class T>
- struct is_base_dimension_unit {
- typedef mpl::false_ type;
- typedef void base_dimension_type;
- };
- template<class T>
- struct is_base_dimension_unit<list<dim<T, static_rational<1> >, dimensionless_type> > {
- typedef mpl::true_ type;
- typedef T base_dimension_type;
- };
- template<int N>
- struct is_simple_system_impl {
- template<class Begin, class Prev>
- struct apply {
- typedef is_base_dimension_unit<typename Begin::item::dimension_type> test;
- typedef mpl::and_<
- typename test::type,
- mpl::less<Prev, typename test::base_dimension_type>,
- typename is_simple_system_impl<N-1>::template apply<
- typename Begin::next,
- typename test::base_dimension_type
- >
- > type;
- static const bool value = (type::value);
- };
- };
- template<>
- struct is_simple_system_impl<0> {
- template<class Begin, class Prev>
- struct apply : mpl::true_ {
- };
- };
- template<class T>
- struct is_simple_system {
- typedef T Begin;
- typedef is_base_dimension_unit<typename Begin::item::dimension_type> test;
- typedef typename mpl::and_<
- typename test::type,
- typename is_simple_system_impl<
- T::size::value - 1
- >::template apply<
- typename Begin::next::type,
- typename test::base_dimension_type
- >
- >::type type;
- static const bool value = type::value;
- };
- template<bool>
- struct calculate_base_unit_exponents_impl;
- template<>
- struct calculate_base_unit_exponents_impl<true> {
- template<class T, class Dimensions>
- struct apply {
- typedef typename expand_dimensions<(T::size::value)>::template apply<
- typename find_base_dimensions<T>::type,
- Dimensions
- >::type type;
- };
- };
- template<>
- struct calculate_base_unit_exponents_impl<false> {
- template<class T, class Dimensions>
- struct apply {
- // find the units that correspond to each base dimension
- typedef normalize_units<T> base_solutions;
- // pad the dimension with zeroes so it can just be a
- // list of numbers, making the multiplication easy
- // e.g. if the arguments are list<pound, foot> and
- // list<mass,time^-2> then this step will
- // yield list<0,1,-2>
- typedef typename expand_dimensions<(base_solutions::dimensions::size::value)>::template apply<
- typename base_solutions::dimensions,
- Dimensions
- >::type dimensions;
- // take the unit corresponding to each base unit
- // multiply each of its exponents by the exponent
- // of the base_dimension in the result and sum.
- typedef typename multiply_add_units<dimensions::size::value>::template apply<
- dimensions,
- typename base_solutions::type
- >::type units;
- // Now, verify that the dummy units really
- // cancel out and remove them.
- typedef typename strip_zeroes_impl<base_solutions::extra>::template apply<units>::type type;
- };
- };
- template<class T, class Dimensions>
- struct calculate_base_unit_exponents {
- typedef typename calculate_base_unit_exponents_impl<is_simple_system<T>::value>::template apply<T, Dimensions>::type type;
- };
- } // namespace detail
- } // namespace units
- } // namespace boost
- #endif