linear_algebra.hpp 32 KB

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