1061 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			1061 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | // 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::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 |