algorithms.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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_ALGORITHMS_HPP
  12. #define _BOOST_UBLAS_TENSOR_ALGORITHMS_HPP
  13. #include <stdexcept>
  14. #include <complex>
  15. #include <functional>
  16. namespace boost {
  17. namespace numeric {
  18. namespace ublas {
  19. /** @brief Copies a tensor to another tensor with different layouts
  20. *
  21. * Implements C[i1,i2,...,ip] = A[i1,i2,...,ip]
  22. *
  23. * @param[in] p rank of input and output tensor
  24. * @param[in] n pointer to the extents of input or output tensor of length p
  25. * @param[in] pi pointer to a one-based permutation tuple of length p
  26. * @param[out] c pointer to the output tensor
  27. * @param[in] wc pointer to the strides of output tensor c
  28. * @param[in] a pointer to the input tensor
  29. * @param[in] wa pointer to the strides of input tensor a
  30. */
  31. template <class PointerOut, class PointerIn, class SizeType>
  32. void copy(const SizeType p, SizeType const*const n,
  33. PointerOut c, SizeType const*const wc,
  34. PointerIn a, SizeType const*const wa)
  35. {
  36. static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn>::value,
  37. "Static error in boost::numeric::ublas::copy: Argument types for pointers are not pointer types.");
  38. if( p == 0 )
  39. return;
  40. if(c == nullptr || a == nullptr)
  41. throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers.");
  42. if(wc == nullptr || wa == nullptr)
  43. throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers.");
  44. if(n == nullptr)
  45. throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers.");
  46. std::function<void(SizeType r, PointerOut c, PointerIn a)> lambda;
  47. lambda = [&lambda, n, wc, wa](SizeType r, PointerOut c, PointerIn a)
  48. {
  49. if(r > 0)
  50. for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d)
  51. lambda(r-1, c, a );
  52. else
  53. for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d)
  54. *c = *a;
  55. };
  56. lambda( p-1, c, a );
  57. }
  58. /** @brief Copies a tensor to another tensor with different layouts applying a unary operation
  59. *
  60. * Implements C[i1,i2,...,ip] = op ( A[i1,i2,...,ip] )
  61. *
  62. * @param[in] p rank of input and output tensor
  63. * @param[in] n pointer to the extents of input or output tensor of length p
  64. * @param[in] pi pointer to a one-based permutation tuple of length p
  65. * @param[out] c pointer to the output tensor
  66. * @param[in] wc pointer to the strides of output tensor c
  67. * @param[in] a pointer to the input tensor
  68. * @param[in] wa pointer to the strides of input tensor a
  69. * @param[in] op unary operation
  70. */
  71. template <class PointerOut, class PointerIn, class SizeType, class UnaryOp>
  72. void transform(const SizeType p,
  73. SizeType const*const n,
  74. PointerOut c, SizeType const*const wc,
  75. PointerIn a, SizeType const*const wa,
  76. UnaryOp op)
  77. {
  78. static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn>::value,
  79. "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types.");
  80. if( p == 0 )
  81. return;
  82. if(c == nullptr || a == nullptr)
  83. throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
  84. if(wc == nullptr || wa == nullptr)
  85. throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
  86. if(n == nullptr)
  87. throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
  88. std::function<void(SizeType r, PointerOut c, PointerIn a)> lambda;
  89. lambda = [&lambda, n, wc, wa, op](SizeType r, PointerOut c, PointerIn a)
  90. {
  91. if(r > 0)
  92. for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d)
  93. lambda(r-1, c, a);
  94. else
  95. for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d)
  96. *c = op(*a);
  97. };
  98. lambda( p-1, c, a );
  99. }
  100. /** @brief Performs a reduce operation with all elements of the tensor and an initial value
  101. *
  102. * Implements k = sum_{i1,..,ip} A[i1,i2,...,ip]
  103. *
  104. * @param[in] r zero-based recursion level starting with r=p-1
  105. * @param[in] n pointer to the extents of input or output tensor
  106. * @param[in] a pointer to the first input tensor
  107. * @param[in] w pointer to the strides of input tensor a
  108. * @param[in] k accumulated value
  109. */
  110. template <class PointerIn, class ValueType, class SizeType>
  111. ValueType accumulate(SizeType const p, SizeType const*const n,
  112. PointerIn a, SizeType const*const w,
  113. ValueType k)
  114. {
  115. static_assert(std::is_pointer<PointerIn>::value,
  116. "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types.");
  117. if( p == 0 )
  118. return k;
  119. if(a == nullptr)
  120. throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
  121. if(w == nullptr)
  122. throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
  123. if(n == nullptr)
  124. throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
  125. std::function<ValueType(SizeType r, PointerIn a, ValueType k)> lambda;
  126. lambda = [&lambda, n, w](SizeType r, PointerIn a, ValueType k)
  127. {
  128. if(r > 0u)
  129. for(auto d = 0u; d < n[r]; a += w[r], ++d)
  130. k = lambda(r-1, a, k);
  131. else
  132. for(auto d = 0u; d < n[0]; a += w[0], ++d)
  133. k += *a;
  134. return k;
  135. };
  136. return lambda( p-1, a, k );
  137. }
  138. /** @brief Performs a reduce operation with all elements of the tensor and an initial value
  139. *
  140. * Implements k = op ( k , A[i1,i2,...,ip] ), for all ir
  141. *
  142. * @param[in] r zero-based recursion level starting with r=p-1
  143. * @param[in] n pointer to the extents of input or output tensor
  144. * @param[in] a pointer to the first input tensor
  145. * @param[in] w pointer to the strides of input tensor a
  146. * @param[in] k accumulated value
  147. * @param[in] op binary operation
  148. */
  149. template <class PointerIn, class ValueType, class SizeType, class BinaryOp>
  150. ValueType accumulate(SizeType const p, SizeType const*const n,
  151. PointerIn a, SizeType const*const w,
  152. ValueType k, BinaryOp op)
  153. {
  154. static_assert(std::is_pointer<PointerIn>::value,
  155. "Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types.");
  156. if( p == 0 )
  157. return k;
  158. if(a == nullptr)
  159. throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
  160. if(w == nullptr)
  161. throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
  162. if(n == nullptr)
  163. throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
  164. std::function<ValueType(SizeType r, PointerIn a, ValueType k)> lambda;
  165. lambda = [&lambda, n, w, op](SizeType r, PointerIn a, ValueType k)
  166. {
  167. if(r > 0u)
  168. for(auto d = 0u; d < n[r]; a += w[r], ++d)
  169. k = lambda(r-1, a, k);
  170. else
  171. for(auto d = 0u; d < n[0]; a += w[0], ++d)
  172. k = op ( k, *a );
  173. return k;
  174. };
  175. return lambda( p-1, a, k );
  176. }
  177. /** @brief Transposes a tensor
  178. *
  179. * Implements C[tau[i1],tau[i2],...,tau[ip]] = A[i1,i2,...,ip]
  180. *
  181. * @note is used in function trans
  182. *
  183. * @param[in] p rank of input and output tensor
  184. * @param[in] na pointer to the extents of the input tensor a of length p
  185. * @param[in] pi pointer to a one-based permutation tuple of length p
  186. * @param[out] c pointer to the output tensor
  187. * @param[in] wc pointer to the strides of output tensor c
  188. * @param[in] a pointer to the input tensor
  189. * @param[in] wa pointer to the strides of input tensor a
  190. */
  191. template <class PointerOut, class PointerIn, class SizeType>
  192. void trans( SizeType const p, SizeType const*const na, SizeType const*const pi,
  193. PointerOut c, SizeType const*const wc,
  194. PointerIn a, SizeType const*const wa)
  195. {
  196. static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn>::value,
  197. "Static error in boost::numeric::ublas::trans: Argument types for pointers are not pointer types.");
  198. if( p < 2)
  199. return;
  200. if(c == nullptr || a == nullptr)
  201. throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
  202. if(na == nullptr)
  203. throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null.");
  204. if(wc == nullptr || wa == nullptr)
  205. throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
  206. if(na == nullptr)
  207. throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
  208. if(pi == nullptr)
  209. throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
  210. std::function<void(SizeType r, PointerOut c, PointerIn a)> lambda;
  211. lambda = [&lambda, na, wc, wa, pi](SizeType r, PointerOut c, PointerIn a)
  212. {
  213. if(r > 0)
  214. for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d)
  215. lambda(r-1, c, a);
  216. else
  217. for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d)
  218. *c = *a;
  219. };
  220. lambda( p-1, c, a );
  221. }
  222. /** @brief Transposes a tensor
  223. *
  224. * Implements C[tau[i1],tau[i2],...,tau[ip]] = A[i1,i2,...,ip]
  225. *
  226. * @note is used in function trans
  227. *
  228. * @param[in] p rank of input and output tensor
  229. * @param[in] na pointer to the extents of the input tensor a of length p
  230. * @param[in] pi pointer to a one-based permutation tuple of length p
  231. * @param[out] c pointer to the output tensor
  232. * @param[in] wc pointer to the strides of output tensor c
  233. * @param[in] a pointer to the input tensor
  234. * @param[in] wa pointer to the strides of input tensor a
  235. */
  236. template <class ValueType, class SizeType>
  237. void trans( SizeType const p,
  238. SizeType const*const na,
  239. SizeType const*const pi,
  240. std::complex<ValueType>* c, SizeType const*const wc,
  241. std::complex<ValueType>* a, SizeType const*const wa)
  242. {
  243. if( p < 2)
  244. return;
  245. if(c == nullptr || a == nullptr)
  246. throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
  247. if(wc == nullptr || wa == nullptr)
  248. throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
  249. if(na == nullptr)
  250. throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
  251. if(pi == nullptr)
  252. throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
  253. std::function<void(SizeType r, std::complex<ValueType>* c, std::complex<ValueType>* a)> lambda;
  254. lambda = [&lambda, na, wc, wa, pi](SizeType r, std::complex<ValueType>* c, std::complex<ValueType>* a)
  255. {
  256. if(r > 0)
  257. for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d)
  258. lambda(r-1, c, a);
  259. else
  260. for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d)
  261. *c = std::conj(*a);
  262. };
  263. lambda( p-1, c, a );
  264. }
  265. }
  266. }
  267. }
  268. #endif