1 #ifndef PYTHONIC_NUMPY_TRANSPOSE_HPP 2 #define PYTHONIC_NUMPY_TRANSPOSE_HPP 3 4 #include "pythonic/include/numpy/transpose.hpp" 5 6 #include "pythonic/utils/functor.hpp" 7 #include "pythonic/utils/numpy_conversion.hpp" 8 #include "pythonic/utils/nested_container.hpp" 9 #include "pythonic/types/ndarray.hpp" 10 #include "pythonic/builtins/ValueError.hpp" 11 12 PYTHONIC_NS_BEGIN 13 14 namespace numpy 15 { 16 namespace 17 { 18 template <class T, class pS, class O, class Indices, class S, class Perm> 19 O const *_transposer(types::ndarray<T, pS> &expr, O const *iter, 20 Indices &indices, S const &shape, Perm const &perm, 21 utils::int_<std::tuple_size<pS>::value - 1>) 22 { 23 for (long i = 0, n = shape[std::tuple_size<pS>::value - 1]; i < n; ++i) { 24 indices[perm[std::tuple_size<pS>::value - 1]] = i; 25 expr.fast(indices) = *iter++; 26 } 27 indices[perm[std::tuple_size<pS>::value - 1]] = 0; 28 return iter; 29 } 30 31 template <class T, class pS, class O, class Indices, class S, class Perm, 32 size_t I> 33 typename std::enable_if<std::tuple_size<pS>::value - 1 != I, 34 O const *>::type _transposer(types::ndarray<T,pS> & expr,O const * iter,Indices & indices,S const & shape,Perm const & perm,utils::int_<I>)35 _transposer(types::ndarray<T, pS> &expr, O const *iter, Indices &indices, 36 S const &shape, Perm const &perm, utils::int_<I>) 37 { 38 for (long i = 0, n = shape[I]; i < n; ++i) { 39 indices[perm[I]] = i; 40 iter = 41 _transposer(expr, iter, indices, shape, perm, utils::int_<I + 1>()); 42 } 43 indices[perm[I]] = 0; 44 return iter; 45 } 46 template <class T, class pS> 47 types::ndarray<T, types::array<long, std::tuple_size<pS>::value>> _transposer(types::ndarray<T,pS> const & a,long const l[std::tuple_size<pS>::value])48 _transposer(types::ndarray<T, pS> const &a, 49 long const l[std::tuple_size<pS>::value]) 50 { 51 auto shape = sutils::getshape(a); 52 types::array<long, std::tuple_size<pS>::value> shp; 53 for (unsigned long i = 0; i < std::tuple_size<pS>::value; ++i) 54 shp[i] = shape[l[i]]; 55 56 types::array<long, std::tuple_size<pS>::value> perm; 57 for (std::size_t i = 0; i < std::tuple_size<pS>::value; ++i) 58 perm[l[i]] = i; 59 60 types::ndarray<T, types::array<long, std::tuple_size<pS>::value>> 61 new_array(shp, builtins::None); 62 63 auto const *iter = a.buffer; 64 types::array<long, std::tuple_size<pS>::value> indices; 65 _transposer(new_array, iter, indices, shape, perm, utils::int_<0>{}); 66 67 return new_array; 68 } 69 } 70 71 template <class T, class pS> 72 typename std::enable_if< 73 (std::tuple_size<pS>::value > 2), 74 types::ndarray<T, types::array<long, std::tuple_size<pS>::value>>>::type transpose(types::ndarray<T,pS> const & a)75 transpose(types::ndarray<T, pS> const &a) 76 { 77 long t[std::tuple_size<pS>::value]; 78 for (unsigned long i = 0; i < std::tuple_size<pS>::value; ++i) 79 t[std::tuple_size<pS>::value - 1 - i] = i; 80 return _transposer(a, t); 81 } 82 83 template <class T, class pS, size_t M> 84 types::ndarray<T, types::array<long, std::tuple_size<pS>::value>> transpose(types::ndarray<T,pS> const & a,types::array<long,M> const & t)85 transpose(types::ndarray<T, pS> const &a, types::array<long, M> const &t) 86 { 87 static_assert(std::tuple_size<pS>::value == M, "axes don't match array"); 88 89 long val = t[M - 1]; 90 if (val >= long(std::tuple_size<pS>::value)) 91 throw types::ValueError("invalid axis for this array"); 92 return _transposer(a, &t[0]); 93 } 94 } 95 PYTHONIC_NS_END 96 97 #endif 98