1#ifndef XTENSOR_XBLOCKWISE_REDUCER_HPP 
    2#define XTENSOR_XBLOCKWISE_REDUCER_HPP 
    4#include "../core/xmultiindex_iterator.hpp" 
    5#include "../core/xshape.hpp" 
    6#include "../reducers/xblockwise_reducer_functors.hpp" 
    7#include "../reducers/xreducer.hpp" 
    8#include "xtl/xclosure.hpp" 
    9#include "xtl/xsequence.hpp" 
   14    template <
class CT, 
class F, 
class X, 
class O>
 
   15    class xblockwise_reducer
 
   19        using self_type = xblockwise_reducer<CT, F, X, O>;
 
   20        using raw_options_type = std::decay_t<O>;
 
   21        using keep_dims = xtl::mpl::contains<raw_options_type, xt::keep_dims_type>;
 
   22        using xexpression_type = std::decay_t<CT>;
 
   24        using functor_type = F;
 
   25        using value_type = 
typename functor_type::value_type;
 
   26        using input_shape_type = 
typename xexpression_type::shape_type;
 
   27        using input_chunk_index_type = filter_fixed_shape_t<input_shape_type>;
 
   28        using input_grid_strides = filter_fixed_shape_t<input_shape_type>;
 
   30        using chunk_shape_type = filter_fixed_shape_t<shape_type>;
 
   33        template <
class E, 
class BS, 
class XX, 
class OO, 
class FF>
 
   34        xblockwise_reducer(E&& e, BS&& block_shape, XX&& axes, OO&& options, FF&& functor);
 
   36        const input_shape_type& input_shape() 
const;
 
   37        const axes_type& axes() 
const;
 
   39        std::size_t dimension() 
const;
 
   41        const shape_type& shape() 
const;
 
   43        const chunk_shape_type& chunk_shape() 
const;
 
   46        void assign_to(R& result) 
const;
 
   50        using mapping_type = filter_fixed_shape_t<shape_type>;
 
   52        using input_const_chunked_iterator_type = 
typename input_chunked_view_type::const_chunk_iterator;
 
   53        using input_chunk_range_type = std::array<xmultiindex_iterator<input_chunk_index_type>, 2>;
 
   56        void assign_to_chunk(CI& result_chunk_iter) 
const;
 
   59        input_chunk_range_type compute_input_chunk_range(CI& result_chunk_iter) 
const;
 
   61        input_const_chunked_iterator_type get_input_chunk_iter(input_chunk_index_type input_chunk_index) 
const;
 
   67        raw_options_type m_options;
 
   68        functor_type m_functor;
 
   69        shape_type m_result_shape;
 
   70        chunk_shape_type m_result_chunk_shape;
 
   71        mapping_type m_mapping;
 
   72        input_grid_strides m_input_grid_strides;
 
 
   75    template <
class CT, 
class F, 
class X, 
class O>
 
   76    template <
class E, 
class BS, 
class XX, 
class OO, 
class FF>
 
   77    xblockwise_reducer<CT, F, X, O>::xblockwise_reducer(E&& e, BS&& block_shape, XX&& axes, OO&& options, FF&& functor)
 
   78        : m_e(std::forward<E>(e))
 
   79        , m_e_chunked_view(m_e, std::forward<BS>(block_shape))
 
   80        , m_axes(std::forward<XX>(axes))
 
   81        , m_options(std::forward<OO>(options))
 
   82        , m_functor(std::forward<FF>(functor))
 
   84        , m_result_chunk_shape()
 
   86        , m_input_grid_strides()
 
   89        resize_container(m_input_grid_strides, m_e.dimension());
 
   90        std::size_t stride = 1;
 
   92        for (std::size_t i = m_input_grid_strides.size(); i != 0; --i)
 
   94            m_input_grid_strides[i - 1] = stride;
 
   95            stride *= m_e_chunked_view.grid_shape()[i - 1];
 
   99    template <
class CT, 
class F, 
class X, 
class O>
 
  100    inline auto xblockwise_reducer<CT, F, X, O>::input_shape() const -> const input_shape_type&
 
  105    template <
class CT, 
class F, 
class X, 
class O>
 
  106    inline auto xblockwise_reducer<CT, F, X, O>::axes() const -> const axes_type&
 
  111    template <
class CT, 
class F, 
class X, 
class O>
 
  112    inline std::size_t xblockwise_reducer<CT, F, X, O>::dimension()
 const 
  114        return m_result_shape.size();
 
  117    template <
class CT, 
class F, 
class X, 
class O>
 
  118    inline auto xblockwise_reducer<CT, F, X, O>::shape() const -> const shape_type&
 
  120        return m_result_shape;
 
  123    template <
class CT, 
class F, 
class X, 
class O>
 
  124    inline auto xblockwise_reducer<CT, F, X, O>::chunk_shape() const -> const chunk_shape_type&
 
  126        return m_result_chunk_shape;
 
  129    template <
class CT, 
class F, 
class X, 
class O>
 
  131    inline void xblockwise_reducer<CT, F, X, O>::assign_to(R& result)
 const 
  133        auto result_chunked_view = as_chunked(result, m_result_chunk_shape);
 
  134        for (
auto chunk_iter = result_chunked_view.chunk_begin(); chunk_iter != result_chunked_view.chunk_end();
 
  137            assign_to_chunk(chunk_iter);
 
  141    template <
class CT, 
class F, 
class X, 
class O>
 
  142    auto xblockwise_reducer<CT, F, X, O>::get_input_chunk_iter(input_chunk_index_type input_chunk_index) 
const 
  143        -> input_const_chunked_iterator_type
 
  145        std::size_t chunk_linear_index = 0;
 
  146        for (std::size_t i = 0; i < m_e_chunked_view.dimension(); ++i)
 
  148            chunk_linear_index += input_chunk_index[i] * m_input_grid_strides[i];
 
  150        return input_const_chunked_iterator_type(m_e_chunked_view, std::move(input_chunk_index), chunk_linear_index);
 
  153    template <
class CT, 
class F, 
class X, 
class O>
 
  155    void xblockwise_reducer<CT, F, X, O>::assign_to_chunk(CI& result_chunk_iter)
 const 
  157        auto result_chunk_view = *result_chunk_iter;
 
  158        auto reduction_variable = m_functor.reduction_variable(result_chunk_view);
 
  161        auto range = compute_input_chunk_range(result_chunk_iter);
 
  166        auto iter = std::get<0>(
range);
 
  167        while (iter != std::get<1>(
range))
 
  169            const auto& input_chunk_index = *iter;
 
  171            auto chunked_input_iter = this->get_input_chunk_iter(input_chunk_index);
 
  172            auto input_chunk_view = *chunked_input_iter;
 
  175            auto block_res = m_functor.compute(input_chunk_view, m_axes, m_options);
 
  178            m_functor.merge(block_res, first, result_chunk_view, reduction_variable);
 
  184        m_functor.finalize(reduction_variable, result_chunk_view, *
this);
 
  187    template <
class CT, 
class F, 
class X, 
class O>
 
  189    auto xblockwise_reducer<CT, F, X, O>::compute_input_chunk_range(CI& result_chunk_iter) 
const 
  190        -> input_chunk_range_type
 
  192        auto input_chunks_begin = xtl::make_sequence<input_chunk_index_type>(m_e_chunked_view.dimension(), 0);
 
  193        auto input_chunks_end = xtl::make_sequence<input_chunk_index_type>(m_e_chunked_view.dimension());
 
  195        XTENSOR_ASSERT(input_chunks_begin.size() == m_e_chunked_view.dimension());
 
  196        XTENSOR_ASSERT(input_chunks_end.size() == m_e_chunked_view.dimension());
 
  199            m_e_chunked_view.grid_shape().begin(),
 
  200            m_e_chunked_view.grid_shape().end(),
 
  201            input_chunks_end.begin()
 
  204        const auto& chunk_index = result_chunk_iter.chunk_index();
 
  205        for (std::size_t result_ax_index = 0; result_ax_index < m_result_shape.size(); ++result_ax_index)
 
  207            if (m_result_shape[result_ax_index] != 1)
 
  209                const auto input_ax_index = m_mapping[result_ax_index];
 
  210                input_chunks_begin[input_ax_index] = chunk_index[result_ax_index];
 
  211                input_chunks_end[input_ax_index] = chunk_index[result_ax_index] + 1;
 
  214        return input_chunk_range_type{
 
  215            multiindex_iterator_begin<input_chunk_index_type>(input_chunks_begin, input_chunks_end),
 
  216            multiindex_iterator_end<input_chunk_index_type>(input_chunks_begin, input_chunks_end)
 
  220    template <
class CT, 
class F, 
class X, 
class O>
 
  221    void xblockwise_reducer<CT, F, X, O>::init_shapes()
 
  223        const auto& shape = m_e.shape();
 
  224        const auto dimension = m_e.dimension();
 
  225        const auto& block_shape = m_e_chunked_view.chunk_shape();
 
  226        if (xtl::mpl::contains<raw_options_type, xt::keep_dims_type>::value)
 
  228            resize_container(m_result_shape, dimension);
 
  229            resize_container(m_result_chunk_shape, dimension);
 
  230            resize_container(m_mapping, dimension);
 
  231            for (std::size_t i = 0; i < dimension; ++i)
 
  234                if (std::find(m_axes.begin(), m_axes.end(), i) == m_axes.end())
 
  237                    m_result_shape[i] = shape[i];
 
  238                    m_result_chunk_shape[i] = block_shape[i];
 
  242                    m_result_shape[i] = 1;
 
  243                    m_result_chunk_shape[i] = 1;
 
  249            const auto result_dim = dimension - m_axes.size();
 
  250            resize_container(m_result_shape, result_dim);
 
  251            resize_container(m_result_chunk_shape, result_dim);
 
  252            resize_container(m_mapping, result_dim);
 
  254            for (std::size_t i = 0, idx = 0; i < dimension; ++i)
 
  256                if (std::find(m_axes.begin(), m_axes.end(), i) == m_axes.end())
 
  259                    m_result_shape[idx] = shape[i];
 
  260                    m_result_chunk_shape[idx] = block_shape[i];
 
  268    template <
class E, 
class CS, 
class A, 
class O, 
class FF>
 
  269    inline auto blockwise_reducer(E&& e, CS&& chunk_shape, A&& axes, O&& raw_options, FF&& functor)
 
  271        using functor_type = std::decay_t<FF>;
 
  272        using closure_type = xtl::const_closure_type_t<E>;
 
  273        using axes_type = std::decay_t<A>;
 
  277            std::forward<CS>(chunk_shape),
 
  278            std::forward<A>(axes),
 
  279            std::forward<O>(raw_options),
 
  280            std::forward<FF>(functor)
 
  287#define XTENSOR_BLOCKWISE_REDUCER_FUNC(FNAME, FUNCTOR)                                                        \ 
  293        class O = DEFAULT_STRATEGY_REDUCERS,                                                                  \ 
  294        XTL_REQUIRES(std::negation<is_reducer_options<X>>, std::negation<xtl::is_integral<std::decay_t<X>>>)> \ 
  295    auto FNAME(E&& e, BS&& block_shape, X&& axes, O options = O())                                            \ 
  297        using input_expression_type = std::decay_t<E>;                                                        \ 
  298        using functor_type = FUNCTOR<typename input_expression_type::value_type, T>;                          \ 
  299        return blockwise_reducer(                                                                             \ 
  300            std::forward<E>(e),                                                                               \ 
  301            std::forward<BS>(block_shape),                                                                    \ 
  302            std::forward<X>(axes),                                                                            \ 
  303            std::forward<O>(options),                                                                         \ 
  312        class O = DEFAULT_STRATEGY_REDUCERS,                                                                  \ 
  313        XTL_REQUIRES(xtl::is_integral<std::decay_t<X>>)>                                                      \ 
  314    auto FNAME(E&& e, BS&& block_shape, X axis, O options = O())                                              \ 
  316        std::array<X, 1> axes{axis};                                                                          \ 
  317        using input_expression_type = std::decay_t<E>;                                                        \ 
  318        using functor_type = FUNCTOR<typename input_expression_type::value_type, T>;                          \ 
  319        return blockwise_reducer(                                                                             \ 
  320            std::forward<E>(e),                                                                               \ 
  321            std::forward<BS>(block_shape),                                                                    \ 
  323            std::forward<O>(options),                                                                         \ 
  331        class O = DEFAULT_STRATEGY_REDUCERS,                                                                  \ 
  332        XTL_REQUIRES(is_reducer_options<O>, std::negation<xtl::is_integral<std::decay_t<O>>>)>                \ 
  333    auto FNAME(E&& e, BS&& block_shape, O options = O())                                                      \ 
  335        using input_expression_type = std::decay_t<E>;                                                        \ 
  336        using axes_type = filter_fixed_shape_t<typename input_expression_type::shape_type>;                   \ 
  337        axes_type axes = xtl::make_sequence<axes_type>(e.dimension());                                        \ 
  338        XTENSOR_ASSERT(axes.size() == e.dimension());                                                         \ 
  339        std::iota(axes.begin(), axes.end(), 0);                                                               \ 
  340        using functor_type = FUNCTOR<typename input_expression_type::value_type, T>;                          \ 
  341        return blockwise_reducer(                                                                             \ 
  342            std::forward<E>(e),                                                                               \ 
  343            std::forward<BS>(block_shape),                                                                    \ 
  345            std::forward<O>(options),                                                                         \ 
  349    template <class T = void, class E, class BS, class I, std::size_t N, class O = DEFAULT_STRATEGY_REDUCERS> \ 
  350    auto FNAME(E&& e, BS&& block_shape, const I(&axes)[N], O options = O())                                   \ 
  352        using input_expression_type = std::decay_t<E>;                                                        \ 
  353        using functor_type = FUNCTOR<typename input_expression_type::value_type, T>;                          \ 
  354        using axes_type = std::array<std::size_t, N>;                                                         \ 
  355        auto ax = xt::forward_normalize<axes_type>(e, axes);                                                  \ 
  356        return blockwise_reducer(                                                                             \ 
  357            std::forward<E>(e),                                                                               \ 
  358            std::forward<BS>(block_shape),                                                                    \ 
  360            std::forward<O>(options),                                                                         \ 
  364        XTENSOR_BLOCKWISE_REDUCER_FUNC(sum, xt::detail::blockwise::sum_functor)
 
  365        XTENSOR_BLOCKWISE_REDUCER_FUNC(prod, xt::detail::blockwise::prod_functor)
 
  366        XTENSOR_BLOCKWISE_REDUCER_FUNC(amin, xt::detail::blockwise::amin_functor)
 
  367        XTENSOR_BLOCKWISE_REDUCER_FUNC(amax, xt::detail::blockwise::amax_functor)
 
  368        XTENSOR_BLOCKWISE_REDUCER_FUNC(mean, xt::detail::blockwise::mean_functor)
 
  369        XTENSOR_BLOCKWISE_REDUCER_FUNC(variance, xt::detail::blockwise::variance_functor)
 
  370        XTENSOR_BLOCKWISE_REDUCER_FUNC(stddev, xt::detail::blockwise::stddev_functor)
 
  372#undef XTENSOR_BLOCKWISE_REDUCER_FUNC 
  377#define XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC(FNAME, FUNCTOR)                                                                     \ 
  382        class O = DEFAULT_STRATEGY_REDUCERS,                                                                                    \ 
  383        XTL_REQUIRES(std::negation<is_reducer_options<X>>, std::negation<xtl::is_integral<std::decay_t<X>>>)>                   \ 
  384    auto FNAME(E&& e, BS&& block_shape, X&& axes, O options = O())                                                              \ 
  386        using input_expression_type = std::decay_t<E>;                                                                          \ 
  387        using functor_type = FUNCTOR<typename input_expression_type::value_type>;                                               \ 
  388        return blockwise_reducer(                                                                                               \ 
  389            std::forward<E>(e),                                                                                                 \ 
  390            std::forward<BS>(block_shape),                                                                                      \ 
  391            std::forward<X>(axes),                                                                                              \ 
  392            std::forward<O>(options),                                                                                           \ 
  396    template <class E, class BS, class X, class O = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(xtl::is_integral<std::decay_t<X>>)> \ 
  397    auto FNAME(E&& e, BS&& block_shape, X axis, O options = O())                                                                \ 
  399        std::array<X, 1> axes{axis};                                                                                            \ 
  400        using input_expression_type = std::decay_t<E>;                                                                          \ 
  401        using functor_type = FUNCTOR<typename input_expression_type::value_type>;                                               \ 
  402        return blockwise_reducer(                                                                                               \ 
  403            std::forward<E>(e),                                                                                                 \ 
  404            std::forward<BS>(block_shape),                                                                                      \ 
  406            std::forward<O>(options),                                                                                           \ 
  413        class O = DEFAULT_STRATEGY_REDUCERS,                                                                                    \ 
  414        XTL_REQUIRES(is_reducer_options<O>, std::negation<xtl::is_integral<std::decay_t<O>>>)>                                  \ 
  415    auto FNAME(E&& e, BS&& block_shape, O options = O())                                                                        \ 
  417        using input_expression_type = std::decay_t<E>;                                                                          \ 
  418        using axes_type = filter_fixed_shape_t<typename input_expression_type::shape_type>;                                     \ 
  419        axes_type axes = xtl::make_sequence<axes_type>(e.dimension());                                                          \ 
  420        XTENSOR_ASSERT(axes.size() == e.dimension());                                                                           \ 
  421        std::iota(axes.begin(), axes.end(), 0);                                                                                 \ 
  422        using functor_type = FUNCTOR<typename input_expression_type::value_type>;                                               \ 
  423        return blockwise_reducer(                                                                                               \ 
  424            std::forward<E>(e),                                                                                                 \ 
  425            std::forward<BS>(block_shape),                                                                                      \ 
  427            std::forward<O>(options),                                                                                           \ 
  431    template <class E, class BS, class I, std::size_t N, class O = DEFAULT_STRATEGY_REDUCERS>                                   \ 
  432    auto FNAME(E&& e, BS&& block_shape, const I(&axes)[N], O options = O())                                                     \ 
  434        using input_expression_type = std::decay_t<E>;                                                                          \ 
  435        using functor_type = FUNCTOR<typename input_expression_type::value_type>;                                               \ 
  436        using axes_type = std::array<std::size_t, N>;                                                                           \ 
  437        auto ax = xt::forward_normalize<axes_type>(e, axes);                                                                    \ 
  438        return blockwise_reducer(                                                                                               \ 
  439            std::forward<E>(e),                                                                                                 \ 
  440            std::forward<BS>(block_shape),                                                                                      \ 
  442            std::forward<O>(options),                                                                                           \ 
  446        XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC(norm_l0, xt::detail::blockwise::norm_l0_functor)
 
  447        XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC(norm_l1, xt::detail::blockwise::norm_l1_functor)
 
  448        XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC(norm_l2, xt::detail::blockwise::norm_l2_functor)
 
  449        XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC(norm_sq, xt::detail::blockwise::norm_sq_functor)
 
  450        XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC(norm_linf, xt::detail::blockwise::norm_linf_functor)
 
  452#undef XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC 
  455#define XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC(FNAME, FUNCTOR)                                                                     \ 
  460        class O = DEFAULT_STRATEGY_REDUCERS,                                                                                    \ 
  461        XTL_REQUIRES(std::negation<is_reducer_options<X>>, std::negation<xtl::is_integral<std::decay_t<X>>>)>                   \ 
  462    auto FNAME(E&& e, BS&& block_shape, double p, X&& axes, O options = O())                                                    \ 
  464        using input_expression_type = std::decay_t<E>;                                                                          \ 
  465        using functor_type = FUNCTOR<typename input_expression_type::value_type>;                                               \ 
  466        return blockwise_reducer(                                                                                               \ 
  467            std::forward<E>(e),                                                                                                 \ 
  468            std::forward<BS>(block_shape),                                                                                      \ 
  469            std::forward<X>(axes),                                                                                              \ 
  470            std::forward<O>(options),                                                                                           \ 
  474    template <class E, class BS, class X, class O = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(xtl::is_integral<std::decay_t<X>>)> \ 
  475    auto FNAME(E&& e, BS&& block_shape, double p, X axis, O options = O())                                                      \ 
  477        std::array<X, 1> axes{axis};                                                                                            \ 
  478        using input_expression_type = std::decay_t<E>;                                                                          \ 
  479        using functor_type = FUNCTOR<typename input_expression_type::value_type>;                                               \ 
  480        return blockwise_reducer(                                                                                               \ 
  481            std::forward<E>(e),                                                                                                 \ 
  482            std::forward<BS>(block_shape),                                                                                      \ 
  484            std::forward<O>(options),                                                                                           \ 
  491        class O = DEFAULT_STRATEGY_REDUCERS,                                                                                    \ 
  492        XTL_REQUIRES(is_reducer_options<O>, std::negation<xtl::is_integral<std::decay_t<O>>>)>                                  \ 
  493    auto FNAME(E&& e, BS&& block_shape, double p, O options = O())                                                              \ 
  495        using input_expression_type = std::decay_t<E>;                                                                          \ 
  496        using axes_type = filter_fixed_shape_t<typename input_expression_type::shape_type>;                                     \ 
  497        axes_type axes = xtl::make_sequence<axes_type>(e.dimension());                                                          \ 
  498        XTENSOR_ASSERT(axes.size() == e.dimension());                                                                           \ 
  499        std::iota(axes.begin(), axes.end(), 0);                                                                                 \ 
  500        using functor_type = FUNCTOR<typename input_expression_type::value_type>;                                               \ 
  501        return blockwise_reducer(                                                                                               \ 
  502            std::forward<E>(e),                                                                                                 \ 
  503            std::forward<BS>(block_shape),                                                                                      \ 
  505            std::forward<O>(options),                                                                                           \ 
  509    template <class E, class BS, class I, std::size_t N, class O = DEFAULT_STRATEGY_REDUCERS>                                   \ 
  510    auto FNAME(E&& e, BS&& block_shape, double p, const I(&axes)[N], O options = O())                                           \ 
  512        using input_expression_type = std::decay_t<E>;                                                                          \ 
  513        using functor_type = FUNCTOR<typename input_expression_type::value_type>;                                               \ 
  514        using axes_type = std::array<std::size_t, N>;                                                                           \ 
  515        auto ax = xt::forward_normalize<axes_type>(e, axes);                                                                    \ 
  516        return blockwise_reducer(                                                                                               \ 
  517            std::forward<E>(e),                                                                                                 \ 
  518            std::forward<BS>(block_shape),                                                                                      \ 
  520            std::forward<O>(options),                                                                                           \ 
  525        XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC(norm_lp_to_p, xt::detail::blockwise::norm_lp_to_p_functor);
 
  526        XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC(norm_lp, xt::detail::blockwise::norm_lp_functor);
 
  528#undef XTENSOR_BLOCKWISE_NORM_REDUCER_FUNC 
standard mathematical functions for xexpressions
auto range(A start_val, B stop_val)
Select a range from start_val to stop_val (excluded).