multi_index_utility.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. //
  2. // Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // The authors gratefully acknowledge the support of
  9. // Fraunhofer IOSB, Ettlingen, Germany
  10. //
  11. #ifndef BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP
  12. #define BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP
  13. #include <tuple>
  14. #include <type_traits>
  15. namespace boost {
  16. namespace numeric {
  17. namespace ublas {
  18. namespace detail {
  19. template<class ... index_types>
  20. struct has_index_impl;
  21. template<class itype_left, class itype_right>
  22. struct has_index_impl<itype_left, itype_right>
  23. {
  24. static constexpr bool value = itype_left::value == itype_right::value;
  25. };
  26. template<class itype_left>
  27. struct has_index_impl <itype_left, std::tuple<> >
  28. {
  29. static constexpr bool value = false;
  30. };
  31. template<class itype_left, class itype_right>
  32. struct has_index_impl <itype_left, std::tuple<itype_right> >
  33. {
  34. static constexpr bool value = has_index_impl<itype_left,itype_right>::value;
  35. };
  36. template<class itype_left, class itype_right, class ... index_types>
  37. struct has_index_impl <itype_left, std::tuple<itype_right, index_types...> >
  38. {
  39. using next_type = has_index_impl<itype_left, std::tuple<index_types...>>;
  40. static constexpr bool value = has_index_impl<itype_left,itype_right>::value || next_type::value;
  41. };
  42. } // namespace detail
  43. /** @brief has_index is true if index occurs once or more in a multi-index
  44. *
  45. * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
  46. *
  47. * @code auto has_index_value = has_index<index_type<1>, std::tuple<index_type<2>,index_type<1>> >::value; @endcode
  48. *
  49. * @tparam index_type type of index
  50. * @tparam tuple_type type of std::tuple representing a multi-index
  51. */
  52. template<class index_type, class tuple_type>
  53. struct has_index
  54. {
  55. static constexpr bool value = detail::has_index_impl<std::decay_t<index_type>,std::decay_t<tuple_type>>::value;
  56. };
  57. } // namespace ublas
  58. } // namespace numeric
  59. } // namespace boost
  60. ////////////////////////////////////////////////
  61. ////////////////////////////////////////////////
  62. namespace boost {
  63. namespace numeric {
  64. namespace ublas {
  65. namespace detail {
  66. template<class ... index_types>
  67. struct valid_multi_index_impl;
  68. template<>
  69. struct valid_multi_index_impl<std::tuple<>>
  70. {
  71. static constexpr bool value = true;
  72. };
  73. template<class itype>
  74. struct valid_multi_index_impl<std::tuple<itype>>
  75. {
  76. static constexpr bool value = true;
  77. };
  78. template<class itype, class ... index_types>
  79. struct valid_multi_index_impl<std::tuple<itype,index_types...>>
  80. {
  81. using ttype = std::tuple<index_types...>;
  82. using has_index_type = has_index<itype, ttype>;
  83. static constexpr bool is_index_zero = itype::value==0ul;
  84. static constexpr bool has_index_value = has_index_type::value && !is_index_zero;
  85. static constexpr bool value = !has_index_value && valid_multi_index_impl<ttype>::value;
  86. };
  87. } // namespace detail
  88. /** @brief valid_multi_index is true if indexes occur only once in a multi-index
  89. *
  90. * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
  91. *
  92. * @code auto valid = valid_multi_index< std::tuple<index_type<2>,index_type<1>> >::value;
  93. * @endcode
  94. *
  95. * @tparam tuple_type type of std::tuple representing a multi-index
  96. */
  97. template<class tupe_type>
  98. struct valid_multi_index
  99. {
  100. static constexpr bool value = detail::valid_multi_index_impl<std::decay_t<tupe_type>>::value;
  101. };
  102. } // namespace ublas
  103. } // namespace numeric
  104. } // namespace boost
  105. ////////////////////////////////////////////////
  106. ////////////////////////////////////////////////
  107. namespace boost {
  108. namespace numeric {
  109. namespace ublas {
  110. namespace detail {
  111. template<class ... index_types >
  112. struct number_equal_indexes_impl;
  113. template<class ... itypes_right >
  114. struct number_equal_indexes_impl < std::tuple<>, std::tuple<itypes_right...>>
  115. {
  116. static constexpr unsigned value = 0;
  117. };
  118. template<class itype, class ... itypes_left, class ... itypes_right>
  119. struct number_equal_indexes_impl < std::tuple<itype,itypes_left...>, std::tuple<itypes_right...>>
  120. {
  121. using tuple_right = std::tuple<itypes_right...>;
  122. using has_index_type = has_index<itype, tuple_right>;
  123. static constexpr bool is_index_zero = itype::value==0ul;
  124. static constexpr bool has_index_value = has_index_type::value && !is_index_zero;
  125. using next_type = number_equal_indexes_impl< std::tuple<itypes_left...>, tuple_right >;
  126. static constexpr unsigned v = has_index_value ? 1 : 0;
  127. static constexpr unsigned value = v + next_type::value;
  128. };
  129. } // namespace detail
  130. /** @brief number_equal_indexes contains the number of equal indexes of two multi-indexes
  131. *
  132. * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
  133. *
  134. *
  135. * @code auto num = number_equal_indexes<
  136. * std::tuple<index_type<2>,index_type<1>>,
  137. * std::tuple<index_type<1>,index_type<3>> >::value;
  138. * @endcode
  139. *
  140. * @tparam tuple_type_left type of left std::tuple representing a multi-index
  141. * @tparam tuple_type_right type of right std::tuple representing a multi-index
  142. */
  143. template<class tuple_left, class tuple_right>
  144. struct number_equal_indexes
  145. {
  146. static constexpr unsigned value =
  147. detail::number_equal_indexes_impl< std::decay_t<tuple_left>, std::decay_t<tuple_right>>::value;
  148. };
  149. } // namespace ublas
  150. } // namespace numeric
  151. } // namespace boost
  152. ////////////////////////////////////////////////
  153. ////////////////////////////////////////////////
  154. namespace boost {
  155. namespace numeric {
  156. namespace ublas {
  157. namespace detail {
  158. template<std::size_t r, std::size_t m, class itype, class ttype>
  159. struct index_position_impl
  160. {
  161. static constexpr auto is_same = std::is_same< std::decay_t<itype>, std::decay_t<std::tuple_element_t<r,ttype>> >::value;
  162. static constexpr auto value = is_same ? r : index_position_impl<r+1,m,itype,ttype>::value;
  163. };
  164. template<std::size_t m, class itype, class ttype>
  165. struct index_position_impl < m, m, itype, ttype>
  166. {
  167. static constexpr auto value = std::tuple_size<ttype>::value;
  168. };
  169. } // namespace detail
  170. /** @brief index_position contains the zero-based index position of an index type within a multi-index
  171. *
  172. * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
  173. *
  174. * @code auto num = index_position<
  175. * index_type<1>,
  176. * std::tuple<index_type<2>,index_type<1>> >::value;
  177. * @endcode
  178. *
  179. * @returns value returns 0 and N-1 if index_type is found, N otherwise where N is tuple_size_v<tuple_type>.
  180. *
  181. * @tparam index_type type of index
  182. * @tparam tuple_type type of std::tuple that is searched for index
  183. */
  184. template<class index_type, class tuple_type>
  185. struct index_position
  186. {
  187. static constexpr auto value = detail::index_position_impl<0ul,std::tuple_size<tuple_type>::value,std::decay_t<index_type>,std::decay_t<tuple_type>>::value;
  188. };
  189. } // namespace ublas
  190. } // namespace numeric
  191. } // namespace boost
  192. ////////////////////////////////////////////////
  193. ////////////////////////////////////////////////
  194. namespace boost {
  195. namespace numeric {
  196. namespace ublas {
  197. namespace detail {
  198. template<std::size_t r, std::size_t m>
  199. struct index_position_pairs_impl
  200. {
  201. template<class array_type, class tuple_left, class tuple_right>
  202. static constexpr void run(array_type& out, tuple_left const& lhs, tuple_right const& rhs, std::size_t p)
  203. {
  204. using index_type = std::tuple_element_t<r-1,tuple_left>;
  205. using has_index_type = has_index<index_type, tuple_right>;
  206. using get_index_type = index_position<index_type,tuple_right>;
  207. using next_type = index_position_pairs_impl<r+1,m>;
  208. if constexpr ( has_index_type::value && index_type::value != 0)
  209. out[p++] = std::make_pair(r-1,get_index_type::value);
  210. next_type::run( out, lhs, rhs, p );
  211. }
  212. };
  213. template<std::size_t m>
  214. struct index_position_pairs_impl<m,m>
  215. {
  216. template<class array_type, class tuple_left, class tuple_right>
  217. static constexpr void run(array_type& out, tuple_left const& , tuple_right const& , std::size_t p)
  218. {
  219. using index_type = std::tuple_element_t<m-1,tuple_left>;
  220. using has_index_type = has_index<index_type, tuple_right>;
  221. using get_index_type = index_position<index_type, tuple_right>;
  222. if constexpr ( has_index_type::value && index_type::value != 0 )
  223. out[p] = std::make_pair(m-1,get_index_type::value);
  224. }
  225. };
  226. template<std::size_t r>
  227. struct index_position_pairs_impl<r,0>
  228. {
  229. template<class array_type, class tuple_left, class tuple_right>
  230. static constexpr void run(array_type&, tuple_left const& , tuple_right const& , std::size_t)
  231. {}
  232. };
  233. } // namespace detail
  234. /** @brief index_position_pairs returns zero-based index positions of matching indexes of two multi-indexes
  235. *
  236. * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
  237. *
  238. * @code auto pairs = index_position_pairs(std::make_tuple(_a,_b), std::make_tuple(_b,_c));
  239. * @endcode
  240. *
  241. * @returns a std::array instance containing index position pairs of type std::pair<std::size_t, std::size_t>.
  242. *
  243. * @param lhs left std::tuple instance representing a multi-index
  244. * @param rhs right std::tuple instance representing a multi-index
  245. */
  246. template<class tuple_left, class tuple_right>
  247. auto index_position_pairs(tuple_left const& lhs, tuple_right const& rhs)
  248. {
  249. using pair_type = std::pair<std::size_t,std::size_t>;
  250. constexpr auto m = std::tuple_size<tuple_left >::value;
  251. constexpr auto p = number_equal_indexes<tuple_left, tuple_right>::value;
  252. auto array = std::array<pair_type,p>{};
  253. detail::index_position_pairs_impl<1,m>::run(array, lhs, rhs,0);
  254. return array;
  255. }
  256. } // namespace ublas
  257. } // namespace numeric
  258. } // namespace boost
  259. ////////////////////////////
  260. ////////////////////////////
  261. ////////////////////////////
  262. ////////////////////////////
  263. namespace boost {
  264. namespace numeric {
  265. namespace ublas {
  266. namespace detail {
  267. template<class array_type, std::size_t ... R>
  268. constexpr auto array_to_vector_impl( array_type const& array, std::index_sequence<R...> )
  269. {
  270. return std::make_pair(
  271. std::vector<std::size_t>{std::get<0>( std::get<R>(array) )+1 ...} ,
  272. std::vector<std::size_t>{std::get<1>( std::get<R>(array) )+1 ...} );
  273. }
  274. } // namespace detail
  275. /** @brief array_to_vector converts a std::array of zero-based index position pairs into two std::vector of one-based index positions
  276. *
  277. * @code auto two_vectors = array_to_vector(std::make_array ( std::make_pair(1,2), std::make_pair(3,4) ) ) ;
  278. * @endcode
  279. *
  280. * @returns two std::vector of one-based index positions
  281. *
  282. * @param array std::array of zero-based index position pairs
  283. */
  284. template<class pair_type, std::size_t N>
  285. constexpr auto array_to_vector( std::array<pair_type,N> const& array)
  286. {
  287. constexpr auto sequence = std::make_index_sequence<N>{};
  288. return detail::array_to_vector_impl( array, sequence );
  289. }
  290. } // namespace ublas
  291. } // namespace numeric
  292. } // namespace boost
  293. #endif // _BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP_