#ifndef PYTHONIC_NUMPY_PARTIAL_SUM_HPP #define PYTHONIC_NUMPY_PARTIAL_SUM_HPP #include "pythonic/include/numpy/partial_sum.hpp" #include "pythonic/types/ndarray.hpp" #include "pythonic/builtins/ValueError.hpp" PYTHONIC_NS_BEGIN namespace numpy { /** * The cast is perform to be numpy compliant * * a = numpy.array([1, 256]) * In [10]: numpy.mod.accumulate(a, dtype=numpy.uint32) * Out[10]: array([1, 1], dtype=uint32) * In [11]: numpy.mod.accumulate(a, dtype=numpy.uint8) * Out[11]: array([1, 0], dtype=uint8) */ namespace { template struct _partial_sum { template A operator()(E const &e, F &o) { auto it_begin = e.begin(); A acc = _partial_sum{}((*it_begin), o); ++it_begin; for (; it_begin < e.end(); ++it_begin) acc = _partial_sum{}(*it_begin, o, acc); return acc; } template A operator()(E const &e, F &o, A acc) { for (auto const &value : e) acc = _partial_sum{}(value, o, acc); return acc; } }; template struct _partial_sum { template A operator()(E const &e, F &o) { auto it_begin = e.begin(); A acc = *it_begin; *o = acc; ++it_begin, ++o; for (; it_begin < e.end(); ++it_begin, ++o) { acc = Op{}(acc, (A)*it_begin); *o = acc; } return acc; } template A operator()(E e, F &o, A acc) { for (auto const &value : e) { acc = Op{}(acc, (A)value); *o = acc; ++o; } return acc; } }; } template types::ndarray> partial_sum(E const &expr, dtype d) { const long count = expr.flat_size(); types::ndarray> the_partial_sum{ types::make_tuple(count), builtins::None}; auto begin_it = the_partial_sum.begin(); _partial_sum{}(expr, begin_it); return the_partial_sum; } template auto partial_sum(E const &expr, long axis, dtype d) -> typename std::enable_if(expr))>::type { if (axis != 0) throw types::ValueError("axis out of bounds"); return partial_sum(expr); } template typename std::enable_if>::type partial_sum(E const &expr, long axis, dtype d) { if (axis < 0 || size_t(axis) >= E::value) throw types::ValueError("axis out of bounds"); auto shape = sutils::getshape(expr); partial_sum_type the_partial_sum{shape, builtins::None}; if (axis == 0) { auto it_begin = the_partial_sum.begin(); _partial_sum>{}(expr, it_begin); } else { std::transform( expr.begin(), expr.end(), the_partial_sum.begin(), [axis, d]( typename std::iterator_traits::value_type other) { return partial_sum(other, axis - 1, d); }); } return the_partial_sum; } } PYTHONIC_NS_END #endif