#ifndef XTENSOR_XBLOCKWISE_REDUCER_FUNCTORS_HPP #define XTENSOR_XBLOCKWISE_REDUCER_FUNCTORS_HPP #include #include #include #include #include "xarray.hpp" #include "xbuilder.hpp" #include "xchunked_array.hpp" #include "xchunked_assign.hpp" #include "xchunked_view.hpp" #include "xexpression.hpp" #include "xmath.hpp" #include "xnorm.hpp" #include "xreducer.hpp" #include "xtl/xclosure.hpp" #include "xtl/xsequence.hpp" #include "xutils.hpp" namespace xt { namespace detail { namespace blockwise { struct empty_reduction_variable { }; struct simple_functor_base { template auto reduction_variable(const E&) const { return empty_reduction_variable(); } template void finalize(const MR&, E&, const R&) const { } }; template struct sum_functor : public simple_functor_base { using value_type = typename std::decay_t(std::declval>()))>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::sum(input, axes, options); } template auto merge(const BR& block_result, bool first, E& result, MR&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) += block_result; } } }; template struct prod_functor : public simple_functor_base { using value_type = typename std::decay_t(std::declval>()))>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::prod(input, axes, options); } template auto merge(const BR& block_result, bool first, E& result, MR&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) *= block_result; } } }; template struct amin_functor : public simple_functor_base { using value_type = typename std::decay_t(std::declval>()))>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::amin(input, axes, options); } template auto merge(const BR& block_result, bool first, E& result, MR&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) = xt::minimum(block_result, result); } } }; template struct amax_functor : public simple_functor_base { using value_type = typename std::decay_t(std::declval>()))>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::amax(input, axes, options); } template auto merge(const BR& block_result, bool first, E& result, MR&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) = xt::maximum(block_result, result); } } }; template struct mean_functor { using value_type = typename std::decay_t(std::declval>()))>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::sum(input, axes, options); } template auto reduction_variable(const E&) const { return empty_reduction_variable(); } template auto merge(const BR& block_result, bool first, E& result, empty_reduction_variable&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) += block_result; } } template void finalize(const empty_reduction_variable&, E& results, const R& reducer) const { const auto& axes = reducer.axes(); std::decay_t factor = 1; for (auto a : axes) { factor *= reducer.input_shape()[a]; } xt::noalias(results) /= static_cast(factor); } }; template struct variance_functor { using value_type = typename std::decay_t(std::declval>()) )>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { double weight = 1.0; for (auto a : axes) { weight *= static_cast(input.shape()[a]); } return std::make_tuple( xt::variance(input, axes, options), xt::mean(input, axes, options), weight ); } template auto reduction_variable(const E&) const { return std::make_tuple(xarray(), 0.0); } template auto merge(const BR& block_result, bool first, E& variance_a, MR& mr) const { auto& mean_a = std::get<0>(mr); auto& n_a = std::get<1>(mr); const auto& variance_b = std::get<0>(block_result); const auto& mean_b = std::get<1>(block_result); const auto& n_b = std::get<2>(block_result); if (first) { xt::noalias(variance_a) = variance_b; xt::noalias(mean_a) = mean_b; n_a += n_b; } else { auto new_mean = (n_a * mean_a + n_b * mean_b) / (n_a + n_b); auto new_variance = (n_a * variance_a + n_b * variance_b + n_a * xt::pow(mean_a - new_mean, 2) + n_b * xt::pow(mean_b - new_mean, 2)) / (n_a + n_b); xt::noalias(variance_a) = new_variance; xt::noalias(mean_a) = new_mean; n_a += n_b; } } template void finalize(const MR&, E&, const R&) const { } }; template struct stddev_functor : public variance_functor { template void finalize(const MR&, E& results, const R&) const { xt::noalias(results) = xt::sqrt(results); } }; template struct norm_l0_functor : public simple_functor_base { using value_type = typename std::decay_t>()))>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::sum(xt::not_equal(input, xt::zeros(input.shape())), axes, options); } template auto merge(const BR& block_result, bool first, E& result, MR&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) += block_result; } } }; template struct norm_l1_functor : public simple_functor_base { using value_type = typename std::decay_t>()))>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::sum(xt::abs(input), axes, options); } template auto merge(const BR& block_result, bool first, E& result, MR&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) += block_result; } } }; template struct norm_l2_functor { using value_type = typename std::decay_t>()))>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::sum(xt::square(input), axes, options); } template auto reduction_variable(const E&) const { return empty_reduction_variable(); } template auto merge(const BR& block_result, bool first, E& result, empty_reduction_variable&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) += block_result; } } template void finalize(const empty_reduction_variable&, E& results, const R&) const { xt::noalias(results) = xt::sqrt(results); } }; template struct norm_sq_functor : public simple_functor_base { using value_type = typename std::decay_t>()))>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::sum(xt::square(input), axes, options); } template auto merge(const BR& block_result, bool first, E& result, MR&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) += block_result; } } }; template struct norm_linf_functor : public simple_functor_base { using value_type = typename std::decay_t>()))>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::amax(xt::abs(input), axes, options); } template auto merge(const BR& block_result, bool first, E& result, MR&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) = xt::maximum(block_result, result); } } }; template class norm_lp_to_p_functor { public: using value_type = typename std::decay_t< decltype(xt::norm_lp_to_p(std::declval>(), 1.0))>::value_type; norm_lp_to_p_functor(double p) : m_p(p) { } template auto compute(const E& input, const A& axes, const O& options) const { return xt::sum(xt::pow(input, m_p), axes, options); } template auto reduction_variable(const E&) const { return empty_reduction_variable(); } template auto merge(const BR& block_result, bool first, E& result, empty_reduction_variable&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) += block_result; } } template void finalize(const empty_reduction_variable&, E&, const R&) const { } private: double m_p; }; template class norm_lp_functor { public: norm_lp_functor(double p) : m_p(p) { } using value_type = typename std::decay_t>(), 1.0) )>::value_type; template auto compute(const E& input, const A& axes, const O& options) const { return xt::sum(xt::pow(input, m_p), axes, options); } template auto reduction_variable(const E&) const { return empty_reduction_variable(); } template auto merge(const BR& block_result, bool first, E& result, empty_reduction_variable&) const { if (first) { xt::noalias(result) = block_result; } else { xt::noalias(result) += block_result; } } template void finalize(const empty_reduction_variable&, E& results, const R&) const { results = xt::pow(results, 1.0 / m_p); } private: double m_p; }; } } } #endif