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