]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/units/include/boost/units/detail/linear_algebra.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / units / include / boost / units / detail / linear_algebra.hpp
CommitLineData
7c673cae
FG
1// Boost.Units - A C++ library for zero-overhead dimensional analysis and
2// unit/quantity manipulation and conversion
3//
4// Copyright (C) 2003-2008 Matthias Christian Schabel
5// Copyright (C) 2008 Steven Watanabe
6//
7// Distributed under the Boost Software License, Version 1.0. (See
8// accompanying file LICENSE_1_0.txt or copy at
9// http://www.boost.org/LICENSE_1_0.txt)
10
11#ifndef BOOST_UNITS_DETAIL_LINEAR_ALGEBRA_HPP
12#define BOOST_UNITS_DETAIL_LINEAR_ALGEBRA_HPP
13
14#include <boost/units/static_rational.hpp>
15#include <boost/mpl/next.hpp>
16#include <boost/mpl/arithmetic.hpp>
17#include <boost/mpl/and.hpp>
18#include <boost/mpl/assert.hpp>
19
20#include <boost/units/dim.hpp>
21#include <boost/units/dimensionless_type.hpp>
22#include <boost/units/static_rational.hpp>
23#include <boost/units/detail/dimension_list.hpp>
24#include <boost/units/detail/sort.hpp>
25
26namespace boost {
27
28namespace units {
29
30namespace detail {
31
32// typedef list<rational> equation;
33
34template<int N>
35struct eliminate_from_pair_of_equations_impl;
36
37template<class E1, class E2>
38struct eliminate_from_pair_of_equations;
39
40template<int N>
41struct elimination_impl;
42
43template<bool is_zero, bool element_is_last>
44struct elimination_skip_leading_zeros_impl;
45
46template<class Equation, class Vars>
47struct substitute;
48
49template<int N>
50struct substitute_impl;
51
52template<bool is_end>
53struct solve_impl;
54
55template<class T>
56struct solve;
57
58template<int N>
59struct check_extra_equations_impl;
60
61template<int N>
62struct normalize_units_impl;
63
64struct inconsistent {};
65
66// generally useful utilies.
67
68template<int N>
69struct divide_equation {
70 template<class Begin, class Divisor>
71 struct apply {
72 typedef list<typename mpl::divides<typename Begin::item, Divisor>::type, typename divide_equation<N - 1>::template apply<typename Begin::next, Divisor>::type> type;
73 };
74};
75
76template<>
77struct divide_equation<0> {
78 template<class Begin, class Divisor>
79 struct apply {
80 typedef dimensionless_type type;
81 };
82};
83
84// eliminate_from_pair_of_equations takes a pair of
85// equations and eliminates the first variable.
86//
87// equation eliminate_from_pair_of_equations(equation l1, equation l2) {
88// rational x1 = l1.front();
89// rational x2 = l2.front();
90// return(transform(pop_front(l1), pop_front(l2), _1 * x2 - _2 * x1));
91// }
92
93template<int N>
94struct eliminate_from_pair_of_equations_impl {
95 template<class Begin1, class Begin2, class X1, class X2>
96 struct apply {
97 typedef list<
98 typename mpl::minus<
99 typename mpl::times<typename Begin1::item, X2>::type,
100 typename mpl::times<typename Begin2::item, X1>::type
101 >::type,
102 typename eliminate_from_pair_of_equations_impl<N - 1>::template apply<
103 typename Begin1::next,
104 typename Begin2::next,
105 X1,
106 X2
107 >::type
108 > type;
109 };
110};
111
112template<>
113struct eliminate_from_pair_of_equations_impl<0> {
114 template<class Begin1, class Begin2, class X1, class X2>
115 struct apply {
116 typedef dimensionless_type type;
117 };
118};
119
120template<class E1, class E2>
121struct eliminate_from_pair_of_equations {
122 typedef E1 begin1;
123 typedef E2 begin2;
124 typedef typename eliminate_from_pair_of_equations_impl<(E1::size::value - 1)>::template apply<
125 typename begin1::next,
126 typename begin2::next,
127 typename begin1::item,
128 typename begin2::item
129 >::type type;
130};
131
132
133
134// Stage 1. Determine which dimensions should
135// have dummy base units. For this purpose
136// row reduce the matrix.
137
138template<int N>
139struct make_zero_vector {
140 typedef list<static_rational<0>, typename make_zero_vector<N - 1>::type> type;
141};
142template<>
143struct make_zero_vector<0> {
144 typedef dimensionless_type type;
145};
146
147template<int Column, int TotalColumns>
148struct create_row_of_identity {
149 typedef list<static_rational<0>, typename create_row_of_identity<Column - 1, TotalColumns - 1>::type> type;
150};
151template<int TotalColumns>
152struct create_row_of_identity<0, TotalColumns> {
153 typedef list<static_rational<1>, typename make_zero_vector<TotalColumns - 1>::type> type;
154};
155template<int Column>
156struct create_row_of_identity<Column, 0> {
157 // error
158};
159
160template<int RemainingRows>
161struct determine_extra_equations_impl;
162
163template<bool first_is_zero, bool is_last>
164struct determine_extra_equations_skip_zeros_impl;
165
166// not the last row and not zero.
167template<>
168struct determine_extra_equations_skip_zeros_impl<false, false> {
169 template<class RowsBegin, int RemainingRows, int CurrentColumn, int TotalColumns, class Result>
170 struct apply {
171 // remove the equation being eliminated against from the set of equations.
172 typedef typename determine_extra_equations_impl<RemainingRows - 1>::template apply<typename RowsBegin::next, typename RowsBegin::item>::type next_equations;
173 // since this column was present, strip it out.
174 typedef Result type;
175 };
176};
177
178// the last row but not zero.
179template<>
180struct determine_extra_equations_skip_zeros_impl<false, true> {
181 template<class RowsBegin, int RemainingRows, int CurrentColumn, int TotalColumns, class Result>
182 struct apply {
183 // remove this equation.
184 typedef dimensionless_type next_equations;
185 // since this column was present, strip it out.
186 typedef Result type;
187 };
188};
189
190
191// the first columns is zero but it is not the last column.
192// continue with the same loop.
193template<>
194struct determine_extra_equations_skip_zeros_impl<true, false> {
195 template<class RowsBegin, int RemainingRows, int CurrentColumn, int TotalColumns, class Result>
196 struct apply {
197 typedef typename RowsBegin::next::item next_row;
198 typedef typename determine_extra_equations_skip_zeros_impl<
199 next_row::item::Numerator == 0,
200 RemainingRows == 2 // the next one will be the last.
201 >::template apply<
202 typename RowsBegin::next,
203 RemainingRows - 1,
204 CurrentColumn,
205 TotalColumns,
206 Result
207 > next;
208 typedef list<typename RowsBegin::item::next, typename next::next_equations> next_equations;
209 typedef typename next::type type;
210 };
211};
212
213// all the elements in this column are zero.
214template<>
215struct determine_extra_equations_skip_zeros_impl<true, true> {
216 template<class RowsBegin, int RemainingRows, int CurrentColumn, int TotalColumns, class Result>
217 struct apply {
218 typedef list<typename RowsBegin::item::next, dimensionless_type> next_equations;
219 typedef list<typename create_row_of_identity<CurrentColumn, TotalColumns>::type, Result> type;
220 };
221};
222
223template<int RemainingRows>
224struct determine_extra_equations_impl {
225 template<class RowsBegin, class EliminateAgainst>
226 struct apply {
227 typedef list<
228 typename eliminate_from_pair_of_equations<typename RowsBegin::item, EliminateAgainst>::type,
229 typename determine_extra_equations_impl<RemainingRows-1>::template apply<typename RowsBegin::next, EliminateAgainst>::type
230 > type;
231 };
232};
233
234template<>
235struct determine_extra_equations_impl<0> {
236 template<class RowsBegin, class EliminateAgainst>
237 struct apply {
238 typedef dimensionless_type type;
239 };
240};
241
242template<int RemainingColumns, bool is_done>
243struct determine_extra_equations {
244 template<class RowsBegin, int TotalColumns, class Result>
245 struct apply {
246 typedef typename RowsBegin::item top_row;
247 typedef typename determine_extra_equations_skip_zeros_impl<
248 top_row::item::Numerator == 0,
249 RowsBegin::size::value == 1
250 >::template apply<
251 RowsBegin,
252 RowsBegin::size::value,
253 TotalColumns - RemainingColumns,
254 TotalColumns,
255 Result
256 > column_info;
257 typedef typename determine_extra_equations<
258 RemainingColumns - 1,
259 column_info::next_equations::size::value == 0
260 >::template apply<
261 typename column_info::next_equations,
262 TotalColumns,
263 typename column_info::type
264 >::type type;
265 };
266};
267
268template<int RemainingColumns>
269struct determine_extra_equations<RemainingColumns, true> {
270 template<class RowsBegin, int TotalColumns, class Result>
271 struct apply {
272 typedef typename determine_extra_equations<RemainingColumns - 1, true>::template apply<
273 RowsBegin,
274 TotalColumns,
275 list<typename create_row_of_identity<TotalColumns - RemainingColumns, TotalColumns>::type, Result>
276 >::type type;
277 };
278};
279
280template<>
281struct determine_extra_equations<0, true> {
282 template<class RowsBegin, int TotalColumns, class Result>
283 struct apply {
284 typedef Result type;
285 };
286};
287
288// Stage 2
289// invert the matrix using Gauss-Jordan elimination
290
291
292template<bool is_zero, bool is_last>
293struct invert_strip_leading_zeroes;
294
295template<int N>
296struct invert_handle_after_pivot_row;
297
298// When processing column N, none of the first N rows
299// can be the pivot column.
300template<int N>
301struct invert_handle_inital_rows {
302 template<class RowsBegin, class IdentityBegin>
303 struct apply {
304 typedef typename invert_handle_inital_rows<N - 1>::template apply<
305 typename RowsBegin::next,
306 typename IdentityBegin::next
307 > next;
308 typedef typename RowsBegin::item current_row;
309 typedef typename IdentityBegin::item current_identity_row;
310 typedef typename next::pivot_row pivot_row;
311 typedef typename next::identity_pivot_row identity_pivot_row;
312 typedef list<
313 typename eliminate_from_pair_of_equations_impl<(current_row::size::value) - 1>::template apply<
314 typename current_row::next,
315 pivot_row,
316 typename current_row::item,
317 static_rational<1>
318 >::type,
319 typename next::new_matrix
320 > new_matrix;
321 typedef list<
322 typename eliminate_from_pair_of_equations_impl<(current_identity_row::size::value)>::template apply<
323 current_identity_row,
324 identity_pivot_row,
325 typename current_row::item,
326 static_rational<1>
327 >::type,
328 typename next::identity_result
329 > identity_result;
330 };
331};
332
333// This handles the switch to searching for a pivot column.
334// The pivot row will be propagated up in the typedefs
335// pivot_row and identity_pivot_row. It is inserted here.
336template<>
337struct invert_handle_inital_rows<0> {
338 template<class RowsBegin, class IdentityBegin>
339 struct apply {
340 typedef typename RowsBegin::item current_row;
341 typedef typename invert_strip_leading_zeroes<
342 (current_row::item::Numerator == 0),
343 (RowsBegin::size::value == 1)
344 >::template apply<
345 RowsBegin,
346 IdentityBegin
347 > next;
348 // results
349 typedef list<typename next::pivot_row, typename next::new_matrix> new_matrix;
350 typedef list<typename next::identity_pivot_row, typename next::identity_result> identity_result;
351 typedef typename next::pivot_row pivot_row;
352 typedef typename next::identity_pivot_row identity_pivot_row;
353 };
354};
355
356// The first internal element which is not zero.
357template<>
358struct invert_strip_leading_zeroes<false, false> {
359 template<class RowsBegin, class IdentityBegin>
360 struct apply {
361 typedef typename RowsBegin::item current_row;
362 typedef typename current_row::item current_value;
363 typedef typename divide_equation<(current_row::size::value - 1)>::template apply<typename current_row::next, current_value>::type new_equation;
364 typedef typename divide_equation<(IdentityBegin::item::size::value)>::template apply<typename IdentityBegin::item, current_value>::type transformed_identity_equation;
365 typedef typename invert_handle_after_pivot_row<(RowsBegin::size::value - 1)>::template apply<
366 typename RowsBegin::next,
367 typename IdentityBegin::next,
368 new_equation,
369 transformed_identity_equation
370 > next;
371
372 // results
373 // Note that we don't add the pivot row to the
374 // results here, because it needs to propagated up
375 // to the diagonal.
376 typedef typename next::new_matrix new_matrix;
377 typedef typename next::identity_result identity_result;
378 typedef new_equation pivot_row;
379 typedef transformed_identity_equation identity_pivot_row;
380 };
381};
382
383// The one and only non-zero element--at the end
384template<>
385struct invert_strip_leading_zeroes<false, true> {
386 template<class RowsBegin, class IdentityBegin>
387 struct apply {
388 typedef typename RowsBegin::item current_row;
389 typedef typename current_row::item current_value;
390 typedef typename divide_equation<(current_row::size::value - 1)>::template apply<typename current_row::next, current_value>::type new_equation;
391 typedef typename divide_equation<(IdentityBegin::item::size::value)>::template apply<typename IdentityBegin::item, current_value>::type transformed_identity_equation;
392
393 // results
394 // Note that we don't add the pivot row to the
395 // results here, because it needs to propagated up
396 // to the diagonal.
397 typedef dimensionless_type identity_result;
398 typedef dimensionless_type new_matrix;
399 typedef new_equation pivot_row;
400 typedef transformed_identity_equation identity_pivot_row;
401 };
402};
403
404// One of the initial zeroes
405template<>
406struct invert_strip_leading_zeroes<true, false> {
407 template<class RowsBegin, class IdentityBegin>
408 struct apply {
409 typedef typename RowsBegin::item current_row;
410 typedef typename RowsBegin::next::item next_row;
411 typedef typename invert_strip_leading_zeroes<
412 next_row::item::Numerator == 0,
413 RowsBegin::size::value == 2
414 >::template apply<
415 typename RowsBegin::next,
416 typename IdentityBegin::next
417 > next;
418 typedef typename IdentityBegin::item current_identity_row;
419 // these are propagated up.
420 typedef typename next::pivot_row pivot_row;
421 typedef typename next::identity_pivot_row identity_pivot_row;
422 typedef list<
423 typename eliminate_from_pair_of_equations_impl<(current_row::size::value - 1)>::template apply<
424 typename current_row::next,
425 pivot_row,
426 typename current_row::item,
427 static_rational<1>
428 >::type,
429 typename next::new_matrix
430 > new_matrix;
431 typedef list<
432 typename eliminate_from_pair_of_equations_impl<(current_identity_row::size::value)>::template apply<
433 current_identity_row,
434 identity_pivot_row,
435 typename current_row::item,
436 static_rational<1>
437 >::type,
438 typename next::identity_result
439 > identity_result;
440 };
441};
442
443// the last element, and is zero.
444// Should never happen.
445template<>
446struct invert_strip_leading_zeroes<true, true> {
447};
448
449template<int N>
450struct invert_handle_after_pivot_row {
451 template<class RowsBegin, class IdentityBegin, class MatrixPivot, class IdentityPivot>
452 struct apply {
453 typedef typename invert_handle_after_pivot_row<N - 1>::template apply<
454 typename RowsBegin::next,
455 typename IdentityBegin::next,
456 MatrixPivot,
457 IdentityPivot
458 > next;
459 typedef typename RowsBegin::item current_row;
460 typedef typename IdentityBegin::item current_identity_row;
461 typedef MatrixPivot pivot_row;
462 typedef IdentityPivot identity_pivot_row;
463
464 // results
465 typedef list<
466 typename eliminate_from_pair_of_equations_impl<(current_row::size::value - 1)>::template apply<
467 typename current_row::next,
468 pivot_row,
469 typename current_row::item,
470 static_rational<1>
471 >::type,
472 typename next::new_matrix
473 > new_matrix;
474 typedef list<
475 typename eliminate_from_pair_of_equations_impl<(current_identity_row::size::value)>::template apply<
476 current_identity_row,
477 identity_pivot_row,
478 typename current_row::item,
479 static_rational<1>
480 >::type,
481 typename next::identity_result
482 > identity_result;
483 };
484};
485
486template<>
487struct invert_handle_after_pivot_row<0> {
488 template<class RowsBegin, class IdentityBegin, class MatrixPivot, class IdentityPivot>
489 struct apply {
490 typedef dimensionless_type new_matrix;
491 typedef dimensionless_type identity_result;
492 };
493};
494
495template<int N>
496struct invert_impl {
497 template<class RowsBegin, class IdentityBegin>
498 struct apply {
499 typedef typename invert_handle_inital_rows<RowsBegin::size::value - N>::template apply<RowsBegin, IdentityBegin> process_column;
500 typedef typename invert_impl<N - 1>::template apply<
501 typename process_column::new_matrix,
502 typename process_column::identity_result
503 >::type type;
504 };
505};
506
507template<>
508struct invert_impl<0> {
509 template<class RowsBegin, class IdentityBegin>
510 struct apply {
511 typedef IdentityBegin type;
512 };
513};
514
515template<int N>
516struct make_identity {
517 template<int Size>
518 struct apply {
519 typedef list<typename create_row_of_identity<Size - N, Size>::type, typename make_identity<N - 1>::template apply<Size>::type> type;
520 };
521};
522
523template<>
524struct make_identity<0> {
525 template<int Size>
526 struct apply {
527 typedef dimensionless_type type;
528 };
529};
530
531template<class Matrix>
532struct make_square_and_invert {
533 typedef typename Matrix::item top_row;
534 typedef typename determine_extra_equations<(top_row::size::value), false>::template apply<
535 Matrix, // RowsBegin
536 top_row::size::value, // TotalColumns
537 Matrix // Result
538 >::type invertible;
539 typedef typename invert_impl<invertible::size::value>::template apply<
540 invertible,
541 typename make_identity<invertible::size::value>::template apply<invertible::size::value>::type
542 >::type type;
543};
544
545
546// find_base_dimensions takes a list of
547// base_units and returns a sorted list
548// of all the base_dimensions they use.
549//
550// list<base_dimension> find_base_dimensions(list<base_unit> l) {
551// set<base_dimension> dimensions;
552// for_each(base_unit unit : l) {
553// for_each(dim d : unit.dimension_type) {
554// dimensions = insert(dimensions, d.tag_type);
555// }
556// }
557// return(sort(dimensions, _1 > _2, front_inserter(list<base_dimension>())));
558// }
559
560typedef char set_no;
561struct set_yes { set_no dummy[2]; };
562
563template<class T>
564struct wrap {};
565
566struct set_end {
567 static set_no lookup(...);
568 typedef mpl::long_<0> size;
569};
570
571template<class T, class Next>
572struct set : Next {
573 using Next::lookup;
574 static set_yes lookup(wrap<T>*);
575 typedef T item;
576 typedef Next next;
577 typedef typename mpl::next<typename Next::size>::type size;
578};
579
580template<bool has_key>
581struct set_insert;
582
583template<>
584struct set_insert<true> {
585 template<class Set, class T>
586 struct apply {
587 typedef Set type;
588 };
589};
590
591template<>
592struct set_insert<false> {
593 template<class Set, class T>
594 struct apply {
595 typedef set<T, Set> type;
596 };
597};
598
599template<class Set, class T>
600struct has_key {
601 static const long size = sizeof(Set::lookup((wrap<T>*)0));
602 static const bool value = (size == sizeof(set_yes));
603};
604
605template<int N>
606struct find_base_dimensions_impl_impl {
607 template<class Begin, class S>
608 struct apply {
609 typedef typename find_base_dimensions_impl_impl<N-1>::template apply<
610 typename Begin::next,
611 S
612 >::type next;
613
614 typedef typename set_insert<
615 (has_key<next, typename Begin::item::tag_type>::value)
616 >::template apply<
617 next,
618 typename Begin::item::tag_type
619 >::type type;
620 };
621};
622
623template<>
624struct find_base_dimensions_impl_impl<0> {
625 template<class Begin, class S>
626 struct apply {
627 typedef S type;
628 };
629};
630
631template<int N>
632struct find_base_dimensions_impl {
633 template<class Begin>
634 struct apply {
635 typedef typename find_base_dimensions_impl_impl<(Begin::item::dimension_type::size::value)>::template apply<
636 typename Begin::item::dimension_type,
637 typename find_base_dimensions_impl<N-1>::template apply<typename Begin::next>::type
638 >::type type;
639 };
640};
641
642template<>
643struct find_base_dimensions_impl<0> {
644 template<class Begin>
645 struct apply {
646 typedef set_end type;
647 };
648};
649
650template<class T>
651struct find_base_dimensions {
652 typedef typename insertion_sort<
653 typename find_base_dimensions_impl<
654 (T::size::value)
655 >::template apply<T>::type
656 >::type type;
657};
658
659// calculate_base_dimension_coefficients finds
660// the coefficients corresponding to the first
661// base_dimension in each of the dimension_lists.
662// It returns two values. The first result
663// is a list of the coefficients. The second
664// is a list with all the incremented iterators.
665// When we encounter a base_dimension that is
666// missing from a dimension_list, we do not
667// increment the iterator and we set the
668// coefficient to zero.
669
670template<bool has_dimension>
671struct calculate_base_dimension_coefficients_func;
672
673template<>
674struct calculate_base_dimension_coefficients_func<true> {
675 template<class T>
676 struct apply {
677 typedef typename T::item::value_type type;
678 typedef typename T::next next;
679 };
680};
681
682template<>
683struct calculate_base_dimension_coefficients_func<false> {
684 template<class T>
685 struct apply {
686 typedef static_rational<0> type;
687 typedef T next;
688 };
689};
690
691// begins_with_dimension returns true iff its first
692// parameter is a valid iterator which yields its
693// second parameter when dereferenced.
694
695template<class Iterator>
696struct begins_with_dimension {
697 template<class Dim>
698 struct apply :
699 boost::is_same<
700 Dim,
701 typename Iterator::item::tag_type
702 > {};
703};
704
705template<>
706struct begins_with_dimension<dimensionless_type> {
707 template<class Dim>
708 struct apply : mpl::false_ {};
709};
710
711template<int N>
712struct calculate_base_dimension_coefficients_impl {
713 template<class BaseUnitDimensions,class Dim,class T>
714 struct apply {
715 typedef typename calculate_base_dimension_coefficients_func<
716 begins_with_dimension<typename BaseUnitDimensions::item>::template apply<
717 Dim
718 >::value
719 >::template apply<
720 typename BaseUnitDimensions::item
721 > result;
722 typedef typename calculate_base_dimension_coefficients_impl<N-1>::template apply<
723 typename BaseUnitDimensions::next,
724 Dim,
725 list<typename result::type, T>
726 > next_;
727 typedef typename next_::type type;
728 typedef list<typename result::next, typename next_::next> next;
729 };
730};
731
732template<>
733struct calculate_base_dimension_coefficients_impl<0> {
734 template<class Begin, class BaseUnitDimensions, class T>
735 struct apply {
736 typedef T type;
737 typedef dimensionless_type next;
738 };
739};
740
741// add_zeroes pushs N zeroes onto the
742// front of a list.
743//
744// list<rational> add_zeroes(list<rational> l, int N) {
745// if(N == 0) {
746// return(l);
747// } else {
748// return(push_front(add_zeroes(l, N-1), 0));
749// }
750// }
751
752template<int N>
753struct add_zeroes_impl {
754 // If you get an error here and your base units are
755 // in fact linearly independent, please report it.
756 BOOST_MPL_ASSERT_MSG((N > 0), base_units_are_probably_not_linearly_independent, (void));
757 template<class T>
758 struct apply {
759 typedef list<
760 static_rational<0>,
761 typename add_zeroes_impl<N-1>::template apply<T>::type
762 > type;
763 };
764};
765
766template<>
767struct add_zeroes_impl<0> {
768 template<class T>
769 struct apply {
770 typedef T type;
771 };
772};
773
774// expand_dimensions finds the exponents of
775// a set of dimensions in a dimension_list.
776// the second parameter is assumed to be
777// a superset of the base_dimensions of
778// the first parameter.
779//
780// list<rational> expand_dimensions(dimension_list, list<base_dimension>);
781
782template<int N>
783struct expand_dimensions {
784 template<class Begin, class DimensionIterator>
785 struct apply {
786 typedef typename calculate_base_dimension_coefficients_func<
787 begins_with_dimension<DimensionIterator>::template apply<typename Begin::item>::value
788 >::template apply<DimensionIterator> result;
789 typedef list<
790 typename result::type,
791 typename expand_dimensions<N-1>::template apply<typename Begin::next, typename result::next>::type
792 > type;
793 };
794};
795
796template<>
797struct expand_dimensions<0> {
798 template<class Begin, class DimensionIterator>
799 struct apply {
800 typedef dimensionless_type type;
801 };
802};
803
804template<int N>
805struct create_unit_matrix {
806 template<class Begin, class Dimensions>
807 struct apply {
808 typedef typename create_unit_matrix<N - 1>::template apply<typename Begin::next, Dimensions>::type next;
809 typedef list<typename expand_dimensions<Dimensions::size::value>::template apply<Dimensions, typename Begin::item::dimension_type>::type, next> type;
810 };
811};
812
813template<>
814struct create_unit_matrix<0> {
815 template<class Begin, class Dimensions>
816 struct apply {
817 typedef dimensionless_type type;
818 };
819};
820
821template<class T>
822struct normalize_units {
823 typedef typename find_base_dimensions<T>::type dimensions;
824 typedef typename create_unit_matrix<(T::size::value)>::template apply<
825 T,
826 dimensions
827 >::type matrix;
828 typedef typename make_square_and_invert<matrix>::type type;
829 static const long extra = (type::size::value) - (T::size::value);
830};
831
832// multiply_add_units computes M x V
833// where M is a matrix and V is a horizontal
834// vector
835//
836// list<rational> multiply_add_units(list<list<rational> >, list<rational>);
837
838template<int N>
839struct multiply_add_units_impl {
840 template<class Begin1, class Begin2 ,class X>
841 struct apply {
842 typedef list<
843 typename mpl::plus<
844 typename mpl::times<
845 typename Begin2::item,
846 X
847 >::type,
848 typename Begin1::item
849 >::type,
850 typename multiply_add_units_impl<N-1>::template apply<
851 typename Begin1::next,
852 typename Begin2::next,
853 X
854 >::type
855 > type;
856 };
857};
858
859template<>
860struct multiply_add_units_impl<0> {
861 template<class Begin1, class Begin2 ,class X>
862 struct apply {
863 typedef dimensionless_type type;
864 };
865};
866
867template<int N>
868struct multiply_add_units {
869 template<class Begin1, class Begin2>
870 struct apply {
871 typedef typename multiply_add_units_impl<
872 (Begin2::item::size::value)
873 >::template apply<
874 typename multiply_add_units<N-1>::template apply<
875 typename Begin1::next,
876 typename Begin2::next
877 >::type,
878 typename Begin2::item,
879 typename Begin1::item
880 >::type type;
881 };
882};
883
884template<>
885struct multiply_add_units<1> {
886 template<class Begin1, class Begin2>
887 struct apply {
888 typedef typename add_zeroes_impl<
889 (Begin2::item::size::value)
890 >::template apply<dimensionless_type>::type type1;
891 typedef typename multiply_add_units_impl<
892 (Begin2::item::size::value)
893 >::template apply<
894 type1,
895 typename Begin2::item,
896 typename Begin1::item
897 >::type type;
898 };
899};
900
901
902// strip_zeroes erases the first N elements of a list if
903// they are all zero, otherwise returns inconsistent
904//
905// list strip_zeroes(list l, int N) {
906// if(N == 0) {
907// return(l);
908// } else if(l.front == 0) {
909// return(strip_zeroes(pop_front(l), N-1));
910// } else {
911// return(inconsistent);
912// }
913// }
914
915template<int N>
916struct strip_zeroes_impl;
917
918template<class T>
919struct strip_zeroes_func {
920 template<class L, int N>
921 struct apply {
922 typedef inconsistent type;
923 };
924};
925
926template<>
927struct strip_zeroes_func<static_rational<0> > {
928 template<class L, int N>
929 struct apply {
930 typedef typename strip_zeroes_impl<N-1>::template apply<typename L::next>::type type;
931 };
932};
933
934template<int N>
935struct strip_zeroes_impl {
936 template<class T>
937 struct apply {
938 typedef typename strip_zeroes_func<typename T::item>::template apply<T, N>::type type;
939 };
940};
941
942template<>
943struct strip_zeroes_impl<0> {
944 template<class T>
945 struct apply {
946 typedef T type;
947 };
948};
949
950// Given a list of base_units, computes the
951// exponents of each base unit for a given
952// dimension.
953//
954// list<rational> calculate_base_unit_exponents(list<base_unit> units, dimension_list dimensions);
955
956template<class T>
957struct is_base_dimension_unit {
958 typedef mpl::false_ type;
959 typedef void base_dimension_type;
960};
961template<class T>
962struct is_base_dimension_unit<list<dim<T, static_rational<1> >, dimensionless_type> > {
963 typedef mpl::true_ type;
964 typedef T base_dimension_type;
965};
966
967template<int N>
968struct is_simple_system_impl {
969 template<class Begin, class Prev>
970 struct apply {
971 typedef is_base_dimension_unit<typename Begin::item::dimension_type> test;
972 typedef mpl::and_<
973 typename test::type,
974 mpl::less<Prev, typename test::base_dimension_type>,
975 typename is_simple_system_impl<N-1>::template apply<
976 typename Begin::next,
977 typename test::base_dimension_type
978 >
979 > type;
980 static const bool value = (type::value);
981 };
982};
983
984template<>
985struct is_simple_system_impl<0> {
986 template<class Begin, class Prev>
987 struct apply : mpl::true_ {
988 };
989};
990
991template<class T>
992struct is_simple_system {
993 typedef T Begin;
994 typedef is_base_dimension_unit<typename Begin::item::dimension_type> test;
995 typedef typename mpl::and_<
996 typename test::type,
997 typename is_simple_system_impl<
998 T::size::value - 1
999 >::template apply<
1000 typename Begin::next::type,
1001 typename test::base_dimension_type
1002 >
1003 >::type type;
1004 static const bool value = type::value;
1005};
1006
1007template<bool>
1008struct calculate_base_unit_exponents_impl;
1009
1010template<>
1011struct calculate_base_unit_exponents_impl<true> {
1012 template<class T, class Dimensions>
1013 struct apply {
1014 typedef typename expand_dimensions<(T::size::value)>::template apply<
1015 typename find_base_dimensions<T>::type,
1016 Dimensions
1017 >::type type;
1018 };
1019};
1020
1021template<>
1022struct calculate_base_unit_exponents_impl<false> {
1023 template<class T, class Dimensions>
1024 struct apply {
1025 // find the units that correspond to each base dimension
1026 typedef normalize_units<T> base_solutions;
1027 // pad the dimension with zeroes so it can just be a
1028 // list of numbers, making the multiplication easy
1029 // e.g. if the arguments are list<pound, foot> and
1030 // list<mass,time^-2> then this step will
1031 // yield list<0,1,-2>
1032 typedef typename expand_dimensions<(base_solutions::dimensions::size::value)>::template apply<
1033 typename base_solutions::dimensions,
1034 Dimensions
1035 >::type dimensions;
1036 // take the unit corresponding to each base unit
1037 // multiply each of its exponents by the exponent
1038 // of the base_dimension in the result and sum.
1039 typedef typename multiply_add_units<dimensions::size::value>::template apply<
1040 dimensions,
1041 typename base_solutions::type
1042 >::type units;
1043 // Now, verify that the dummy units really
1044 // cancel out and remove them.
1045 typedef typename strip_zeroes_impl<base_solutions::extra>::template apply<units>::type type;
1046 };
1047};
1048
1049template<class T, class Dimensions>
1050struct calculate_base_unit_exponents {
1051 typedef typename calculate_base_unit_exponents_impl<is_simple_system<T>::value>::template apply<T, Dimensions>::type type;
1052};
1053
1054} // namespace detail
1055
1056} // namespace units
1057
1058} // namespace boost
1059
1060#endif